diff --git a/.gitignore b/.gitignore index e24cfca..e978b24 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,20 @@ node_modules -i18n -configs -venv + .sass-cache .DS_Store public +*.mo +*.po contents+*.lr +*.egg-info +*.pyc +__pycache__ + +### Lektor Temps ### +*~* + ### Emacs ### # -*- mode: gitignore; -*- *~ diff --git a/configs/i18n.ini b/configs/i18n.ini new file mode 100644 index 0000000..819685e --- /dev/null +++ b/configs/i18n.ini @@ -0,0 +1,4 @@ +content = en +i18npath = i18n +translations= en +translate_paragraphwise = True diff --git a/i18n/.gitignore b/i18n/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/i18n/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/venv/bin/EXIF.py b/venv/bin/EXIF.py new file mode 100755 index 0000000..751dc2d --- /dev/null +++ b/venv/bin/EXIF.py @@ -0,0 +1,132 @@ +#!/home/hiro/Workspace/newsletter/venv/bin/python +# -*- coding: utf-8 -*- +# +# +# Library to extract Exif information from digital camera image files. +# https://github.com/ianare/exif-py +# +# +# Copyright (c) 2002-2007 Gene Cash +# Copyright (c) 2007-2014 Ianaré Sévi and contributors +# +# See LICENSE.txt file for licensing information +# See CHANGES.txt file for all contributors and changes +# + +""" +Runs Exif tag extraction in command line. +""" + +import sys +import getopt +import logging +import timeit +from exifread.tags import DEFAULT_STOP_TAG, FIELD_TYPES +from exifread import process_file, exif_log, __version__ + +logger = exif_log.get_logger() + + +def usage(exit_status): + """Show command line usage.""" + msg = ('Usage: EXIF.py [OPTIONS] file1 [file2 ...]\n' + 'Extract EXIF information from digital camera image files.\n\nOptions:\n' + '-h --help Display usage information and exit.\n' + '-v --version Display version information and exit.\n' + '-q --quick Do not process MakerNotes.\n' + '-t TAG --stop-tag TAG Stop processing when this tag is retrieved.\n' + '-s --strict Run in strict mode (stop on errors).\n' + '-d --debug Run in debug mode (display extra info).\n' + '-c --color Output in color (only works with debug on POSIX).\n' + ) + print(msg) + sys.exit(exit_status) + + +def show_version(): + """Show the program version.""" + print('Version %s on Python%s' % (__version__, sys.version_info[0])) + sys.exit(0) + + +def main(): + """Parse command line options/arguments and execute.""" + try: + arg_names = ["help", "version", "quick", "strict", "debug", "stop-tag="] + opts, args = getopt.getopt(sys.argv[1:], "hvqsdct:v", arg_names) + except getopt.GetoptError: + usage(2) + + detailed = True + stop_tag = DEFAULT_STOP_TAG + debug = False + strict = False + color = False + + for option, arg in opts: + if option in ("-h", "--help"): + usage(0) + if option in ("-v", "--version"): + show_version() + if option in ("-q", "--quick"): + detailed = False + if option in ("-t", "--stop-tag"): + stop_tag = arg + if option in ("-s", "--strict"): + strict = True + if option in ("-d", "--debug"): + debug = True + if option in ("-c", "--color"): + color = True + + if not args: + usage(2) + + exif_log.setup_logger(debug, color) + + # output info for each file + for filename in args: + file_start = timeit.default_timer() + try: + img_file = open(str(filename), 'rb') + except IOError: + logger.error("'%s' is unreadable", filename) + continue + logger.info("Opening: %s", filename) + + tag_start = timeit.default_timer() + + # get the tags + data = process_file(img_file, stop_tag=stop_tag, details=detailed, strict=strict, debug=debug) + + tag_stop = timeit.default_timer() + + if not data: + logger.warning("No EXIF information found\n") + continue + + if 'JPEGThumbnail' in data: + logger.info('File has JPEG thumbnail') + del data['JPEGThumbnail'] + if 'TIFFThumbnail' in data: + logger.info('File has TIFF thumbnail') + del data['TIFFThumbnail'] + + tag_keys = list(data.keys()) + tag_keys.sort() + + for i in tag_keys: + try: + logger.info('%s (%s): %s', i, FIELD_TYPES[data[i].field_type][2], data[i].printable) + except: + logger.error("%s : %s", i, str(data[i])) + + file_stop = timeit.default_timer() + + logger.debug("Tags processed in %s seconds", tag_stop - tag_start) + logger.debug("File processed in %s seconds", file_stop - file_start) + print("") + + +if __name__ == '__main__': + main() diff --git a/venv/bin/activate b/venv/bin/activate new file mode 100644 index 0000000..ce9d6fc --- /dev/null +++ b/venv/bin/activate @@ -0,0 +1,78 @@ +# This file must be used with "source bin/activate" *from bash* +# you cannot run it directly + +deactivate () { + unset -f pydoc >/dev/null 2>&1 + + # reset old environment variables + # ! [ -z ${VAR+_} ] returns true if VAR is declared at all + if ! [ -z "${_OLD_VIRTUAL_PATH+_}" ] ; then + PATH="$_OLD_VIRTUAL_PATH" + export PATH + unset _OLD_VIRTUAL_PATH + fi + if ! [ -z "${_OLD_VIRTUAL_PYTHONHOME+_}" ] ; then + PYTHONHOME="$_OLD_VIRTUAL_PYTHONHOME" + export PYTHONHOME + unset _OLD_VIRTUAL_PYTHONHOME + fi + + # This should detect bash and zsh, which have a hash command that must + # be called to get it to forget past commands. Without forgetting + # past commands the $PATH changes we made may not be respected + if [ -n "${BASH-}" ] || [ -n "${ZSH_VERSION-}" ] ; then + hash -r 2>/dev/null + fi + + if ! [ -z "${_OLD_VIRTUAL_PS1+_}" ] ; then + PS1="$_OLD_VIRTUAL_PS1" + export PS1 + unset _OLD_VIRTUAL_PS1 + fi + + unset VIRTUAL_ENV + if [ ! "${1-}" = "nondestructive" ] ; then + # Self destruct! + unset -f deactivate + fi +} + +# unset irrelevant variables +deactivate nondestructive + +VIRTUAL_ENV="/home/hiro/Workspace/newsletter/venv" +export VIRTUAL_ENV + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/bin:$PATH" +export PATH + +# unset PYTHONHOME if set +if ! [ -z "${PYTHONHOME+_}" ] ; then + _OLD_VIRTUAL_PYTHONHOME="$PYTHONHOME" + unset PYTHONHOME +fi + +if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT-}" ] ; then + _OLD_VIRTUAL_PS1="$PS1" + if [ "x" != x ] ; then + PS1="$PS1" + else + PS1="(`basename \"$VIRTUAL_ENV\"`) $PS1" + fi + export PS1 +fi + +# Make sure to unalias pydoc if it's already there +alias pydoc 2>/dev/null >/dev/null && unalias pydoc + +pydoc () { + python -m pydoc "$@" +} + +# This should detect bash and zsh, which have a hash command that must +# be called to get it to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +if [ -n "${BASH-}" ] || [ -n "${ZSH_VERSION-}" ] ; then + hash -r 2>/dev/null +fi diff --git a/venv/bin/activate.csh b/venv/bin/activate.csh new file mode 100644 index 0000000..f46dd19 --- /dev/null +++ b/venv/bin/activate.csh @@ -0,0 +1,36 @@ +# This file must be used with "source bin/activate.csh" *from csh*. +# You cannot run it directly. +# Created by Davide Di Blasi . + +alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate && unalias pydoc' + +# Unset irrelevant variables. +deactivate nondestructive + +setenv VIRTUAL_ENV "/home/hiro/Workspace/newsletter/venv" + +set _OLD_VIRTUAL_PATH="$PATH" +setenv PATH "$VIRTUAL_ENV/bin:$PATH" + + + +if ("" != "") then + set env_name = "" +else + set env_name = `basename "$VIRTUAL_ENV"` +endif + +# Could be in a non-interactive environment, +# in which case, $prompt is undefined and we wouldn't +# care about the prompt anyway. +if ( $?prompt ) then + set _OLD_VIRTUAL_PROMPT="$prompt" + set prompt = "[$env_name] $prompt" +endif + +unset env_name + +alias pydoc python -m pydoc + +rehash + diff --git a/venv/bin/activate.fish b/venv/bin/activate.fish new file mode 100644 index 0000000..e351713 --- /dev/null +++ b/venv/bin/activate.fish @@ -0,0 +1,76 @@ +# This file must be used using `. bin/activate.fish` *within a running fish ( http://fishshell.com ) session*. +# Do not run it directly. + +function deactivate -d 'Exit virtualenv mode and return to the normal environment.' + # reset old environment variables + if test -n "$_OLD_VIRTUAL_PATH" + set -gx PATH $_OLD_VIRTUAL_PATH + set -e _OLD_VIRTUAL_PATH + end + + if test -n "$_OLD_VIRTUAL_PYTHONHOME" + set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME + set -e _OLD_VIRTUAL_PYTHONHOME + end + + if test -n "$_OLD_FISH_PROMPT_OVERRIDE" + # Set an empty local `$fish_function_path` to allow the removal of `fish_prompt` using `functions -e`. + set -l fish_function_path + + # Erase virtualenv's `fish_prompt` and restore the original. + functions -e fish_prompt + functions -c _old_fish_prompt fish_prompt + functions -e _old_fish_prompt + set -e _OLD_FISH_PROMPT_OVERRIDE + end + + set -e VIRTUAL_ENV + + if test "$argv[1]" != 'nondestructive' + # Self-destruct! + functions -e pydoc + functions -e deactivate + end +end + +# Unset irrelevant variables. +deactivate nondestructive + +set -gx VIRTUAL_ENV "/home/hiro/Workspace/newsletter/venv" + +set -gx _OLD_VIRTUAL_PATH $PATH +set -gx PATH "$VIRTUAL_ENV/bin" $PATH + +# Unset `$PYTHONHOME` if set. +if set -q PYTHONHOME + set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME + set -e PYTHONHOME +end + +function pydoc + python -m pydoc $argv +end + +if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" + # Copy the current `fish_prompt` function as `_old_fish_prompt`. + functions -c fish_prompt _old_fish_prompt + + function fish_prompt + # Save the current $status, for fish_prompts that display it. + set -l old_status $status + + # Prompt override provided? + # If not, just prepend the environment name. + if test -n "" + printf '%s%s' "" (set_color normal) + else + printf '%s(%s) ' (set_color normal) (basename "$VIRTUAL_ENV") + end + + # Restore the original $status + echo "exit $old_status" | source + _old_fish_prompt + end + + set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" +end diff --git a/venv/bin/activate_this.py b/venv/bin/activate_this.py new file mode 100644 index 0000000..f18193b --- /dev/null +++ b/venv/bin/activate_this.py @@ -0,0 +1,34 @@ +"""By using execfile(this_file, dict(__file__=this_file)) you will +activate this virtualenv environment. + +This can be used when you must use an existing Python interpreter, not +the virtualenv bin/python +""" + +try: + __file__ +except NameError: + raise AssertionError( + "You must run this like execfile('path/to/activate_this.py', dict(__file__='path/to/activate_this.py'))") +import sys +import os + +old_os_path = os.environ.get('PATH', '') +os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + os.pathsep + old_os_path +base = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +if sys.platform == 'win32': + site_packages = os.path.join(base, 'Lib', 'site-packages') +else: + site_packages = os.path.join(base, 'lib', 'python%s' % sys.version[:3], 'site-packages') +prev_sys_path = list(sys.path) +import site +site.addsitedir(site_packages) +sys.real_prefix = sys.prefix +sys.prefix = base +# Move the added items to the front of the path: +new_sys_path = [] +for item in list(sys.path): + if item not in prev_sys_path: + new_sys_path.append(item) + sys.path.remove(item) +sys.path[:0] = new_sys_path diff --git a/venv/bin/chardetect b/venv/bin/chardetect new file mode 100755 index 0000000..7f9e0fc --- /dev/null +++ b/venv/bin/chardetect @@ -0,0 +1,11 @@ +#!/home/hiro/Workspace/newsletter/venv/bin/python + +# -*- coding: utf-8 -*- +import re +import sys + +from chardet.cli.chardetect import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/easy_install b/venv/bin/easy_install new file mode 100755 index 0000000..f1f1bd5 --- /dev/null +++ b/venv/bin/easy_install @@ -0,0 +1,11 @@ +#!/home/hiro/Workspace/newsletter/venv/bin/python + +# -*- coding: utf-8 -*- +import re +import sys + +from setuptools.command.easy_install import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/easy_install-2.7 b/venv/bin/easy_install-2.7 new file mode 100755 index 0000000..f1f1bd5 --- /dev/null +++ b/venv/bin/easy_install-2.7 @@ -0,0 +1,11 @@ +#!/home/hiro/Workspace/newsletter/venv/bin/python + +# -*- coding: utf-8 -*- +import re +import sys + +from setuptools.command.easy_install import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/flask b/venv/bin/flask new file mode 100755 index 0000000..c1e3474 --- /dev/null +++ b/venv/bin/flask @@ -0,0 +1,11 @@ +#!/home/hiro/Workspace/newsletter/venv/bin/python + +# -*- coding: utf-8 -*- +import re +import sys + +from flask.cli import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/lektor b/venv/bin/lektor new file mode 100755 index 0000000..d4d5771 --- /dev/null +++ b/venv/bin/lektor @@ -0,0 +1,11 @@ +#!/home/hiro/Workspace/newsletter/venv/bin/python + +# -*- coding: utf-8 -*- +import re +import sys + +from lektor.cli import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/pip b/venv/bin/pip new file mode 100755 index 0000000..0a53e38 --- /dev/null +++ b/venv/bin/pip @@ -0,0 +1,11 @@ +#!/home/hiro/Workspace/newsletter/venv/bin/python + +# -*- coding: utf-8 -*- +import re +import sys + +from pip._internal import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/pip2 b/venv/bin/pip2 new file mode 100755 index 0000000..0a53e38 --- /dev/null +++ b/venv/bin/pip2 @@ -0,0 +1,11 @@ +#!/home/hiro/Workspace/newsletter/venv/bin/python + +# -*- coding: utf-8 -*- +import re +import sys + +from pip._internal import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/pip2.7 b/venv/bin/pip2.7 new file mode 100755 index 0000000..0a53e38 --- /dev/null +++ b/venv/bin/pip2.7 @@ -0,0 +1,11 @@ +#!/home/hiro/Workspace/newsletter/venv/bin/python + +# -*- coding: utf-8 -*- +import re +import sys + +from pip._internal import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/pybabel b/venv/bin/pybabel new file mode 100755 index 0000000..6d50e54 --- /dev/null +++ b/venv/bin/pybabel @@ -0,0 +1,11 @@ +#!/home/hiro/Workspace/newsletter/venv/bin/python + +# -*- coding: utf-8 -*- +import re +import sys + +from babel.messages.frontend import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/python b/venv/bin/python new file mode 100755 index 0000000..58e3d46 Binary files /dev/null and b/venv/bin/python differ diff --git a/venv/bin/python-config b/venv/bin/python-config new file mode 100755 index 0000000..f27789b --- /dev/null +++ b/venv/bin/python-config @@ -0,0 +1,78 @@ +#!/home/hiro/Workspace/newsletter/venv/bin/python + +import sys +import getopt +import sysconfig + +valid_opts = ['prefix', 'exec-prefix', 'includes', 'libs', 'cflags', + 'ldflags', 'help'] + +if sys.version_info >= (3, 2): + valid_opts.insert(-1, 'extension-suffix') + valid_opts.append('abiflags') +if sys.version_info >= (3, 3): + valid_opts.append('configdir') + + +def exit_with_usage(code=1): + sys.stderr.write("Usage: {0} [{1}]\n".format( + sys.argv[0], '|'.join('--'+opt for opt in valid_opts))) + sys.exit(code) + +try: + opts, args = getopt.getopt(sys.argv[1:], '', valid_opts) +except getopt.error: + exit_with_usage() + +if not opts: + exit_with_usage() + +pyver = sysconfig.get_config_var('VERSION') +getvar = sysconfig.get_config_var + +opt_flags = [flag for (flag, val) in opts] + +if '--help' in opt_flags: + exit_with_usage(code=0) + +for opt in opt_flags: + if opt == '--prefix': + print(sysconfig.get_config_var('prefix')) + + elif opt == '--exec-prefix': + print(sysconfig.get_config_var('exec_prefix')) + + elif opt in ('--includes', '--cflags'): + flags = ['-I' + sysconfig.get_path('include'), + '-I' + sysconfig.get_path('platinclude')] + if opt == '--cflags': + flags.extend(getvar('CFLAGS').split()) + print(' '.join(flags)) + + elif opt in ('--libs', '--ldflags'): + abiflags = getattr(sys, 'abiflags', '') + libs = ['-lpython' + pyver + abiflags] + libs += getvar('LIBS').split() + libs += getvar('SYSLIBS').split() + # add the prefix/lib/pythonX.Y/config dir, but only if there is no + # shared library in prefix/lib/. + if opt == '--ldflags': + if not getvar('Py_ENABLE_SHARED'): + libs.insert(0, '-L' + getvar('LIBPL')) + if not getvar('PYTHONFRAMEWORK'): + libs.extend(getvar('LINKFORSHARED').split()) + print(' '.join(libs)) + + elif opt == '--extension-suffix': + ext_suffix = sysconfig.get_config_var('EXT_SUFFIX') + if ext_suffix is None: + ext_suffix = sysconfig.get_config_var('SO') + print(ext_suffix) + + elif opt == '--abiflags': + if not getattr(sys, 'abiflags', None): + exit_with_usage() + print(sys.abiflags) + + elif opt == '--configdir': + print(sysconfig.get_config_var('LIBPL')) diff --git a/venv/bin/python2 b/venv/bin/python2 new file mode 120000 index 0000000..d8654aa --- /dev/null +++ b/venv/bin/python2 @@ -0,0 +1 @@ +python \ No newline at end of file diff --git a/venv/bin/python2.7 b/venv/bin/python2.7 new file mode 120000 index 0000000..d8654aa --- /dev/null +++ b/venv/bin/python2.7 @@ -0,0 +1 @@ +python \ No newline at end of file diff --git a/venv/bin/watchmedo b/venv/bin/watchmedo new file mode 100755 index 0000000..d705ba7 --- /dev/null +++ b/venv/bin/watchmedo @@ -0,0 +1,11 @@ +#!/home/hiro/Workspace/newsletter/venv/bin/python + +# -*- coding: utf-8 -*- +import re +import sys + +from watchdog.watchmedo import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/wheel b/venv/bin/wheel new file mode 100755 index 0000000..fc6f9f4 --- /dev/null +++ b/venv/bin/wheel @@ -0,0 +1,11 @@ +#!/home/hiro/Workspace/newsletter/venv/bin/python + +# -*- coding: utf-8 -*- +import re +import sys + +from wheel.tool import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/include/python2.7 b/venv/include/python2.7 new file mode 120000 index 0000000..ad4ca80 --- /dev/null +++ b/venv/include/python2.7 @@ -0,0 +1 @@ +/usr/include/python2.7 \ No newline at end of file diff --git a/venv/lib/python2.7/UserDict.py b/venv/lib/python2.7/UserDict.py new file mode 120000 index 0000000..1dcde33 --- /dev/null +++ b/venv/lib/python2.7/UserDict.py @@ -0,0 +1 @@ +/usr/lib/python2.7/UserDict.py \ No newline at end of file diff --git a/venv/lib/python2.7/_abcoll.py b/venv/lib/python2.7/_abcoll.py new file mode 120000 index 0000000..e39c38d --- /dev/null +++ b/venv/lib/python2.7/_abcoll.py @@ -0,0 +1 @@ +/usr/lib/python2.7/_abcoll.py \ No newline at end of file diff --git a/venv/lib/python2.7/_weakrefset.py b/venv/lib/python2.7/_weakrefset.py new file mode 120000 index 0000000..a3c1cd4 --- /dev/null +++ b/venv/lib/python2.7/_weakrefset.py @@ -0,0 +1 @@ +/usr/lib/python2.7/_weakrefset.py \ No newline at end of file diff --git a/venv/lib/python2.7/abc.py b/venv/lib/python2.7/abc.py new file mode 120000 index 0000000..cb3e5d1 --- /dev/null +++ b/venv/lib/python2.7/abc.py @@ -0,0 +1 @@ +/usr/lib/python2.7/abc.py \ No newline at end of file diff --git a/venv/lib/python2.7/codecs.py b/venv/lib/python2.7/codecs.py new file mode 120000 index 0000000..50169dc --- /dev/null +++ b/venv/lib/python2.7/codecs.py @@ -0,0 +1 @@ +/usr/lib/python2.7/codecs.py \ No newline at end of file diff --git a/venv/lib/python2.7/copy_reg.py b/venv/lib/python2.7/copy_reg.py new file mode 120000 index 0000000..5dc0af3 --- /dev/null +++ b/venv/lib/python2.7/copy_reg.py @@ -0,0 +1 @@ +/usr/lib/python2.7/copy_reg.py \ No newline at end of file diff --git a/venv/lib/python2.7/distutils/__init__.py b/venv/lib/python2.7/distutils/__init__.py new file mode 100644 index 0000000..29fc1da --- /dev/null +++ b/venv/lib/python2.7/distutils/__init__.py @@ -0,0 +1,101 @@ +import os +import sys +import warnings +import imp +import opcode # opcode is not a virtualenv module, so we can use it to find the stdlib + # Important! To work on pypy, this must be a module that resides in the + # lib-python/modified-x.y.z directory + +dirname = os.path.dirname + +distutils_path = os.path.join(os.path.dirname(opcode.__file__), 'distutils') +if os.path.normpath(distutils_path) == os.path.dirname(os.path.normpath(__file__)): + warnings.warn( + "The virtualenv distutils package at %s appears to be in the same location as the system distutils?") +else: + __path__.insert(0, distutils_path) + real_distutils = imp.load_module("_virtualenv_distutils", None, distutils_path, ('', '', imp.PKG_DIRECTORY)) + # Copy the relevant attributes + try: + __revision__ = real_distutils.__revision__ + except AttributeError: + pass + __version__ = real_distutils.__version__ + +from distutils import dist, sysconfig + +try: + basestring +except NameError: + basestring = str + +## patch build_ext (distutils doesn't know how to get the libs directory +## path on windows - it hardcodes the paths around the patched sys.prefix) + +if sys.platform == 'win32': + from distutils.command.build_ext import build_ext as old_build_ext + class build_ext(old_build_ext): + def finalize_options (self): + if self.library_dirs is None: + self.library_dirs = [] + elif isinstance(self.library_dirs, basestring): + self.library_dirs = self.library_dirs.split(os.pathsep) + + self.library_dirs.insert(0, os.path.join(sys.real_prefix, "Libs")) + old_build_ext.finalize_options(self) + + from distutils.command import build_ext as build_ext_module + build_ext_module.build_ext = build_ext + +## distutils.dist patches: + +old_find_config_files = dist.Distribution.find_config_files +def find_config_files(self): + found = old_find_config_files(self) + system_distutils = os.path.join(distutils_path, 'distutils.cfg') + #if os.path.exists(system_distutils): + # found.insert(0, system_distutils) + # What to call the per-user config file + if os.name == 'posix': + user_filename = ".pydistutils.cfg" + else: + user_filename = "pydistutils.cfg" + user_filename = os.path.join(sys.prefix, user_filename) + if os.path.isfile(user_filename): + for item in list(found): + if item.endswith('pydistutils.cfg'): + found.remove(item) + found.append(user_filename) + return found +dist.Distribution.find_config_files = find_config_files + +## distutils.sysconfig patches: + +old_get_python_inc = sysconfig.get_python_inc +def sysconfig_get_python_inc(plat_specific=0, prefix=None): + if prefix is None: + prefix = sys.real_prefix + return old_get_python_inc(plat_specific, prefix) +sysconfig_get_python_inc.__doc__ = old_get_python_inc.__doc__ +sysconfig.get_python_inc = sysconfig_get_python_inc + +old_get_python_lib = sysconfig.get_python_lib +def sysconfig_get_python_lib(plat_specific=0, standard_lib=0, prefix=None): + if standard_lib and prefix is None: + prefix = sys.real_prefix + return old_get_python_lib(plat_specific, standard_lib, prefix) +sysconfig_get_python_lib.__doc__ = old_get_python_lib.__doc__ +sysconfig.get_python_lib = sysconfig_get_python_lib + +old_get_config_vars = sysconfig.get_config_vars +def sysconfig_get_config_vars(*args): + real_vars = old_get_config_vars(*args) + if sys.platform == 'win32': + lib_dir = os.path.join(sys.real_prefix, "libs") + if isinstance(real_vars, dict) and 'LIBDIR' not in real_vars: + real_vars['LIBDIR'] = lib_dir # asked for all + elif isinstance(real_vars, list) and 'LIBDIR' in args: + real_vars = real_vars + [lib_dir] # asked for list + return real_vars +sysconfig_get_config_vars.__doc__ = old_get_config_vars.__doc__ +sysconfig.get_config_vars = sysconfig_get_config_vars diff --git a/venv/lib/python2.7/distutils/distutils.cfg b/venv/lib/python2.7/distutils/distutils.cfg new file mode 100644 index 0000000..1af230e --- /dev/null +++ b/venv/lib/python2.7/distutils/distutils.cfg @@ -0,0 +1,6 @@ +# This is a config file local to this virtualenv installation +# You may include options that will be used by all distutils commands, +# and by easy_install. For instance: +# +# [easy_install] +# find_links = http://mylocalsite diff --git a/venv/lib/python2.7/encodings b/venv/lib/python2.7/encodings new file mode 120000 index 0000000..1250ad8 --- /dev/null +++ b/venv/lib/python2.7/encodings @@ -0,0 +1 @@ +/usr/lib/python2.7/encodings \ No newline at end of file diff --git a/venv/lib/python2.7/fnmatch.py b/venv/lib/python2.7/fnmatch.py new file mode 120000 index 0000000..ec3e10c --- /dev/null +++ b/venv/lib/python2.7/fnmatch.py @@ -0,0 +1 @@ +/usr/lib/python2.7/fnmatch.py \ No newline at end of file diff --git a/venv/lib/python2.7/genericpath.py b/venv/lib/python2.7/genericpath.py new file mode 120000 index 0000000..cb8897c --- /dev/null +++ b/venv/lib/python2.7/genericpath.py @@ -0,0 +1 @@ +/usr/lib/python2.7/genericpath.py \ No newline at end of file diff --git a/venv/lib/python2.7/lib-dynload b/venv/lib/python2.7/lib-dynload new file mode 120000 index 0000000..c706a1e --- /dev/null +++ b/venv/lib/python2.7/lib-dynload @@ -0,0 +1 @@ +/usr/lib/python2.7/lib-dynload \ No newline at end of file diff --git a/venv/lib/python2.7/linecache.py b/venv/lib/python2.7/linecache.py new file mode 120000 index 0000000..943c429 --- /dev/null +++ b/venv/lib/python2.7/linecache.py @@ -0,0 +1 @@ +/usr/lib/python2.7/linecache.py \ No newline at end of file diff --git a/venv/lib/python2.7/locale.py b/venv/lib/python2.7/locale.py new file mode 120000 index 0000000..92c243c --- /dev/null +++ b/venv/lib/python2.7/locale.py @@ -0,0 +1 @@ +/usr/lib/python2.7/locale.py \ No newline at end of file diff --git a/venv/lib/python2.7/no-global-site-packages.txt b/venv/lib/python2.7/no-global-site-packages.txt new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python2.7/ntpath.py b/venv/lib/python2.7/ntpath.py new file mode 120000 index 0000000..5659ae1 --- /dev/null +++ b/venv/lib/python2.7/ntpath.py @@ -0,0 +1 @@ +/usr/lib/python2.7/ntpath.py \ No newline at end of file diff --git a/venv/lib/python2.7/orig-prefix.txt b/venv/lib/python2.7/orig-prefix.txt new file mode 100644 index 0000000..e25db58 --- /dev/null +++ b/venv/lib/python2.7/orig-prefix.txt @@ -0,0 +1 @@ +/usr \ No newline at end of file diff --git a/venv/lib/python2.7/os.py b/venv/lib/python2.7/os.py new file mode 120000 index 0000000..950fc8d --- /dev/null +++ b/venv/lib/python2.7/os.py @@ -0,0 +1 @@ +/usr/lib/python2.7/os.py \ No newline at end of file diff --git a/venv/lib/python2.7/posixpath.py b/venv/lib/python2.7/posixpath.py new file mode 120000 index 0000000..30cb8ca --- /dev/null +++ b/venv/lib/python2.7/posixpath.py @@ -0,0 +1 @@ +/usr/lib/python2.7/posixpath.py \ No newline at end of file diff --git a/venv/lib/python2.7/re.py b/venv/lib/python2.7/re.py new file mode 120000 index 0000000..56a0731 --- /dev/null +++ b/venv/lib/python2.7/re.py @@ -0,0 +1 @@ +/usr/lib/python2.7/re.py \ No newline at end of file diff --git a/venv/lib/python2.7/site-packages/.libs_cffi_backend/libffi-45372312.so.6.0.4 b/venv/lib/python2.7/site-packages/.libs_cffi_backend/libffi-45372312.so.6.0.4 new file mode 100755 index 0000000..59e65c0 Binary files /dev/null and b/venv/lib/python2.7/site-packages/.libs_cffi_backend/libffi-45372312.so.6.0.4 differ diff --git a/venv/lib/python2.7/site-packages/Babel-2.6.0.dist-info/INSTALLER b/venv/lib/python2.7/site-packages/Babel-2.6.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python2.7/site-packages/Babel-2.6.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python2.7/site-packages/Babel-2.6.0.dist-info/LICENSE.txt b/venv/lib/python2.7/site-packages/Babel-2.6.0.dist-info/LICENSE.txt new file mode 100644 index 0000000..b517a52 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Babel-2.6.0.dist-info/LICENSE.txt @@ -0,0 +1,29 @@ +Copyright (c) 2013-2018 by the Babel Team, see AUTHORS for more information. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The name of the author may not be used to endorse or promote + products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/lib/python2.7/site-packages/Babel-2.6.0.dist-info/METADATA b/venv/lib/python2.7/site-packages/Babel-2.6.0.dist-info/METADATA new file mode 100644 index 0000000..854af03 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Babel-2.6.0.dist-info/METADATA @@ -0,0 +1,30 @@ +Metadata-Version: 2.1 +Name: Babel +Version: 2.6.0 +Summary: Internationalization utilities +Home-page: http://babel.pocoo.org/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +License: BSD +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* +Requires-Dist: pytz (>=0a) + +A collection of tools for internationalizing Python applications. + + diff --git a/venv/lib/python2.7/site-packages/Babel-2.6.0.dist-info/RECORD b/venv/lib/python2.7/site-packages/Babel-2.6.0.dist-info/RECORD new file mode 100644 index 0000000..7868808 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Babel-2.6.0.dist-info/RECORD @@ -0,0 +1,792 @@ +Babel-2.6.0.dist-info/LICENSE.txt,sha256=F4uZyQ34mNC-6EvTNfNrZ5x2-vqdPCiLTq6k69kthgI,1451 +Babel-2.6.0.dist-info/METADATA,sha256=4F6JnSPqnoIJ96elOSy-c-Igu4cX3tRCHH6Dc-gUTEY,1169 +Babel-2.6.0.dist-info/RECORD,, +Babel-2.6.0.dist-info/WHEEL,sha256=J3CsTk7Mf2JNUyhImI-mjX-fmI4oDjyiXgWT4qgZiCE,110 +Babel-2.6.0.dist-info/entry_points.txt,sha256=dyIkorJhQj3IvTvmMylr1wEzW7vfxTw5RTOWa8zoqh0,764 +Babel-2.6.0.dist-info/top_level.txt,sha256=mQO3vNkqlcYs_xRaL5EpRIy1IRjMp4N9_vdwmiemPXo,6 +babel/__init__.py,sha256=cEfRV-f_6Fabbhg15hffY1ypWc783sGPOgL4re2CWL0,714 +babel/_compat.py,sha256=Xj04LRv0xGTmr8BdU-rEi2Bwj2lkXHxJH8nI9aMtdhY,1676 +babel/core.py,sha256=iBd57fCwKHNB8FlJENjiQOtwR1cKejeYfv8DTn4QdrY,36894 +babel/dates.py,sha256=dRLm7HTTTxuDSYH4hGvd7u86eLQZDA4B2RRJ-k2xWOU,66933 +babel/global.dat,sha256=l3phuoeOS90LSmp_YXlaggBC0tZHZ7qEunGOV0WhmmU,248621 +babel/languages.py,sha256=2xIS92vR-dAFKuOfCSAc_5nhg5LFwsHhmlWJeDnIvgQ,2742 +babel/lists.py,sha256=BqCQEdVn2TR1gwTlUbITO_UuJJ-RIa4vbMjzoPXSKuY,2720 +babel/localedata.py,sha256=lqTqZ5OXf5pmh-QYrlTa7gHms48zeWIs4meHv6S2uTA,6959 +babel/numbers.py,sha256=Tu8nSwSeIZITAmRXYjoWeLQt3rrBaYrYuDV10mlg3bs,32745 +babel/plural.py,sha256=KbIZEUY6On7NPVb8F6cWDvNDBk-WYYR2ctTdx5QvcfA,21312 +babel/support.py,sha256=uej0yw-kYYz3nLESXxk7rVceMiu-cMo1zdgzfNBgwYc,22302 +babel/units.py,sha256=-xQnD_MZJ1lNpiqA7I09I3-pWo1o4RTFacMCXO-p7cE,11095 +babel/util.py,sha256=vmQS4n0tUXwAMaHmYE_qU0TV4Z2Y2r6olejcf3gsGQc,8801 +babel/locale-data/af.dat,sha256=I1El0veHhHkio0wX1WbWKWKXxiNcHPoLGP9QGU0QrrQ,162490 +babel/locale-data/af_NA.dat,sha256=nMWmWh8dFdp7VQvBxesHS8u0hGsa9UkaE203QaldSwM,1076 +babel/locale-data/af_ZA.dat,sha256=7gx1WD8yfIAKG17BKT0sqW146xKS5GTJlMEnC4DP_88,594 +babel/locale-data/agq.dat,sha256=HE7KGjcwZGJiwwE3ZhcrzJvmDJRGewZ1gX9xoyxcplg,17361 +babel/locale-data/agq_CM.dat,sha256=V_cnrPohWiXWQKh2kPtuWDBCZuUZ1ggafN4w77okvoo,595 +babel/locale-data/ak.dat,sha256=hP7h4AJ8B_RNCag6_mQHiL9IE2j_4676rE6PLGGNRBE,15873 +babel/locale-data/ak_GH.dat,sha256=2Q1KDrKPO35AMXg9hb5Y3M85lBC5EvWPrUhu269hmQg,575 +babel/locale-data/am.dat,sha256=ECv44K_9_Th4jMjgNnSMpBRkqzZus9hz9GkkPOLiS64,193348 +babel/locale-data/am_ET.dat,sha256=SJqsAU74ok1VoyFedn2Rm6r1NcNOatz7XEV91cBl_IM,594 +babel/locale-data/ar.dat,sha256=wW5Hx0szLUTI4X2jeXsMg9K2vUAXN1_UJg9EB67ZcOA,320037 +babel/locale-data/ar_001.dat,sha256=KCeAowfKtRvCLch5Y-0aRdV3r-EhmhUaWnPXV8MmaWI,1666 +babel/locale-data/ar_AE.dat,sha256=0NX1Pom4pT4zLe819bPsImGLSE7_QVC0WqMAX3apctQ,1024 +babel/locale-data/ar_BH.dat,sha256=0l45NgKTVsm4fvjOx6VhPCbGi2G_jYfRmsOGAttBKCs,637 +babel/locale-data/ar_DJ.dat,sha256=PiTGkF8Nu4DG_M7Yoqa49JVOcnI-aDsU0Y6C3qX_LxA,615 +babel/locale-data/ar_DZ.dat,sha256=NzembXe9V3sa-zNLTnAfBWp6smEIhNSVPRc1lhHjpxk,2213 +babel/locale-data/ar_EG.dat,sha256=a-FinnbB9GuiGmXHm7oQHKo6jRzCehoS-Gdru1vuNAc,674 +babel/locale-data/ar_EH.dat,sha256=eniOJWRhKI3Tbw9sQKIjK49nEKgr3GAV3L_ovPFzPt8,575 +babel/locale-data/ar_ER.dat,sha256=dGkTBxwZ5zXbwURg8GPFieSZbqtUEvHxVk3HNoZjd8Y,596 +babel/locale-data/ar_IL.dat,sha256=yi0bpgaDojP3cpnlE4rQGCn-st4aH48kbHosI4TYq1E,1181 +babel/locale-data/ar_IQ.dat,sha256=adVMNcG1NrGTf_y8fPywE7NDyjwRrp5W7ht3_LOQ6IM,2322 +babel/locale-data/ar_JO.dat,sha256=zB4mLkFpJxajHlTW1T6AUg6t2G8sBW4qNYDyRjha39U,2321 +babel/locale-data/ar_KM.dat,sha256=sPUf0ckmEscGb5Mn5pjyz1jUh6VWrWgm75L8QMGKSAs,1147 +babel/locale-data/ar_KW.dat,sha256=U5DCu2920Fevfag_6N71RUg9n1fs3iaMhgSGLcAMVKE,637 +babel/locale-data/ar_LB.dat,sha256=9R-isUiC0mZOeN3rD753YCBjqm0iFEdc8rXjyEbvhbE,2322 +babel/locale-data/ar_LY.dat,sha256=y6v7r9roARGwNbdRQmZYwT6TLIQMn81vbXShqasPw9w,1638 +babel/locale-data/ar_MA.dat,sha256=VyTJmBNoBj6l4x8iTTfoeK6q2dBpC6stg25ibyvnPCw,2550 +babel/locale-data/ar_MR.dat,sha256=peGJph3lNgYriME3ZqT-RqeQfjQRb1PN-mG2ion8ljA,2159 +babel/locale-data/ar_OM.dat,sha256=bEyvT722Rz80DzC1nkxNv-a3sGaEAgrfeBvHHW55cMg,637 +babel/locale-data/ar_PS.dat,sha256=cRvobvn4SQUd5NDwhVPGZeru7wlarmySyrJ7qHg6WLo,2259 +babel/locale-data/ar_QA.dat,sha256=I9NyxwTl3Ts_Bin9Egc1JNUxPnLn0iva_OA1Mok_lBo,637 +babel/locale-data/ar_SA.dat,sha256=PJ8noLePXory-HE_ra-OM9hIiOTdW8qJMe-YUCexu4U,1856 +babel/locale-data/ar_SD.dat,sha256=JEwLCeBvU5LPpiCeeY4HbeJtE_lZvOx37o3fE37DwKU,637 +babel/locale-data/ar_SO.dat,sha256=xKHiH4DpktwL5E0qACWksFbFyPjMIUZUvACPA38ybkU,594 +babel/locale-data/ar_SS.dat,sha256=cdhJxqTyS-r9AxZ1kmThd6TuwRDqxm7Ukm_1qk9cELk,617 +babel/locale-data/ar_SY.dat,sha256=GhCnA7ywlBYT1cPZ-oaX-5FUzWAz4oFKg3E20j3RGns,2321 +babel/locale-data/ar_TD.dat,sha256=dqigfWyhtxh05dym1JGihIvJNMbqR8RiupIL697Z_KA,575 +babel/locale-data/ar_TN.dat,sha256=9Ejyisc59-o4CKxmPDxETgEMCeiFe6geqH957M0m4HE,2213 +babel/locale-data/ar_YE.dat,sha256=5h0gcvLollFJZUDXy8KrrrwHfTpGbEUEyl8DA5-TxSM,637 +babel/locale-data/as.dat,sha256=y-aAKRJLNpX13jG_jXeraJ6LdkqlkDVbSaECd9apM1A,220525 +babel/locale-data/as_IN.dat,sha256=zNErf1weV_mDN4rnW0L2rM4L5078LitDV_x16beqFgk,617 +babel/locale-data/asa.dat,sha256=o1EbJqsCa9DyHbxxRD9TMndT0iLBNOPwQJZE5ACc6Gs,16202 +babel/locale-data/asa_TZ.dat,sha256=Q7cxJZ0vM1tLhbZwDmEzgQZvtLxvwrx8Ri8WCgZyEzM,576 +babel/locale-data/ast.dat,sha256=1hli7Od1sG5cGSVAgAfA_d5uRDDvN8gJZ_VeJOVbn1w,211391 +babel/locale-data/ast_ES.dat,sha256=3hphQXd8HQELORaTTUVsonYBhTt13NKgHjJP8Z28qJc,613 +babel/locale-data/az.dat,sha256=pLU1z_7bMUaWBBOrq1-qTyX4PjzlHuSK8tiVv_A7Y4Q,186762 +babel/locale-data/az_Cyrl.dat,sha256=b4ShSF69zwqCH9DN2K3yoziNJ_11KMiyrsS7Fh7zYMI,38949 +babel/locale-data/az_Cyrl_AZ.dat,sha256=YMWKOj_GsclfGn-kM-tGtIHJ8ouiyoQoNzV-dZSncto,594 +babel/locale-data/az_Latn.dat,sha256=1qwqks7q4Ux5QjWfklZGB_gO5-BgBIoRVI-VnIJVlMs,2208 +babel/locale-data/az_Latn_AZ.dat,sha256=YMWKOj_GsclfGn-kM-tGtIHJ8ouiyoQoNzV-dZSncto,594 +babel/locale-data/bas.dat,sha256=ClOGaCCnQW2rHIZqpsYsSNbC86XpCdGKM_rw0MBR7Bs,17146 +babel/locale-data/bas_CM.dat,sha256=Egk85a6F970nOvERbTHHs1ejjXySEfk0_BwHJgLaYnE,595 +babel/locale-data/be.dat,sha256=zbRODsnNMsV3PKUet7MEFWgsttsrAq-RdUZ-wm-gb-g,246504 +babel/locale-data/be_BY.dat,sha256=ETNrc_a2EZNbwXWtuxoynifL--Vwc4kpgVJFiOAB4oU,594 +babel/locale-data/bem.dat,sha256=KNZ_S7_Ev50D1MMPChotZOdTnw3OM-lOEdROS745QBA,6517 +babel/locale-data/bem_ZM.dat,sha256=yrXhdGEP-7J5TgqmY__4394Z2ZY0FLIEpV2mk0_twkc,576 +babel/locale-data/bez.dat,sha256=nHWtGkEUv9ZxCE4Hq2GrQbNtEO6cgzOiE1AU20omv-4,16993 +babel/locale-data/bez_TZ.dat,sha256=JFpk70P5VHc2i-8rh8xwOBnd_Q47VSj25hbaf7cb4kU,576 +babel/locale-data/bg.dat,sha256=aheQFu_noLPqqnKcUd2O6XEaoBk0a2P4oCWQRdNIc3M,222691 +babel/locale-data/bg_BG.dat,sha256=aXXMXU9VZpiJYUzDy303WkX-42jw62awvD-31Ti-UNk,612 +babel/locale-data/bm.dat,sha256=PE0B9E5zK6QyVNjXjfvC-zm3fpmXJmyNdYA9NbTKyF8,15900 +babel/locale-data/bm_ML.dat,sha256=mmK2NiJt25dqA_ncMmr6Bn_m65uvN8OKgywE1xF8cJw,575 +babel/locale-data/bn.dat,sha256=6pEjVX1e61eVMe0NDsq91A3EGku9sa1U076Y6C3wpaw,253072 +babel/locale-data/bn_BD.dat,sha256=v-F5b_nYJQFbtAT3F8RAro5IoSSC93xrvmwe5rctbVM,594 +babel/locale-data/bn_IN.dat,sha256=QXGQVcndIaU-ka1YCyoVHUqEaFKJJ4Fpb0ZY6NJPE6U,886 +babel/locale-data/bo.dat,sha256=ftRHFKfkJUdhBh0eByCA1EmB3UhK23cc5qylI_GQqE4,22508 +babel/locale-data/bo_CN.dat,sha256=oVacJOAfraWhDx_tfJlbAdJhOqIucCWrdnQ7vM-MbDI,594 +babel/locale-data/bo_IN.dat,sha256=ud5I4cIncy8pDTb2uOfHCbXwwzesWOS19QfI-W9qeCA,690 +babel/locale-data/br.dat,sha256=wUJAQ8vMjey7ND593yu1qSfFhfiEFrmFVsGtH3movyM,251407 +babel/locale-data/br_FR.dat,sha256=fQ09-yG8R-3rGKnnmGRXowctUvx3bKPKkQsp_TI7N0w,612 +babel/locale-data/brx.dat,sha256=bvAwVNOGnCfQ9i_vm5hFKYMX-h-Dp1k116KYjnEG5Dw,124120 +babel/locale-data/brx_IN.dat,sha256=Ah7o10X6tDhJRSjy9VVZff4RPAxjR-KdBCgOuC_8YGc,618 +babel/locale-data/bs.dat,sha256=N1B2KTC1rQAwuwODof7MNuCLAAGfG5OS93A9C5IggmA,229349 +babel/locale-data/bs_Cyrl.dat,sha256=9cL0j0uRVmeabLCS3qKmuhoXaH6qj1fdrgEIQwvL7bw,190119 +babel/locale-data/bs_Cyrl_BA.dat,sha256=m4bl9_ps9JXk5M7pqf8cOak0EBVd8u7B_jieMkWNekc,594 +babel/locale-data/bs_Latn.dat,sha256=omH45kOjJ4tcD3WiCM4I1zRfAPkD5u-_sxzLyRIVo8U,1940 +babel/locale-data/bs_Latn_BA.dat,sha256=gunxrFK2qwAOG9LtPGwyaA5KBkwJZH3YGpwx0wtIY60,594 +babel/locale-data/ca.dat,sha256=tAQHj9fYrKmY8Y75tpFaTlTxn-ar4kp1Jqq2R3_o8tg,202059 +babel/locale-data/ca_AD.dat,sha256=tYMcvYvGsTC0h3wzE-b04moTj-o4Zd30gVPvSidpuFk,612 +babel/locale-data/ca_ES.dat,sha256=Eg6rPemotoYHbTcX_idJdHKHA-4tVufSannybXNCrf0,612 +babel/locale-data/ca_ES_VALENCIA.dat,sha256=Qh0Gs95TPjD4mAiRUZS9CWWxsmKAReX74aWh3d-k7mY,3662 +babel/locale-data/ca_FR.dat,sha256=C2UxkngWSJL-gLjhA9TEcPdhw8USLEBWNzIib12p7yw,631 +babel/locale-data/ca_IT.dat,sha256=QO6dPphsB5mT93QlNTbbRnjKL2o-rxyR-szD1Jw3cBg,612 +babel/locale-data/ccp.dat,sha256=Oh_jadmBgapNO28IUbu1kl5UEtIEUt-wHHxk6iwU-bQ,276002 +babel/locale-data/ccp_BD.dat,sha256=bWMbiFFOj5w3LVbmC8EbLSXhQIUbswHAUXYYGEqCZvI,595 +babel/locale-data/ccp_IN.dat,sha256=kFCtVbT_kZhbhu9uSirX2p3uhXg6V2zZbGRT9b92Vrs,618 +babel/locale-data/ce.dat,sha256=pdFyzNA2YV19L37TViggJx_IAMJYfy67U3bChMRDlVM,138389 +babel/locale-data/ce_RU.dat,sha256=SfccXuRds-J9YljaHWfE8gy1V3Ob7ElnT-W6zH70CPE,612 +babel/locale-data/cgg.dat,sha256=2n6t0aRZMj6G4My_YagV3Py_-k5YGyU8rdfq68HFBiM,16243 +babel/locale-data/cgg_UG.dat,sha256=1lBdlGtbeOJkAHWaigj3saCAclAKCzWsDLDVzgQHu-o,576 +babel/locale-data/chr.dat,sha256=m6nAeYicCb5DEITJpljQTOp1ZT9gRzoIFjBUvBYlpWs,188091 +babel/locale-data/chr_US.dat,sha256=a0obnU_kEeTMhgTbKQiWMcsmZMnXkpYcjJNq7c3jwp0,613 +babel/locale-data/ckb.dat,sha256=JSZcxZ0MWdIkY_lRzj_XAflXknz1Ox4_iedt52LnYjo,27527 +babel/locale-data/ckb_IQ.dat,sha256=kJ1rcyfupBeUpL5kXGhKT6bME63CDzFd5m74p8SHnvE,638 +babel/locale-data/ckb_IR.dat,sha256=hVTw7SHvVgFl-jXpi3zWQLRUD3dckRKQ3GkE2GJbNyA,1190 +babel/locale-data/cs.dat,sha256=iI-y9P8t4sOfoGu7kLMtpWUAOq2RvYshdrZUuhqlFlw,283848 +babel/locale-data/cs_CZ.dat,sha256=RH1xiFFjhqZ9CW628eBXt6GvQvUTvyq0Q5-bYUHts4A,612 +babel/locale-data/cu.dat,sha256=JcdZQs4mFhXzEq_dNpXXDAX8K9_qsRjTz8cAKGNkHbg,20215 +babel/locale-data/cu_RU.dat,sha256=n08UaQPNAvg3XDtpdDSLubQX4KACaWm7GBpMZ8VrYts,612 +babel/locale-data/cy.dat,sha256=fFxtEnDYJWhAKF6IQr_YzXIdJD7Sg6yk8T8zA0OvMRg,308512 +babel/locale-data/cy_GB.dat,sha256=r0NB2JMKR6OB0DAuv8KgdOEC-2EdLnGE4hSBajaSZ0w,612 +babel/locale-data/da.dat,sha256=gBFVg3SxJSaL5wfgH2AawhmO7eZUOceY83XGoEYIuOo,192919 +babel/locale-data/da_DK.dat,sha256=0W2byC7WIDSljDrVIYnScpspzPJWena1DfPZFUPKjRM,612 +babel/locale-data/da_GL.dat,sha256=oXDzlfLQDsa4AGwjR585Txbky4JVxcv5oV23K0oLYUw,575 +babel/locale-data/dav.dat,sha256=5_AEmL3O4b4sues1jgsqRexPY-P36Qi0Z0nVp6C4zhU,16285 +babel/locale-data/dav_KE.dat,sha256=RUuSmZauYgcUiILLoMot1AR7PypCWhbIaH-CFCrHg1A,595 +babel/locale-data/de.dat,sha256=zR1F7RyKp4S2538fjRZUJJzqdOBCcfHBkJrSMafyAGs,206374 +babel/locale-data/de_AT.dat,sha256=UMPb5HTtvs-ZLuesqeuUJHsEDJzjP5guIaEwgBxxau8,2549 +babel/locale-data/de_BE.dat,sha256=_H4Qkh1Bp7WE24Cvzfpm-tH8Ttplizyn2Lq0Qc1kRBo,612 +babel/locale-data/de_CH.dat,sha256=oTL3IcZZoeXCOXgAiRl6_EgpDwy1fUNao1zmvLvrMmE,3527 +babel/locale-data/de_DE.dat,sha256=e5ZtCMEKWnzvu-WZ5rJuyGnjrKy2Xvg-qrwl7QKC6ng,612 +babel/locale-data/de_IT.dat,sha256=7GrrqH_7YoTjuIBocadcBc17Iw7OaRG7qylL6n4ZS9c,1605 +babel/locale-data/de_LI.dat,sha256=2kk5EmAtkMNB_WOd2dBcPsQwMWQTiGOFusSiHQir-mc,1307 +babel/locale-data/de_LU.dat,sha256=uF_EGRtZRi-koTH0M7WSvJBz0S0Q77DADTImX--xFkY,1051 +babel/locale-data/dje.dat,sha256=lptZ9HI5tQlzaOGJvEXEWhDMxZ2bGkv9fi2f1VDLog8,16207 +babel/locale-data/dje_NE.dat,sha256=Shm_5V4X41mwYX0Vvhn4wMWTk2f0uNV9WORkl4VJEwg,576 +babel/locale-data/dsb.dat,sha256=FS-PoLClLXWbNsdmOMH27nyKY6k1vBQSIt3UwOMx54s,179143 +babel/locale-data/dsb_DE.dat,sha256=mgWVrKr6izGo6jVDU4aevQ5I63HxLCso6thzakdGSCM,613 +babel/locale-data/dua.dat,sha256=ARfVY_KYmhY63ijx0sJE013r9z_Ch2xAjRtPVRZynRY,5338 +babel/locale-data/dua_CM.dat,sha256=EdLukZgDF76NBhnO3g2TPHXK2Ma2scg_-SQIjjhrx9A,595 +babel/locale-data/dyo.dat,sha256=QSvJxslwAGQeeEp2qLZW0OJLhQTLgQP1HXalbjBoqes,10524 +babel/locale-data/dyo_SN.dat,sha256=0FsQpVGm58kkJioUAgVxLzepgi4yb-zsENE-6uK3Ees,576 +babel/locale-data/dz.dat,sha256=DFfmq8ZHqKwjfDTExR6VcwuZDz94HLdJEkyZ9xvjmho,89788 +babel/locale-data/dz_BT.dat,sha256=XDmD80wZ8z8erGke-AeRDcJVPtdWQ9r1FsaN_nT7Rnw,594 +babel/locale-data/ebu.dat,sha256=56274pCTP6RhiuGMdnLYHD2PdN_6dIUf5apXrH6NmiQ,16257 +babel/locale-data/ebu_KE.dat,sha256=1EFM68Gfz35hKUg6fX0Vy0tBoxZqZqTxufxDuMhJah4,595 +babel/locale-data/ee.dat,sha256=aVsoIlnPcKaMkWhVS59-qhd-U9fRxFP6p-TLZAG43C0,142214 +babel/locale-data/ee_GH.dat,sha256=p2_DzgV5IbjPkbLQ-GDH0hj9azCLB4f9loWrCqvgQzE,575 +babel/locale-data/ee_TG.dat,sha256=1YcuW3_kitfKtTIS25zJC9yDYStYYjJgZSzfk9fL6S4,1127 +babel/locale-data/el.dat,sha256=D40owXTvuQM5ki8FJuQXI1WyB3LXx1PVRDXBCBcrw1A,232218 +babel/locale-data/el_CY.dat,sha256=E9_RIb7GczMZ3PdMWffoSRZKW4Hz9ltgnNUOq8Ntusg,594 +babel/locale-data/el_GR.dat,sha256=5BDRaUGSgibfEGs7X-NHNLfzklKoCumE333KvBEVbR0,612 +babel/locale-data/en.dat,sha256=kpDwIbvRysK8YunMW6BFcjkMhyZO-3mSpnCFSdgIuI4,178005 +babel/locale-data/en_001.dat,sha256=F6i7LdSHrX-N4QwpcyfxBqhxP8dUrEAGktm8KBt4bg8,23642 +babel/locale-data/en_150.dat,sha256=LiTk4kwBdW9HwXa8xBP3tgH3pCZwWZv9Ubdh0MKztOk,1795 +babel/locale-data/en_AG.dat,sha256=8ip2opUZLqI6ihC6YEgal3E7bKHlmnvC32Dk6sNsZOA,613 +babel/locale-data/en_AI.dat,sha256=P73RJkiBr42Z71XnX7yCasK408857cHgAizr2qFGL3U,1165 +babel/locale-data/en_AS.dat,sha256=US2ZaM-wrPYo9btUtNcOBZ33S-b7OZQFM3Iis1C-5X0,594 +babel/locale-data/en_AT.dat,sha256=arzDSR7sVhSriNw9LRGxO1bw8zZ4f8ePuQAI52SdYUc,1143 +babel/locale-data/en_AU.dat,sha256=1tQlxQu34mZLik0Ev9fnI1hmS2v75OpHDdde41eaJ_k,21589 +babel/locale-data/en_BB.dat,sha256=azIA42tQUratb-ahPTtlb2kVB6biUrcbHeJHEZZlECA,594 +babel/locale-data/en_BE.dat,sha256=2dr4zKfWSeJKSymEr5iaAf9S88MoXisc4IOqgwII4g0,2023 +babel/locale-data/en_BI.dat,sha256=TCBo5LUUqmJhhPI6gPjXu2FevEFG5rJ49IApEwK4JDM,596 +babel/locale-data/en_BM.dat,sha256=qDwK7ec31tlpGLv1t2aEcG-eClk2O21Gn1_s21_2l9w,613 +babel/locale-data/en_BS.dat,sha256=TIbGCurwG_HRA2FNfP6o-_N48QIG9BIoq6lCLLkP2PM,797 +babel/locale-data/en_BW.dat,sha256=ucj_vHr8Q9Szp1fDOzvNcOkfhQ1A3-CpSNKffNpTPPU,2757 +babel/locale-data/en_BZ.dat,sha256=4yD7CCUF7WzqoCaksLH0jLEpbyfRT8jPv41qZopKZdw,2936 +babel/locale-data/en_CA.dat,sha256=VY9ZmLc0J66ceBvwZeqxKyg-LyyV3l2KMu-SABUNQNU,23567 +babel/locale-data/en_CC.dat,sha256=-2VPbd9-VTb6S1G0tcY2Og0by-Mk3DSlREexEeVFpwE,1146 +babel/locale-data/en_CH.dat,sha256=GMbhmyCPJQ-xbvKgl-J2zC3pQO5FrAbeIwU_pC5Z2Mw,1063 +babel/locale-data/en_CK.dat,sha256=z-W8gmF8PuDBggr2zJWE5FGOgfb5Lq_T657V_4ajfN4,1146 +babel/locale-data/en_CM.dat,sha256=EQHcwaslvYAdGH_lXF-GHaHopqcKmo0Ts_oVTFmNNFY,1396 +babel/locale-data/en_CX.dat,sha256=bcO3D_78R2l7de5QC1prWnPQLdHfhk-O9Y5wVLrsWd8,1146 +babel/locale-data/en_CY.dat,sha256=AHiILKSZESkCYmyI7nc3LYb_L1B34FY31E-5cqVwMmU,594 +babel/locale-data/en_DE.dat,sha256=f8RNR9BDX5kWmUBOUqdKpCYo3qjTN4HncnyggxwSt_Q,895 +babel/locale-data/en_DG.dat,sha256=SkX1ThWDNXnXn6HVqsGY7d4w1JN-G8hyrhtXWX7kJC8,1127 +babel/locale-data/en_DK.dat,sha256=FbjtExawbDj6O5QbepTz6383jsZVvH81Wdme5GGHeC8,2261 +babel/locale-data/en_DM.dat,sha256=WKLlYGTWgXFqb0tUEXGnEbWJEsg_wjo-9zTA7JqGCSQ,613 +babel/locale-data/en_ER.dat,sha256=V3AUMOVa8Ky7taM5uNhazPttt-MSWpeVs2lo8NhC1V0,846 +babel/locale-data/en_FI.dat,sha256=gDH4PNohbvvYczNC-7DjxmKr716jyfG6InfL-H4nTyU,2246 +babel/locale-data/en_FJ.dat,sha256=Lq-TVB04KvuPaiGR3qU7MgVEdPDlmNJQ0qGfPErcZkw,631 +babel/locale-data/en_FK.dat,sha256=bYSmL7KI7QVUg8gzafTBydSbdnnW1YRyohLSv8uVAPk,1169 +babel/locale-data/en_FM.dat,sha256=R-mQy9GvdW6gZhYaPW2yUBgEDrDAuMeItiaXiydR3Gs,575 +babel/locale-data/en_GB.dat,sha256=46kd-y5EiKD8JrNK1GYoQc8nUy0S2bBMaE32R1gt4Tw,8497 +babel/locale-data/en_GD.dat,sha256=L9vtmopuTqRgfVe_jvxkpPjPrmiRfvWXG4uiCb02i7I,594 +babel/locale-data/en_GG.dat,sha256=5_kd9rhZ2tRNH8f7UzupTSi9lU_34Vnde9AbtZOs1fY,1232 +babel/locale-data/en_GH.dat,sha256=8eOUwqrhgAwlvvupzA6IAZQI-ni9F8BXgf-d47kDftE,848 +babel/locale-data/en_GI.dat,sha256=H5YWwg5IxxqSLdf5Zru1hBOp_OGGaloDwabr5qqVmFc,1187 +babel/locale-data/en_GM.dat,sha256=ltnIDJm0fdkmUq_5-oqWh1I-klqU060VUQ9aIKEr1SA,844 +babel/locale-data/en_GU.dat,sha256=3b944D0T-ZDJieU3yBMGOcPP9EHjJIasL7QtXDquQYU,674 +babel/locale-data/en_GY.dat,sha256=wkLjPz1KkZ7SRQgKkVB9gIiRTbQRe_Be9Er2kkBRrsk,653 +babel/locale-data/en_HK.dat,sha256=Tp2RpSe8RoC2MrI9sNJrBSfEeWSpUkHP4JZk8-LK_dM,1994 +babel/locale-data/en_IE.dat,sha256=YUdnc0jmLTwLG8bV915sqFcfgM6uyCHQ2vqJb3RhRjo,2029 +babel/locale-data/en_IL.dat,sha256=DAQ3IyZDUAo33bPW8aorlVMIj_vSt8P_4HI-sNFtvqM,1383 +babel/locale-data/en_IM.dat,sha256=IZLiGfvZ3AKRU9XJBqcRyIe-0WBWBRNKquLxZCegGfQ,1232 +babel/locale-data/en_IN.dat,sha256=143RMtD32jpfEdJz0FZm2WPGggXZogrIoXki4Vs12zk,2786 +babel/locale-data/en_IO.dat,sha256=DJjRE-uuMNQBMHBdt_v6hD31FFTOpT-fPBzbaUulozA,1127 +babel/locale-data/en_JE.dat,sha256=gQdRG5CkJCntPHmZOaihOwGxx70WdRF5Xmufnwj99dk,1232 +babel/locale-data/en_JM.dat,sha256=m9QZosD9HcQv7SGLBmOIjVrqJvSbTL5AXQbJQ2z35DM,1585 +babel/locale-data/en_KE.dat,sha256=-GOsojcxhA-pKX0CFoAfSHZqtKfiT9v86srV_8MvwzM,1417 +babel/locale-data/en_KI.dat,sha256=A9NG8c4u5WbduXb0APePGTvYRU-O5VQuTbGtMkMf7dw,594 +babel/locale-data/en_KN.dat,sha256=TTQkev-O-x03J3QFVPXKWXxR-3S-BX6RYgGhgXLY5O8,594 +babel/locale-data/en_KY.dat,sha256=aF7XzwKfNgmNw_YJQ5Kl8CYO-mvlRRkXoj9MUh7oRaI,778 +babel/locale-data/en_LC.dat,sha256=RU4eIks5fniWA4Re56svK7T8wTQl5QGq9zRwm-X7pMc,594 +babel/locale-data/en_LR.dat,sha256=T94Errq0ujcw5AxH7ymiU_PFWwmzv1u3XAFWy78GDX8,844 +babel/locale-data/en_LS.dat,sha256=9ctePFXVAeriVtbPZkBMwdFxokcxvns5jVx6s_FUrv8,844 +babel/locale-data/en_MG.dat,sha256=71cQSH0Skt58GANeqcly7Z3_Mv8UQgg6waCcSZW4WPw,1397 +babel/locale-data/en_MH.dat,sha256=ZxEhlP-4P73jcV_ZgjuWwpve70MBHXitZeazlaRlp5o,1327 +babel/locale-data/en_MO.dat,sha256=r73LxQBYLTH0kFIMO6BJB3DkH46EHgfbX5xnm4ymcKk,789 +babel/locale-data/en_MP.dat,sha256=mSOdHDMz3YYlHC1b3uTl6Vg0vHVnYfOAmimxaGde4hE,1308 +babel/locale-data/en_MS.dat,sha256=1GJucprDaDc3WvW2oDR6uvXe0pcEdhBOlG3O-juRvdE,1146 +babel/locale-data/en_MT.dat,sha256=dt3dx-82OePUlh4cnNWe1RX17IJl4GGp99KF-1lID8g,1913 +babel/locale-data/en_MU.dat,sha256=cpgtJdOKTCqHgsvE9BB1z-jAgAqUK9ANKVpVILNEK78,1397 +babel/locale-data/en_MW.dat,sha256=ljIuVSSJuOr7kPKj2a2SkUXjRYYu90HwzZHVE6kz6Hc,845 +babel/locale-data/en_MY.dat,sha256=nYUL1jHv421e9iS2nbwx5QspA2b5ve5APiPRcz4BEa4,675 +babel/locale-data/en_NA.dat,sha256=IoK1HpBfMMb1lreHC-64p6CetcbrmrnsMEdYP6sqVPs,844 +babel/locale-data/en_NF.dat,sha256=K-6uEJ0AOVzpvC5xero6zRp1KdEle4JlfyDdBEPPTHk,1146 +babel/locale-data/en_NG.dat,sha256=_PZwH1Df0ANyPSr6rcUfuCuVNAQT9fSL_0I74dAjwdM,846 +babel/locale-data/en_NL.dat,sha256=UrSIb6mH9FQPi5Icoxn1nkyNdtkNBHeqJw8jUKcqxH8,1039 +babel/locale-data/en_NR.dat,sha256=MqCEDXsFDAZBpE-fM6H1q3Rd7pxhCSN9dlQlfWREOFk,1146 +babel/locale-data/en_NU.dat,sha256=hLa5ZgUnKU3uslIdjQ-ZF7WI_vhYEHBQM8uEaKVQuRE,1146 +babel/locale-data/en_NZ.dat,sha256=kbZkwYpSgOQT14j0xJoBpXSNoAJdimAUTMSs85qyh5U,2293 +babel/locale-data/en_PG.dat,sha256=M8XdBf7Z3fnSqCQtlkkcQMPYxyCCHbfx4a-4jTQI2ck,594 +babel/locale-data/en_PH.dat,sha256=svFdat83tKq2UzCL76fVu1jfzBktG_RJANle4FPaAFI,615 +babel/locale-data/en_PK.dat,sha256=53Pb-XWQvdHLAW9-v0unA7A4lcQJAGQ1PK8kVb_80QI,1945 +babel/locale-data/en_PN.dat,sha256=vn2WIk_IvddtYrvoq9kqGEIOv_W926wAOKDzJxyX80A,1146 +babel/locale-data/en_PR.dat,sha256=tQJQMuuG0ks-wg2v1kHjqTlsmOZm-PWDn1Pd4vqFf6Y,594 +babel/locale-data/en_PW.dat,sha256=swtLTK7POWxvDBrV6xFe8wwycKWwIgV7EJ6LAefv6-Q,759 +babel/locale-data/en_RW.dat,sha256=lv3k5dniwhYKMjJzbWAkMwQRen4gYLpMWpPtn5dJFw0,1397 +babel/locale-data/en_SB.dat,sha256=X9pU6FPjm1HdFjXM2UHP_Wn1meGiRRDiyXwFTZn3rpg,594 +babel/locale-data/en_SC.dat,sha256=8DRj9m3WpgbpyxVRrtwzfoNsjn2rJFPkgkvXyEiAhmw,1147 +babel/locale-data/en_SD.dat,sha256=e1llYtTS1djuGRNqC6TX5_NF933Xy9KM-X5IftV_NMI,887 +babel/locale-data/en_SE.dat,sha256=BBq5VyivPNNj2mst-Bpr6aYSOkVRLgRpPvHGsmNM6VY,1391 +babel/locale-data/en_SG.dat,sha256=pJVdA8-mZcETUeMLFFdU5w6vByjv0-E4KILECh6k66w,2043 +babel/locale-data/en_SH.dat,sha256=UFf4a9J-dzNjDPTYtvcua4vqS_vlQITNqvbEiZl4IEk,1169 +babel/locale-data/en_SI.dat,sha256=YHoytFwpZHB_A_zcxBfMHtqc1N7Yzn2B17aIXY5Oo6I,911 +babel/locale-data/en_SL.dat,sha256=dR0Nfl4gKbggnz2ZX-qSSWOSo4dtf9QqH40QLDVVf6g,845 +babel/locale-data/en_SS.dat,sha256=bvHOMDtmKMDX7jUzoSwYArJqHKMb5pZh37aIZelYsQ4,867 +babel/locale-data/en_SX.dat,sha256=26k4L3-_CCC6nplhE17j7TUjXv_ku9yP_nF1BsY-74s,1149 +babel/locale-data/en_SZ.dat,sha256=MGcYfYdjPM7wUAr7Dhf-kltjqRkRf5AmwsnEsXUwOW4,844 +babel/locale-data/en_TC.dat,sha256=3zaCMuRxNjRrUWqSPF3sPlHk96SxNknNHLisYAoXknw,575 +babel/locale-data/en_TK.dat,sha256=1pRKzxFueHafzj_e-ewMyDEbcABX43wnGc0H41vsvvM,1146 +babel/locale-data/en_TO.dat,sha256=Rj2B-3IIhaKgu_v-B8vhBCXKN1O8AmmelXq2npchRxQ,595 +babel/locale-data/en_TT.dat,sha256=uJrxiTRY1xIuwKEjb3W6zRmoxdOImOJTK8vRvP1RzpA,613 +babel/locale-data/en_TV.dat,sha256=ALLNB8yGJAcDVD59MY7V3Z7lSg2lMu6Hi4TMbuQ53wY,1146 +babel/locale-data/en_TZ.dat,sha256=EhGAWaWype3uzlZY-HenhC5gw-aC3k0CInNpMzvtv1U,1398 +babel/locale-data/en_UG.dat,sha256=JCb1ZX_HKd3Er6L845GYjdedtsi9gASe4Y-sGke6Auc,1398 +babel/locale-data/en_UM.dat,sha256=k8mGz1zCiS7Hh01FvWc9MAA38_F02YxLfG_mWds0VYw,612 +babel/locale-data/en_US.dat,sha256=5ZoNfA_9qZda8s010ePoVRoVKwYrOydx7k2NXp0PMH4,612 +babel/locale-data/en_US_POSIX.dat,sha256=rqC3gB3IKVDawlr5ZjmKAx5tngbBlUfEmtEtvuS6l64,1190 +babel/locale-data/en_VC.dat,sha256=pPDLkjBcEpqHP1CGAgzqbD-VOCasIHxHIzIVClQr_6Y,594 +babel/locale-data/en_VG.dat,sha256=S53tu_DZBL16XjFZUZuRq8-4XaNjIdLq7fPGGimSo4Q,575 +babel/locale-data/en_VI.dat,sha256=ZoyWCmswjcn_MCx-PxOVqhzMTQR4jRqSBBpCpGafiaA,612 +babel/locale-data/en_VU.dat,sha256=3QACkxR5V4oUnK1PmhK1DHRXvnmsDAC9nIseHL8aguw,595 +babel/locale-data/en_WS.dat,sha256=CevZJ0gbIIW5-OIDty22mp8ZqXlwsK7vAKOmpCxR5K0,615 +babel/locale-data/en_ZA.dat,sha256=nipgRp10wYnhPVar_NRNZvb1xe-I_o7h4c4x7PvLsDc,3252 +babel/locale-data/en_ZM.dat,sha256=co8aOxkO7cGqpEGRdCxnt6Ohe5eX81JCcf5IrRJ7TGU,844 +babel/locale-data/en_ZW.dat,sha256=4bNWODAwnTVLOE4ngqXWYNLZjtSAbiuqrjAwlrhYlQ4,3182 +babel/locale-data/eo.dat,sha256=vLQ_a8AvYYj1hntQ7IgGXtFtcqvDfwmluN8fPPpVK70,40636 +babel/locale-data/eo_001.dat,sha256=0d7wjrv29JjdUbBix6QfAFFcq8DcnnQMsLjxSWaIiQQ,809 +babel/locale-data/es.dat,sha256=WBruoa8pZfghjOdVKNBIcc2gOzv5-FDFFaTB0uZMZ5Y,189209 +babel/locale-data/es_419.dat,sha256=VOPob-7dAFrTpq_FfExVlomoPCbwHapQ197iR4iDyg0,25629 +babel/locale-data/es_AR.dat,sha256=lTMq931yWE7uVrMeeG0Y4P-1Po4jzhpZtU4Z4jzU2qk,9192 +babel/locale-data/es_BO.dat,sha256=SLZzfj_RkUzDhpRgMe_jod_4JD1q7ARuxTnSSKiNT5A,1953 +babel/locale-data/es_BR.dat,sha256=nMj8LlmT9pbTXsY1iy7Tb4uhEfXX2B0AJixMiTAPlAI,614 +babel/locale-data/es_BZ.dat,sha256=2wjIZPbWwJjCsT0gLFY0ENng9EyTnYjQyNKlZeW6LZA,613 +babel/locale-data/es_CL.dat,sha256=z8J9C18aODJDaWYt6jIwH6X8JS_lcNExfAOqO8qTRqk,5471 +babel/locale-data/es_CO.dat,sha256=IK7saAQ9KzcoQEoOOI-is3UzNGQGBktnTcsw8AhcnvU,8779 +babel/locale-data/es_CR.dat,sha256=R2QFVLLu0VksT6op4l98j4zMTe93b8V4x8Yy6ex_O1g,1798 +babel/locale-data/es_CU.dat,sha256=oelFULooytedB42j_L4PKIu8Iw9vTN_oiURhgOE3XJs,615 +babel/locale-data/es_DO.dat,sha256=2m_Hb7cUDmolsPr9AiW1Zd64h2hBxGBCjgLiiLtebM8,4327 +babel/locale-data/es_EA.dat,sha256=VIhdWVNJihtaOWrlAaCfq8Xto1NhvjAsivFvJOQtwWY,575 +babel/locale-data/es_EC.dat,sha256=RENZQlqIjh4OpVPSY3V683fHIctxIEEsJ9D7aECqXJg,3380 +babel/locale-data/es_ES.dat,sha256=9yqlYwIf4F8fKElcOtrCbdGHKL_9mxsp_kNO5L0u-9I,612 +babel/locale-data/es_GQ.dat,sha256=BvsCWl4rmeOx6p8lzY8XxTXkyQeHwx_LlzXyh6d3VeE,858 +babel/locale-data/es_GT.dat,sha256=jqEvcT9v9uEhW4Hd70la575Rrgyb5Ss7SKkzNEx0gEs,5289 +babel/locale-data/es_HN.dat,sha256=mxG8SWtbQrwcArD6KToTYkCbs-ACWhtmxkSxzNLe-AM,3582 +babel/locale-data/es_IC.dat,sha256=JEz-ULyped48aMdmcki9CZXtvGA67VOaCR45YoJQ7Wg,575 +babel/locale-data/es_MX.dat,sha256=ZP-nkvtof-5YheT9gWEE6rpDUl-9ETllIdOy1SckVRw,27226 +babel/locale-data/es_NI.dat,sha256=9nYwVF9BjlvMhrJzFEQVLy-EYu72Nmk9QoSMqOdlDjw,1732 +babel/locale-data/es_PA.dat,sha256=jRwfhvfwFBdhrf5O9S_voMfiuS6i2gxtYI_NqGjfiPc,3990 +babel/locale-data/es_PE.dat,sha256=vnB6ZSFeNwUll9GDZo0Dq73cpmPZzvnrPpKHILK_iW4,4425 +babel/locale-data/es_PH.dat,sha256=OL-R8ZaRLyyAkA1QTpr5RjvFnfYjapdBVIuEugcp5EA,1191 +babel/locale-data/es_PR.dat,sha256=-grDrVk_mHFGYZFFkQf6jVqRLiRcbzkoRAsuC2HrA_E,3851 +babel/locale-data/es_PY.dat,sha256=87IJo405_ppAkEutnEMn3IJinvXlsTZ6twn6p4Zit9k,5648 +babel/locale-data/es_SV.dat,sha256=LZuS4sIBTmuOWPtLZeh1HQTU5EfH703B5U-TzG57itM,1440 +babel/locale-data/es_US.dat,sha256=cSaqQyNEcyr-0K0UhbRabnD7nVVEAKxMzFzXLKfDFKQ,24642 +babel/locale-data/es_UY.dat,sha256=RtWqYVtp3W0n62PpyuUFm3f9ROA15WkgSC8TVRuB0xo,2559 +babel/locale-data/es_VE.dat,sha256=l9p4lm12GDCJ6d4cDaPGVOTmvs9AfklPqXMpkeE-HQE,3661 +babel/locale-data/et.dat,sha256=GSbHaa7BahUD2s_EYlb8xYjjg8DHj27jyyWNLwm6DpI,194192 +babel/locale-data/et_EE.dat,sha256=T_Ml5dIpzpQSGXpumxadcRwjQN8wQcp9P1naPW0c4pY,612 +babel/locale-data/eu.dat,sha256=8KYmGxe4h3nIsLIB3G5upngnA6Z3NsMR9aDnYFluIyg,166649 +babel/locale-data/eu_ES.dat,sha256=9G3hRPFlMAUhuJiNhwAFnkoSIN0FV4IqhLLIlrfcLdU,612 +babel/locale-data/ewo.dat,sha256=u0H2xMgalGHVdIgkSZr1yajmR6zE5Yu9gr-H2BGXQ0I,17610 +babel/locale-data/ewo_CM.dat,sha256=6wqVZnIG07EDxPa7GYwOX7_ULEEelJHQlk5hnyGI_30,595 +babel/locale-data/fa.dat,sha256=xhj_L5ZUqLuasN0VdG1qE1ex0kLBUpOxkcBJEVkxmeU,202324 +babel/locale-data/fa_AF.dat,sha256=Q9u4tkBagyMrssGPRPPPxKFkS4kb_sF_2u-A8jDubm0,10854 +babel/locale-data/fa_IR.dat,sha256=J1tB-LdrDPUr8MsHTzcasBGAnSbs6x4f1p9A1We1EqA,637 +babel/locale-data/ff.dat,sha256=kxorvaiFU5QVwrAQDH8STsiqM_pwkigDqM9GYYw6vXk,16099 +babel/locale-data/ff_CM.dat,sha256=YbVmcDZU185t3rrxZK4MEV09s6dlXm7ZXHs9tytNav0,594 +babel/locale-data/ff_GN.dat,sha256=carzHHEc53DnuKPFWe7CZtsWQwzZD2HeIBq1DzQcox4,595 +babel/locale-data/ff_MR.dat,sha256=QGI7gTN8t33KTIWVISgarQztOHM8OlVhJ3gqybT8Y3A,1171 +babel/locale-data/ff_SN.dat,sha256=FMLaEwicmedyLlnMoGthlc6ed2Bfl8lSIzEe2sib3us,575 +babel/locale-data/fi.dat,sha256=iVS45rYw6buyhksXq0nEgDPx9ALb8NSTqQeFCm-pBTY,215741 +babel/locale-data/fi_FI.dat,sha256=xx9NJ2G8Vg-TBkTKr1_eb9nh_ON_uWEy4K011A5cG2I,612 +babel/locale-data/fil.dat,sha256=sftR6pnrdeHpprilZNG3hKp3jFBVLFyGixlh0Jm6S84,169342 +babel/locale-data/fil_PH.dat,sha256=41ckeWA2RfmxKIJBCuZZYBz9S7LGs2saUTHi_2GGALE,595 +babel/locale-data/fo.dat,sha256=QgToLyLTC0vONDF_wBCz-4gtWHnuhHKYqY_xuwOJoSE,156971 +babel/locale-data/fo_DK.dat,sha256=fhxnRQMc0JTJ6Ye9Ou_V2tS4AjF-Oz823sKgdfao3aU,633 +babel/locale-data/fo_FO.dat,sha256=CH2274jjF2XYBeO9h1r-cV2ygO19o6eZjoHvvS_6ZyU,612 +babel/locale-data/fr.dat,sha256=p3mHqzCwz3nW30za2_IS4_Q5O5-4q33x3YdKSXtqDlo,208407 +babel/locale-data/fr_BE.dat,sha256=0zOihsqb9lBfezAM6aAFG5oO7AmVgQqVntjQa-leYAM,1407 +babel/locale-data/fr_BF.dat,sha256=DM5VD-MWomg8_hZmo-Gu-SjfG2XovWqYoOBpeOUzCHw,575 +babel/locale-data/fr_BI.dat,sha256=B7X6hkelEt2v0TG2fCMaX77F1-6ekIL_ZtbtgwEMA0A,596 +babel/locale-data/fr_BJ.dat,sha256=oRh0HuTPIkhplgAuSRMaQjCRMrZyAihk9oX8wYwDqBQ,575 +babel/locale-data/fr_BL.dat,sha256=wvV5Q-dwbwF2AtnowI1FqWbLU_tj8-AjfFT5X8mMG8s,575 +babel/locale-data/fr_CA.dat,sha256=uPOj-cEB-xlMiqY7jk0PHVNRBEoyce7pi8LZbjs1_vU,41436 +babel/locale-data/fr_CD.dat,sha256=fS9-jbghFmwp67i44Eyr-nyIJFs77v_DO9FAndnRw5o,1092 +babel/locale-data/fr_CF.dat,sha256=1SNYDsRE_2T5xEjuKTR9GxqOF_aiNt_HoYYVEZnvRxA,575 +babel/locale-data/fr_CG.dat,sha256=vbyA3qBU7121zsJDFPxS0aZVqXs2clsRliUTtR2lMS8,575 +babel/locale-data/fr_CH.dat,sha256=0zD6F2uRmRhm5-sypg1oFeQourSXkWyuypkHgTD8Wno,3092 +babel/locale-data/fr_CI.dat,sha256=tCE07AH2di4un0V-zoMn_rZN4MwM2OvXF-VLS19nifw,575 +babel/locale-data/fr_CM.dat,sha256=ugBBThWZNwZIxOjatsQaQAuCD1Pi_aUj5V-SL0P4-fg,2069 +babel/locale-data/fr_DJ.dat,sha256=uSVQbAFnjuaxtZtvmIHg3URmuLNjj61R3Vf08P6dvzE,1191 +babel/locale-data/fr_DZ.dat,sha256=xiTCE7m0syGvH8e1zz6fbHGC_ZB4sa2H-u4lX5CRpZ0,1233 +babel/locale-data/fr_FR.dat,sha256=OcLcQsDh6ZJfM-vdEtS7sn3DPDhC8dmYwXRT12VFgSM,612 +babel/locale-data/fr_GA.dat,sha256=QxfVsfX9Ofen_UTLkYW83JG7T3GCD2wojerUXr9AXb4,575 +babel/locale-data/fr_GF.dat,sha256=klOPdiLUssy-zolVZPhW06MpSpZMMfAo1ohqITLtLVw,678 +babel/locale-data/fr_GN.dat,sha256=a0lG_FaPijwHXX6zBi9OT7a2wwKLt9h0ZYIx8P-6pyo,595 +babel/locale-data/fr_GP.dat,sha256=ADKEVqkpS_VQ-oIRBUkmwStMf7a7VqDDomPkieb8aE0,612 +babel/locale-data/fr_GQ.dat,sha256=KW3WgRxIpMGpiJiP-8oIGyEEo-wwMxWs_ytOg2D_wz8,575 +babel/locale-data/fr_HT.dat,sha256=39VdIcWeCMTv4CnOvKSjNbrIt8RT_fBVem4C-oMl9hU,1859 +babel/locale-data/fr_KM.dat,sha256=ZQh4NtR67gYG6VAwxC719smlQmUDZ4z9MFna6fIXYZY,595 +babel/locale-data/fr_LU.dat,sha256=xbS84vPT3puYvuy8AfLz9LRxm4Ir8K_ZDGvLb0xVg0Q,673 +babel/locale-data/fr_MA.dat,sha256=UtwUCrpkuQXSpCgRN7UhVZKmSfGq9cFZ0OUzkuzCP-I,1325 +babel/locale-data/fr_MC.dat,sha256=0lxU68vBJH3cLw6zQpd3VA_qJHSQvAgF3ZmipzJoDh4,612 +babel/locale-data/fr_MF.dat,sha256=B3KknZMh9cDHDXJngTZDo8G7txIsKxUKbTWI24C0YPM,575 +babel/locale-data/fr_MG.dat,sha256=rdz0agNIO_As-rILIVGzgbtdqys_J11hqhetO2T86qo,595 +babel/locale-data/fr_ML.dat,sha256=eFENEIA9LKdrp2uB07YKdhr02pkgbm69OYs26mR1v-w,1112 +babel/locale-data/fr_MQ.dat,sha256=J3mP-B5VP2tYOX1ZhScR9cNLS8hsB9l14eS-R9ChK4k,612 +babel/locale-data/fr_MR.dat,sha256=Hbkvr3lE1cIrDwQ5NTLO4edGpEfVUz-4Aiuopmf8hBE,1171 +babel/locale-data/fr_MU.dat,sha256=z4Ve_HQnRkR305C-diYmJKAOXMQY4h7qQ4ZMPQbbOLk,595 +babel/locale-data/fr_NC.dat,sha256=RuQW9g3OeQOU9klBvkAofW8cjh9OgVnuLlu1Ta7Ri6c,575 +babel/locale-data/fr_NE.dat,sha256=PmCodG7S_Mv2R-kUJBVhfTzKXUXrk8ydLsY8e6vFZYQ,575 +babel/locale-data/fr_PF.dat,sha256=d9G5Xh5vKpELiZM7Bc5lKs3IRIwf0pW2EHlH1FNMzus,575 +babel/locale-data/fr_PM.dat,sha256=TogdZ9ptC1xTbWOGMCH6rhHfVujXx8MeXAW9zO4DB9o,575 +babel/locale-data/fr_RE.dat,sha256=kR0XHzVPnO5kznAcR2YDC9bGVeySwEuvNLIeAfP2lF4,1128 +babel/locale-data/fr_RW.dat,sha256=8glNa4u8sWRJ8SRoZEo-R0L8m5JVJwTIcJ8u2sGCSI0,595 +babel/locale-data/fr_SC.dat,sha256=fyhgMctaLoAzr7JPgCxrvYtGShZ4th5192DuArdyTG8,595 +babel/locale-data/fr_SN.dat,sha256=OET4Eqi4WKo8EtHDxz-prp__aDK3u-MENXjvnUMN0xo,1263 +babel/locale-data/fr_SY.dat,sha256=VDzn39bs-ALUmQWFpM41UW_j_J_eCkyaLPNPNdhIeIg,1233 +babel/locale-data/fr_TD.dat,sha256=uOxDIqUkTli02bbU0TuAUMUQL90Wm2u0Ke1sS4DM17c,1151 +babel/locale-data/fr_TG.dat,sha256=xhX0XynVS1e-oMOBh6Fdpd0uSoaRJ5WnDEhBmMIddrI,575 +babel/locale-data/fr_TN.dat,sha256=35_otWzYxetFn1MX-psINTxkoKR-AI8Aq5ERilaPjlc,1233 +babel/locale-data/fr_VU.dat,sha256=77dX-IUP1nO7X9o2YoOKVooX2l1k7bs7zirt1AJZc_U,1171 +babel/locale-data/fr_WF.dat,sha256=P74uD25R5swPxEkvSZ_i6n4gd-VzQyft6TcLgEq7uSg,575 +babel/locale-data/fr_YT.dat,sha256=M4BeZzJffHLAn359OGQgYEjGon3Xn7rs9jFFz2sk-uY,575 +babel/locale-data/fur.dat,sha256=bM_n3CPD1_zbig6NjyU7eQMuJWPuDUoxT-6pCo7n6L0,34997 +babel/locale-data/fur_IT.dat,sha256=if9XP-Fk2gsdoHIWCE_diR6QX9X2lGAf5WJlbILqIpg,613 +babel/locale-data/fy.dat,sha256=lWvqU34az7Ndc-zEqQuKOPoKDr2tNARrDTGTpD-LCLs,109974 +babel/locale-data/fy_NL.dat,sha256=a_uGKJyjwGssF8CxhGxg_jDRAIVNr_-byOVLTQx15jU,612 +babel/locale-data/ga.dat,sha256=P2m2AgWvD_4UheAT5R3j0xeNr1AkvF_abPTA4wF5sWs,307187 +babel/locale-data/ga_IE.dat,sha256=1opKEUBuu2bCLXhsiemyzYRVnqoiDWK7yaBoYttmOGY,612 +babel/locale-data/gd.dat,sha256=MgK18PsSdGTPaqpidSq3l3XiitcHr_mDzsVuZ1M5VM4,285334 +babel/locale-data/gd_GB.dat,sha256=XQ8lMXmfYVm9uIHfl-Gw9itulBXRfKaLbkWLvrIT3Po,612 +babel/locale-data/gl.dat,sha256=-aC9SsWu9vJ22B60NLchfoGwuPh-NwIt9F3d2-60svQ,166755 +babel/locale-data/gl_ES.dat,sha256=j-E1eEntVp82Czdv4hVDskHS19yiB5GdCu2D4ufQ8-I,612 +babel/locale-data/gsw.dat,sha256=d6H13WqYijW9Fu-pkKnK3jLlYQ-_soH_Zdxw_wlTFfY,107858 +babel/locale-data/gsw_CH.dat,sha256=MIlhajh09_omS7UXZEAdykj-j9KDYUmTg7ZgJ94AVoE,613 +babel/locale-data/gsw_FR.dat,sha256=CMJhCOKNfllteJ5GaGyJ-Znhk4K2C1WG0ocgboFttyY,613 +babel/locale-data/gsw_LI.dat,sha256=KQbUX4TWt1xBgHlfnAx8NzpLYfS1cJ4n8Eu8WLHgyGI,613 +babel/locale-data/gu.dat,sha256=H0L062pxyaybT9665o7nlapZ1NyGgWEps1kX_W0zGcY,235035 +babel/locale-data/gu_IN.dat,sha256=89qaeyH8x3h8nUjvBVGZYRTUr7tKbwzKydVH_KfMSmw,617 +babel/locale-data/guz.dat,sha256=tCAZNGh_Z1fNsHfDoD_W-6hh4PXJBVxb8mszcX4rGqI,16030 +babel/locale-data/guz_KE.dat,sha256=bwdgnI2FkqFjrA7mWlDRdhOPEb5SmznIdav_n6e79XI,595 +babel/locale-data/gv.dat,sha256=vCi0syG19dkQO7YVEdXBFrA4BOKBm5b_xtayz0o86N4,4129 +babel/locale-data/gv_IM.dat,sha256=Dsxi2FsUmONpIhoMLhZAxJEFKhxLi4QLU7M1KUOKSas,593 +babel/locale-data/ha.dat,sha256=ogXpd88RUZM07iwWST0c345taeTNNwXRGUfyBAhZc_0,30586 +babel/locale-data/ha_GH.dat,sha256=PfmulS4AVDIEr_Kteht72WTsmi20Xg7csXYQi0K-vQU,598 +babel/locale-data/ha_NE.dat,sha256=iyOkVzwjvNUt-6tG5Gf8vo-9SntYZVCz2eMFuXFxDmE,792 +babel/locale-data/ha_NG.dat,sha256=yThHGuz9HOmRTyIGcrtjoW1RzyMKlOZoHjxa9um4_Xg,575 +babel/locale-data/haw.dat,sha256=VGka7LciZW4XvscK2kdj5CnUwgqDrWmr3v6wp81RtPI,16226 +babel/locale-data/haw_US.dat,sha256=wmaUmE6jOHb5gXUS7RIU7OVOd23eoeqyMYbg3s2rJBE,613 +babel/locale-data/he.dat,sha256=fVJFf5eGiceghHCXpbM8Yw75GN3n4lu0_KX3K-jLN7Y,255586 +babel/locale-data/he_IL.dat,sha256=Aq00nAb_ugFPM215RsB7bbDM6_4HgmxPwszNKaZOzv8,637 +babel/locale-data/hi.dat,sha256=wLREWXt28LRJefBNxenfSOwIPj7Ml-tLEUrDrUnbFkA,233886 +babel/locale-data/hi_IN.dat,sha256=for7rJ8vU_dPkRAMGXuj8YbYsRgHomBNmqfVr2loFMk,617 +babel/locale-data/hr.dat,sha256=IdEd7ENaOp6xGpz5fQ95-8dlkQXANhGjCtCIPMkIEU0,236347 +babel/locale-data/hr_BA.dat,sha256=ngn32_bOiW8uPq59JV5swOmZYNkacWbuntem5a6vrLY,1147 +babel/locale-data/hr_HR.dat,sha256=OQIwUpsAMoQD2gmAgOJ7jgQ-SIqUHlDbi6svNyRqtDQ,594 +babel/locale-data/hsb.dat,sha256=swFsSTF-bMruhuZjXMkvVI4NHbVv-6lCsUmZMPo2nKk,178677 +babel/locale-data/hsb_DE.dat,sha256=EJgkyjJyFha4kb7n21uVK-zxIZqtBbbxly7G5sVQyRs,613 +babel/locale-data/hu.dat,sha256=wvBmd4C0NNlsIOVgnVqphXO1z7mVuitHpUwcYeFfkHU,186066 +babel/locale-data/hu_HU.dat,sha256=WWcNAM8UHpNKjFrlhyGv8M6BXEPy8kGHtwt07iC2OAU,612 +babel/locale-data/hy.dat,sha256=Fryh8W2CHMt9IZjOnyLrnVEQGy2MZ0r99HdV_3A_lLA,201572 +babel/locale-data/hy_AM.dat,sha256=jYcuuccBZjdJxv0aec7TxrTVAfXVTH-3SMCJIARuY3Q,594 +babel/locale-data/id.dat,sha256=J1WliMGfC1ElIiHgk8vuJTakbjahJ-Xkv2DIh7fP--E,162652 +babel/locale-data/id_ID.dat,sha256=fGRHXojXJUarC5UMR1MnzuQM3KfVq_Eceo8N_mYuUR8,594 +babel/locale-data/ig.dat,sha256=lsJJ70O8ygTI8yrFmVk5KqYk3sv4fJg3qa-maI050eA,14515 +babel/locale-data/ig_NG.dat,sha256=zW7SFnCemHoW8v-PGQYdLlMsCbptx-9J_vOg41rgVnQ,575 +babel/locale-data/ii.dat,sha256=_XGrpu1KB8Ow5hkuktKDjog1r0rsOrDJIhyoh6rI6qc,12538 +babel/locale-data/ii_CN.dat,sha256=1fpIxWA41PwpwLlLwnm9iKhU6J1uEcnq5PgvzbXEQow,594 +babel/locale-data/is.dat,sha256=LV8XQXNBTqY-8dc9HRkJeLwq9--paECtrmNskrT4D0c,179389 +babel/locale-data/is_IS.dat,sha256=hQbrFRelURz0xLmdXvaN_jwbCyAGA7raRH0VukeRAqg,612 +babel/locale-data/it.dat,sha256=5WPa3LYoT_t2xCtCGET-X9iaT7Ig0gME_2WnwxwuZDw,181967 +babel/locale-data/it_CH.dat,sha256=tZ5XC9GJn0TH0qkpSmv1vASay1iBXt3aRgwr8P5Xr_Q,2762 +babel/locale-data/it_IT.dat,sha256=6E4ks2fYW4jMzBkRIs5nXI1nnig4MLzLLmTbopTWoCM,612 +babel/locale-data/it_SM.dat,sha256=F9zWcFFojzchi7nLTgPf_OcXrlkYqqTQgB0CkUtky6A,612 +babel/locale-data/it_VA.dat,sha256=nTt9_9s-GEw9T1aGSNAQJbutXg8rVB11b9Q7mwgkjFY,612 +babel/locale-data/ja.dat,sha256=c-q5E6_ospP5ErHa66RjQBwOxfjyL47D_mVzYH3vf1w,192235 +babel/locale-data/ja_JP.dat,sha256=uGdbogrwrT7djKMJE25VguThXOBwXXcptJrsDuIUEiM,594 +babel/locale-data/jgo.dat,sha256=tZ46oFCwm5eoin-zdTwuDlli5Y-j73Bf5-iCjMIM-C0,12611 +babel/locale-data/jgo_CM.dat,sha256=I5Sz0GDFUhryorSoYydjIsKC_LojQBqwl8tyZHCAEio,595 +babel/locale-data/jmc.dat,sha256=O0pezZOR4Hms7MDcPRRAq8vuhC2BpjuAYVF3n5bowEI,16082 +babel/locale-data/jmc_TZ.dat,sha256=4OwQymia0CKNgOx7DUQjnGEaZ65_2Mx31i9QyWTWBvE,576 +babel/locale-data/ka.dat,sha256=oAiH4fGnRAyrL4Jp4dING0EGZtjTfoRsesXcdAxoph0,250309 +babel/locale-data/ka_GE.dat,sha256=yyCDbCFiwWszIUKwy5jEX7MdsyECpd593QCmjGC9DzI,594 +babel/locale-data/kab.dat,sha256=TXCBPqKBk7ooO2Gi7JgpPHPPm3Ra3dq1XVjblqe7mDU,134726 +babel/locale-data/kab_DZ.dat,sha256=uscTFJKW-nl9K9YB99pmcfIbunARcf7-L7yeEysHMnE,638 +babel/locale-data/kam.dat,sha256=5BqANwDz4f5fT5FuGsZGwOCOAT9iBeWAd_3LBdFxuXU,16189 +babel/locale-data/kam_KE.dat,sha256=gdYtmfmPr5cD6z7d4zMTgjEaHDhRQVvn-eK04exyg7Q,595 +babel/locale-data/kde.dat,sha256=pmOMRRVq4maFCt0GFPj2StlX8PB6l2Q1jCbuTNn4QtA,16489 +babel/locale-data/kde_TZ.dat,sha256=T0J38YQ_xX8-kV597cGF6Ht-KPXcLci1-t6J9cRm4_s,576 +babel/locale-data/kea.dat,sha256=ZXgzZ8Sk15x6AdM6rRa8ysBVutHdGtI247gPLbJrSoM,71136 +babel/locale-data/kea_CV.dat,sha256=3TG94VNQHtY-RkfcS2YxcbMD9jsInEbFISFgAB4o7AM,576 +babel/locale-data/khq.dat,sha256=S4BkZDJz1Vd5ElABQGyLk2Sh1CDhJfh9HXfpaJaTx1I,15954 +babel/locale-data/khq_ML.dat,sha256=teE-r78FUOw25Mks7hiv83Krh99jOfJGl7B-VtPsax4,576 +babel/locale-data/ki.dat,sha256=lknpUwEpL9X9L92DCWFgh2hxejd02dFy_nn5rohPhC4,16137 +babel/locale-data/ki_KE.dat,sha256=qTrjqZYbtlx1ZjxTHsMKz9xqCykrkQc6sZuLW3pXkTc,594 +babel/locale-data/kk.dat,sha256=vUi17nunvqck9VvrJZZL5PHlSiRlkjPODWGpQ28Tndc,196219 +babel/locale-data/kk_KZ.dat,sha256=7EyEfXd8erAMXDGv-Fbia4Kt6VYQ2cGQaQ5oAdPBUUQ,594 +babel/locale-data/kkj.dat,sha256=3IyQXQ2CuPmYPuK1BFnYY3pytF6APoauOyaSaaEFOVI,4869 +babel/locale-data/kkj_CM.dat,sha256=HcCp5w6BildlCdSb65M4D08SlaP76QqJkojiLazj-6Y,595 +babel/locale-data/kl.dat,sha256=PET6ekK03k3wbiw0XF4-gSKpuKq-JZdrJ-MXU28PSA8,58154 +babel/locale-data/kl_GL.dat,sha256=91kcCMfFiTB9LETHhJRZmG9hHbSpors3_DlVRs7h5Lg,575 +babel/locale-data/kln.dat,sha256=0Mrkq9beQGoaiuPGHp6kRn68XbbB0b2hXHuD1434sRo,18024 +babel/locale-data/kln_KE.dat,sha256=bHMOLDyMiJJjTmg8Ym4OvTotfSbR27I0G55rlRxJ8ck,595 +babel/locale-data/km.dat,sha256=6_yKiLC9mh-MLMxZQOx5KUYQ291PEFv42NBolP-Fjf4,195649 +babel/locale-data/km_KH.dat,sha256=UnHrYozkculMa6ZKNIC3bzhvmaWSnXyt0GoWgIUhQnk,594 +babel/locale-data/kn.dat,sha256=BAnGDS40ur5xBejFyYbpOkwKFcc8LtAuGwFVe54cG6M,249117 +babel/locale-data/kn_IN.dat,sha256=hBXajSTXvDowl9xWM2IMSMeKUpD5t5-JT1qJpBYili4,617 +babel/locale-data/ko.dat,sha256=aE_VI9rcgN82-dqyShjMOAzfEcJLyIth8Q78KQORYHk,168390 +babel/locale-data/ko_KP.dat,sha256=d1PisuOtDrC2a5DAwAi3DT9t7dKMLDwERnkadg3GTTo,775 +babel/locale-data/ko_KR.dat,sha256=kwoW2qpGBb6THsYECa4N2x4D3pn7EWPTBRN7UwSlLNk,594 +babel/locale-data/kok.dat,sha256=nXMEU3BGJjaHgbDS7kHqzxosPgICnq6ZQxgCAIhik98,61882 +babel/locale-data/kok_IN.dat,sha256=UpqnoSabtcJCzbwuYD91ydT2refhVRKXR57KsO6e2Qo,618 +babel/locale-data/ks.dat,sha256=2BMSXdxYj_n0UA44fjWmk6Sm8c9FeQK08XFxgSRIWT4,103592 +babel/locale-data/ks_IN.dat,sha256=kaZjLrRzH9TScdAmm-cjR5t42ULgxl_lF8YlIqOvmNg,617 +babel/locale-data/ksb.dat,sha256=ti-5XvZbU7zvUYayuad-UNJ7jukcucIeiX9mJ-UYo9k,16057 +babel/locale-data/ksb_TZ.dat,sha256=gEg_oCUg2LiAUvvarxqqFQebjrZ0PE44i7GEU0h_ATM,576 +babel/locale-data/ksf.dat,sha256=Tp6aBOm_P40KHdKyTu2GqAWWPIemgFGIMKlDTuofu8Q,16531 +babel/locale-data/ksf_CM.dat,sha256=7EQOBzsWl1wzjDupYRj0dxzTft-8xV8Uo3gqOFp6I5E,595 +babel/locale-data/ksh.dat,sha256=s1n25cLfdN07oSneQDn4xZAW4gTebpwbBl5m4AHdFUo,88745 +babel/locale-data/ksh_DE.dat,sha256=FA_YtKhufAa5eiIko4d2eErDdhWIOzaAeC1m6TPKbZo,613 +babel/locale-data/kw.dat,sha256=XxlknsbhOSmPxsRcKWxr97I0-j0b4FYWTpNqMRmOH_4,4502 +babel/locale-data/kw_GB.dat,sha256=tmHV8qZirnwjceiSPqkaYV4mGCjGS3CsKZXrCr_lP_E,612 +babel/locale-data/ky.dat,sha256=P7iCQnPAV8iNWWqFDDwa5VjRM7hj6MoPM5vVFGTrOvc,191530 +babel/locale-data/ky_KG.dat,sha256=sdytPk-d2bJ-HC_XLcV2ngIctLGljBEKQ5PayxqeqZw,594 +babel/locale-data/lag.dat,sha256=oXhraYOLFC5fOljo0xVT3eKa7_zrFbEiIy5VeQDMh-0,17156 +babel/locale-data/lag_TZ.dat,sha256=yf4BUXd2mAmlONSPPvAp3v0uh7uAx3aSrHLKLRAwoOY,576 +babel/locale-data/lb.dat,sha256=xIzgh4AHMrnCNEo6UktO1m3n4UXJmX7WRhRfFQQwphw,164110 +babel/locale-data/lb_LU.dat,sha256=o7nfb5axxMi-7-d6KsJ6jJrtHmBkOmeGM7j9wZ_mYGQ,612 +babel/locale-data/lg.dat,sha256=tJWhQUkAR5g-Gxig-7J2AT2Zb-3sHUu6z_QWSga7C6s,16449 +babel/locale-data/lg_UG.dat,sha256=sFMdoAhUNrss-2KomFKx4ZuzNgj4Gh4rRQhTnd2j_hM,575 +babel/locale-data/lkt.dat,sha256=iHUS0G3kDD_dRfulEQO-XtiA8CMpcASWOpJU_YaaCZc,12749 +babel/locale-data/lkt_US.dat,sha256=IHvNyWl6mnemjyy53BbUs18rRHNPcWde9gMf2r4xRIY,613 +babel/locale-data/ln.dat,sha256=wxovXHrfIY5Lv5dhE1uxGiXPKLhhxwAs2B8JmfzYG4Y,25906 +babel/locale-data/ln_AO.dat,sha256=zZw-GNarkwMf9qOobSyEXnXu_dTW0pgufa4RfGg5EKk,595 +babel/locale-data/ln_CD.dat,sha256=rMiN0BXKqv1c3LTv_QeefbLM_8TojydgFA2VNxh2VDk,575 +babel/locale-data/ln_CF.dat,sha256=ecUyZJsFXtu5T8DZiCri-aemYRcW42tGci_vs9W0MzA,575 +babel/locale-data/ln_CG.dat,sha256=FIUSPTIs005E7I9Yjd1dt9FqDjdmvmozoVlk7azU1Qs,575 +babel/locale-data/lo.dat,sha256=_WDDSvHdrrMvpzDsNbO10I7ULYe9wRED-94ljGzNpwE,210728 +babel/locale-data/lo_LA.dat,sha256=PAskaHJpH_zmsQAUKF9wPAMoM4mADzbw7a0Z3At_1qI,594 +babel/locale-data/lrc.dat,sha256=7laMPZFUPKrH1UtJV9eBCdXln_y_-Y01jZwfgpiTj4o,18284 +babel/locale-data/lrc_IQ.dat,sha256=fkivYC3Nidg3d68qa6reVfBRfFYQKSdNvUfR90uw6oM,1214 +babel/locale-data/lrc_IR.dat,sha256=2qyMswdcrHjaexo0k7VuUZB__aDcXnjiLMhPuruup2g,638 +babel/locale-data/lt.dat,sha256=2KmoS9UsE0jP9zmnHulVYJAOX9hhgjJqBbTni7ZZhYw,273798 +babel/locale-data/lt_LT.dat,sha256=kH4w_umt2etGqthLy9rnMFeSPoWtOtcoU2239kUvvy0,612 +babel/locale-data/lu.dat,sha256=6HRJYdpJs2IJJxRgTq-NUQAb-UGrpwZhpDs7OzA1Z4g,15902 +babel/locale-data/lu_CD.dat,sha256=uyzHsadLotg9NWjeqdb8-Jgarg6CKoQ1yXOlibTqgvU,575 +babel/locale-data/luo.dat,sha256=ggLeixoB-vcCrYRDNydhYr83jhrH3pVxm79xRh4bq2U,15899 +babel/locale-data/luo_KE.dat,sha256=j89wfdrKh9_xgfHh5rvGLaWwV9vbwLMYq3SfDsoZN1k,595 +babel/locale-data/luy.dat,sha256=lMVs0VIeQWWLe3ojV0gdOinO_JKSor9pqwt-XZJwmWs,15873 +babel/locale-data/luy_KE.dat,sha256=QwFVEuaypDTiatm9cL285XpGvC_CD6JGSKXmAgoQMJY,595 +babel/locale-data/lv.dat,sha256=RWCsqX4uhmOOqnupANGWNV6wu_-ndOmZqETeVCoiHGs,207592 +babel/locale-data/lv_LV.dat,sha256=T9VP8GtEskLgOtJ0ibXAwDpaemJLkypArzVs_jeji3E,594 +babel/locale-data/mas.dat,sha256=xf3cHmGKT8R6iRaGDe9YXFRPwlgkewpmIPSn34XgNeA,17311 +babel/locale-data/mas_KE.dat,sha256=FsqNLhGZ0YdBER4_Jgt4EjF9iZliQyZDLIxRPJAFk7o,595 +babel/locale-data/mas_TZ.dat,sha256=5zxGMBLDy9bVdfdIvYo-ILNUrCDjg3VRJyOYI5YfpQI,597 +babel/locale-data/mer.dat,sha256=PxLBgUU0LA8B0hMCVy195Avby6qr28adpl_CaBkhk-Q,16102 +babel/locale-data/mer_KE.dat,sha256=Fb8TyxdsqWgI013nMkAJORwxOLDLnRhBQF-edbt5QO0,595 +babel/locale-data/mfe.dat,sha256=cKlyj0FqhGe30ya294A2j0y3pb4O0SHKO5X9GC-DbKM,15131 +babel/locale-data/mfe_MU.dat,sha256=Rqb3GU-lML_LlzrTeFD_fq0pqL51wqIiYFzNQvTcu8w,576 +babel/locale-data/mg.dat,sha256=VwM_8E8e4x5GfYYVF0NFJPmhTK-E4wb6gSU29PBYjP4,23701 +babel/locale-data/mg_MG.dat,sha256=6fld5wfdl9PJejnMrIaGG0I6ixNDIN8KduUWWua7u9E,575 +babel/locale-data/mgh.dat,sha256=l0AZFVbXiLGiYLKGOW_SejCVMvIVUnSu9ydCE0vwN_c,10494 +babel/locale-data/mgh_MZ.dat,sha256=aXnKgXZnTV53ATHfqbuqW867vVALu2MNgtqiAgAj0b4,595 +babel/locale-data/mgo.dat,sha256=9qEAp7rNL1sjibCqpT2xgj1JCMDIeyKZm7B9qIvRvS4,8164 +babel/locale-data/mgo_CM.dat,sha256=XFzwt-G-8DEnzNWaWTwZXO4r19HTiu-gQsjg4_WYHg0,595 +babel/locale-data/mk.dat,sha256=x6HrugOrvXGfdZuj_fF2AkbZQURCq940yM7PgNiaeV4,224491 +babel/locale-data/mk_MK.dat,sha256=lueGx4kbGFSLypEM7o-Z2D1R_0FOqRifvpblFDec7mw,594 +babel/locale-data/ml.dat,sha256=0WNxRJTk2D8ViBM1TtAGrdzgTuEqRl3E-nsW4fGrgS0,277253 +babel/locale-data/ml_IN.dat,sha256=-6qnc5WcllNYCvTO_xoBbowA5eWZUWRG5vRgJ8FO1vg,617 +babel/locale-data/mn.dat,sha256=QKM42kCK3CO7nOSdYmMBiNGcvcl-bHxiY830hINBBSA,187399 +babel/locale-data/mn_MN.dat,sha256=3ywCN_Xsf2vZSnkacHBcsOlNyCc7b6B-2Q7mSKFlVIU,594 +babel/locale-data/mr.dat,sha256=RhPlnSjTbXPfFhod-SGpAKafTyNzHF02swkc95j6d58,236486 +babel/locale-data/mr_IN.dat,sha256=894Hg3XT2HtqaGTpqpiXOf2urSBzGGcOY9ay8rMgsZE,617 +babel/locale-data/ms.dat,sha256=ehtzqxReNuQz_tZMTzl4okuB7rWm7zTRXeo_x8D5qKg,140295 +babel/locale-data/ms_BN.dat,sha256=Ra7pyaq5gAx3mqvfMiEgG3T79W65mRHUdWKVlZSV1GY,1243 +babel/locale-data/ms_MY.dat,sha256=TvcEqnrhHe3Legqmumye27FgQdgurFX2MhY7AzyEGr8,594 +babel/locale-data/ms_SG.dat,sha256=DJ5GltTejZ3Ip8uVhB-3FX6wGUWY1KfCcNU4spKaNo4,613 +babel/locale-data/mt.dat,sha256=CNHqdGdwzJsZ_tRV_F2EHZoDXgcrERehX1LbLhTbWy4,87129 +babel/locale-data/mt_MT.dat,sha256=GCW72m8IAUqms0TpYxQ8oDYzrAMEakK69jgdhMRc6Fs,594 +babel/locale-data/mua.dat,sha256=ClBP21FCnFwwVikldPg7XdefY_kIyQd9ck7aIu8_tCY,16586 +babel/locale-data/mua_CM.dat,sha256=f4mOxz4FnwuNRylj4ZWjULpezamVBgW3pkXgt9BggsQ,595 +babel/locale-data/my.dat,sha256=nyGIS7GmeIe4eLs7PrkWuaF1un9JecdIQIe7Z6N3Lc8,200059 +babel/locale-data/my_MM.dat,sha256=1dJmMqi4nqU96RlQJ2IL3bPpAw5tCv4Yh6N2_tJFrk8,594 +babel/locale-data/mzn.dat,sha256=iPE9wQl4Q2gYj91boThBRToL9VbEgyeBJjmvFNrwigY,65316 +babel/locale-data/mzn_IR.dat,sha256=YjcmgHcjsJBpcnllif6uAGUmlRCwtfLKfRqFVrcpOGA,638 +babel/locale-data/naq.dat,sha256=1sjRz6Oh5_0WxNWEc0O2tEgwsqmDH8vlNERRbhNbO88,16632 +babel/locale-data/naq_NA.dat,sha256=j3arpRTWPT_kAyIypVgQWdiDBTFgThbyPuilomtOINM,576 +babel/locale-data/nb.dat,sha256=dqmvm4PdTNvOCasQ3xw5CyGsTjupJFooEPhl6jrclWI,203220 +babel/locale-data/nb_NO.dat,sha256=whwRm-2CkDx2sTQh8cf0tR5UFy7IHOhfFNe2ROue5jo,612 +babel/locale-data/nb_SJ.dat,sha256=hs2w9d0NC78QFFy0wW6vm9tJ7sPMh78t8dObH7Z_9oo,593 +babel/locale-data/nd.dat,sha256=1-9CgRg-3IbhUxtTXb9bna6d9xJryP9TOMK62pWciiU,16326 +babel/locale-data/nd_ZW.dat,sha256=ui1oujhIu8dxMK4YSImFmPsF5JYzVoaS6lCgXTGVWmA,594 +babel/locale-data/nds.dat,sha256=2g5qQ_yemVS6zviaPjninGeQCKhZsjowORkGmQGiVgY,50582 +babel/locale-data/nds_DE.dat,sha256=TvkEIRGxukm-yMPNtdppqFLLcUAYJDzGOmXTbVpre24,613 +babel/locale-data/nds_NL.dat,sha256=aa_WimvNkXPJCiQ2L7DT2Lg8f2GzRbijd1C8EIGCTU4,613 +babel/locale-data/ne.dat,sha256=AW2XvWoupe7ldEMKS3-CJTBy3SIjb5uLmAVjeWMpJNE,235926 +babel/locale-data/ne_IN.dat,sha256=pxv5KvpFgve3Dq74sXww9Cxbg-R1fO_iknyqJxA0jmo,1251 +babel/locale-data/ne_NP.dat,sha256=uQVEl2qte70uFqft_u88op3KbxDmVWfaC9dEHc67MAo,594 +babel/locale-data/nl.dat,sha256=gCulo2SZ8QXV5gSqpd2zpo4VHEivJYFUAM00YERj2Ls,204884 +babel/locale-data/nl_AW.dat,sha256=Jm66mxcT1TTYN3TjJl8dWoSmdq0h3tUymx64INEhssI,597 +babel/locale-data/nl_BE.dat,sha256=QTqRwoJ2a5GG2aGc2JFD-eKg9MCsW2i_i4dXgjNjS1I,2074 +babel/locale-data/nl_BQ.dat,sha256=4YLHx-7KEyn-Ws0nEGa58jOQwcPSzZLTzDyo58tSPO0,594 +babel/locale-data/nl_CW.dat,sha256=2JpuEKCZomzkaaLSaVytWEfTDb2bvzA_PuIvcpW9OiE,597 +babel/locale-data/nl_NL.dat,sha256=fa7FN-97BwPAuVWsla-0i00ZYfNFR_vyCT4h5MoNWOc,612 +babel/locale-data/nl_SR.dat,sha256=YzUnhvZcviNbDNvwq0daEWZIfxnLRpZPNW8Q26BnRs4,655 +babel/locale-data/nl_SX.dat,sha256=ovlBTI-RgWwhXQRNv0DAYmL-Y7FDyooQSwaeZhtR088,597 +babel/locale-data/nmg.dat,sha256=bB-ql4jXwfas8ump88E5apNNFCsPN3fibAdV59IhCLU,16203 +babel/locale-data/nmg_CM.dat,sha256=UlGNzs-sd22YoJ1l0_6TBBDk_7QrAi-q8rGXFi94Nvc,595 +babel/locale-data/nn.dat,sha256=8BoSkMw_NggoBu8SMOG8AV5cZptldFdkxp3f37w4qi4,179508 +babel/locale-data/nn_NO.dat,sha256=mG08sOCkVJgsYJC-3Dx8Lqs4Gz1s3-EljKE25Fqteso,612 +babel/locale-data/nnh.dat,sha256=pqx4eigZUcr9Yp2K9PSYECN718aHa7PUOPIt1RP6004,6749 +babel/locale-data/nnh_CM.dat,sha256=AW2IJL5RJJsiLVDfjgIvg3XId0GaCPPNN6TIlw0H5uo,595 +babel/locale-data/nus.dat,sha256=Y0l0tb6FZSpOEI4D0IV6_Z4QHAM0hznmmJXucH8LDc0,9145 +babel/locale-data/nus_SS.dat,sha256=wFHVQg9OFzYNeyYHmO7RL9E0fBxNRw89oNX0TnYL3Do,576 +babel/locale-data/nyn.dat,sha256=wzo0_U2S69_K3OLDNxvwmi8zTIGonI9fg_SoAaeNd-s,16290 +babel/locale-data/nyn_UG.dat,sha256=MUob9xJGktiaWN6D5V77wLu8KrWVCGEtoy7G3j3EGhs,576 +babel/locale-data/om.dat,sha256=cN1ePR11OsL7SW_phnhydHjihK715DjZeBt23qM9K7E,16505 +babel/locale-data/om_ET.dat,sha256=BLMEcN1IKzqRS4DPAHgKeQ5XwipJ_45fjLMqS8lDy8s,594 +babel/locale-data/om_KE.dat,sha256=Puw2BMdCWAyLKd7Ww9MpntRxxsXZ6_fOMUdee3nD5qQ,1552 +babel/locale-data/or.dat,sha256=oxB3__7t1486Gxl-tCdzZyxm8ADOjvZRdO_PwWTKk3c,227399 +babel/locale-data/or_IN.dat,sha256=EN0J_rZT1Vtqc9FhFkx3hZrFCk6sOv524SnJJBwOhvg,617 +babel/locale-data/os.dat,sha256=cOhnNLL6U7H0g51-M2wEzlfsdjkjsmVCu4kxW1LouCI,17546 +babel/locale-data/os_GE.dat,sha256=Nu03DcgLg5mVIfmerMDdgRig6KULmeEWjb_NLz4svNw,594 +babel/locale-data/os_RU.dat,sha256=yctIp0TmNpmjvbWVlkRR3bifxX3PY0s9PqNO4EVie6M,654 +babel/locale-data/pa.dat,sha256=eXCnqSzNyOTutczyArzE4SHCondgZXpUZk7h40S6Xls,233245 +babel/locale-data/pa_Arab.dat,sha256=IzgKkFsOqQaLCBuBOk6K6EPwKX35KsfFcoX9RC4F8u8,3929 +babel/locale-data/pa_Arab_PK.dat,sha256=CfUbsx9ZLIH4YkL1PXZ-X8b_YlSlbBLvxF2G-b2bOtU,594 +babel/locale-data/pa_Guru.dat,sha256=BUs3HKHs-jstc_r4Bsh_WN4v6y2r5Qkw2uHkzsgEPz8,1235 +babel/locale-data/pa_Guru_IN.dat,sha256=AG77KhIem6K1xBozfgXnZF5lHcUgTANHhyO9GZV-7VI,617 +babel/locale-data/pl.dat,sha256=83nyVnGooPlq9KpKEZ0xjdbsSygkEVH5OS_tSsqk7E4,238684 +babel/locale-data/pl_PL.dat,sha256=uQ-UR5hpp2HTZtxGt_6WHpHD5TOvkYbOsajd6A3CFoY,612 +babel/locale-data/prg.dat,sha256=EM6DC4I9zjQT0PopsB4pZQO8T-KCIM2yMSCB13PousQ,20088 +babel/locale-data/prg_001.dat,sha256=86dUSwihSWKlQOPiZqvEi4oMu4epWnQwqX2WaxEVXzg,1553 +babel/locale-data/ps.dat,sha256=wz6_1oJcT6h1zcjSUThkPDCQKIAynzGu8xbhxuoO3xM,157163 +babel/locale-data/ps_AF.dat,sha256=5DHxL32RvpjDaFiGKhkPklHCKqihYkzeTPPsHqlqn1Y,637 +babel/locale-data/pt.dat,sha256=Dz6Nj1xqO6C9892BDwdZOjeHALQ2vhWB5pZcO_C-qxo,199547 +babel/locale-data/pt_AO.dat,sha256=JsbTMs0kHdoQqTad572TPUxMxqoxx3Bl85fVLmxS3_s,981 +babel/locale-data/pt_BR.dat,sha256=pcc38t0Dt0h0sJGhNoiypkd_lYoanbcWR98vySIIbsw,594 +babel/locale-data/pt_CH.dat,sha256=nz-IKj3RjhHjBmeccEh7ROlFMRbA7Xaouiq1rbqY1uI,612 +babel/locale-data/pt_CV.dat,sha256=FVIDfwHHCO879XAzqG0KAlTkmUtVUAhv9lKm5MYSQEs,1006 +babel/locale-data/pt_GQ.dat,sha256=FH7e40m1AMpzpbE3lBScL3Bwho4tYWS4dkeDxfL7vUc,575 +babel/locale-data/pt_GW.dat,sha256=BG3wY3-4ugGRxvNNHjyE-zajkJIspy4r3_G2yNXfldQ,961 +babel/locale-data/pt_LU.dat,sha256=zp0FAYQDDqYczNWuNiHPeUFid0yyybpMdp2h5v0TAT0,631 +babel/locale-data/pt_MO.dat,sha256=RhWBuMT-2_gLBN133BeJ3ddTb2tmVYF4lE-XIoC5p0s,1578 +babel/locale-data/pt_MZ.dat,sha256=yS92vneC9bpco6b4s5W8bg83zuxBpiGx3tueqFQEw6A,1001 +babel/locale-data/pt_PT.dat,sha256=1-5CmfBQrvGEwmGNvi8clwQzw0w1A3RtAZct7BxjXfw,77083 +babel/locale-data/pt_ST.dat,sha256=1MFFkGGa5Nypg0wptIRcOf0lI87W5HmEbSQCIakSXaU,981 +babel/locale-data/pt_TL.dat,sha256=odpTScCdVAbRqjTKughnK2oqb2ysr4JoPqzEtA5Fd90,961 +babel/locale-data/qu.dat,sha256=mCB4dUnhPu2kQosUtHR-ciIRaolQ8AvHr6M_bd7x2DY,56553 +babel/locale-data/qu_BO.dat,sha256=s6v0S-h9H9U50w0Igks0fwFDPAaljRRRlb0Il0bgYKQ,822 +babel/locale-data/qu_EC.dat,sha256=AUrfJdt7PAaqQCDhmiFpa6wDkQ74GJXATU0linQLiIU,796 +babel/locale-data/qu_PE.dat,sha256=YFZ24zPyOgncoDoukcpNEAMTOplVysgOtmR_SvuYPsQ,594 +babel/locale-data/rm.dat,sha256=2Rt_QkOBmsv-7ZOPOGnAcjM_kPemuSONNc1ntoccmAQ,67747 +babel/locale-data/rm_CH.dat,sha256=qQttVblvBcp937t7WYJ-BynxhhiRqgnD3JeguMteOJc,612 +babel/locale-data/rn.dat,sha256=A2RrOB7CBu3FXVvXgFvsmIRX1dzfAZsr-T-gZunsV4k,16796 +babel/locale-data/rn_BI.dat,sha256=F1FNeikdC9km3AlBMuwEztpUm95_5_v4lfD-lLKpRjw,575 +babel/locale-data/ro.dat,sha256=QwCYq0gXl69YPXvH8zLPhwY8entbrEl3SmG6V9cjVag,213755 +babel/locale-data/ro_MD.dat,sha256=vNL9FTi1Hmey5Q9bQ2Njed4lSBIap43EGJJF761kJ1w,3412 +babel/locale-data/ro_RO.dat,sha256=rTmaTLZ9wBhODpZTGYglCHd9G_6ZfT3ysR7MI0Evr-s,594 +babel/locale-data/rof.dat,sha256=Lb1go3dBzy8KgGsOe4NWWWdc70VFt0MvmHzSfA2s5SQ,16184 +babel/locale-data/rof_TZ.dat,sha256=OM8nqoYasKPjoVMfAJr0DtAckgrtlT0hhMqP2oxOLUs,576 +babel/locale-data/root.dat,sha256=5R6jZYxvB4XF8hAKXMJpJJwRcDok7-5T7jTLSoN1ipo,35604 +babel/locale-data/ru.dat,sha256=HiBfDt31eUzl6o3yykKIOKBvH9PZ4ePcQIemYPURnfI,287379 +babel/locale-data/ru_BY.dat,sha256=tTJUuSXMbycvAlJ11xYDv7zFGrcmf3odpP1JUc2Cxxs,635 +babel/locale-data/ru_KG.dat,sha256=geBbY9MVsYARfkTi3DL4BxNpqJbS2G6svjIHwyFw8O4,618 +babel/locale-data/ru_KZ.dat,sha256=PASjoiPUJrKoHmwxcUNhIIE7capyfjvKdSMbwD6Xa1c,615 +babel/locale-data/ru_MD.dat,sha256=FNWe5GlNeYTDzPysdUrLDC9uySKyok_bBSkWnTTI9XY,613 +babel/locale-data/ru_RU.dat,sha256=qFuUla88C7c0XUwTlba9D5xJUINJDem1ZILnn8cOHgc,612 +babel/locale-data/ru_UA.dat,sha256=re5op21CusmNC4Uh_fLfkZvbQruhXT9Ccs7XAg7X958,2490 +babel/locale-data/rw.dat,sha256=H9e9_P_T1BZRJmvi_p-l4ETmj06De23w1mfTW7T4Z7U,16114 +babel/locale-data/rw_RW.dat,sha256=uajemiNjW7GAFpr3zT-QOZLMtbWl0SSN6IHCMNDeqKM,575 +babel/locale-data/rwk.dat,sha256=GST46VJzghMjmZ_caMbuv-zluMoyZXj0vB7ItB49P5M,16071 +babel/locale-data/rwk_TZ.dat,sha256=uHNMeLyA3enVbBEFyDBEKPD1HWKkhYv-ZHnoTDmR-Pw,576 +babel/locale-data/sah.dat,sha256=muk3FdT0wZjZGOXOpPPlb673crPHjNxS8bwpLzjBfTg,47919 +babel/locale-data/sah_RU.dat,sha256=9Oegqzgr9K5UXM1lm3-7NcTDpmyY2MrtIOfH_nTZ4Qk,613 +babel/locale-data/saq.dat,sha256=kEfkcdRVb3JhZI9c0wb0E24dPh0zQe_sseAwITcU2e8,16469 +babel/locale-data/saq_KE.dat,sha256=G7AvOTptUtlrU4UGFHOTX5HuGE-ZLMGX6XwrSEYqLX8,595 +babel/locale-data/sbp.dat,sha256=tx1AVgDrAqD7V1rNgUe0Qgm2AhXfmo6CWDP0Hppqu5M,16494 +babel/locale-data/sbp_TZ.dat,sha256=L7rZPkNpCtZIOXzTN-fylwZyQ0MHbXmsqx7ZbSPCuzo,576 +babel/locale-data/sd.dat,sha256=rYyzjqNUe4p-yLIv4fyFl0nGgpfS7HDCEF5QS45tR1I,179764 +babel/locale-data/sd_PK.dat,sha256=U8s-K-I0yIZ05R61DSWLh922Th6dTwj86guuql0qPAs,594 +babel/locale-data/se.dat,sha256=3rNUQoJiQT4B-IKdaKNccvcMWkaDoFaGBjcKiTg1OMY,72427 +babel/locale-data/se_FI.dat,sha256=e4CYmxiPj4FlnpgrNz7wjcAT25DflbT2qjw6SQmhWGM,46503 +babel/locale-data/se_NO.dat,sha256=GkR1YCNEUBaTaN1iGtk0TZJXsqP_id7G7tj1U3SfyH0,612 +babel/locale-data/se_SE.dat,sha256=E9RzO3Fn7UShEZ4SYA3qaJ0FQ8fj3Ay8LqjWwxYt7sg,653 +babel/locale-data/seh.dat,sha256=5FsFs8psKEphTgD7M0KE76XC4vKNJ2FV7KnOFmMj3JE,15925 +babel/locale-data/seh_MZ.dat,sha256=k4mEUGg9bQY4WTPVx-Q2IYlBrAeY3U4ceE_2011qNgI,595 +babel/locale-data/ses.dat,sha256=F_YUvpp-GvwpbUhXw8aps1Smzjr7T-AZhAhkBgtp5cg,16013 +babel/locale-data/ses_ML.dat,sha256=4Q-8J2RbvqyuUSXn-IctABaedAYSpg_Ge5SIJ-Vc7Jc,576 +babel/locale-data/sg.dat,sha256=X_XUG-uDUGEWg8NkCNAp-WXdsRSIPz43cBUF-iDgaBw,16650 +babel/locale-data/sg_CF.dat,sha256=ULuAEg_GKp6Wy-JeA6QwPSg2QRctjQZNC1hX2AGrsbk,575 +babel/locale-data/shi.dat,sha256=joixlSJnQMrbhpPRRnFx-_Nh0rkBdIlLzBVelGOHdbM,22068 +babel/locale-data/shi_Latn.dat,sha256=FidqtDH_z5qjgMTqX3kOa1B4kmobH7nWvhFZH7Nw2hE,15632 +babel/locale-data/shi_Latn_MA.dat,sha256=taPpGbpbIDPv9LnaGTVBA-SQ-n4YimKqKNn6RqlA_hk,638 +babel/locale-data/shi_Tfng.dat,sha256=Z8tSvlGBj8iH-Pa8tHyURIVUQL-qfZTO5066eEbxz1g,933 +babel/locale-data/shi_Tfng_MA.dat,sha256=taPpGbpbIDPv9LnaGTVBA-SQ-n4YimKqKNn6RqlA_hk,638 +babel/locale-data/si.dat,sha256=D-AYYw29PuwBp9yhYB-e33sMuVkGMzEPkwjDbXwB5cU,229886 +babel/locale-data/si_LK.dat,sha256=xr9fCap1xmIMS7R15Q5PHRFWCtXITUD0M-ZQl9i6wDw,594 +babel/locale-data/sk.dat,sha256=ryGRqKLnf9X12yHxqAvC6N0fG41UESs-q3jh1ob2_-A,242171 +babel/locale-data/sk_SK.dat,sha256=WpoB8-b6bskGoNfvE4Ao3wEVjHgK12FZAc2hftca4YI,612 +babel/locale-data/sl.dat,sha256=72lUpB1k109jGuRbwd7v1cBVThF9chFYNHgOu9CM7p8,231866 +babel/locale-data/sl_SI.dat,sha256=DoLRx01Ag1iiuD8Q8bNYLP6rVFrK-krq4gA5cO8K8bU,594 +babel/locale-data/smn.dat,sha256=Vb3AfavGIIG-i0yiSQG2AxENBQ8V3hvnMp5bkKdcfNM,42596 +babel/locale-data/smn_FI.dat,sha256=B0C6nuYPGo3pPHF_50uUOsFc8FSwIyTo_vokgtOsABo,613 +babel/locale-data/sn.dat,sha256=Hfu5xs_BXm5nTEqFJfHjNBI0DeSS8MZaCpc5DkTinBY,23403 +babel/locale-data/sn_ZW.dat,sha256=fg4Dn-sWVH7BZIFBl0eAL35raEBsjR0UVr_aqddaE9I,594 +babel/locale-data/so.dat,sha256=SNjuNuy5BW6IZT9H5aowq5w_hqyi2-QWOA6DSGihB6E,26587 +babel/locale-data/so_DJ.dat,sha256=796oSoiwBkobIVqu_KLqG8tFeTPPeheO8zvORWJun50,615 +babel/locale-data/so_ET.dat,sha256=9u7nTr-2hVMr-9XP-PDjW2K6jMxlEfikA0eTUl9Ltf4,614 +babel/locale-data/so_KE.dat,sha256=Z9RCJqqGwTiwO1nCkUHoHRRdK_ar-RHqDibHFXU2vH8,1167 +babel/locale-data/so_SO.dat,sha256=gqd5aCQzbs-RWQbPWjIsJ8BtPqd1VJiadvPGfyEWMzc,575 +babel/locale-data/sq.dat,sha256=K8LcYL7ENGTSdYeCfPXlbKKYgn2ZiCtEp9pWuTzVTIA,166369 +babel/locale-data/sq_AL.dat,sha256=_hlSny9P4R94SitMnH0m1M5ELqqDK-mnygAbA29Qqys,594 +babel/locale-data/sq_MK.dat,sha256=1AWyAozEKeehR5h2AU5p7NL1NENxKwIAUhiV8fjOjAM,1167 +babel/locale-data/sq_XK.dat,sha256=kvztNXels_7a8-pmuezNrVsAZasD4EywHGu27ew7SAE,1146 +babel/locale-data/sr.dat,sha256=Qs-GyUFQ9Ob9bdqQyotZtI6USUKzPKDA3xEl48u37eM,269552 +babel/locale-data/sr_Cyrl.dat,sha256=S8ov68LvRx__Kv_7kM4Y2EjMkGfvT-km9zI4xbTBZyc,1940 +babel/locale-data/sr_Cyrl_BA.dat,sha256=QXjQq7UgomMiL7IYiP-WXj7W5e-AjUhQ8YY2_saHjSQ,5135 +babel/locale-data/sr_Cyrl_ME.dat,sha256=PeqnE582IlRp9ykPAG8pIkI1NKMm6jpKAxiUGrbIVTE,4219 +babel/locale-data/sr_Cyrl_RS.dat,sha256=K4wHRZd72gC3ki3zztknNj7fQYJEJG3-g3CxNtrzMfU,594 +babel/locale-data/sr_Cyrl_XK.dat,sha256=sRpVo9w0e_9KQ1-YpzqddfbGS8p_jpWF2h79ZFlBvNU,3104 +babel/locale-data/sr_Latn.dat,sha256=WLhGhU3l1UdFBBc_sc-IpwuOBDfFUWSuedW-FWQ7uRM,223650 +babel/locale-data/sr_Latn_BA.dat,sha256=ZT_ppASpBBbdC37I_dxU6PCBlml66okW5wNXM7LvFzE,4411 +babel/locale-data/sr_Latn_ME.dat,sha256=u0Kj_iml3SdGhZcA5R0sh98QDA48HW0gOtzm1thIPGY,3539 +babel/locale-data/sr_Latn_RS.dat,sha256=K4wHRZd72gC3ki3zztknNj7fQYJEJG3-g3CxNtrzMfU,594 +babel/locale-data/sr_Latn_XK.dat,sha256=bcZROWaHItqN7zgdP7urKmUwnpjA-y-XBJn4Ac6yfEk,2661 +babel/locale-data/sv.dat,sha256=mktbQ9msTg8ahcZSG2TQNUxbAJ7ZkWxrORhSD00NNBs,207854 +babel/locale-data/sv_AX.dat,sha256=Jhvd7Mvm8p7NtuAUWhN6g1D3qMWvoEhP7PH4lKj-2MQ,612 +babel/locale-data/sv_FI.dat,sha256=wFfrxOfDFlnVrJjr0OjaqWRMjCl93cycyn7V2CK0WCE,1359 +babel/locale-data/sv_SE.dat,sha256=De__XwpyJ6Ho0j7f-Lj8OY8j56PX8O3IJCt_mAwq89Y,612 +babel/locale-data/sw.dat,sha256=uffEuzRZNOFEniajcryJMCyI4q2524bhEYAF1EgLlDI,170625 +babel/locale-data/sw_CD.dat,sha256=kQYDnBqadKKxThOpcMwvbJa8WpAw8B6ZjNbOsiMaXCg,2740 +babel/locale-data/sw_KE.dat,sha256=o1jRlRGLe3qYPtwjtes_6NxkLx4aA2UNl_gM91ilWTk,2709 +babel/locale-data/sw_TZ.dat,sha256=fux8VwszdSZuxUtopOJsHcCqBA1KF0QIgWq5ilwF90Q,575 +babel/locale-data/sw_UG.dat,sha256=OocX1s_1wWafvOOYuFcowE16QRR3P3Ol3zZFQNNoHvY,596 +babel/locale-data/ta.dat,sha256=f-UATtzQQoZ0nT_DWRcp26K8eU8hGVsBIy7ZKG2UkE4,250754 +babel/locale-data/ta_IN.dat,sha256=KvK5HNWti1zqtZXqPj3eusjqcDXohyKFelKULbisLbI,617 +babel/locale-data/ta_LK.dat,sha256=wyO1Fq65uEb01iChQddD0gj-LGsntzkG_jg1BKmSklM,1167 +babel/locale-data/ta_MY.dat,sha256=TAHdH0084dxmd8roC9NFQjaZQkgSt_-rP20P4E9DLRo,1224 +babel/locale-data/ta_SG.dat,sha256=2FPkFGbZ1sIvNW7-2L0okBvSNpqCFSR2bKnh7zLXYVg,1243 +babel/locale-data/te.dat,sha256=uzOmfhYPRyGzLtVaP35sIuCnhFcJMeHJVWRYUdl7Igo,248429 +babel/locale-data/te_IN.dat,sha256=o4mBbvNYQKzI6Q32_F0iH2swEsrsaJyx8M37DpY1qWw,617 +babel/locale-data/teo.dat,sha256=HvETeKPMPdvBj3HtbCweOw_NK_hoTwztCC984kW5zp0,16685 +babel/locale-data/teo_KE.dat,sha256=Aye4pcdYZrRFJXvwaFfp2eUwGVscq1GtCS37Q6M9Qi4,616 +babel/locale-data/teo_UG.dat,sha256=n2wSGQP-tgbbgJhhjvW4KfYt3Xe1DrjKuBty_Qg2reE,576 +babel/locale-data/tg.dat,sha256=QQfPfQ5qgj0ee7BKnu3N1huCtDjU8jR2u8lQVprejsM,29564 +babel/locale-data/tg_TJ.dat,sha256=u_Al2SO1UtGQUWoXKSK16HPKQkkQGumOvOECZSTIP3g,594 +babel/locale-data/th.dat,sha256=ItMuAG_3eCv9i40ZuCgbpnFA2rjOlPiXU8lTvazzWdA,225873 +babel/locale-data/th_TH.dat,sha256=X-Ke5fYHaa0-m_X7xD9LAxSHKxWcbCw-w5hzks4zpv0,594 +babel/locale-data/ti.dat,sha256=GaWrAjaVp3NI7Q0v_zFnH7lWgtt28i72Uy8lkUotN8U,72943 +babel/locale-data/ti_ER.dat,sha256=auIt074WdhRvRkhgIFzQQg0oIj7gXx16aIPf6wWXEAs,944 +babel/locale-data/ti_ET.dat,sha256=oZR23bqziqABKb3cXWCCOd5HehtdNegNgGQr7hR8VIc,594 +babel/locale-data/tk.dat,sha256=t_a4be6biwmLcRSlj74pNoPpYx-kq6u8k4UelAn4x7o,156928 +babel/locale-data/tk_TM.dat,sha256=y1bNBcw7_ZtYhiDitwtiIKBC6Y22HciG2SY91Ia6hLc,594 +babel/locale-data/to.dat,sha256=r2hOLBMzW1tMTZ5OLV5jJJeuoG-MMXxBePl2LP-9yeQ,156463 +babel/locale-data/to_TO.dat,sha256=p3FA9d40fsIRI32_JKVW-RorJfljnOcH4JPaCdgqp6Q,575 +babel/locale-data/tr.dat,sha256=fEs5k_JZOu9pPb2Ac4nbu8tVcD8grblz1pjlSxrfPvU,200253 +babel/locale-data/tr_CY.dat,sha256=3NiYaibVQGotYuRlroe2urzfsE0odTL36foFQPfzGUA,1170 +babel/locale-data/tr_TR.dat,sha256=FE8Ve9UPUxQde0YhpMU7-_aTNB79KAtbBYxx7RaY9zM,594 +babel/locale-data/tt.dat,sha256=hamTberFKk_GdqsIjTGftor8N58ulZUeCm05wJHsktA,33308 +babel/locale-data/tt_RU.dat,sha256=r6z2MY7vDunM6iZWp29qtpX0Lkvy-KiNGFQEdgFVu9I,612 +babel/locale-data/twq.dat,sha256=eXTCEqoF3IamKDzIwCylWNFF7VbG_mlA59Mx5ngflwM,16186 +babel/locale-data/twq_NE.dat,sha256=oTe_pKBEZj7K-ohxQ_vSc_1A2CaNCT3wYP7Qu4JngHk,576 +babel/locale-data/tzm.dat,sha256=rNf5FgW_hIi5ECF7gVG6JRTjZSbAyESHh9W_Ns6N03Q,16162 +babel/locale-data/tzm_MA.dat,sha256=g3lMK0Rnnh8rIzHu02jgz51krcWY-DMYw3WF9ePNkSM,638 +babel/locale-data/ug.dat,sha256=LuvMklRJ2jP9mK_S6NWlpvMJ8X6TLv_UvWLQOtiFuEs,128172 +babel/locale-data/ug_CN.dat,sha256=4tEm5r9VjRJDIsbha5yQTo2jtqnRgPFtOhlLqtu7pEU,594 +babel/locale-data/uk.dat,sha256=69-0lMSKqF_irEO5SNYpmF6I72fEUzeKbZReQrbLSPk,294883 +babel/locale-data/uk_UA.dat,sha256=FHlouirRBCg5aTxgOg1W5OwiyF_-qsnv4Y14_y4mtN8,594 +babel/locale-data/ur.dat,sha256=0GxHYNXtc8SOCO83TiB-WAzFKsrDUFEbP8_ADyRims4,187295 +babel/locale-data/ur_IN.dat,sha256=Mmt2CPx4Iz4dXgmVZ_PX_q1J4z3-IG2_kKTqphA5_fk,12578 +babel/locale-data/ur_PK.dat,sha256=IsEOqI0sg-a24NEyPWk93F2uHgGHg0i3u0NaRbucmLY,594 +babel/locale-data/uz.dat,sha256=4xIMIGcOnFpfqOMLBxqvAPXTpFACqW_Mi49kEcAWzOE,162858 +babel/locale-data/uz_Arab.dat,sha256=7RGOn6BrYCi8w_f4228OCHLwRDcH5_BMEWtWJmAtDW4,4097 +babel/locale-data/uz_Arab_AF.dat,sha256=ep-zNVV6M2xpdGyCYkz1eq2px5PGWgsvLnITOjOybyk,637 +babel/locale-data/uz_Cyrl.dat,sha256=uTPZqIy1r8eCdU-NwzWKOwY-mz5kTmiSCmYS_1chlGA,97962 +babel/locale-data/uz_Cyrl_UZ.dat,sha256=Z6emj4sUsjiIt7yVU8VOfSvgi0PcdgKDOV4JnncpMgM,594 +babel/locale-data/uz_Latn.dat,sha256=YqBZmAypkxHU92mt-IinpgsHvKvG4gqXtAesiL1My1w,1251 +babel/locale-data/uz_Latn_UZ.dat,sha256=w5jLVYBzVH4zK537J_U97J5Q5Ip_LX7Qv2ccHX_VFh4,594 +babel/locale-data/vai.dat,sha256=RsC03j8xHG7RPpPFx8F4R2J1R7qt_qL1tFsj3KeVvy8,19008 +babel/locale-data/vai_Latn.dat,sha256=Uagq-lIbFxni2ToB6Zxt4-KuV9QLwqkI60VyT4HWJIk,15273 +babel/locale-data/vai_Latn_LR.dat,sha256=kKdKBolV6kkG4i77FlhGUJ9ybiP9wiANIJVVXnsdiaY,576 +babel/locale-data/vai_Vaii.dat,sha256=GQlrEmZa3jPxLmlWyBgw075EqFAYrqBCjxHDIxLje3c,652 +babel/locale-data/vai_Vaii_LR.dat,sha256=kKdKBolV6kkG4i77FlhGUJ9ybiP9wiANIJVVXnsdiaY,576 +babel/locale-data/vi.dat,sha256=i8JqE4DcNvBHu_5wVY5jtx2K6MFviry2yX0kCQoF2Gs,163704 +babel/locale-data/vi_VN.dat,sha256=MT971u0doT2sS_FKmMSfGpKjhjwJj7trA3SYz-9xOFY,594 +babel/locale-data/vo.dat,sha256=FclgDib_PFzrb05gyxTFLNsRCcTlK_f3iym-_6QFCLs,5208 +babel/locale-data/vo_001.dat,sha256=MO1UK_QrSFowzndRFwd_XpUErLb8xspFgga5L9XjH7U,809 +babel/locale-data/vun.dat,sha256=PDHx2JM-uFDTrT-0ZeWwg8qx7iYR7vDYFUb0apL2s8Q,16081 +babel/locale-data/vun_TZ.dat,sha256=o0tT80Fmcmp6hiByl_TLuHXDGUPWRnSoJ7XTUXkgci4,576 +babel/locale-data/wae.dat,sha256=53iTDyqe8DpckImC48A8xtwb5MUnqC90t3C_pawY0Hc,28610 +babel/locale-data/wae_CH.dat,sha256=JkuBIOHx2bWSyVTBCyA9LGWJkT5LuPDQxErA7JPn-q8,613 +babel/locale-data/wo.dat,sha256=PxOUNdcWct9YPwCj7xORCn382G1I-IZ2nsxPaaDLgIA,25653 +babel/locale-data/wo_SN.dat,sha256=84YH7D9Mfb2-z4qkXu4JmOza0r7kRjjoNUXzFJ8DOjs,575 +babel/locale-data/xog.dat,sha256=BDqeCZPVW10lFyTQul6Ozd9XL9GpC29vdP3-wq6u818,16570 +babel/locale-data/xog_UG.dat,sha256=hnmmHgvXnka_qPcY_JSTVwiuuPfqxFE1vhtrvgIV8Qk,576 +babel/locale-data/yav.dat,sha256=pqXK-Ocjddv-xp5iqSQGKWNDjvJOu4VIcnFvX_F_KA4,15316 +babel/locale-data/yav_CM.dat,sha256=eDcSyzDiW-zWiMgbDftrGQ-JawS5UkyhLjnpJwAXfM8,595 +babel/locale-data/yi.dat,sha256=-UxTQUycPPab6Cv_9nOEbgMp8we1UsHG03VbYfkFbRA,30365 +babel/locale-data/yi_001.dat,sha256=a_PWAcOfMcgD3Ci-Xxmd7Z0U-JykH88OotSs2r4TbgE,871 +babel/locale-data/yo.dat,sha256=0Kiu0UyT34b8cSiQxSqx6GeOItwQHsFXtWdKgRfkHWU,30966 +babel/locale-data/yo_BJ.dat,sha256=P39DNFlwBelLj1w2iXYzNQziIvDRbCiwEs-vUxxdXJc,17415 +babel/locale-data/yo_NG.dat,sha256=SPGHHrsG646a8-CXkBSedjkIQfSlSzNxhOkFTSam4_U,575 +babel/locale-data/yue.dat,sha256=ObBX1E-Qy4pDmOAzVTkBgu8q1w157zFu6rJUUo0JNPI,174656 +babel/locale-data/yue_Hans.dat,sha256=E_JuKsqtSVI72MI5aYuL4AMe9b8LyTFKuokE2FFyvJs,174506 +babel/locale-data/yue_Hans_CN.dat,sha256=FD6PtLWYGIGvuBQRwxxnGcAqSgduEBK7Bfk80ikplo0,595 +babel/locale-data/yue_Hant.dat,sha256=toSvN_ttGDQTMqHHBOh_qe8bdTlPC161zW4uhHbDLmY,1265 +babel/locale-data/yue_Hant_HK.dat,sha256=5L25AqxWLcf5G1-1EHsYlnllD6Kj6Ft5Heb-is59r28,595 +babel/locale-data/zgh.dat,sha256=RDR_sxf8HlDaGto3mYJQ6D_-f9hh2EF4_x5ssBi8_yE,30698 +babel/locale-data/zgh_MA.dat,sha256=-mIsbG_OUFgRA4M4O1PO1oCk3gG8wtmqOefW6wz629c,638 +babel/locale-data/zh.dat,sha256=2sJ-YuGeLZMMqp355XYStn3MxEKUQXeOC4sSe9vIIdg,173089 +babel/locale-data/zh_Hans.dat,sha256=9RPX-KVVfMN2IHOVZMdejlC7Jmr1NcubQu53ib_AGrs,1264 +babel/locale-data/zh_Hans_CN.dat,sha256=m73pQQXwSIRzZtmVo89LdJJ4Ily98FRff6B-ynvTgaY,594 +babel/locale-data/zh_Hans_HK.dat,sha256=xRj9Lo5HPNr-Qp4m-hgvxo3N_OZvbrd1CawyLP-9Y3s,4232 +babel/locale-data/zh_Hans_MO.dat,sha256=crCTIywkRvGEDBie_gbQLkpRF1cskesvQPwDog9xDlo,3195 +babel/locale-data/zh_Hans_SG.dat,sha256=hqfFDqZWwo8yxETsJBVl-gH_y7-RalbiOn2JVhwAAB0,3391 +babel/locale-data/zh_Hant.dat,sha256=CJrkC6wMlup-tOBprKPJybYG4olxFeacHsA4ws0yAQ8,179603 +babel/locale-data/zh_Hant_HK.dat,sha256=MwQKgqj8Wc9WLOD393m9M_voeI-g6_jgSS9X5XSjJWc,53128 +babel/locale-data/zh_Hant_MO.dat,sha256=jdV1f_QStKTosT88LZj-RbybiNe8d2lY7nQwQElCmMo,616 +babel/locale-data/zh_Hant_TW.dat,sha256=1UYSSxiof-Tu4-mndBS1rR8_9JWpekz2e0lAyT4g0uQ,594 +babel/locale-data/zu.dat,sha256=L2GmnpEBVsyOj8S4-T1ediQVn6A90l0TEK9smFD-Hn4,163774 +babel/locale-data/zu_ZA.dat,sha256=3mOuEXdrwuqqCbS9Aw43PixPjySzgnW8oxM_Rz1_Thw,594 +babel/localtime/__init__.py,sha256=9dw84jijHKYc6pYSsFUuZX1vPAkIAgW7vgrYvZWhgMU,1721 +babel/localtime/_unix.py,sha256=P66o3ErKXzhFvj3e3Qk6MBS7AR0qsDqSQclIAMHKp18,4801 +babel/localtime/_win32.py,sha256=PCCuG9Y-FU5X_VtbNTiJSrZg6rJ40NatSkMfywA-1Zw,3076 +babel/messages/__init__.py,sha256=TN0VsuADkMq-5E1e8xDDSF2Kstyr3U0MUQLyAusUv00,254 +babel/messages/catalog.py,sha256=KFrZAQiLOXs-z0GrpRUi8TjSOV8fwPWsEAatPF0jfhA,32110 +babel/messages/checkers.py,sha256=Ll0yoxc6DZtzojnZKegvnGla-hq6yLSQ1DPkGSk1cKM,6085 +babel/messages/extract.py,sha256=BoJZ07KDiqBjKSThu721rN0ip-z13v5smJvCWqjAgew,26428 +babel/messages/frontend.py,sha256=GOuDb8eRGXFCaO6J8qGXA_K1brSE4lT1Aj7s2OJSVJI,38113 +babel/messages/jslexer.py,sha256=NNw-D2cIBpNri2rGIqPqUZJT51wqGc1Y2eTl_WpwOS0,6334 +babel/messages/mofile.py,sha256=x9t4CpWsIo-sT7xUrl5_Fw1Xy1y8Ql1DCZzBdNNORX4,7299 +babel/messages/plurals.py,sha256=JjbYuu9Gj1VkEfjKRuSDv7OcdTJPdEiSSuh1mRNkBg8,7206 +babel/messages/pofile.py,sha256=5T4xuLKocK0VT_asCpMBPIB9VQMkhoMjyfDlHblDRJo,20583 +../../../bin/pybabel,sha256=j3RmbgGsFLe79Ofed5jzQNB3nzOqI8SP7kzZ996HtwY,257 +Babel-2.6.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +babel/messages/plurals.pyc,, +babel/messages/frontend.pyc,, +babel/messages/pofile.pyc,, +babel/localedata.pyc,, +babel/messages/jslexer.pyc,, +babel/messages/mofile.pyc,, +babel/core.pyc,, +babel/support.pyc,, +babel/util.pyc,, +babel/languages.pyc,, +babel/plural.pyc,, +babel/messages/extract.pyc,, +babel/localtime/__init__.pyc,, +babel/messages/__init__.pyc,, +babel/messages/checkers.pyc,, +babel/localtime/_win32.pyc,, +babel/numbers.pyc,, +babel/localtime/_unix.pyc,, +babel/__init__.pyc,, +babel/units.pyc,, +babel/lists.pyc,, +babel/_compat.pyc,, +babel/messages/catalog.pyc,, +babel/dates.pyc,, diff --git a/venv/lib/python2.7/site-packages/Babel-2.6.0.dist-info/WHEEL b/venv/lib/python2.7/site-packages/Babel-2.6.0.dist-info/WHEEL new file mode 100644 index 0000000..f21b51c --- /dev/null +++ b/venv/lib/python2.7/site-packages/Babel-2.6.0.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.31.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/lib/python2.7/site-packages/Babel-2.6.0.dist-info/entry_points.txt b/venv/lib/python2.7/site-packages/Babel-2.6.0.dist-info/entry_points.txt new file mode 100644 index 0000000..18c3a58 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Babel-2.6.0.dist-info/entry_points.txt @@ -0,0 +1,22 @@ + + [console_scripts] + pybabel = babel.messages.frontend:main + + [distutils.commands] + compile_catalog = babel.messages.frontend:compile_catalog + extract_messages = babel.messages.frontend:extract_messages + init_catalog = babel.messages.frontend:init_catalog + update_catalog = babel.messages.frontend:update_catalog + + [distutils.setup_keywords] + message_extractors = babel.messages.frontend:check_message_extractors + + [babel.checkers] + num_plurals = babel.messages.checkers:num_plurals + python_format = babel.messages.checkers:python_format + + [babel.extractors] + ignore = babel.messages.extract:extract_nothing + python = babel.messages.extract:extract_python + javascript = babel.messages.extract:extract_javascript + \ No newline at end of file diff --git a/venv/lib/python2.7/site-packages/Babel-2.6.0.dist-info/top_level.txt b/venv/lib/python2.7/site-packages/Babel-2.6.0.dist-info/top_level.txt new file mode 100644 index 0000000..98f6593 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Babel-2.6.0.dist-info/top_level.txt @@ -0,0 +1 @@ +babel diff --git a/venv/lib/python2.7/site-packages/ExifRead-2.1.2.dist-info/DESCRIPTION.rst b/venv/lib/python2.7/site-packages/ExifRead-2.1.2.dist-info/DESCRIPTION.rst new file mode 100644 index 0000000..f6839fe --- /dev/null +++ b/venv/lib/python2.7/site-packages/ExifRead-2.1.2.dist-info/DESCRIPTION.rst @@ -0,0 +1,146 @@ +******* +EXIF.py +******* + +.. image:: https://pypip.in/v/ExifRead/badge.png + :target: https://crate.io/packages/ExifRead +.. image:: https://pypip.in/d/ExifRead/badge.png + :target: https://crate.io/packages/ExifRead +.. image:: https://travis-ci.org/ianare/exif-py.png + :target: https://travis-ci.org/ianare/exif-py + +Easy to use Python module to extract Exif metadata from tiff and jpeg files. + +Originally written by Gene Cash & Thierry Bousch. + + +Installation +************ + +PyPI +==== +The recommended process is to install the `PyPI package `_, +as it allows easily staying up to date:: + + $ pip install exifread + +See the `pip documentation `_ for more info. + +Archive +======= +Download an archive from the project's `releases page `_. + +Extract and enjoy. + + +Compatibility +************* + +EXIF.py is tested on the following Python versions: + +- 2.6 +- 2.7 +- 3.2 +- 3.3 +- 3.4 + + +Usage +***** + +Command line +============ + +Some examples:: + + $ EXIF.py image1.jpg + $ EXIF.py image1.jpg image2.tiff + $ find ~/Pictures -name "*.jpg" -name "*.tiff" | xargs EXIF.py + +Show command line options:: + + $ EXIF.py + +Python Script +============= +:: + + import exifread + # Open image file for reading (binary mode) + f = open(path_name, 'rb') + + # Return Exif tags + tags = exifread.process_file(f) + +*Note:* To use this library in your project as a Git submodule, you should:: + + from import exifread + +Returned tags will be a dictionary mapping names of Exif tags to their +values in the file named by path_name. +You can process the tags as you wish. In particular, you can iterate through all the tags with:: + + for tag in tags.keys(): + if tag not in ('JPEGThumbnail', 'TIFFThumbnail', 'Filename', 'EXIF MakerNote'): + print "Key: %s, value %s" % (tag, tags[tag]) + +An ``if`` statement is used to avoid printing out a few of the tags that tend to be long or boring. + +The tags dictionary will include keys for all of the usual Exif tags, and will also include keys for +Makernotes used by some cameras, for which we have a good specification. + +Note that the dictionary keys are the IFD name followed by the tag name. For example:: + + 'EXIF DateTimeOriginal', 'Image Orientation', 'MakerNote FocusMode' + + +Tag Descriptions +**************** + +Tags are divided into these main categories: + +- ``Image``: information related to the main image (IFD0 of the Exif data). +- ``Thumbnail``: information related to the thumbnail image, if present (IFD1 of the Exif data). +- ``EXIF``: Exif information (sub-IFD). +- ``GPS``: GPS information (sub-IFD). +- ``Interoperability``: Interoperability information (sub-IFD). +- ``MakerNote``: Manufacturer specific information. There are no official published references for these tags. + + +Processing Options +****************** + +These options can be used both in command line mode and within a script. + +Faster Processing +================= + +Don't process makernote tags, don't extract the thumbnail image (if any). + +Pass the ``-q`` or ``--quick`` command line arguments, or as:: + + tags = exifread.process_file(f, details=False) + +Stop at a Given Tag +=================== + +To stop processing the file after a specified tag is retrieved. + +Pass the ``-t TAG`` or ``--stop-tag TAG`` argument, or as:: + + tags = exifread.process_file(f, stop_tag='TAG') + +where ``TAG`` is a valid tag name, ex ``'DateTimeOriginal'``. + +*The two above options are useful to speed up processing of large numbers of files.* + +Strict Processing +================= + +Return an error on invalid tags instead of silently ignoring. + +Pass the ``-s`` or ``--strict`` argument, or as:: + + tags = exifread.process_file(f, strict=True) + + diff --git a/venv/lib/python2.7/site-packages/ExifRead-2.1.2.dist-info/INSTALLER b/venv/lib/python2.7/site-packages/ExifRead-2.1.2.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python2.7/site-packages/ExifRead-2.1.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python2.7/site-packages/ExifRead-2.1.2.dist-info/METADATA b/venv/lib/python2.7/site-packages/ExifRead-2.1.2.dist-info/METADATA new file mode 100644 index 0000000..9aa33df --- /dev/null +++ b/venv/lib/python2.7/site-packages/ExifRead-2.1.2.dist-info/METADATA @@ -0,0 +1,169 @@ +Metadata-Version: 2.0 +Name: ExifRead +Version: 2.1.2 +Summary: Read Exif metadata from tiff and jpeg files. +Home-page: https://github.com/ianare/exif-py +Author: Ianaré Sévi +Author-email: ianare@gmail.com +License: BSD +Keywords: exif image metadata photo +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Console +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: End Users/Desktop +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3.2 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Topic :: Utilities + +******* +EXIF.py +******* + +.. image:: https://pypip.in/v/ExifRead/badge.png + :target: https://crate.io/packages/ExifRead +.. image:: https://pypip.in/d/ExifRead/badge.png + :target: https://crate.io/packages/ExifRead +.. image:: https://travis-ci.org/ianare/exif-py.png + :target: https://travis-ci.org/ianare/exif-py + +Easy to use Python module to extract Exif metadata from tiff and jpeg files. + +Originally written by Gene Cash & Thierry Bousch. + + +Installation +************ + +PyPI +==== +The recommended process is to install the `PyPI package `_, +as it allows easily staying up to date:: + + $ pip install exifread + +See the `pip documentation `_ for more info. + +Archive +======= +Download an archive from the project's `releases page `_. + +Extract and enjoy. + + +Compatibility +************* + +EXIF.py is tested on the following Python versions: + +- 2.6 +- 2.7 +- 3.2 +- 3.3 +- 3.4 + + +Usage +***** + +Command line +============ + +Some examples:: + + $ EXIF.py image1.jpg + $ EXIF.py image1.jpg image2.tiff + $ find ~/Pictures -name "*.jpg" -name "*.tiff" | xargs EXIF.py + +Show command line options:: + + $ EXIF.py + +Python Script +============= +:: + + import exifread + # Open image file for reading (binary mode) + f = open(path_name, 'rb') + + # Return Exif tags + tags = exifread.process_file(f) + +*Note:* To use this library in your project as a Git submodule, you should:: + + from import exifread + +Returned tags will be a dictionary mapping names of Exif tags to their +values in the file named by path_name. +You can process the tags as you wish. In particular, you can iterate through all the tags with:: + + for tag in tags.keys(): + if tag not in ('JPEGThumbnail', 'TIFFThumbnail', 'Filename', 'EXIF MakerNote'): + print "Key: %s, value %s" % (tag, tags[tag]) + +An ``if`` statement is used to avoid printing out a few of the tags that tend to be long or boring. + +The tags dictionary will include keys for all of the usual Exif tags, and will also include keys for +Makernotes used by some cameras, for which we have a good specification. + +Note that the dictionary keys are the IFD name followed by the tag name. For example:: + + 'EXIF DateTimeOriginal', 'Image Orientation', 'MakerNote FocusMode' + + +Tag Descriptions +**************** + +Tags are divided into these main categories: + +- ``Image``: information related to the main image (IFD0 of the Exif data). +- ``Thumbnail``: information related to the thumbnail image, if present (IFD1 of the Exif data). +- ``EXIF``: Exif information (sub-IFD). +- ``GPS``: GPS information (sub-IFD). +- ``Interoperability``: Interoperability information (sub-IFD). +- ``MakerNote``: Manufacturer specific information. There are no official published references for these tags. + + +Processing Options +****************** + +These options can be used both in command line mode and within a script. + +Faster Processing +================= + +Don't process makernote tags, don't extract the thumbnail image (if any). + +Pass the ``-q`` or ``--quick`` command line arguments, or as:: + + tags = exifread.process_file(f, details=False) + +Stop at a Given Tag +=================== + +To stop processing the file after a specified tag is retrieved. + +Pass the ``-t TAG`` or ``--stop-tag TAG`` argument, or as:: + + tags = exifread.process_file(f, stop_tag='TAG') + +where ``TAG`` is a valid tag name, ex ``'DateTimeOriginal'``. + +*The two above options are useful to speed up processing of large numbers of files.* + +Strict Processing +================= + +Return an error on invalid tags instead of silently ignoring. + +Pass the ``-s`` or ``--strict`` argument, or as:: + + tags = exifread.process_file(f, strict=True) + + diff --git a/venv/lib/python2.7/site-packages/ExifRead-2.1.2.dist-info/RECORD b/venv/lib/python2.7/site-packages/ExifRead-2.1.2.dist-info/RECORD new file mode 100644 index 0000000..0dfd201 --- /dev/null +++ b/venv/lib/python2.7/site-packages/ExifRead-2.1.2.dist-info/RECORD @@ -0,0 +1,43 @@ +exifread/classes.py,sha256=F7F4wGw86QkLrTiqvJyTHum88uo909i4i00m0Up2NwY,23281 +exifread/__init__.py,sha256=orsDM4UpQNRtgKjeSMv9uHPuL9fXawdtl9d5sRkeqlo,11014 +exifread/exif_log.py,sha256=xBaUZVkBs8Tbs0JIdBh4Me7spQ9BlumqlWH-N2Xzkl8,2030 +exifread/utils.py,sha256=fk3WYWcrzBjRmbmVmZMupKoTMqtE-HjSEOkP81wBt1A,1888 +exifread/tags/exif.py,sha256=rSUNUwwShUbRaUV1U21n8Jp4XtdfuhfPnBj9mr47HEQ,13576 +exifread/tags/makernote_apple.py,sha256=UTJuQgw7EvpBQyWuhC_AZhodvsK11lQb4fnVVVavWsw,270 +exifread/tags/__init__.py,sha256=m6HFOnx413zUuddbjYRjBgoZRJNHs39rygnkEjsEIds,624 +exifread/tags/makernote_canon.py,sha256=_04WcljVvLlzZZ8Pubfl80tAPackBgkTLpmX3eXznn8,22907 +exifread/tags/makernote.py,sha256=WfoDim4CkKi8bMSoHRSiGxgIo6yQCM_KRy9BZG5pkVU,16878 +exifread/tags/makernote_fujifilm.py,sha256=w8zeRu3fl8ST0S01L-o-geLttfZ_eNTagRHevulIuFE,3011 +exifread/tags/makernote/canon.py,sha256=_04WcljVvLlzZZ8Pubfl80tAPackBgkTLpmX3eXznn8,22907 +exifread/tags/makernote/nikon.py,sha256=nI85caRIcps8MnAB2Uk1toC_EbUj-CHLeI4bVHbRMPo,7606 +exifread/tags/makernote/__init__.py,sha256=2q-9uS1gOcJXtJSvlMTmveS-lEI4BenfmzqDLS_Yd8w,161 +exifread/tags/makernote/casio.py,sha256=jx9LPNpxZrcLNWbHt5fotlnbOe-KIBX3-Zo-jIfNrDo,1283 +exifread/tags/makernote/olympus.py,sha256=wF9mtvG1qb2J8Ks1DBK-nWt933KhD990p1QwZ5gvDdM,7782 +exifread/tags/makernote/apple.py,sha256=UTJuQgw7EvpBQyWuhC_AZhodvsK11lQb4fnVVVavWsw,270 +exifread/tags/makernote/fujifilm.py,sha256=rdyAymrlUQxAXSWlrp_vM08IAwFAfpB5HjAcV-7Qhxk,3018 +ExifRead-2.1.2.dist-info/top_level.txt,sha256=C-Ho9vfEuMuxXuhnMTkhKK78VLwdjMQ0dqDVJazcBdw,9 +ExifRead-2.1.2.dist-info/DESCRIPTION.rst,sha256=E4agT9eJyt62T_RtDjQqFhRnUVtxZlYYATx5gjjWwSQ,3803 +ExifRead-2.1.2.dist-info/metadata.json,sha256=wPRxTWy56ZxMWW0MEiOFytCT7zw1-ach0FmLg_E6IlM,956 +ExifRead-2.1.2.dist-info/WHEEL,sha256=54bVun1KfEBTJ68SHUmbxNPj80VxlQ0sHi4gZdGZXEY,92 +ExifRead-2.1.2.dist-info/RECORD,, +ExifRead-2.1.2.dist-info/METADATA,sha256=Z-XfRIegVrNYosGKvM7cElkiVyNPVQABBMaXeXcFm3g,4640 +../../../bin/EXIF.py,sha256=1M3-RLSh_SzeQ9oEWltGJ9SYlQVzEcHquDI2_PG81AY,3926 +ExifRead-2.1.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +exifread/tags/makernote/fujifilm.pyc,, +exifread/tags/makernote/olympus.pyc,, +exifread/classes.pyc,, +../../../bin/EXIF.pyc,, +exifread/tags/exif.pyc,, +exifread/__init__.pyc,, +exifread/tags/makernote_fujifilm.pyc,, +exifread/tags/makernote/__init__.pyc,, +exifread/tags/makernote/canon.pyc,, +exifread/tags/makernote/casio.pyc,, +exifread/tags/__init__.pyc,, +exifread/tags/makernote_apple.pyc,, +exifread/tags/makernote.pyc,, +exifread/utils.pyc,, +exifread/tags/makernote/apple.pyc,, +exifread/tags/makernote/nikon.pyc,, +exifread/tags/makernote_canon.pyc,, +exifread/exif_log.pyc,, diff --git a/venv/lib/python2.7/site-packages/ExifRead-2.1.2.dist-info/WHEEL b/venv/lib/python2.7/site-packages/ExifRead-2.1.2.dist-info/WHEEL new file mode 100644 index 0000000..45a0cd8 --- /dev/null +++ b/venv/lib/python2.7/site-packages/ExifRead-2.1.2.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.24.0) +Root-Is-Purelib: true +Tag: py2-none-any + diff --git a/venv/lib/python2.7/site-packages/ExifRead-2.1.2.dist-info/metadata.json b/venv/lib/python2.7/site-packages/ExifRead-2.1.2.dist-info/metadata.json new file mode 100644 index 0000000..9c1551a --- /dev/null +++ b/venv/lib/python2.7/site-packages/ExifRead-2.1.2.dist-info/metadata.json @@ -0,0 +1 @@ +{"license": "BSD", "name": "ExifRead", "metadata_version": "2.0", "generator": "bdist_wheel (0.24.0)", "summary": "Read Exif metadata from tiff and jpeg files.", "version": "2.1.2", "extensions": {"python.details": {"project_urls": {"Home": "https://github.com/ianare/exif-py"}, "document_names": {"description": "DESCRIPTION.rst"}, "contacts": [{"role": "author", "email": "ianare@gmail.com", "name": "Ianar\u00e9 S\u00e9vi"}]}}, "keywords": ["exif", "image", "metadata", "photo"], "classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Console", "Intended Audience :: Developers", "Intended Audience :: End Users/Desktop", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Topic :: Utilities"]} \ No newline at end of file diff --git a/venv/lib/python2.7/site-packages/ExifRead-2.1.2.dist-info/top_level.txt b/venv/lib/python2.7/site-packages/ExifRead-2.1.2.dist-info/top_level.txt new file mode 100644 index 0000000..0e65e81 --- /dev/null +++ b/venv/lib/python2.7/site-packages/ExifRead-2.1.2.dist-info/top_level.txt @@ -0,0 +1 @@ +exifread diff --git a/venv/lib/python2.7/site-packages/Flask-1.0.2.dist-info/INSTALLER b/venv/lib/python2.7/site-packages/Flask-1.0.2.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python2.7/site-packages/Flask-1.0.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python2.7/site-packages/Flask-1.0.2.dist-info/LICENSE.txt b/venv/lib/python2.7/site-packages/Flask-1.0.2.dist-info/LICENSE.txt new file mode 100644 index 0000000..8f9252f --- /dev/null +++ b/venv/lib/python2.7/site-packages/Flask-1.0.2.dist-info/LICENSE.txt @@ -0,0 +1,31 @@ +Copyright © 2010 by the Pallets team. + +Some rights reserved. + +Redistribution and use in source and binary forms of the software as +well as documentation, with or without modification, are permitted +provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/venv/lib/python2.7/site-packages/Flask-1.0.2.dist-info/METADATA b/venv/lib/python2.7/site-packages/Flask-1.0.2.dist-info/METADATA new file mode 100644 index 0000000..c600e73 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Flask-1.0.2.dist-info/METADATA @@ -0,0 +1,130 @@ +Metadata-Version: 2.1 +Name: Flask +Version: 1.0.2 +Summary: A simple framework for building complex web applications. +Home-page: https://www.palletsprojects.com/p/flask/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets team +Maintainer-email: contact@palletsprojects.com +License: BSD +Project-URL: Documentation, http://flask.pocoo.org/docs/ +Project-URL: Code, https://github.com/pallets/flask +Project-URL: Issue tracker, https://github.com/pallets/flask/issues +Platform: any +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Framework :: Flask +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application +Classifier: Topic :: Software Development :: Libraries :: Application Frameworks +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Provides-Extra: dev +Provides-Extra: docs +Provides-Extra: dotenv +Requires-Dist: Werkzeug (>=0.14) +Requires-Dist: Jinja2 (>=2.10) +Requires-Dist: itsdangerous (>=0.24) +Requires-Dist: click (>=5.1) +Provides-Extra: dev +Requires-Dist: pytest (>=3); extra == 'dev' +Requires-Dist: coverage; extra == 'dev' +Requires-Dist: tox; extra == 'dev' +Requires-Dist: sphinx; extra == 'dev' +Requires-Dist: pallets-sphinx-themes; extra == 'dev' +Requires-Dist: sphinxcontrib-log-cabinet; extra == 'dev' +Provides-Extra: docs +Requires-Dist: sphinx; extra == 'docs' +Requires-Dist: pallets-sphinx-themes; extra == 'docs' +Requires-Dist: sphinxcontrib-log-cabinet; extra == 'docs' +Provides-Extra: dotenv +Requires-Dist: python-dotenv; extra == 'dotenv' + +Flask +===== + +Flask is a lightweight `WSGI`_ web application framework. It is designed +to make getting started quick and easy, with the ability to scale up to +complex applications. It began as a simple wrapper around `Werkzeug`_ +and `Jinja`_ and has become one of the most popular Python web +application frameworks. + +Flask offers suggestions, but doesn't enforce any dependencies or +project layout. It is up to the developer to choose the tools and +libraries they want to use. There are many extensions provided by the +community that make adding new functionality easy. + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + pip install -U Flask + + +A Simple Example +---------------- + +.. code-block:: python + + from flask import Flask + + app = Flask(__name__) + + @app.route('/') + def hello(): + return 'Hello, World!' + +.. code-block:: text + + $ FLASK_APP=hello.py flask run + * Serving Flask app "hello" + * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) + + +Donate +------ + +The Pallets organization develops and supports Flask and the libraries +it uses. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, `please +donate today`_. + +.. _please donate today: https://psfmember.org/civicrm/contribute/transact?reset=1&id=20 + + +Links +----- + +* Website: https://www.palletsprojects.com/p/flask/ +* Documentation: http://flask.pocoo.org/docs/ +* License: `BSD `_ +* Releases: https://pypi.org/project/Flask/ +* Code: https://github.com/pallets/flask +* Issue tracker: https://github.com/pallets/flask/issues +* Test status: + + * Linux, Mac: https://travis-ci.org/pallets/flask + * Windows: https://ci.appveyor.com/project/pallets/flask + +* Test coverage: https://codecov.io/gh/pallets/flask + +.. _WSGI: https://wsgi.readthedocs.io +.. _Werkzeug: https://www.palletsprojects.com/p/werkzeug/ +.. _Jinja: https://www.palletsprojects.com/p/jinja/ +.. _pip: https://pip.pypa.io/en/stable/quickstart/ + + diff --git a/venv/lib/python2.7/site-packages/Flask-1.0.2.dist-info/RECORD b/venv/lib/python2.7/site-packages/Flask-1.0.2.dist-info/RECORD new file mode 100644 index 0000000..53ea1d9 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Flask-1.0.2.dist-info/RECORD @@ -0,0 +1,48 @@ +Flask-1.0.2.dist-info/LICENSE.txt,sha256=ziEXA3AIuaiUn1qe4cd1XxCESWTYrk4TjN7Qb06J3l8,1575 +Flask-1.0.2.dist-info/METADATA,sha256=iA5tiNWzTtgCVe80aTZGNWsckj853fJyfvHs9U-WZRk,4182 +Flask-1.0.2.dist-info/RECORD,, +Flask-1.0.2.dist-info/WHEEL,sha256=J3CsTk7Mf2JNUyhImI-mjX-fmI4oDjyiXgWT4qgZiCE,110 +Flask-1.0.2.dist-info/entry_points.txt,sha256=gBLA1aKg0OYR8AhbAfg8lnburHtKcgJLDU52BBctN0k,42 +Flask-1.0.2.dist-info/top_level.txt,sha256=dvi65F6AeGWVU0TBpYiC04yM60-FX1gJFkK31IKQr5c,6 +flask/__init__.py,sha256=qq8lK6QQbxJALf1igz7qsvUwOTAoKvFGfdLm7jPNsso,1673 +flask/__main__.py,sha256=pgIXrHhxM5MAMvgzAqWpw_t6AXZ1zG38us4JRgJKtxk,291 +flask/_compat.py,sha256=UDFGhosh6mOdNB-4evKPuneHum1OpcAlwTNJCRm0irQ,2892 +flask/app.py,sha256=ahpe3T8w98rQd_Er5d7uDxK57S1nnqGQx3V3hirBovU,94147 +flask/blueprints.py,sha256=Cyhl_x99tgwqEZPtNDJUFneAfVJxWfEU4bQA7zWS6VU,18331 +flask/cli.py,sha256=30QYAO10Do9LbZYCLgfI_xhKjASdLopL8wKKVUGS2oA,29442 +flask/config.py,sha256=kznUhj4DLYxsTF_4kfDG8GEHto1oZG_kqblyrLFtpqQ,9951 +flask/ctx.py,sha256=leFzS9fzmo0uaLCdxpHc5_iiJZ1H0X_Ig4yPCOvT--g,16224 +flask/debughelpers.py,sha256=1ceC-UyqZTd4KsJkf0OObHPsVt5R3T6vnmYhiWBjV-w,6479 +flask/globals.py,sha256=pGg72QW_-4xUfsI33I5L_y76c21AeqfSqXDcbd8wvXU,1649 +flask/helpers.py,sha256=YCl8D1plTO1evEYP4KIgaY3H8Izww5j4EdgRJ89oHTw,40106 +flask/logging.py,sha256=qV9h0vt7NIRkKM9OHDWndzO61E5CeBMlqPJyTt-W2Wc,2231 +flask/sessions.py,sha256=2XHV4ASREhSEZ8bsPQW6pNVNuFtbR-04BzfKg0AfvHo,14452 +flask/signals.py,sha256=BGQbVyCYXnzKK2DVCzppKFyWN1qmrtW1QMAYUs-1Nr8,2211 +flask/templating.py,sha256=FDfWMbpgpC3qObW8GGXRAVrkHFF8K4CHOJymB1wvULI,4914 +flask/testing.py,sha256=XD3gWNvLUV8dqVHwKd9tZzsj81fSHtjOphQ1wTNtlMs,9379 +flask/views.py,sha256=Wy-_WkUVtCfE2zCXYeJehNgHuEtviE4v3HYfJ--MpbY,5733 +flask/wrappers.py,sha256=1Z9hF5-hXQajn_58XITQFRY8efv3Vy3uZ0avBfZu6XI,7511 +flask/json/__init__.py,sha256=Ns1Hj805XIxuBMh2z0dYnMVfb_KUgLzDmP3WoUYaPhw,10729 +flask/json/tag.py,sha256=9ehzrmt5k7hxf7ZEK0NOs3swvQyU9fWNe-pnYe69N60,8223 +../../../bin/flask,sha256=1f3FFsDm3yJrUf29khrJ2W3Vaj9B0Gd35rtgmchPZts,243 +Flask-1.0.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +flask/config.pyc,, +flask/testing.pyc,, +flask/wrappers.pyc,, +flask/views.pyc,, +flask/logging.pyc,, +flask/json/__init__.pyc,, +flask/helpers.pyc,, +flask/blueprints.pyc,, +flask/__main__.pyc,, +flask/templating.pyc,, +flask/signals.pyc,, +flask/__init__.pyc,, +flask/debughelpers.pyc,, +flask/json/tag.pyc,, +flask/ctx.pyc,, +flask/cli.pyc,, +flask/_compat.pyc,, +flask/app.pyc,, +flask/globals.pyc,, +flask/sessions.pyc,, diff --git a/venv/lib/python2.7/site-packages/Flask-1.0.2.dist-info/WHEEL b/venv/lib/python2.7/site-packages/Flask-1.0.2.dist-info/WHEEL new file mode 100644 index 0000000..f21b51c --- /dev/null +++ b/venv/lib/python2.7/site-packages/Flask-1.0.2.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.31.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/lib/python2.7/site-packages/Flask-1.0.2.dist-info/entry_points.txt b/venv/lib/python2.7/site-packages/Flask-1.0.2.dist-info/entry_points.txt new file mode 100644 index 0000000..1eb0252 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Flask-1.0.2.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +flask = flask.cli:main + diff --git a/venv/lib/python2.7/site-packages/Flask-1.0.2.dist-info/top_level.txt b/venv/lib/python2.7/site-packages/Flask-1.0.2.dist-info/top_level.txt new file mode 100644 index 0000000..7e10602 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Flask-1.0.2.dist-info/top_level.txt @@ -0,0 +1 @@ +flask diff --git a/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/DESCRIPTION.rst b/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/DESCRIPTION.rst new file mode 100644 index 0000000..1594da5 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/DESCRIPTION.rst @@ -0,0 +1,37 @@ + +Jinja2 +~~~~~~ + +Jinja2 is a template engine written in pure Python. It provides a +`Django`_ inspired non-XML syntax but supports inline expressions and +an optional `sandboxed`_ environment. + +Nutshell +-------- + +Here a small example of a Jinja template:: + + {% extends 'base.html' %} + {% block title %}Memberlist{% endblock %} + {% block content %} + + {% endblock %} + +Philosophy +---------- + +Application logic is for the controller but don't try to make the life +for the template designer too hard by giving him too few functionality. + +For more informations visit the new `Jinja2 webpage`_ and `documentation`_. + +.. _sandboxed: https://en.wikipedia.org/wiki/Sandbox_(computer_security) +.. _Django: https://www.djangoproject.com/ +.. _Jinja2 webpage: http://jinja.pocoo.org/ +.. _documentation: http://jinja.pocoo.org/2/documentation/ + + diff --git a/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/INSTALLER b/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/LICENSE.txt b/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/LICENSE.txt new file mode 100644 index 0000000..10145a2 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/LICENSE.txt @@ -0,0 +1,31 @@ +Copyright (c) 2009 by the Jinja Team, see AUTHORS for more details. + +Some rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/METADATA b/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/METADATA new file mode 100644 index 0000000..40f2b46 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/METADATA @@ -0,0 +1,68 @@ +Metadata-Version: 2.0 +Name: Jinja2 +Version: 2.10 +Summary: A small but fast and easy to use stand-alone template engine written in pure python. +Home-page: http://jinja.pocoo.org/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +License: BSD +Description-Content-Type: UNKNOWN +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Text Processing :: Markup :: HTML +Requires-Dist: MarkupSafe (>=0.23) +Provides-Extra: i18n +Requires-Dist: Babel (>=0.8); extra == 'i18n' + + +Jinja2 +~~~~~~ + +Jinja2 is a template engine written in pure Python. It provides a +`Django`_ inspired non-XML syntax but supports inline expressions and +an optional `sandboxed`_ environment. + +Nutshell +-------- + +Here a small example of a Jinja template:: + + {% extends 'base.html' %} + {% block title %}Memberlist{% endblock %} + {% block content %} + + {% endblock %} + +Philosophy +---------- + +Application logic is for the controller but don't try to make the life +for the template designer too hard by giving him too few functionality. + +For more informations visit the new `Jinja2 webpage`_ and `documentation`_. + +.. _sandboxed: https://en.wikipedia.org/wiki/Sandbox_(computer_security) +.. _Django: https://www.djangoproject.com/ +.. _Jinja2 webpage: http://jinja.pocoo.org/ +.. _documentation: http://jinja.pocoo.org/2/documentation/ + + diff --git a/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/RECORD b/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/RECORD new file mode 100644 index 0000000..8f555ae --- /dev/null +++ b/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/RECORD @@ -0,0 +1,61 @@ +Jinja2-2.10.dist-info/DESCRIPTION.rst,sha256=b5ckFDoM7vVtz_mAsJD4OPteFKCqE7beu353g4COoYI,978 +Jinja2-2.10.dist-info/LICENSE.txt,sha256=JvzUNv3Io51EiWrAPm8d_SXjhJnEjyDYvB3Tvwqqils,1554 +Jinja2-2.10.dist-info/METADATA,sha256=18EgU8zR6-av-0-5y_gXebzK4GnBB_76lALUsl-6QHM,2258 +Jinja2-2.10.dist-info/RECORD,, +Jinja2-2.10.dist-info/WHEEL,sha256=kdsN-5OJAZIiHN-iO4Rhl82KyS0bDWf4uBwMbkNafr8,110 +Jinja2-2.10.dist-info/entry_points.txt,sha256=NdzVcOrqyNyKDxD09aERj__3bFx2paZhizFDsKmVhiA,72 +Jinja2-2.10.dist-info/metadata.json,sha256=NPUJ9TMBxVQAv_kTJzvU8HwmP-4XZvbK9mz6_4YUVl4,1473 +Jinja2-2.10.dist-info/top_level.txt,sha256=PkeVWtLb3-CqjWi1fO29OCbj55EhX_chhKrCdrVe_zs,7 +jinja2/__init__.py,sha256=xJHjaMoy51_KXn1wf0cysH6tUUifUxZCwSOfcJGEYZw,2614 +jinja2/_compat.py,sha256=xP60CE5Qr8FTYcDE1f54tbZLKGvMwYml4-8T7Q4KG9k,2596 +jinja2/_identifier.py,sha256=W1QBSY-iJsyt6oR_nKSuNNCzV95vLIOYgUNPUI1d5gU,1726 +jinja2/asyncfilters.py,sha256=cTDPvrS8Hp_IkwsZ1m9af_lr5nHysw7uTa5gV0NmZVE,4144 +jinja2/asyncsupport.py,sha256=UErQ3YlTLaSjFb94P4MVn08-aVD9jJxty2JVfMRb-1M,7878 +jinja2/bccache.py,sha256=nQldx0ZRYANMyfvOihRoYFKSlUdd5vJkS7BjxNwlOZM,12794 +jinja2/compiler.py,sha256=BqC5U6JxObSRhblyT_a6Tp5GtEU5z3US1a4jLQaxxgo,65386 +jinja2/constants.py,sha256=uwwV8ZUhHhacAuz5PTwckfsbqBaqM7aKfyJL7kGX5YQ,1626 +jinja2/debug.py,sha256=WTVeUFGUa4v6ReCsYv-iVPa3pkNB75OinJt3PfxNdXs,12045 +jinja2/defaults.py,sha256=Em-95hmsJxIenDCZFB1YSvf9CNhe9rBmytN3yUrBcWA,1400 +jinja2/environment.py,sha256=VnkAkqw8JbjZct4tAyHlpBrka2vqB-Z58RAP-32P1ZY,50849 +jinja2/exceptions.py,sha256=_Rj-NVi98Q6AiEjYQOsP8dEIdu5AlmRHzcSNOPdWix4,4428 +jinja2/ext.py,sha256=atMQydEC86tN1zUsdQiHw5L5cF62nDbqGue25Yiu3N4,24500 +jinja2/filters.py,sha256=yOAJk0MsH-_gEC0i0U6NweVQhbtYaC-uE8xswHFLF4w,36528 +jinja2/idtracking.py,sha256=2GbDSzIvGArEBGLkovLkqEfmYxmWsEf8c3QZwM4uNsw,9197 +jinja2/lexer.py,sha256=ySEPoXd1g7wRjsuw23uimS6nkGN5aqrYwcOKxCaVMBQ,28559 +jinja2/loaders.py,sha256=xiTuURKAEObyym0nU8PCIXu_Qp8fn0AJ5oIADUUm-5Q,17382 +jinja2/meta.py,sha256=fmKHxkmZYAOm9QyWWy8EMd6eefAIh234rkBMW2X4ZR8,4340 +jinja2/nativetypes.py,sha256=_sJhS8f-8Q0QMIC0dm1YEdLyxEyoO-kch8qOL5xUDfE,7308 +jinja2/nodes.py,sha256=L10L_nQDfubLhO3XjpF9qz46FSh2clL-3e49ogVlMmA,30853 +jinja2/optimizer.py,sha256=MsdlFACJ0FRdPtjmCAdt7JQ9SGrXFaDNUaslsWQaG3M,1722 +jinja2/parser.py,sha256=lPzTEbcpTRBLw8ii6OYyExHeAhaZLMA05Hpv4ll3ULk,35875 +jinja2/runtime.py,sha256=DHdD38Pq8gj7uWQC5usJyWFoNWL317A9AvXOW_CLB34,27755 +jinja2/sandbox.py,sha256=TVyZHlNqqTzsv9fv2NvJNmSdWRHTguhyMHdxjWms32U,16708 +jinja2/tests.py,sha256=iJQLwbapZr-EKquTG_fVOVdwHUUKf3SX9eNkjQDF8oU,4237 +jinja2/utils.py,sha256=q24VupGZotQ-uOyrJxCaXtDWhZC1RgsQG7kcdmjck2Q,20629 +jinja2/visitor.py,sha256=JD1H1cANA29JcntFfN5fPyqQxB4bI4wC00BzZa-XHks,3316 +Jinja2-2.10.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +jinja2/_compat.pyc,, +jinja2/defaults.pyc,, +jinja2/sandbox.pyc,, +jinja2/environment.pyc,, +jinja2/runtime.pyc,, +jinja2/utils.pyc,, +jinja2/parser.pyc,, +jinja2/debug.pyc,, +jinja2/visitor.pyc,, +jinja2/ext.pyc,, +jinja2/lexer.pyc,, +jinja2/_identifier.pyc,, +jinja2/nodes.pyc,, +jinja2/meta.pyc,, +jinja2/compiler.pyc,, +jinja2/nativetypes.pyc,, +jinja2/exceptions.pyc,, +jinja2/bccache.pyc,, +jinja2/filters.pyc,, +jinja2/__init__.pyc,, +jinja2/constants.pyc,, +jinja2/loaders.pyc,, +jinja2/optimizer.pyc,, +jinja2/tests.pyc,, +jinja2/idtracking.pyc,, diff --git a/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/WHEEL b/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/WHEEL new file mode 100644 index 0000000..7332a41 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.30.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/entry_points.txt b/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/entry_points.txt new file mode 100644 index 0000000..32e6b75 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/entry_points.txt @@ -0,0 +1,4 @@ + + [babel.extractors] + jinja2 = jinja2.ext:babel_extract[i18n] + \ No newline at end of file diff --git a/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/metadata.json b/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/metadata.json new file mode 100644 index 0000000..7f5dc38 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/metadata.json @@ -0,0 +1 @@ +{"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Text Processing :: Markup :: HTML"], "description_content_type": "UNKNOWN", "extensions": {"python.details": {"contacts": [{"email": "armin.ronacher@active-4.com", "name": "Armin Ronacher", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst", "license": "LICENSE.txt"}, "project_urls": {"Home": "http://jinja.pocoo.org/"}}, "python.exports": {"babel.extractors": {"jinja2": "jinja2.ext:babel_extract [i18n]"}}}, "extras": ["i18n"], "generator": "bdist_wheel (0.30.0)", "license": "BSD", "metadata_version": "2.0", "name": "Jinja2", "run_requires": [{"extra": "i18n", "requires": ["Babel (>=0.8)"]}, {"requires": ["MarkupSafe (>=0.23)"]}], "summary": "A small but fast and easy to use stand-alone template engine written in pure python.", "version": "2.10"} \ No newline at end of file diff --git a/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/top_level.txt b/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/top_level.txt new file mode 100644 index 0000000..7f7afbf --- /dev/null +++ b/venv/lib/python2.7/site-packages/Jinja2-2.10.dist-info/top_level.txt @@ -0,0 +1 @@ +jinja2 diff --git a/venv/lib/python2.7/site-packages/Lektor-3.1.1.dist-info/INSTALLER b/venv/lib/python2.7/site-packages/Lektor-3.1.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python2.7/site-packages/Lektor-3.1.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python2.7/site-packages/Lektor-3.1.1.dist-info/METADATA b/venv/lib/python2.7/site-packages/Lektor-3.1.1.dist-info/METADATA new file mode 100644 index 0000000..b06b969 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Lektor-3.1.1.dist-info/METADATA @@ -0,0 +1,43 @@ +Metadata-Version: 2.1 +Name: Lektor +Version: 3.1.1 +Summary: A static content management system. +Home-page: http://github.com/lektor/lektor/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +License: BSD +Platform: any +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Provides-Extra: test +Provides-Extra: ipython +Requires-Dist: Jinja2 (>=2.4) +Requires-Dist: click (>=6.0) +Requires-Dist: watchdog +Requires-Dist: mistune (>=0.7.0) +Requires-Dist: Flask +Requires-Dist: EXIFRead +Requires-Dist: inifile +Requires-Dist: Babel +Requires-Dist: setuptools +Requires-Dist: pip +Requires-Dist: requests[security] +Provides-Extra: ipython +Requires-Dist: ipython; extra == 'ipython' +Provides-Extra: test +Requires-Dist: pytest; extra == 'test' +Requires-Dist: pytest-cov; extra == 'test' +Requires-Dist: pytest-mock; extra == 'test' +Requires-Dist: pytest-click; extra == 'test' +Requires-Dist: pytest-pylint; extra == 'test' + +UNKNOWN + + diff --git a/venv/lib/python2.7/site-packages/Lektor-3.1.1.dist-info/RECORD b/venv/lib/python2.7/site-packages/Lektor-3.1.1.dist-info/RECORD new file mode 100644 index 0000000..3894d7e --- /dev/null +++ b/venv/lib/python2.7/site-packages/Lektor-3.1.1.dist-info/RECORD @@ -0,0 +1,202 @@ +Lektor-3.1.1.dist-info/METADATA,sha256=Z-m3XYiGuEf3w035do8299mGCRUFM9waEtAKPGCzOhw,1336 +Lektor-3.1.1.dist-info/RECORD,, +Lektor-3.1.1.dist-info/WHEEL,sha256=1GbQwWo-bz5MQ7TWgxmoj0u3qc5GM8qVkJvIGW53qLM,93 +Lektor-3.1.1.dist-info/entry_points.txt,sha256=T0VAQffOGZ1ei92JnlBsjj9sRxSkTmLWFu6QDTUZ63Y,62 +Lektor-3.1.1.dist-info/top_level.txt,sha256=cutZ_vGXL_Ib0DKNb_hAT4AXMJyFvyEjzv3l7lh0caU,7 +lektor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +lektor/_compat.py,sha256=yGyoDqaQUQuQ-CV2vsK-k3TAf7By5ppQZgJIGvyhhzU,2052 +lektor/assets.py,sha256=luIK4fb9AZz7tVBEvF5dwd5f80hjj2Zi1FisM-U0hn8,3881 +lektor/build_programs.py,sha256=ohn71FKbJYMH1txOpXhIoxuAtFwVSlJr0MSxMlfpFdk,9273 +lektor/builder.py,sha256=QKKO-UlGk4uuPlWygXR_6E1A-lq5hvkrYFpOoxydUmc,43198 +lektor/buildfailures.py,sha256=bdmXY7zstuxgq3h5U6-bt6L7dhJRYXTFnJ0sJ6KVzjY,1967 +lektor/cli.py,sha256=bjsdse3vX5NAplHBKoGpVE3LFVKrEqCeim_DkKyxdCY,22501 +lektor/context.py,sha256=gbN476FemOIX1yXOo6ns8jgjmpW2HGMsWiNbThZgpsM,6774 +lektor/databags.py,sha256=eIqlfxJb0vJ_tMPzsVreHQpqwxCLdmisq3jiLpvs5SA,2214 +lektor/datamodel.py,sha256=W1K9jxI10p5he8SXUDA1oUOLSnTAaJPXblDvuy-6Jkw,23279 +lektor/db.py,sha256=OGlndplJqnZ4_SsnpyfaF_TuEUjcFL_51r_nw5C5lho,65132 +lektor/devcli.py,sha256=uECtnwrYoXPuUb7DhB_Rq2g1Kqj5ywZKZ6d7-CYxiqE,4095 +lektor/devserver.py,sha256=FulhSAuJnpy8ndhMonqM1RKuO6JttnRQKZ4P1VGy_DM,4511 +lektor/editor.py,sha256=jBSNMh22p4Y1bcdOlPGwtDXqCVmUpmb9qGg2AgpLgMU,13938 +lektor/environment.py,sha256=4xjT9hU-27JM8kN8xoyuTkj_DyRNgCqbGj8PIC3-s_E,21421 +lektor/exception.py,sha256=EItO_Kh7L6nOTxTy6AHu-r2sIsMgkE4spPbv8AWMmdg,651 +lektor/filecontents.py,sha256=vVSUbw_Kh_KKIxTKd41rlkapUUbQ1tnLaLST8kZS06Y,2327 +lektor/i18n.py,sha256=T9bahq8A_tHLgf75kUVeeJzh9sDt6Xmesq08pLE8BDM,2727 +lektor/imagetools.py,sha256=TyjdKzc0jFpUz36n2Wk3a9RgtPCZ93Dmv1ZhfeZ2N7c,13932 +lektor/markdown.py,sha256=jKNZ37cK65sy5ia8XgKLCP1w_oGW2vhmvxMkqUPBUHg,4224 +lektor/metaformat.py,sha256=qzIoyZ6W7DwdIMKR2bqR7LctKEv6b9CRLlHGlnRnROw,3258 +lektor/packages.py,sha256=QrOZIx19fcyam6UHPEENkgz1u3XdFbax5h5CMyuduLI,9809 +lektor/pagination.py,sha256=mRjNeNkHIufnpGXEkTdw5ElTT5gBuLndD2ENjwLmGcM,3606 +lektor/pluginsystem.py,sha256=EAAeHqtVXIzjhmjfSHv6ch0iTtKuPLvF0wxVIxfYF88,5176 +lektor/project.py,sha256=AYKvjdS4EPryQMTr4VK7VscJgHzcoO-ZcUdgzfOYe0Q,5239 +lektor/publisher.py,sha256=NvC3W7DbmJVQJGaJj4ES5g-FCK71tpVqtFG38t1a2KI,22628 +lektor/quickstart.py,sha256=hz5hYrLq1YQUj9WGH_udFzaCu3GaqECREzk5YB58lO0,9031 +lektor/reporter.py,sha256=mwYKXRqR0LKlOZmIJqWRpI4QV6o-yTUUQHLZH145FdI,11038 +lektor/sourceobj.py,sha256=kcRga6DeERGMJ-C-4jiTdID-jpHj7snTQB2pr4fo7w8,4783 +lektor/sourcesearch.py,sha256=XLEO3qmQak4QuQjh2sYd4Cz2sVyLl-94e519WImOARA,3707 +lektor/uilink.py,sha256=DL6i_mIBsbQD7SqAMCoitwMpVwtL6nyFRnct2JGYtYI,1309 +lektor/utils.py,sha256=bph99uUxVqANytej6wM_00OSdVeQe8t-xc1X9FbNRy0,18766 +lektor/watcher.py,sha256=Qherkt_5CUJwpOGnQukQ4ViGWiVAiRivwWvU4lZVGIs,2649 +lektor/admin/__init__.py,sha256=lamGWSFepQTzUZpRQxIkbc-3YsgB3deMWIYgC5FmvRk,53 +lektor/admin/package-lock.json,sha256=BbulXDwXlwJJDeXvCxGVB5hHuO9Lyc96yvvkdTQDluo,229804 +lektor/admin/package.json,sha256=JAS-uKe9CXeH6QFuFEZYIU357R-uLDEOh7kJsYj2xKs,1815 +lektor/admin/utils.py,sha256=6_XIBLnFkeN7oTdvdM33F99XO8RDzyj4slOvrUSyh44,635 +lektor/admin/webui.py,sha256=4uqn2wleIP9UeXUH1ISuKiHfOJ694MLLxpymQzNOM5Y,3287 +lektor/admin/modules/__init__.py,sha256=oDb1nLjPlb-pAlXlOGek6AoqOmhxchpLkHFLyART39k,185 +lektor/admin/modules/api.py,sha256=ibE6qdHho6QlPBczjohQxdS2P-M4BRXvDGW4pWTd2Og,9320 +lektor/admin/modules/common.py,sha256=TpGxKBMTXF8b6ciUR-5p62V7TbVZzkDp9cglpiFbhgY,919 +lektor/admin/modules/dash.py,sha256=BM-fsT8rhmAciwpKebDtkkNboCsjZvY1o9wdPVXyQEU,1425 +lektor/admin/modules/serve.py,sha256=pu2T8s34zw9Lw-GxTRY2PsdGew2BdY-xsB-_ARhNwbY,4231 +lektor/admin/static/webpack.config.js,sha256=w_EoLnYZ9B9Lp9pcnArWz09ERVUWsO_Rinotu-fpVQk,1767 +lektor/admin/static/fonts/LICENSE,sha256=0kmvAd8bkc7ReDbKJdPFUdE1WkfYU4v9dcHkJGGKfcc,559 +lektor/admin/static/fonts/RobotoSlab-Light-webfont.ttf,sha256=wPI5Soym20VC9d7HF5VTLWy_Fgm5Vk-F4M8bi3wzQvk,54088 +lektor/admin/static/fonts/RobotoSlab-Regular-webfont.ttf,sha256=X6-gGp92rufjvlbqNT8BUcRrLVdA--6IBT7TEAve7f0,54876 +lektor/admin/static/gen/478c97f5f24d794b1ce6b93cab5a4dad.ttf,sha256=X6-gGp92rufjvlbqNT8BUcRrLVdA--6IBT7TEAve7f0,54876 +lektor/admin/static/gen/674f50d287a8c48dc19ba404d20fe713.eot,sha256=e_yrbbmdXPvxcFygU23ceFhUMsxfpBu9etDwCQM7KXk,165742 +lektor/admin/static/gen/912ec66d7572ff821749319396470bde.svg,sha256=rWFXkmwWIrpOHQPUePFUE2hSS_xG9R5C_g2UX37zI-Q,444379 +lektor/admin/static/gen/af7ae505a9eed503f8b8e6982036873e.woff2,sha256=Kt78vAQefRj88tQXh53FoJmXqmTWdbejxLbOM9oT8_4,77160 +lektor/admin/static/gen/app.js,sha256=7dSVmqbBDAwIT-78NoWag38cFEAyFTW-NKQZiKCRyyM,389216 +lektor/admin/static/gen/app.js.map,sha256=zxLEhmJ8G79KlHXNYBV2d8c89C-xYKuU6MJdG8G3NvY,415300 +lektor/admin/static/gen/b06871f281fee6b241d60582ae9369b9.ttf,sha256=qljzPyOaD7AvXHpsRcBD16msmgkzNYBmlOzW1O3A1qg,165548 +lektor/admin/static/gen/fdbcf4476a0ad35d64fa51b0a5720495.ttf,sha256=wPI5Soym20VC9d7HF5VTLWy_Fgm5Vk-F4M8bi3wzQvk,54088 +lektor/admin/static/gen/fee66e712a8a08eef5805a46892932ad.woff,sha256=ugxZ3rVFD1y0Gz-TYJ7i0NmVQVh33foiPoqKdTNHTwc,98024 +lektor/admin/static/gen/styles.css,sha256=KXp29BSYqgaSd2phWc064Rr_lmUW5cNb9AooJ7d88TU,240009 +lektor/admin/static/gen/styles.css.map,sha256=Q9DnKpOP0DbEtLZh4sBDh7Y0vDYt-gvRHhWnNuu6B94,87 +lektor/admin/static/gen/styles.js,sha256=D3XTGcVv4p77HCy1D7KDux4qbTtYdBdG3VmXTjV9ZiY,164 +lektor/admin/static/gen/styles.js.map,sha256=HmxGagE2etRADqnnypOrmsjbPL0f8xc0QLJQOMnsxG0,296 +lektor/admin/static/gen/vendor.js,sha256=aRaPX87x6WSiXuiD1_M6vVGq7bQGt9RoHcf6pd9m3Gg,1280196 +lektor/admin/static/gen/vendor.js.map,sha256=RIgZM-sKfeIovophPvCSW9wJuGgfva-KptrPpycr7e8,1564399 +lektor/admin/static/js/bootstrap-extras.jsx,sha256=pKWMpC1V7paElLcLPfT_fax7EM8wnLRNixwZO7HBrCk,318 +lektor/admin/static/js/dialogSystem.jsx,sha256=6ooyPm7FoavmWRRaCj4RqrcD_wj8ubJEBh07-vlAQv8,1321 +lektor/admin/static/js/events.jsx,sha256=sd7kb28NYvOu4bPa-XHI_pzxcByeYt9EShN0IM94dI0,891 +lektor/admin/static/js/hub.jsx,sha256=xzZhWnXsxP5kUGFS6MbSs1053R8CGIn2G5j7RM_ZibE,1349 +lektor/admin/static/js/i18n.jsx,sha256=qRfQUK3zPH7-IBrm7f0x5a33s_bDaCTZeQCNjsW2re4,815 +lektor/admin/static/js/main.jsx,sha256=SRI15Ndt4XW-6FApSnU1F5s8PDI8hQsymkf7CyNNps0,2077 +lektor/admin/static/js/metaformat.jsx,sha256=TO0GBJldM1CI-6HUr_i0x7JNoo8BNH8zO7V0PhKMgDs,2256 +lektor/admin/static/js/richPromise.jsx,sha256=Sc51OfgEa6TJbUvKBZg0-ckCs2SyfovDDAhFh56oYfk,706 +lektor/admin/static/js/userLabel.jsx,sha256=_OnO7U6u1JyqDncO6mYLHeqUc8cFb9kqvdtxijvN-go,759 +lektor/admin/static/js/utils.jsx,sha256=rwdm0XY8AZaRJR6_xrg4OR0gktGyZnDcZmQ8OK_6oek,10901 +lektor/admin/static/js/widgets.jsx,sha256=WmgfzqU5hhlqxQhmQc4GGAHA-RpUFWvMNt24MhY-hdQ,4980 +lektor/admin/static/js/components/BaseComponent.jsx,sha256=16tgVFx1lYm6kqLATlnXNvd0ld29aNUjcbDTJTwG-KE,521 +lektor/admin/static/js/components/BreadCrumbs.jsx,sha256=_TJuRHO_BLzEmbuPMY9F-7Jv1sNlZuSWAklXiKSDSCw,4633 +lektor/admin/static/js/components/Component.jsx,sha256=ji2OvmMJG3u2UKfKl5Hq9ZHMP3btSYquWmAt-Jfu6ao,2185 +lektor/admin/static/js/components/DialogSlot.jsx,sha256=GDInBpU6ipzjOTiN46RdL8J6WuFXXZaubBB0V3wInB8,1468 +lektor/admin/static/js/components/Link.jsx,sha256=pr0VujOB5T8xsXzGldO3iYCINjNCfG0BpK2x5-4nPTw,520 +lektor/admin/static/js/components/RecordComponent.jsx,sha256=oqLmhxDFrNKfAHyZAz7QhcZeJIPhWTXArZgBbDJe06s,2482 +lektor/admin/static/js/components/RecordEditComponent.jsx,sha256=12bRTn0A2qY49NkZUaLjniWpPZZglocDKzMzNhfUD20,454 +lektor/admin/static/js/components/ServerStatus.jsx,sha256=N-4r7shKzThnNlepsyyVlJAPpVbgPPmpxh5SCNgd5ic,1516 +lektor/admin/static/js/components/Sidebar.jsx,sha256=lpYbOMACE5EjEXOzTpDQ0K1cl1y6BF0GWi2ZUShLcoE,9486 +lektor/admin/static/js/components/SlideDialog.jsx,sha256=tAIVZlFYix6X_FUKB8Y_C_5yuGocQv9FHb7z_5k0AkE,1615 +lektor/admin/static/js/components/ToggleGroup.jsx,sha256=LCk9v-Y4kYQk3Wi3E0vQFBNkZ9z4qJcr7W7QhrctrcE,1097 +lektor/admin/static/js/components/ToggleGroup.test.js,sha256=AJUQe8Cl7zitd1HPnIXEU1OP-lr_hIz_OH-V8oIQAUs,1629 +lektor/admin/static/js/dialogs/Refresh.jsx,sha256=DsZ4oJsRGB_KtuaIAR4z8BkiddiRXuXKOYWM57ULEaQ,2037 +lektor/admin/static/js/dialogs/errorDialog.jsx,sha256=wGBGQZgaPXblGGvjqWhYMat4BrzqNSuRU5iH6Oo-aQg,913 +lektor/admin/static/js/dialogs/findFiles.jsx,sha256=whePlZK_L15EtjO_WdwNsYHZw1QAmbw9UfR_uGN2B3U,3314 +lektor/admin/static/js/dialogs/publish.jsx,sha256=amtChm-rqDtP3LZAxjRhBPhrtujmKVCdrdPMsc_2bXs,4173 +lektor/admin/static/js/views/AddAttachmentPage.jsx,sha256=t0vZqL-C2Zirzxk672Ojr2GDEFhQcF1KswhRru7woaE,3148 +lektor/admin/static/js/views/AddChildPage.jsx,sha256=v1x6ASC1s6GwKD1dCPCY6HHlX335h8kE2838zp2gjvI,5507 +lektor/admin/static/js/views/App.jsx,sha256=t7vN5pNl-kmo99g1ZkjpEQTZucwad5_l6Yy0Vvvk--Q,1391 +lektor/admin/static/js/views/Dash.jsx,sha256=7RPUADaZl-7VcsrbODX6fakBJQ7SOWTpwRTDNIi58W4,331 +lektor/admin/static/js/views/DeletePage.jsx,sha256=IOIAeX59-sfTP6v91zcb5jCmEf3GH3RpK8Wgxb4ZTBM,6359 +lektor/admin/static/js/views/EditPage.jsx,sha256=CEqtlG2yGBBWA3QgxOF3eFwrvTSiJbRW9q9bSfoZ2yc,6229 +lektor/admin/static/js/views/PreviewPage.jsx,sha256=ZZ9daF4c7kTAPgaxlPuSUVmOSLY29RJA-SwCbtha2ds,2463 +lektor/admin/static/js/widgets/fakeWidgets.jsx,sha256=J9B-xGyJ3-D9-IOYupm3DykdUVUYpmwYF9_g4hrNOi0,1189 +lektor/admin/static/js/widgets/flowWidget.jsx,sha256=mm9YgJb-Xch_Sntinvg-F1GKOhJK6dLt7JPdAC_7wo0,8136 +lektor/admin/static/js/widgets/mixins.jsx,sha256=PsHOGm2fJt665Gq2Y2a95PzRbgzKIXi653wWfB5EawQ,790 +lektor/admin/static/js/widgets/multiWidgets.jsx,sha256=_s2S93c3RkWn9aa5OMixT6OUJJKg03YLhrYdXMPLmuU,2804 +lektor/admin/static/js/widgets/primitiveWidgets.jsx,sha256=vrVuNjLJek9Lav3zQleNaldD2PaDKZAkoY_acJyuoIk,8427 +lektor/admin/static/less/bootstrap-overrides.less,sha256=sQBC4Yf8y56f1sOSWbMfYtVYVrj0SZjZZQF-rJuj1KY,3763 +lektor/admin/static/less/main.less,sha256=MGDT8OUqnaChMGpJUABLKnUy7ON9XijwkbUYw9P5E8U,9441 +lektor/admin/static/less/utils.less,sha256=O76Y80ABRQSxZMaa45AwLMc-1MNd30-TJV-EQ76e_94,927 +lektor/admin/templates/base.html,sha256=SBiXvfHYXpuZY3sH7NSRExAUcUnntWT5-YguqMJcEoQ,318 +lektor/admin/templates/build-failure.html,sha256=e6kigTweOtog5qykvBh3lW3W19ETM5PSrbry0oZ1DUM,244 +lektor/admin/templates/dash.html,sha256=I3GQ2y2JwTN5U7AJWLNF_FHzj0FKrdoALRMweYkJ-Qs,674 +lektor/admin/templates/layout.html,sha256=GI2hhM8IO0jkDZhTfg2LSNkXCl4Kn0g9YMPhs3NdUNI,123 +lektor/quickstart-templates/plugin/.gitignore.in,sha256=wTx1ahxIGqls_OXAw_-5-X603myNl3UP6a5IpODhAm0,34 +lektor/quickstart-templates/plugin/@plugin_module@.py.in,sha256=IqZmYMx8sVtIKeUwhidcBbQr73keAf2OSTPx8tqOllU,371 +lektor/quickstart-templates/plugin/setup.py.in,sha256=nriKvhcRbJnBZ5hvuWRanqC_jac7AJlqL8aPbxbUBYY,342 +lektor/quickstart-templates/project/@project_name@.lektorproject.in,sha256=vUKl89rkDwaTgxF5_k0sC5UkVHUTaMYAbfWufltWcsc,33 +lektor/quickstart-templates/project/assets/static/style.css.in,sha256=ItbEC56BUSQPaY2Wn-ndbWkEv5edLpVsxjnNBb-m7ic,538 +lektor/quickstart-templates/project/content/contents.lr.in,sha256=kq4Qnqyijv115qBRPohZ-f1DTUCyexyWDH3gP19ndks,181 +lektor/quickstart-templates/project/content/about/contents.lr.in,sha256=v8rklERjEGd2YaFvSCXPH63O9TcE3ZuKQB6bdpF2n5A,144 +lektor/quickstart-templates/project/content/blog/contents.lr.in,sha256=57reR-aGTRMGkpTkxfzj9zV8ydbYfGHcNApibxThCs8,54 +lektor/quickstart-templates/project/content/blog/first-post/contents.lr.in,sha256=ekpgactWy2URihrkohHuFlEg55Pu4yoIZ0iWq0hE8qA,180 +lektor/quickstart-templates/project/content/projects/contents.lr.in,sha256=cyLzsnkXBvHbYK9Z-UUxBqjtWrneWDlqgU1THWbPwbQ,96 +lektor/quickstart-templates/project/models/blog-post.ini.in,sha256=u1Udd81Jp_OjwiIIWzWzjmtkm2CTc9lhdqMTFSW14mg,405 +lektor/quickstart-templates/project/models/blog.ini.in,sha256=djHda-R3oSz2evZSYHk_YDi63pBGmQmKxawZlfvU-Bw,215 +lektor/quickstart-templates/project/models/page.ini.in,sha256=JZSWW1xxSsL3QyhfqjArpw3tzQBcZj5QTq8D0AqlX54,133 +lektor/quickstart-templates/project/templates/blog-post.html.in,sha256=7rcZ1Lp_4Yv0ioCdPdAdewH-LN0VqnAVOl3ihGPnkqw,218 +lektor/quickstart-templates/project/templates/blog.html.in,sha256=XrRGgsHxWd0J1oyCYJo4Bwxm8MYD5hQ2hA9Bh8ChliE,401 +lektor/quickstart-templates/project/templates/layout.html.in,sha256=pk8L_Rrpz_3S2uWPjGxNUGNg3OaHEYsH5Z3R99T9wxY,913 +lektor/quickstart-templates/project/templates/page.html.in,sha256=FyuHTiHMYMif9Z-Oe26wx51LMYZqMsOjvhgv-NTmMNA,154 +lektor/quickstart-templates/project/templates/macros/blog.html.in,sha256=YoZOhjubMSnixklN8wz9TaSt0bSEC_f7r_5Ixbv0zuM,555 +lektor/quickstart-templates/project/templates/macros/pagination.html.in,sha256=rdtqaw5vVCsWStYuu8WXLKHolX2d0-YC4WAtTgf6D9w,475 +lektor/translations/ca.json,sha256=HjmZ_rE5IWDJImsjzmXBHKgdjMejZAVinPiEs0hxliM,6556 +lektor/translations/de.json,sha256=9EbCu86gkfp5ljrg8Ru-MI0JsXBgngcuuHa1KVbQrFk,6742 +lektor/translations/en.json,sha256=fbeC8dsm7faaxW6LdsoSsRy4z0rJkTj5wJcTYvv2nEo,6150 +lektor/translations/es.json,sha256=Aj_J4G6vkq_aMzw38Eg1yr83ypofunMFY05gxZlPpUQ,6524 +lektor/translations/fr.json,sha256=51ipoWU_yeskQ6PArhic8ljR5ZQy_3RSD3YSE-WoJDk,7104 +lektor/translations/it.json,sha256=Z-OKqo2DNpzdRNm2j1gvGZSnlQxQTKmMsHxWz1JwmNc,6576 +lektor/translations/ja.json,sha256=XuDz68clQr4XeI5gcMhDv-OYek9FJC37DabxBG4IuXw,7641 +lektor/translations/ko.json,sha256=CwkRZOkGVEru3rIaX8zvIefxdbD6ehEo2W3D2brKWJk,7048 +lektor/translations/nl.json,sha256=wkE2EqMU0HZyriMAFXuFMuUW48Os7Nj_LTYL6KrMPXw,6543 +lektor/translations/pl.json,sha256=r3EaTcF7U2rNtB6zzznONYtDBKExRS5HU4fnheGiTRg,6713 +lektor/translations/pt.json,sha256=6bu3R_rUw6zIjjAq8RRFhGnFrhAqk6q7mUhxiqqTH9A,6434 +lektor/translations/ru.json,sha256=J1MrvyR7sbcHSSvq2FJbacwdtXquskdp3PXvRYGD3zs,8674 +lektor/translations/zh.json,sha256=LmpyUVAGQSAfFOjqXp-shHjHfiTOEwojTiIrF63mj8g,5855 +lektor/types/__init__.py,sha256=ENQyCxZxhYWzXREh1qFDOfJ6DtKwd-ACQZVoPFVRFSc,3540 +lektor/types/fake.py,sha256=3NOgI__tFz4wK_3r7FG_Jvj3_AxcHX1ilDE_J0Hqfkw,765 +lektor/types/flow.py,sha256=_M7G-tQ-QuH3uL9zV63pWN4dSI8pBHipRZgkTTmiSLQ,7204 +lektor/types/formats.py,sha256=GGtKK-BtNu-N_PpkmYgwGXR5wTpMCOrJzdicGO7JRWQ,448 +lektor/types/multi.py,sha256=hRhlr_v1hxoakjVmW46cCrF_KieGJddocS3a6XLDYh8,4591 +lektor/types/primitives.py,sha256=3AUJ9NHt1iSSac8ncMJv7LDBUnkgXrdjnMN1FDlbX7M,4101 +lektor/types/special.py,sha256=Z_lvuN9_5TcPH0WPg0I97xr7J6MMh4XQGDnY_9Incx0,820 +../../../bin/lektor,sha256=dBTa2i0erXiMPjFtYTO4N9XbEqlSu11ykjsj_lrxhVI,244 +Lektor-3.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +lektor/editor.pyc,, +lektor/watcher.pyc,, +lektor/metaformat.pyc,, +lektor/admin/modules/dash.pyc,, +lektor/admin/modules/api.pyc,, +lektor/pluginsystem.pyc,, +lektor/db.pyc,, +lektor/project.pyc,, +lektor/__init__.pyc,, +lektor/environment.pyc,, +lektor/sourceobj.pyc,, +lektor/types/flow.pyc,, +lektor/types/formats.pyc,, +lektor/packages.pyc,, +lektor/buildfailures.pyc,, +lektor/build_programs.pyc,, +lektor/context.pyc,, +lektor/pagination.pyc,, +lektor/admin/modules/common.pyc,, +lektor/exception.pyc,, +lektor/markdown.pyc,, +lektor/types/fake.pyc,, +lektor/databags.pyc,, +lektor/imagetools.pyc,, +lektor/publisher.pyc,, +lektor/utils.pyc,, +lektor/types/__init__.pyc,, +lektor/i18n.pyc,, +lektor/quickstart.pyc,, +lektor/admin/modules/serve.pyc,, +lektor/filecontents.pyc,, +lektor/uilink.pyc,, +lektor/devcli.pyc,, +lektor/datamodel.pyc,, +lektor/devserver.pyc,, +lektor/admin/__init__.pyc,, +lektor/assets.pyc,, +lektor/types/special.pyc,, +lektor/admin/modules/__init__.pyc,, +lektor/sourcesearch.pyc,, +lektor/_compat.pyc,, +lektor/admin/utils.pyc,, +lektor/reporter.pyc,, +lektor/types/primitives.pyc,, +lektor/admin/webui.pyc,, +lektor/types/multi.pyc,, +lektor/builder.pyc,, +lektor/cli.pyc,, diff --git a/venv/lib/python2.7/site-packages/Lektor-3.1.1.dist-info/WHEEL b/venv/lib/python2.7/site-packages/Lektor-3.1.1.dist-info/WHEEL new file mode 100644 index 0000000..2b1e253 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Lektor-3.1.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.31.1) +Root-Is-Purelib: true +Tag: cp27-none-any + diff --git a/venv/lib/python2.7/site-packages/Lektor-3.1.1.dist-info/entry_points.txt b/venv/lib/python2.7/site-packages/Lektor-3.1.1.dist-info/entry_points.txt new file mode 100644 index 0000000..868299d --- /dev/null +++ b/venv/lib/python2.7/site-packages/Lektor-3.1.1.dist-info/entry_points.txt @@ -0,0 +1,4 @@ + + [console_scripts] + lektor=lektor.cli:main + \ No newline at end of file diff --git a/venv/lib/python2.7/site-packages/Lektor-3.1.1.dist-info/top_level.txt b/venv/lib/python2.7/site-packages/Lektor-3.1.1.dist-info/top_level.txt new file mode 100644 index 0000000..58717e8 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Lektor-3.1.1.dist-info/top_level.txt @@ -0,0 +1 @@ +lektor diff --git a/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/INSTALLER b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/LICENSE.txt b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/LICENSE.txt new file mode 100644 index 0000000..5d26938 --- /dev/null +++ b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/LICENSE.txt @@ -0,0 +1,33 @@ +Copyright (c) 2010 by Armin Ronacher and contributors. See AUTHORS +for more details. + +Some rights reserved. + +Redistribution and use in source and binary forms of the software as well +as documentation, with or without modification, are permitted provided +that the following conditions are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +* The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT +NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. diff --git a/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/METADATA b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/METADATA new file mode 100644 index 0000000..25a3ad1 --- /dev/null +++ b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/METADATA @@ -0,0 +1,135 @@ +Metadata-Version: 2.1 +Name: MarkupSafe +Version: 1.0 +Summary: Implements a XML/HTML/XHTML Markup safe string for Python +Home-page: http://github.com/pallets/markupsafe +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +License: BSD +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Text Processing :: Markup :: HTML + +MarkupSafe +========== + +Implements a unicode subclass that supports HTML strings: + +.. code-block:: python + + >>> from markupsafe import Markup, escape + >>> escape("") + Markup(u'<script>alert(document.cookie);</script>') + >>> tmpl = Markup("%s") + >>> tmpl % "Peter > Lustig" + Markup(u'Peter > Lustig') + +If you want to make an object unicode that is not yet unicode +but don't want to lose the taint information, you can use the +``soft_unicode`` function. (On Python 3 you can also use ``soft_str`` which +is a different name for the same function). + +.. code-block:: python + + >>> from markupsafe import soft_unicode + >>> soft_unicode(42) + u'42' + >>> soft_unicode(Markup('foo')) + Markup(u'foo') + +HTML Representations +-------------------- + +Objects can customize their HTML markup equivalent by overriding +the ``__html__`` function: + +.. code-block:: python + + >>> class Foo(object): + ... def __html__(self): + ... return 'Nice' + ... + >>> escape(Foo()) + Markup(u'Nice') + >>> Markup(Foo()) + Markup(u'Nice') + +Silent Escapes +-------------- + +Since MarkupSafe 0.10 there is now also a separate escape function +called ``escape_silent`` that returns an empty string for ``None`` for +consistency with other systems that return empty strings for ``None`` +when escaping (for instance Pylons' webhelpers). + +If you also want to use this for the escape method of the Markup +object, you can create your own subclass that does that: + +.. code-block:: python + + from markupsafe import Markup, escape_silent as escape + + class SilentMarkup(Markup): + __slots__ = () + + @classmethod + def escape(cls, s): + return cls(escape(s)) + +New-Style String Formatting +--------------------------- + +Starting with MarkupSafe 0.21 new style string formats from Python 2.6 and +3.x are now fully supported. Previously the escape behavior of those +functions was spotty at best. The new implementations operates under the +following algorithm: + +1. if an object has an ``__html_format__`` method it is called as + replacement for ``__format__`` with the format specifier. It either + has to return a string or markup object. +2. if an object has an ``__html__`` method it is called. +3. otherwise the default format system of Python kicks in and the result + is HTML escaped. + +Here is how you can implement your own formatting: + +.. code-block:: python + + class User(object): + + def __init__(self, id, username): + self.id = id + self.username = username + + def __html_format__(self, format_spec): + if format_spec == 'link': + return Markup('{1}').format( + self.id, + self.__html__(), + ) + elif format_spec: + raise ValueError('Invalid format spec') + return self.__html__() + + def __html__(self): + return Markup('{0}').format(self.username) + +And to format that user: + +.. code-block:: python + + >>> user = User(1, 'foo') + >>> Markup('

User: {0:link}').format(user) + Markup(u'

User: foo') + +Markupsafe supports Python 2.6, 2.7 and Python 3.3 and higher. + + diff --git a/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/RECORD b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/RECORD new file mode 100644 index 0000000..bb19982 --- /dev/null +++ b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/RECORD @@ -0,0 +1,15 @@ +MarkupSafe-1.0.dist-info/LICENSE.txt,sha256=C76IIo_WPSDsCX9k5Y1aCkZRI64TkUChjUBsYLSIJLU,1582 +MarkupSafe-1.0.dist-info/METADATA,sha256=RTBfxOEfHqiY9goR2QvR2sG0-pRm52r0QWcGi_pUYCQ,4182 +MarkupSafe-1.0.dist-info/RECORD,, +MarkupSafe-1.0.dist-info/WHEEL,sha256=1GbQwWo-bz5MQ7TWgxmoj0u3qc5GM8qVkJvIGW53qLM,93 +MarkupSafe-1.0.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11 +markupsafe/__init__.py,sha256=xtkRdxhzJzgp65wUo1D4DjnazxHU88pPldaAuDekBeY,10697 +markupsafe/_compat.py,sha256=r1HE0CpcAZeb-AiTV9wITR91PeLHn0CzZ_XHkYoozpI,565 +markupsafe/_constants.py,sha256=U_xybFQsyXKCgHSfranJnFzo-z9nn9fuBeSk243sE5Q,4795 +markupsafe/_native.py,sha256=E2Un1ysOf-w45d18YCj8UelT5UP7Vt__IuFPYJ7YRIs,1187 +markupsafe/_speedups.c,sha256=B6Mf6Fn33WqkagfwY7q5ZBSm_vJoHDYxDB0Jp_DP7Jw,5936 +MarkupSafe-1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +markupsafe/_native.pyc,, +markupsafe/__init__.pyc,, +markupsafe/_constants.pyc,, +markupsafe/_compat.pyc,, diff --git a/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/WHEEL b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/WHEEL new file mode 100644 index 0000000..2b1e253 --- /dev/null +++ b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.31.1) +Root-Is-Purelib: true +Tag: cp27-none-any + diff --git a/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/top_level.txt b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/top_level.txt new file mode 100644 index 0000000..75bf729 --- /dev/null +++ b/venv/lib/python2.7/site-packages/MarkupSafe-1.0.dist-info/top_level.txt @@ -0,0 +1 @@ +markupsafe diff --git a/venv/lib/python2.7/site-packages/OpenSSL/SSL.py b/venv/lib/python2.7/site-packages/OpenSSL/SSL.py new file mode 100644 index 0000000..e3eddae --- /dev/null +++ b/venv/lib/python2.7/site-packages/OpenSSL/SSL.py @@ -0,0 +1,2499 @@ +import os +import socket +from sys import platform +from functools import wraps, partial +from itertools import count, chain +from weakref import WeakValueDictionary +from errno import errorcode + +from cryptography.utils import deprecated + +from six import ( + binary_type as _binary_type, integer_types as integer_types, int2byte, + indexbytes) + +from OpenSSL._util import ( + UNSPECIFIED as _UNSPECIFIED, + exception_from_error_queue as _exception_from_error_queue, + ffi as _ffi, + lib as _lib, + make_assert as _make_assert, + native as _native, + path_string as _path_string, + text_to_bytes_and_warn as _text_to_bytes_and_warn, + no_zero_allocator as _no_zero_allocator, +) + +from OpenSSL.crypto import ( + FILETYPE_PEM, _PassphraseHelper, PKey, X509Name, X509, X509Store) + +__all__ = [ + 'OPENSSL_VERSION_NUMBER', + 'SSLEAY_VERSION', + 'SSLEAY_CFLAGS', + 'SSLEAY_PLATFORM', + 'SSLEAY_DIR', + 'SSLEAY_BUILT_ON', + 'SENT_SHUTDOWN', + 'RECEIVED_SHUTDOWN', + 'SSLv2_METHOD', + 'SSLv3_METHOD', + 'SSLv23_METHOD', + 'TLSv1_METHOD', + 'TLSv1_1_METHOD', + 'TLSv1_2_METHOD', + 'OP_NO_SSLv2', + 'OP_NO_SSLv3', + 'OP_NO_TLSv1', + 'OP_NO_TLSv1_1', + 'OP_NO_TLSv1_2', + 'MODE_RELEASE_BUFFERS', + 'OP_SINGLE_DH_USE', + 'OP_SINGLE_ECDH_USE', + 'OP_EPHEMERAL_RSA', + 'OP_MICROSOFT_SESS_ID_BUG', + 'OP_NETSCAPE_CHALLENGE_BUG', + 'OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG', + 'OP_SSLREF2_REUSE_CERT_TYPE_BUG', + 'OP_MICROSOFT_BIG_SSLV3_BUFFER', + 'OP_MSIE_SSLV2_RSA_PADDING', + 'OP_SSLEAY_080_CLIENT_DH_BUG', + 'OP_TLS_D5_BUG', + 'OP_TLS_BLOCK_PADDING_BUG', + 'OP_DONT_INSERT_EMPTY_FRAGMENTS', + 'OP_CIPHER_SERVER_PREFERENCE', + 'OP_TLS_ROLLBACK_BUG', + 'OP_PKCS1_CHECK_1', + 'OP_PKCS1_CHECK_2', + 'OP_NETSCAPE_CA_DN_BUG', + 'OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG', + 'OP_NO_COMPRESSION', + 'OP_NO_QUERY_MTU', + 'OP_COOKIE_EXCHANGE', + 'OP_NO_TICKET', + 'OP_ALL', + 'VERIFY_PEER', + 'VERIFY_FAIL_IF_NO_PEER_CERT', + 'VERIFY_CLIENT_ONCE', + 'VERIFY_NONE', + 'SESS_CACHE_OFF', + 'SESS_CACHE_CLIENT', + 'SESS_CACHE_SERVER', + 'SESS_CACHE_BOTH', + 'SESS_CACHE_NO_AUTO_CLEAR', + 'SESS_CACHE_NO_INTERNAL_LOOKUP', + 'SESS_CACHE_NO_INTERNAL_STORE', + 'SESS_CACHE_NO_INTERNAL', + 'SSL_ST_CONNECT', + 'SSL_ST_ACCEPT', + 'SSL_ST_MASK', + 'SSL_CB_LOOP', + 'SSL_CB_EXIT', + 'SSL_CB_READ', + 'SSL_CB_WRITE', + 'SSL_CB_ALERT', + 'SSL_CB_READ_ALERT', + 'SSL_CB_WRITE_ALERT', + 'SSL_CB_ACCEPT_LOOP', + 'SSL_CB_ACCEPT_EXIT', + 'SSL_CB_CONNECT_LOOP', + 'SSL_CB_CONNECT_EXIT', + 'SSL_CB_HANDSHAKE_START', + 'SSL_CB_HANDSHAKE_DONE', + 'Error', + 'WantReadError', + 'WantWriteError', + 'WantX509LookupError', + 'ZeroReturnError', + 'SysCallError', + 'SSLeay_version', + 'Session', + 'Context', + 'Connection' +] + +try: + _buffer = buffer +except NameError: + class _buffer(object): + pass + +OPENSSL_VERSION_NUMBER = _lib.OPENSSL_VERSION_NUMBER +SSLEAY_VERSION = _lib.SSLEAY_VERSION +SSLEAY_CFLAGS = _lib.SSLEAY_CFLAGS +SSLEAY_PLATFORM = _lib.SSLEAY_PLATFORM +SSLEAY_DIR = _lib.SSLEAY_DIR +SSLEAY_BUILT_ON = _lib.SSLEAY_BUILT_ON + +SENT_SHUTDOWN = _lib.SSL_SENT_SHUTDOWN +RECEIVED_SHUTDOWN = _lib.SSL_RECEIVED_SHUTDOWN + +SSLv2_METHOD = 1 +SSLv3_METHOD = 2 +SSLv23_METHOD = 3 +TLSv1_METHOD = 4 +TLSv1_1_METHOD = 5 +TLSv1_2_METHOD = 6 + +OP_NO_SSLv2 = _lib.SSL_OP_NO_SSLv2 +OP_NO_SSLv3 = _lib.SSL_OP_NO_SSLv3 +OP_NO_TLSv1 = _lib.SSL_OP_NO_TLSv1 +OP_NO_TLSv1_1 = _lib.SSL_OP_NO_TLSv1_1 +OP_NO_TLSv1_2 = _lib.SSL_OP_NO_TLSv1_2 + +MODE_RELEASE_BUFFERS = _lib.SSL_MODE_RELEASE_BUFFERS + +OP_SINGLE_DH_USE = _lib.SSL_OP_SINGLE_DH_USE +OP_SINGLE_ECDH_USE = _lib.SSL_OP_SINGLE_ECDH_USE +OP_EPHEMERAL_RSA = _lib.SSL_OP_EPHEMERAL_RSA +OP_MICROSOFT_SESS_ID_BUG = _lib.SSL_OP_MICROSOFT_SESS_ID_BUG +OP_NETSCAPE_CHALLENGE_BUG = _lib.SSL_OP_NETSCAPE_CHALLENGE_BUG +OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG = ( + _lib.SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG +) +OP_SSLREF2_REUSE_CERT_TYPE_BUG = _lib.SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG +OP_MICROSOFT_BIG_SSLV3_BUFFER = _lib.SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER +OP_MSIE_SSLV2_RSA_PADDING = _lib.SSL_OP_MSIE_SSLV2_RSA_PADDING +OP_SSLEAY_080_CLIENT_DH_BUG = _lib.SSL_OP_SSLEAY_080_CLIENT_DH_BUG +OP_TLS_D5_BUG = _lib.SSL_OP_TLS_D5_BUG +OP_TLS_BLOCK_PADDING_BUG = _lib.SSL_OP_TLS_BLOCK_PADDING_BUG +OP_DONT_INSERT_EMPTY_FRAGMENTS = _lib.SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS +OP_CIPHER_SERVER_PREFERENCE = _lib.SSL_OP_CIPHER_SERVER_PREFERENCE +OP_TLS_ROLLBACK_BUG = _lib.SSL_OP_TLS_ROLLBACK_BUG +OP_PKCS1_CHECK_1 = _lib.SSL_OP_PKCS1_CHECK_1 +OP_PKCS1_CHECK_2 = _lib.SSL_OP_PKCS1_CHECK_2 +OP_NETSCAPE_CA_DN_BUG = _lib.SSL_OP_NETSCAPE_CA_DN_BUG +OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG = ( + _lib.SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG +) +OP_NO_COMPRESSION = _lib.SSL_OP_NO_COMPRESSION + +OP_NO_QUERY_MTU = _lib.SSL_OP_NO_QUERY_MTU +OP_COOKIE_EXCHANGE = _lib.SSL_OP_COOKIE_EXCHANGE +OP_NO_TICKET = _lib.SSL_OP_NO_TICKET + +OP_ALL = _lib.SSL_OP_ALL + +VERIFY_PEER = _lib.SSL_VERIFY_PEER +VERIFY_FAIL_IF_NO_PEER_CERT = _lib.SSL_VERIFY_FAIL_IF_NO_PEER_CERT +VERIFY_CLIENT_ONCE = _lib.SSL_VERIFY_CLIENT_ONCE +VERIFY_NONE = _lib.SSL_VERIFY_NONE + +SESS_CACHE_OFF = _lib.SSL_SESS_CACHE_OFF +SESS_CACHE_CLIENT = _lib.SSL_SESS_CACHE_CLIENT +SESS_CACHE_SERVER = _lib.SSL_SESS_CACHE_SERVER +SESS_CACHE_BOTH = _lib.SSL_SESS_CACHE_BOTH +SESS_CACHE_NO_AUTO_CLEAR = _lib.SSL_SESS_CACHE_NO_AUTO_CLEAR +SESS_CACHE_NO_INTERNAL_LOOKUP = _lib.SSL_SESS_CACHE_NO_INTERNAL_LOOKUP +SESS_CACHE_NO_INTERNAL_STORE = _lib.SSL_SESS_CACHE_NO_INTERNAL_STORE +SESS_CACHE_NO_INTERNAL = _lib.SSL_SESS_CACHE_NO_INTERNAL + +SSL_ST_CONNECT = _lib.SSL_ST_CONNECT +SSL_ST_ACCEPT = _lib.SSL_ST_ACCEPT +SSL_ST_MASK = _lib.SSL_ST_MASK +if _lib.Cryptography_HAS_SSL_ST: + SSL_ST_INIT = _lib.SSL_ST_INIT + SSL_ST_BEFORE = _lib.SSL_ST_BEFORE + SSL_ST_OK = _lib.SSL_ST_OK + SSL_ST_RENEGOTIATE = _lib.SSL_ST_RENEGOTIATE + __all__.extend([ + 'SSL_ST_INIT', + 'SSL_ST_BEFORE', + 'SSL_ST_OK', + 'SSL_ST_RENEGOTIATE', + ]) + +SSL_CB_LOOP = _lib.SSL_CB_LOOP +SSL_CB_EXIT = _lib.SSL_CB_EXIT +SSL_CB_READ = _lib.SSL_CB_READ +SSL_CB_WRITE = _lib.SSL_CB_WRITE +SSL_CB_ALERT = _lib.SSL_CB_ALERT +SSL_CB_READ_ALERT = _lib.SSL_CB_READ_ALERT +SSL_CB_WRITE_ALERT = _lib.SSL_CB_WRITE_ALERT +SSL_CB_ACCEPT_LOOP = _lib.SSL_CB_ACCEPT_LOOP +SSL_CB_ACCEPT_EXIT = _lib.SSL_CB_ACCEPT_EXIT +SSL_CB_CONNECT_LOOP = _lib.SSL_CB_CONNECT_LOOP +SSL_CB_CONNECT_EXIT = _lib.SSL_CB_CONNECT_EXIT +SSL_CB_HANDSHAKE_START = _lib.SSL_CB_HANDSHAKE_START +SSL_CB_HANDSHAKE_DONE = _lib.SSL_CB_HANDSHAKE_DONE + +# Taken from https://golang.org/src/crypto/x509/root_linux.go +_CERTIFICATE_FILE_LOCATIONS = [ + "/etc/ssl/certs/ca-certificates.crt", # Debian/Ubuntu/Gentoo etc. + "/etc/pki/tls/certs/ca-bundle.crt", # Fedora/RHEL 6 + "/etc/ssl/ca-bundle.pem", # OpenSUSE + "/etc/pki/tls/cacert.pem", # OpenELEC + "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", # CentOS/RHEL 7 +] + +_CERTIFICATE_PATH_LOCATIONS = [ + "/etc/ssl/certs", # SLES10/SLES11 +] + +# These values are compared to output from cffi's ffi.string so they must be +# byte strings. +_CRYPTOGRAPHY_MANYLINUX1_CA_DIR = b"/opt/pyca/cryptography/openssl/certs" +_CRYPTOGRAPHY_MANYLINUX1_CA_FILE = b"/opt/pyca/cryptography/openssl/cert.pem" + + +class Error(Exception): + """ + An error occurred in an `OpenSSL.SSL` API. + """ + + +_raise_current_error = partial(_exception_from_error_queue, Error) +_openssl_assert = _make_assert(Error) + + +class WantReadError(Error): + pass + + +class WantWriteError(Error): + pass + + +class WantX509LookupError(Error): + pass + + +class ZeroReturnError(Error): + pass + + +class SysCallError(Error): + pass + + +class _CallbackExceptionHelper(object): + """ + A base class for wrapper classes that allow for intelligent exception + handling in OpenSSL callbacks. + + :ivar list _problems: Any exceptions that occurred while executing in a + context where they could not be raised in the normal way. Typically + this is because OpenSSL has called into some Python code and requires a + return value. The exceptions are saved to be raised later when it is + possible to do so. + """ + + def __init__(self): + self._problems = [] + + def raise_if_problem(self): + """ + Raise an exception from the OpenSSL error queue or that was previously + captured whe running a callback. + """ + if self._problems: + try: + _raise_current_error() + except Error: + pass + raise self._problems.pop(0) + + +class _VerifyHelper(_CallbackExceptionHelper): + """ + Wrap a callback such that it can be used as a certificate verification + callback. + """ + + def __init__(self, callback): + _CallbackExceptionHelper.__init__(self) + + @wraps(callback) + def wrapper(ok, store_ctx): + x509 = _lib.X509_STORE_CTX_get_current_cert(store_ctx) + _lib.X509_up_ref(x509) + cert = X509._from_raw_x509_ptr(x509) + error_number = _lib.X509_STORE_CTX_get_error(store_ctx) + error_depth = _lib.X509_STORE_CTX_get_error_depth(store_ctx) + + index = _lib.SSL_get_ex_data_X509_STORE_CTX_idx() + ssl = _lib.X509_STORE_CTX_get_ex_data(store_ctx, index) + connection = Connection._reverse_mapping[ssl] + + try: + result = callback( + connection, cert, error_number, error_depth, ok + ) + except Exception as e: + self._problems.append(e) + return 0 + else: + if result: + _lib.X509_STORE_CTX_set_error(store_ctx, _lib.X509_V_OK) + return 1 + else: + return 0 + + self.callback = _ffi.callback( + "int (*)(int, X509_STORE_CTX *)", wrapper) + + +class _NpnAdvertiseHelper(_CallbackExceptionHelper): + """ + Wrap a callback such that it can be used as an NPN advertisement callback. + """ + + def __init__(self, callback): + _CallbackExceptionHelper.__init__(self) + + @wraps(callback) + def wrapper(ssl, out, outlen, arg): + try: + conn = Connection._reverse_mapping[ssl] + protos = callback(conn) + + # Join the protocols into a Python bytestring, length-prefixing + # each element. + protostr = b''.join( + chain.from_iterable((int2byte(len(p)), p) for p in protos) + ) + + # Save our callback arguments on the connection object. This is + # done to make sure that they don't get freed before OpenSSL + # uses them. Then, return them appropriately in the output + # parameters. + conn._npn_advertise_callback_args = [ + _ffi.new("unsigned int *", len(protostr)), + _ffi.new("unsigned char[]", protostr), + ] + outlen[0] = conn._npn_advertise_callback_args[0][0] + out[0] = conn._npn_advertise_callback_args[1] + return 0 + except Exception as e: + self._problems.append(e) + return 2 # SSL_TLSEXT_ERR_ALERT_FATAL + + self.callback = _ffi.callback( + "int (*)(SSL *, const unsigned char **, unsigned int *, void *)", + wrapper + ) + + +class _NpnSelectHelper(_CallbackExceptionHelper): + """ + Wrap a callback such that it can be used as an NPN selection callback. + """ + + def __init__(self, callback): + _CallbackExceptionHelper.__init__(self) + + @wraps(callback) + def wrapper(ssl, out, outlen, in_, inlen, arg): + try: + conn = Connection._reverse_mapping[ssl] + + # The string passed to us is actually made up of multiple + # length-prefixed bytestrings. We need to split that into a + # list. + instr = _ffi.buffer(in_, inlen)[:] + protolist = [] + while instr: + length = indexbytes(instr, 0) + proto = instr[1:length + 1] + protolist.append(proto) + instr = instr[length + 1:] + + # Call the callback + outstr = callback(conn, protolist) + + # Save our callback arguments on the connection object. This is + # done to make sure that they don't get freed before OpenSSL + # uses them. Then, return them appropriately in the output + # parameters. + conn._npn_select_callback_args = [ + _ffi.new("unsigned char *", len(outstr)), + _ffi.new("unsigned char[]", outstr), + ] + outlen[0] = conn._npn_select_callback_args[0][0] + out[0] = conn._npn_select_callback_args[1] + return 0 + except Exception as e: + self._problems.append(e) + return 2 # SSL_TLSEXT_ERR_ALERT_FATAL + + self.callback = _ffi.callback( + ("int (*)(SSL *, unsigned char **, unsigned char *, " + "const unsigned char *, unsigned int, void *)"), + wrapper + ) + + +class _ALPNSelectHelper(_CallbackExceptionHelper): + """ + Wrap a callback such that it can be used as an ALPN selection callback. + """ + + def __init__(self, callback): + _CallbackExceptionHelper.__init__(self) + + @wraps(callback) + def wrapper(ssl, out, outlen, in_, inlen, arg): + try: + conn = Connection._reverse_mapping[ssl] + + # The string passed to us is made up of multiple + # length-prefixed bytestrings. We need to split that into a + # list. + instr = _ffi.buffer(in_, inlen)[:] + protolist = [] + while instr: + encoded_len = indexbytes(instr, 0) + proto = instr[1:encoded_len + 1] + protolist.append(proto) + instr = instr[encoded_len + 1:] + + # Call the callback + outstr = callback(conn, protolist) + + if not isinstance(outstr, _binary_type): + raise TypeError("ALPN callback must return a bytestring.") + + # Save our callback arguments on the connection object to make + # sure that they don't get freed before OpenSSL can use them. + # Then, return them in the appropriate output parameters. + conn._alpn_select_callback_args = [ + _ffi.new("unsigned char *", len(outstr)), + _ffi.new("unsigned char[]", outstr), + ] + outlen[0] = conn._alpn_select_callback_args[0][0] + out[0] = conn._alpn_select_callback_args[1] + return 0 + except Exception as e: + self._problems.append(e) + return 2 # SSL_TLSEXT_ERR_ALERT_FATAL + + self.callback = _ffi.callback( + ("int (*)(SSL *, unsigned char **, unsigned char *, " + "const unsigned char *, unsigned int, void *)"), + wrapper + ) + + +class _OCSPServerCallbackHelper(_CallbackExceptionHelper): + """ + Wrap a callback such that it can be used as an OCSP callback for the server + side. + + Annoyingly, OpenSSL defines one OCSP callback but uses it in two different + ways. For servers, that callback is expected to retrieve some OCSP data and + hand it to OpenSSL, and may return only SSL_TLSEXT_ERR_OK, + SSL_TLSEXT_ERR_FATAL, and SSL_TLSEXT_ERR_NOACK. For clients, that callback + is expected to check the OCSP data, and returns a negative value on error, + 0 if the response is not acceptable, or positive if it is. These are + mutually exclusive return code behaviours, and they mean that we need two + helpers so that we always return an appropriate error code if the user's + code throws an exception. + + Given that we have to have two helpers anyway, these helpers are a bit more + helpery than most: specifically, they hide a few more of the OpenSSL + functions so that the user has an easier time writing these callbacks. + + This helper implements the server side. + """ + + def __init__(self, callback): + _CallbackExceptionHelper.__init__(self) + + @wraps(callback) + def wrapper(ssl, cdata): + try: + conn = Connection._reverse_mapping[ssl] + + # Extract the data if any was provided. + if cdata != _ffi.NULL: + data = _ffi.from_handle(cdata) + else: + data = None + + # Call the callback. + ocsp_data = callback(conn, data) + + if not isinstance(ocsp_data, _binary_type): + raise TypeError("OCSP callback must return a bytestring.") + + # If the OCSP data was provided, we will pass it to OpenSSL. + # However, we have an early exit here: if no OCSP data was + # provided we will just exit out and tell OpenSSL that there + # is nothing to do. + if not ocsp_data: + return 3 # SSL_TLSEXT_ERR_NOACK + + # Pass the data to OpenSSL. Insanely, OpenSSL doesn't make a + # private copy of this data, so we need to keep it alive, but + # it *does* want to free it itself if it gets replaced. This + # somewhat bonkers behaviour means we need to use + # OPENSSL_malloc directly, which is a pain in the butt to work + # with. It's ok for us to "leak" the memory here because + # OpenSSL now owns it and will free it. + ocsp_data_length = len(ocsp_data) + data_ptr = _lib.OPENSSL_malloc(ocsp_data_length) + _ffi.buffer(data_ptr, ocsp_data_length)[:] = ocsp_data + + _lib.SSL_set_tlsext_status_ocsp_resp( + ssl, data_ptr, ocsp_data_length + ) + + return 0 + except Exception as e: + self._problems.append(e) + return 2 # SSL_TLSEXT_ERR_ALERT_FATAL + + self.callback = _ffi.callback("int (*)(SSL *, void *)", wrapper) + + +class _OCSPClientCallbackHelper(_CallbackExceptionHelper): + """ + Wrap a callback such that it can be used as an OCSP callback for the client + side. + + Annoyingly, OpenSSL defines one OCSP callback but uses it in two different + ways. For servers, that callback is expected to retrieve some OCSP data and + hand it to OpenSSL, and may return only SSL_TLSEXT_ERR_OK, + SSL_TLSEXT_ERR_FATAL, and SSL_TLSEXT_ERR_NOACK. For clients, that callback + is expected to check the OCSP data, and returns a negative value on error, + 0 if the response is not acceptable, or positive if it is. These are + mutually exclusive return code behaviours, and they mean that we need two + helpers so that we always return an appropriate error code if the user's + code throws an exception. + + Given that we have to have two helpers anyway, these helpers are a bit more + helpery than most: specifically, they hide a few more of the OpenSSL + functions so that the user has an easier time writing these callbacks. + + This helper implements the client side. + """ + + def __init__(self, callback): + _CallbackExceptionHelper.__init__(self) + + @wraps(callback) + def wrapper(ssl, cdata): + try: + conn = Connection._reverse_mapping[ssl] + + # Extract the data if any was provided. + if cdata != _ffi.NULL: + data = _ffi.from_handle(cdata) + else: + data = None + + # Get the OCSP data. + ocsp_ptr = _ffi.new("unsigned char **") + ocsp_len = _lib.SSL_get_tlsext_status_ocsp_resp(ssl, ocsp_ptr) + if ocsp_len < 0: + # No OCSP data. + ocsp_data = b'' + else: + # Copy the OCSP data, then pass it to the callback. + ocsp_data = _ffi.buffer(ocsp_ptr[0], ocsp_len)[:] + + valid = callback(conn, ocsp_data, data) + + # Return 1 on success or 0 on error. + return int(bool(valid)) + + except Exception as e: + self._problems.append(e) + # Return negative value if an exception is hit. + return -1 + + self.callback = _ffi.callback("int (*)(SSL *, void *)", wrapper) + + +def _asFileDescriptor(obj): + fd = None + if not isinstance(obj, integer_types): + meth = getattr(obj, "fileno", None) + if meth is not None: + obj = meth() + + if isinstance(obj, integer_types): + fd = obj + + if not isinstance(fd, integer_types): + raise TypeError("argument must be an int, or have a fileno() method.") + elif fd < 0: + raise ValueError( + "file descriptor cannot be a negative integer (%i)" % (fd,)) + + return fd + + +def SSLeay_version(type): + """ + Return a string describing the version of OpenSSL in use. + + :param type: One of the :const:`SSLEAY_` constants defined in this module. + """ + return _ffi.string(_lib.SSLeay_version(type)) + + +def _make_requires(flag, error): + """ + Builds a decorator that ensures that functions that rely on OpenSSL + functions that are not present in this build raise NotImplementedError, + rather than AttributeError coming out of cryptography. + + :param flag: A cryptography flag that guards the functions, e.g. + ``Cryptography_HAS_NEXTPROTONEG``. + :param error: The string to be used in the exception if the flag is false. + """ + def _requires_decorator(func): + if not flag: + @wraps(func) + def explode(*args, **kwargs): + raise NotImplementedError(error) + return explode + else: + return func + + return _requires_decorator + + +_requires_npn = _make_requires( + _lib.Cryptography_HAS_NEXTPROTONEG, "NPN not available" +) + + +_requires_alpn = _make_requires( + _lib.Cryptography_HAS_ALPN, "ALPN not available" +) + + +_requires_sni = _make_requires( + _lib.Cryptography_HAS_TLSEXT_HOSTNAME, "SNI not available" +) + + +class Session(object): + """ + A class representing an SSL session. A session defines certain connection + parameters which may be re-used to speed up the setup of subsequent + connections. + + .. versionadded:: 0.14 + """ + pass + + +class Context(object): + """ + :class:`OpenSSL.SSL.Context` instances define the parameters for setting + up new SSL connections. + + :param method: One of SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, or + TLSv1_METHOD. + """ + _methods = { + SSLv2_METHOD: "SSLv2_method", + SSLv3_METHOD: "SSLv3_method", + SSLv23_METHOD: "SSLv23_method", + TLSv1_METHOD: "TLSv1_method", + TLSv1_1_METHOD: "TLSv1_1_method", + TLSv1_2_METHOD: "TLSv1_2_method", + } + _methods = dict( + (identifier, getattr(_lib, name)) + for (identifier, name) in _methods.items() + if getattr(_lib, name, None) is not None) + + def __init__(self, method): + if not isinstance(method, integer_types): + raise TypeError("method must be an integer") + + try: + method_func = self._methods[method] + except KeyError: + raise ValueError("No such protocol") + + method_obj = method_func() + _openssl_assert(method_obj != _ffi.NULL) + + context = _lib.SSL_CTX_new(method_obj) + _openssl_assert(context != _ffi.NULL) + context = _ffi.gc(context, _lib.SSL_CTX_free) + + # If SSL_CTX_set_ecdh_auto is available then set it so the ECDH curve + # will be auto-selected. This function was added in 1.0.2 and made a + # noop in 1.1.0+ (where it is set automatically). + try: + res = _lib.SSL_CTX_set_ecdh_auto(context, 1) + _openssl_assert(res == 1) + except AttributeError: + pass + + self._context = context + self._passphrase_helper = None + self._passphrase_callback = None + self._passphrase_userdata = None + self._verify_helper = None + self._verify_callback = None + self._info_callback = None + self._tlsext_servername_callback = None + self._app_data = None + self._npn_advertise_helper = None + self._npn_advertise_callback = None + self._npn_select_helper = None + self._npn_select_callback = None + self._alpn_select_helper = None + self._alpn_select_callback = None + self._ocsp_helper = None + self._ocsp_callback = None + self._ocsp_data = None + + self.set_mode(_lib.SSL_MODE_ENABLE_PARTIAL_WRITE) + + def load_verify_locations(self, cafile, capath=None): + """ + Let SSL know where we can find trusted certificates for the certificate + chain. Note that the certificates have to be in PEM format. + + If capath is passed, it must be a directory prepared using the + ``c_rehash`` tool included with OpenSSL. Either, but not both, of + *pemfile* or *capath* may be :data:`None`. + + :param cafile: In which file we can find the certificates (``bytes`` or + ``unicode``). + :param capath: In which directory we can find the certificates + (``bytes`` or ``unicode``). + + :return: None + """ + if cafile is None: + cafile = _ffi.NULL + else: + cafile = _path_string(cafile) + + if capath is None: + capath = _ffi.NULL + else: + capath = _path_string(capath) + + load_result = _lib.SSL_CTX_load_verify_locations( + self._context, cafile, capath + ) + if not load_result: + _raise_current_error() + + def _wrap_callback(self, callback): + @wraps(callback) + def wrapper(size, verify, userdata): + return callback(size, verify, self._passphrase_userdata) + return _PassphraseHelper( + FILETYPE_PEM, wrapper, more_args=True, truncate=True) + + def set_passwd_cb(self, callback, userdata=None): + """ + Set the passphrase callback. This function will be called + when a private key with a passphrase is loaded. + + :param callback: The Python callback to use. This must accept three + positional arguments. First, an integer giving the maximum length + of the passphrase it may return. If the returned passphrase is + longer than this, it will be truncated. Second, a boolean value + which will be true if the user should be prompted for the + passphrase twice and the callback should verify that the two values + supplied are equal. Third, the value given as the *userdata* + parameter to :meth:`set_passwd_cb`. The *callback* must return + a byte string. If an error occurs, *callback* should return a false + value (e.g. an empty string). + :param userdata: (optional) A Python object which will be given as + argument to the callback + :return: None + """ + if not callable(callback): + raise TypeError("callback must be callable") + + self._passphrase_helper = self._wrap_callback(callback) + self._passphrase_callback = self._passphrase_helper.callback + _lib.SSL_CTX_set_default_passwd_cb( + self._context, self._passphrase_callback) + self._passphrase_userdata = userdata + + def set_default_verify_paths(self): + """ + Specify that the platform provided CA certificates are to be used for + verification purposes. This method has some caveats related to the + binary wheels that cryptography (pyOpenSSL's primary dependency) ships: + + * macOS will only load certificates using this method if the user has + the ``openssl@1.1`` `Homebrew `_ formula installed + in the default location. + * Windows will not work. + * manylinux1 cryptography wheels will work on most common Linux + distributions in pyOpenSSL 17.1.0 and above. pyOpenSSL detects the + manylinux1 wheel and attempts to load roots via a fallback path. + + :return: None + """ + # SSL_CTX_set_default_verify_paths will attempt to load certs from + # both a cafile and capath that are set at compile time. However, + # it will first check environment variables and, if present, load + # those paths instead + set_result = _lib.SSL_CTX_set_default_verify_paths(self._context) + _openssl_assert(set_result == 1) + # After attempting to set default_verify_paths we need to know whether + # to go down the fallback path. + # First we'll check to see if any env vars have been set. If so, + # we won't try to do anything else because the user has set the path + # themselves. + dir_env_var = _ffi.string( + _lib.X509_get_default_cert_dir_env() + ).decode("ascii") + file_env_var = _ffi.string( + _lib.X509_get_default_cert_file_env() + ).decode("ascii") + if not self._check_env_vars_set(dir_env_var, file_env_var): + default_dir = _ffi.string(_lib.X509_get_default_cert_dir()) + default_file = _ffi.string(_lib.X509_get_default_cert_file()) + # Now we check to see if the default_dir and default_file are set + # to the exact values we use in our manylinux1 builds. If they are + # then we know to load the fallbacks + if ( + default_dir == _CRYPTOGRAPHY_MANYLINUX1_CA_DIR and + default_file == _CRYPTOGRAPHY_MANYLINUX1_CA_FILE + ): + # This is manylinux1, let's load our fallback paths + self._fallback_default_verify_paths( + _CERTIFICATE_FILE_LOCATIONS, + _CERTIFICATE_PATH_LOCATIONS + ) + + def _check_env_vars_set(self, dir_env_var, file_env_var): + """ + Check to see if the default cert dir/file environment vars are present. + + :return: bool + """ + return ( + os.environ.get(file_env_var) is not None or + os.environ.get(dir_env_var) is not None + ) + + def _fallback_default_verify_paths(self, file_path, dir_path): + """ + Default verify paths are based on the compiled version of OpenSSL. + However, when pyca/cryptography is compiled as a manylinux1 wheel + that compiled location can potentially be wrong. So, like Go, we + will try a predefined set of paths and attempt to load roots + from there. + + :return: None + """ + for cafile in file_path: + if os.path.isfile(cafile): + self.load_verify_locations(cafile) + break + + for capath in dir_path: + if os.path.isdir(capath): + self.load_verify_locations(None, capath) + break + + def use_certificate_chain_file(self, certfile): + """ + Load a certificate chain from a file. + + :param certfile: The name of the certificate chain file (``bytes`` or + ``unicode``). Must be PEM encoded. + + :return: None + """ + certfile = _path_string(certfile) + + result = _lib.SSL_CTX_use_certificate_chain_file( + self._context, certfile + ) + if not result: + _raise_current_error() + + def use_certificate_file(self, certfile, filetype=FILETYPE_PEM): + """ + Load a certificate from a file + + :param certfile: The name of the certificate file (``bytes`` or + ``unicode``). + :param filetype: (optional) The encoding of the file, which is either + :const:`FILETYPE_PEM` or :const:`FILETYPE_ASN1`. The default is + :const:`FILETYPE_PEM`. + + :return: None + """ + certfile = _path_string(certfile) + if not isinstance(filetype, integer_types): + raise TypeError("filetype must be an integer") + + use_result = _lib.SSL_CTX_use_certificate_file( + self._context, certfile, filetype + ) + if not use_result: + _raise_current_error() + + def use_certificate(self, cert): + """ + Load a certificate from a X509 object + + :param cert: The X509 object + :return: None + """ + if not isinstance(cert, X509): + raise TypeError("cert must be an X509 instance") + + use_result = _lib.SSL_CTX_use_certificate(self._context, cert._x509) + if not use_result: + _raise_current_error() + + def add_extra_chain_cert(self, certobj): + """ + Add certificate to chain + + :param certobj: The X509 certificate object to add to the chain + :return: None + """ + if not isinstance(certobj, X509): + raise TypeError("certobj must be an X509 instance") + + copy = _lib.X509_dup(certobj._x509) + add_result = _lib.SSL_CTX_add_extra_chain_cert(self._context, copy) + if not add_result: + # TODO: This is untested. + _lib.X509_free(copy) + _raise_current_error() + + def _raise_passphrase_exception(self): + if self._passphrase_helper is not None: + self._passphrase_helper.raise_if_problem(Error) + + _raise_current_error() + + def use_privatekey_file(self, keyfile, filetype=_UNSPECIFIED): + """ + Load a private key from a file + + :param keyfile: The name of the key file (``bytes`` or ``unicode``) + :param filetype: (optional) The encoding of the file, which is either + :const:`FILETYPE_PEM` or :const:`FILETYPE_ASN1`. The default is + :const:`FILETYPE_PEM`. + + :return: None + """ + keyfile = _path_string(keyfile) + + if filetype is _UNSPECIFIED: + filetype = FILETYPE_PEM + elif not isinstance(filetype, integer_types): + raise TypeError("filetype must be an integer") + + use_result = _lib.SSL_CTX_use_PrivateKey_file( + self._context, keyfile, filetype) + if not use_result: + self._raise_passphrase_exception() + + def use_privatekey(self, pkey): + """ + Load a private key from a PKey object + + :param pkey: The PKey object + :return: None + """ + if not isinstance(pkey, PKey): + raise TypeError("pkey must be a PKey instance") + + use_result = _lib.SSL_CTX_use_PrivateKey(self._context, pkey._pkey) + if not use_result: + self._raise_passphrase_exception() + + def check_privatekey(self): + """ + Check if the private key (loaded with :meth:`use_privatekey`) matches + the certificate (loaded with :meth:`use_certificate`) + + :return: :data:`None` (raises :exc:`Error` if something's wrong) + """ + if not _lib.SSL_CTX_check_private_key(self._context): + _raise_current_error() + + def load_client_ca(self, cafile): + """ + Load the trusted certificates that will be sent to the client. Does + not actually imply any of the certificates are trusted; that must be + configured separately. + + :param bytes cafile: The path to a certificates file in PEM format. + :return: None + """ + ca_list = _lib.SSL_load_client_CA_file( + _text_to_bytes_and_warn("cafile", cafile) + ) + _openssl_assert(ca_list != _ffi.NULL) + _lib.SSL_CTX_set_client_CA_list(self._context, ca_list) + + def set_session_id(self, buf): + """ + Set the session id to *buf* within which a session can be reused for + this Context object. This is needed when doing session resumption, + because there is no way for a stored session to know which Context + object it is associated with. + + :param bytes buf: The session id. + + :returns: None + """ + buf = _text_to_bytes_and_warn("buf", buf) + _openssl_assert( + _lib.SSL_CTX_set_session_id_context( + self._context, + buf, + len(buf), + ) == 1 + ) + + def set_session_cache_mode(self, mode): + """ + Set the behavior of the session cache used by all connections using + this Context. The previously set mode is returned. See + :const:`SESS_CACHE_*` for details about particular modes. + + :param mode: One or more of the SESS_CACHE_* flags (combine using + bitwise or) + :returns: The previously set caching mode. + + .. versionadded:: 0.14 + """ + if not isinstance(mode, integer_types): + raise TypeError("mode must be an integer") + + return _lib.SSL_CTX_set_session_cache_mode(self._context, mode) + + def get_session_cache_mode(self): + """ + Get the current session cache mode. + + :returns: The currently used cache mode. + + .. versionadded:: 0.14 + """ + return _lib.SSL_CTX_get_session_cache_mode(self._context) + + def set_verify(self, mode, callback): + """ + et the verification flags for this Context object to *mode* and specify + that *callback* should be used for verification callbacks. + + :param mode: The verify mode, this should be one of + :const:`VERIFY_NONE` and :const:`VERIFY_PEER`. If + :const:`VERIFY_PEER` is used, *mode* can be OR:ed with + :const:`VERIFY_FAIL_IF_NO_PEER_CERT` and + :const:`VERIFY_CLIENT_ONCE` to further control the behaviour. + :param callback: The Python callback to use. This should take five + arguments: A Connection object, an X509 object, and three integer + variables, which are in turn potential error number, error depth + and return code. *callback* should return True if verification + passes and False otherwise. + :return: None + + See SSL_CTX_set_verify(3SSL) for further details. + """ + if not isinstance(mode, integer_types): + raise TypeError("mode must be an integer") + + if not callable(callback): + raise TypeError("callback must be callable") + + self._verify_helper = _VerifyHelper(callback) + self._verify_callback = self._verify_helper.callback + _lib.SSL_CTX_set_verify(self._context, mode, self._verify_callback) + + def set_verify_depth(self, depth): + """ + Set the maximum depth for the certificate chain verification that shall + be allowed for this Context object. + + :param depth: An integer specifying the verify depth + :return: None + """ + if not isinstance(depth, integer_types): + raise TypeError("depth must be an integer") + + _lib.SSL_CTX_set_verify_depth(self._context, depth) + + def get_verify_mode(self): + """ + Retrieve the Context object's verify mode, as set by + :meth:`set_verify`. + + :return: The verify mode + """ + return _lib.SSL_CTX_get_verify_mode(self._context) + + def get_verify_depth(self): + """ + Retrieve the Context object's verify depth, as set by + :meth:`set_verify_depth`. + + :return: The verify depth + """ + return _lib.SSL_CTX_get_verify_depth(self._context) + + def load_tmp_dh(self, dhfile): + """ + Load parameters for Ephemeral Diffie-Hellman + + :param dhfile: The file to load EDH parameters from (``bytes`` or + ``unicode``). + + :return: None + """ + dhfile = _path_string(dhfile) + + bio = _lib.BIO_new_file(dhfile, b"r") + if bio == _ffi.NULL: + _raise_current_error() + bio = _ffi.gc(bio, _lib.BIO_free) + + dh = _lib.PEM_read_bio_DHparams(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL) + dh = _ffi.gc(dh, _lib.DH_free) + _lib.SSL_CTX_set_tmp_dh(self._context, dh) + + def set_tmp_ecdh(self, curve): + """ + Select a curve to use for ECDHE key exchange. + + :param curve: A curve object to use as returned by either + :meth:`OpenSSL.crypto.get_elliptic_curve` or + :meth:`OpenSSL.crypto.get_elliptic_curves`. + + :return: None + """ + _lib.SSL_CTX_set_tmp_ecdh(self._context, curve._to_EC_KEY()) + + def set_cipher_list(self, cipher_list): + """ + Set the list of ciphers to be used in this context. + + See the OpenSSL manual for more information (e.g. + :manpage:`ciphers(1)`). + + :param bytes cipher_list: An OpenSSL cipher string. + :return: None + """ + cipher_list = _text_to_bytes_and_warn("cipher_list", cipher_list) + + if not isinstance(cipher_list, bytes): + raise TypeError("cipher_list must be a byte string.") + + _openssl_assert( + _lib.SSL_CTX_set_cipher_list(self._context, cipher_list) == 1 + ) + + def set_client_ca_list(self, certificate_authorities): + """ + Set the list of preferred client certificate signers for this server + context. + + This list of certificate authorities will be sent to the client when + the server requests a client certificate. + + :param certificate_authorities: a sequence of X509Names. + :return: None + + .. versionadded:: 0.10 + """ + name_stack = _lib.sk_X509_NAME_new_null() + _openssl_assert(name_stack != _ffi.NULL) + + try: + for ca_name in certificate_authorities: + if not isinstance(ca_name, X509Name): + raise TypeError( + "client CAs must be X509Name objects, not %s " + "objects" % ( + type(ca_name).__name__, + ) + ) + copy = _lib.X509_NAME_dup(ca_name._name) + _openssl_assert(copy != _ffi.NULL) + push_result = _lib.sk_X509_NAME_push(name_stack, copy) + if not push_result: + _lib.X509_NAME_free(copy) + _raise_current_error() + except Exception: + _lib.sk_X509_NAME_free(name_stack) + raise + + _lib.SSL_CTX_set_client_CA_list(self._context, name_stack) + + def add_client_ca(self, certificate_authority): + """ + Add the CA certificate to the list of preferred signers for this + context. + + The list of certificate authorities will be sent to the client when the + server requests a client certificate. + + :param certificate_authority: certificate authority's X509 certificate. + :return: None + + .. versionadded:: 0.10 + """ + if not isinstance(certificate_authority, X509): + raise TypeError("certificate_authority must be an X509 instance") + + add_result = _lib.SSL_CTX_add_client_CA( + self._context, certificate_authority._x509) + _openssl_assert(add_result == 1) + + def set_timeout(self, timeout): + """ + Set the timeout for newly created sessions for this Context object to + *timeout*. The default value is 300 seconds. See the OpenSSL manual + for more information (e.g. :manpage:`SSL_CTX_set_timeout(3)`). + + :param timeout: The timeout in (whole) seconds + :return: The previous session timeout + """ + if not isinstance(timeout, integer_types): + raise TypeError("timeout must be an integer") + + return _lib.SSL_CTX_set_timeout(self._context, timeout) + + def get_timeout(self): + """ + Retrieve session timeout, as set by :meth:`set_timeout`. The default + is 300 seconds. + + :return: The session timeout + """ + return _lib.SSL_CTX_get_timeout(self._context) + + def set_info_callback(self, callback): + """ + Set the information callback to *callback*. This function will be + called from time to time during SSL handshakes. + + :param callback: The Python callback to use. This should take three + arguments: a Connection object and two integers. The first integer + specifies where in the SSL handshake the function was called, and + the other the return code from a (possibly failed) internal + function call. + :return: None + """ + @wraps(callback) + def wrapper(ssl, where, return_code): + callback(Connection._reverse_mapping[ssl], where, return_code) + self._info_callback = _ffi.callback( + "void (*)(const SSL *, int, int)", wrapper) + _lib.SSL_CTX_set_info_callback(self._context, self._info_callback) + + def get_app_data(self): + """ + Get the application data (supplied via :meth:`set_app_data()`) + + :return: The application data + """ + return self._app_data + + def set_app_data(self, data): + """ + Set the application data (will be returned from get_app_data()) + + :param data: Any Python object + :return: None + """ + self._app_data = data + + def get_cert_store(self): + """ + Get the certificate store for the context. This can be used to add + "trusted" certificates without using the + :meth:`load_verify_locations` method. + + :return: A X509Store object or None if it does not have one. + """ + store = _lib.SSL_CTX_get_cert_store(self._context) + if store == _ffi.NULL: + # TODO: This is untested. + return None + + pystore = X509Store.__new__(X509Store) + pystore._store = store + return pystore + + def set_options(self, options): + """ + Add options. Options set before are not cleared! + This method should be used with the :const:`OP_*` constants. + + :param options: The options to add. + :return: The new option bitmask. + """ + if not isinstance(options, integer_types): + raise TypeError("options must be an integer") + + return _lib.SSL_CTX_set_options(self._context, options) + + def set_mode(self, mode): + """ + Add modes via bitmask. Modes set before are not cleared! This method + should be used with the :const:`MODE_*` constants. + + :param mode: The mode to add. + :return: The new mode bitmask. + """ + if not isinstance(mode, integer_types): + raise TypeError("mode must be an integer") + + return _lib.SSL_CTX_set_mode(self._context, mode) + + @_requires_sni + def set_tlsext_servername_callback(self, callback): + """ + Specify a callback function to be called when clients specify a server + name. + + :param callback: The callback function. It will be invoked with one + argument, the Connection instance. + + .. versionadded:: 0.13 + """ + @wraps(callback) + def wrapper(ssl, alert, arg): + callback(Connection._reverse_mapping[ssl]) + return 0 + + self._tlsext_servername_callback = _ffi.callback( + "int (*)(const SSL *, int *, void *)", wrapper) + _lib.SSL_CTX_set_tlsext_servername_callback( + self._context, self._tlsext_servername_callback) + + def set_tlsext_use_srtp(self, profiles): + """ + Enable support for negotiating SRTP keying material. + + :param bytes profiles: A colon delimited list of protection profile + names, like ``b'SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32'``. + :return: None + """ + if not isinstance(profiles, bytes): + raise TypeError("profiles must be a byte string.") + + _openssl_assert( + _lib.SSL_CTX_set_tlsext_use_srtp(self._context, profiles) == 0 + ) + + @_requires_npn + def set_npn_advertise_callback(self, callback): + """ + Specify a callback function that will be called when offering `Next + Protocol Negotiation + `_ as a server. + + :param callback: The callback function. It will be invoked with one + argument, the :class:`Connection` instance. It should return a + list of bytestrings representing the advertised protocols, like + ``[b'http/1.1', b'spdy/2']``. + + .. versionadded:: 0.15 + """ + self._npn_advertise_helper = _NpnAdvertiseHelper(callback) + self._npn_advertise_callback = self._npn_advertise_helper.callback + _lib.SSL_CTX_set_next_protos_advertised_cb( + self._context, self._npn_advertise_callback, _ffi.NULL) + + @_requires_npn + def set_npn_select_callback(self, callback): + """ + Specify a callback function that will be called when a server offers + Next Protocol Negotiation options. + + :param callback: The callback function. It will be invoked with two + arguments: the Connection, and a list of offered protocols as + bytestrings, e.g. ``[b'http/1.1', b'spdy/2']``. It should return + one of those bytestrings, the chosen protocol. + + .. versionadded:: 0.15 + """ + self._npn_select_helper = _NpnSelectHelper(callback) + self._npn_select_callback = self._npn_select_helper.callback + _lib.SSL_CTX_set_next_proto_select_cb( + self._context, self._npn_select_callback, _ffi.NULL) + + @_requires_alpn + def set_alpn_protos(self, protos): + """ + Specify the protocols that the client is prepared to speak after the + TLS connection has been negotiated using Application Layer Protocol + Negotiation. + + :param protos: A list of the protocols to be offered to the server. + This list should be a Python list of bytestrings representing the + protocols to offer, e.g. ``[b'http/1.1', b'spdy/2']``. + """ + # Take the list of protocols and join them together, prefixing them + # with their lengths. + protostr = b''.join( + chain.from_iterable((int2byte(len(p)), p) for p in protos) + ) + + # Build a C string from the list. We don't need to save this off + # because OpenSSL immediately copies the data out. + input_str = _ffi.new("unsigned char[]", protostr) + _lib.SSL_CTX_set_alpn_protos(self._context, input_str, len(protostr)) + + @_requires_alpn + def set_alpn_select_callback(self, callback): + """ + Specify a callback function that will be called on the server when a + client offers protocols using ALPN. + + :param callback: The callback function. It will be invoked with two + arguments: the Connection, and a list of offered protocols as + bytestrings, e.g ``[b'http/1.1', b'spdy/2']``. It should return + one of those bytestrings, the chosen protocol. + """ + self._alpn_select_helper = _ALPNSelectHelper(callback) + self._alpn_select_callback = self._alpn_select_helper.callback + _lib.SSL_CTX_set_alpn_select_cb( + self._context, self._alpn_select_callback, _ffi.NULL) + + def _set_ocsp_callback(self, helper, data): + """ + This internal helper does the common work for + ``set_ocsp_server_callback`` and ``set_ocsp_client_callback``, which is + almost all of it. + """ + self._ocsp_helper = helper + self._ocsp_callback = helper.callback + if data is None: + self._ocsp_data = _ffi.NULL + else: + self._ocsp_data = _ffi.new_handle(data) + + rc = _lib.SSL_CTX_set_tlsext_status_cb( + self._context, self._ocsp_callback + ) + _openssl_assert(rc == 1) + rc = _lib.SSL_CTX_set_tlsext_status_arg(self._context, self._ocsp_data) + _openssl_assert(rc == 1) + + def set_ocsp_server_callback(self, callback, data=None): + """ + Set a callback to provide OCSP data to be stapled to the TLS handshake + on the server side. + + :param callback: The callback function. It will be invoked with two + arguments: the Connection, and the optional arbitrary data you have + provided. The callback must return a bytestring that contains the + OCSP data to staple to the handshake. If no OCSP data is available + for this connection, return the empty bytestring. + :param data: Some opaque data that will be passed into the callback + function when called. This can be used to avoid needing to do + complex data lookups or to keep track of what context is being + used. This parameter is optional. + """ + helper = _OCSPServerCallbackHelper(callback) + self._set_ocsp_callback(helper, data) + + def set_ocsp_client_callback(self, callback, data=None): + """ + Set a callback to validate OCSP data stapled to the TLS handshake on + the client side. + + :param callback: The callback function. It will be invoked with three + arguments: the Connection, a bytestring containing the stapled OCSP + assertion, and the optional arbitrary data you have provided. The + callback must return a boolean that indicates the result of + validating the OCSP data: ``True`` if the OCSP data is valid and + the certificate can be trusted, or ``False`` if either the OCSP + data is invalid or the certificate has been revoked. + :param data: Some opaque data that will be passed into the callback + function when called. This can be used to avoid needing to do + complex data lookups or to keep track of what context is being + used. This parameter is optional. + """ + helper = _OCSPClientCallbackHelper(callback) + self._set_ocsp_callback(helper, data) + + +ContextType = deprecated( + Context, __name__, + "ContextType has been deprecated, use Context instead", DeprecationWarning +) + + +class Connection(object): + """ + """ + _reverse_mapping = WeakValueDictionary() + + def __init__(self, context, socket=None): + """ + Create a new Connection object, using the given OpenSSL.SSL.Context + instance and socket. + + :param context: An SSL Context to use for this connection + :param socket: The socket to use for transport layer + """ + if not isinstance(context, Context): + raise TypeError("context must be a Context instance") + + ssl = _lib.SSL_new(context._context) + self._ssl = _ffi.gc(ssl, _lib.SSL_free) + # We set SSL_MODE_AUTO_RETRY to handle situations where OpenSSL returns + # an SSL_ERROR_WANT_READ when processing a non-application data packet + # even though there is still data on the underlying transport. + # See https://github.com/openssl/openssl/issues/6234 for more details. + _lib.SSL_set_mode(self._ssl, _lib.SSL_MODE_AUTO_RETRY) + self._context = context + self._app_data = None + + # References to strings used for Next Protocol Negotiation. OpenSSL's + # header files suggest that these might get copied at some point, but + # doesn't specify when, so we store them here to make sure they don't + # get freed before OpenSSL uses them. + self._npn_advertise_callback_args = None + self._npn_select_callback_args = None + + # References to strings used for Application Layer Protocol + # Negotiation. These strings get copied at some point but it's well + # after the callback returns, so we have to hang them somewhere to + # avoid them getting freed. + self._alpn_select_callback_args = None + + self._reverse_mapping[self._ssl] = self + + if socket is None: + self._socket = None + # Don't set up any gc for these, SSL_free will take care of them. + self._into_ssl = _lib.BIO_new(_lib.BIO_s_mem()) + _openssl_assert(self._into_ssl != _ffi.NULL) + + self._from_ssl = _lib.BIO_new(_lib.BIO_s_mem()) + _openssl_assert(self._from_ssl != _ffi.NULL) + + _lib.SSL_set_bio(self._ssl, self._into_ssl, self._from_ssl) + else: + self._into_ssl = None + self._from_ssl = None + self._socket = socket + set_result = _lib.SSL_set_fd( + self._ssl, _asFileDescriptor(self._socket)) + _openssl_assert(set_result == 1) + + def __getattr__(self, name): + """ + Look up attributes on the wrapped socket object if they are not found + on the Connection object. + """ + if self._socket is None: + raise AttributeError("'%s' object has no attribute '%s'" % ( + self.__class__.__name__, name + )) + else: + return getattr(self._socket, name) + + def _raise_ssl_error(self, ssl, result): + if self._context._verify_helper is not None: + self._context._verify_helper.raise_if_problem() + if self._context._npn_advertise_helper is not None: + self._context._npn_advertise_helper.raise_if_problem() + if self._context._npn_select_helper is not None: + self._context._npn_select_helper.raise_if_problem() + if self._context._alpn_select_helper is not None: + self._context._alpn_select_helper.raise_if_problem() + if self._context._ocsp_helper is not None: + self._context._ocsp_helper.raise_if_problem() + + error = _lib.SSL_get_error(ssl, result) + if error == _lib.SSL_ERROR_WANT_READ: + raise WantReadError() + elif error == _lib.SSL_ERROR_WANT_WRITE: + raise WantWriteError() + elif error == _lib.SSL_ERROR_ZERO_RETURN: + raise ZeroReturnError() + elif error == _lib.SSL_ERROR_WANT_X509_LOOKUP: + # TODO: This is untested. + raise WantX509LookupError() + elif error == _lib.SSL_ERROR_SYSCALL: + if _lib.ERR_peek_error() == 0: + if result < 0: + if platform == "win32": + errno = _ffi.getwinerror()[0] + else: + errno = _ffi.errno + + if errno != 0: + raise SysCallError(errno, errorcode.get(errno)) + raise SysCallError(-1, "Unexpected EOF") + else: + # TODO: This is untested. + _raise_current_error() + elif error == _lib.SSL_ERROR_NONE: + pass + else: + _raise_current_error() + + def get_context(self): + """ + Retrieve the :class:`Context` object associated with this + :class:`Connection`. + """ + return self._context + + def set_context(self, context): + """ + Switch this connection to a new session context. + + :param context: A :class:`Context` instance giving the new session + context to use. + """ + if not isinstance(context, Context): + raise TypeError("context must be a Context instance") + + _lib.SSL_set_SSL_CTX(self._ssl, context._context) + self._context = context + + @_requires_sni + def get_servername(self): + """ + Retrieve the servername extension value if provided in the client hello + message, or None if there wasn't one. + + :return: A byte string giving the server name or :data:`None`. + + .. versionadded:: 0.13 + """ + name = _lib.SSL_get_servername( + self._ssl, _lib.TLSEXT_NAMETYPE_host_name + ) + if name == _ffi.NULL: + return None + + return _ffi.string(name) + + @_requires_sni + def set_tlsext_host_name(self, name): + """ + Set the value of the servername extension to send in the client hello. + + :param name: A byte string giving the name. + + .. versionadded:: 0.13 + """ + if not isinstance(name, bytes): + raise TypeError("name must be a byte string") + elif b"\0" in name: + raise TypeError("name must not contain NUL byte") + + # XXX I guess this can fail sometimes? + _lib.SSL_set_tlsext_host_name(self._ssl, name) + + def pending(self): + """ + Get the number of bytes that can be safely read from the SSL buffer + (**not** the underlying transport buffer). + + :return: The number of bytes available in the receive buffer. + """ + return _lib.SSL_pending(self._ssl) + + def send(self, buf, flags=0): + """ + Send data on the connection. NOTE: If you get one of the WantRead, + WantWrite or WantX509Lookup exceptions on this, you have to call the + method again with the SAME buffer. + + :param buf: The string, buffer or memoryview to send + :param flags: (optional) Included for compatibility with the socket + API, the value is ignored + :return: The number of bytes written + """ + # Backward compatibility + buf = _text_to_bytes_and_warn("buf", buf) + + if isinstance(buf, memoryview): + buf = buf.tobytes() + if isinstance(buf, _buffer): + buf = str(buf) + if not isinstance(buf, bytes): + raise TypeError("data must be a memoryview, buffer or byte string") + if len(buf) > 2147483647: + raise ValueError("Cannot send more than 2**31-1 bytes at once.") + + result = _lib.SSL_write(self._ssl, buf, len(buf)) + self._raise_ssl_error(self._ssl, result) + return result + write = send + + def sendall(self, buf, flags=0): + """ + Send "all" data on the connection. This calls send() repeatedly until + all data is sent. If an error occurs, it's impossible to tell how much + data has been sent. + + :param buf: The string, buffer or memoryview to send + :param flags: (optional) Included for compatibility with the socket + API, the value is ignored + :return: The number of bytes written + """ + buf = _text_to_bytes_and_warn("buf", buf) + + if isinstance(buf, memoryview): + buf = buf.tobytes() + if isinstance(buf, _buffer): + buf = str(buf) + if not isinstance(buf, bytes): + raise TypeError("buf must be a memoryview, buffer or byte string") + + left_to_send = len(buf) + total_sent = 0 + data = _ffi.new("char[]", buf) + + while left_to_send: + # SSL_write's num arg is an int, + # so we cannot send more than 2**31-1 bytes at once. + result = _lib.SSL_write( + self._ssl, + data + total_sent, + min(left_to_send, 2147483647) + ) + self._raise_ssl_error(self._ssl, result) + total_sent += result + left_to_send -= result + + def recv(self, bufsiz, flags=None): + """ + Receive data on the connection. + + :param bufsiz: The maximum number of bytes to read + :param flags: (optional) The only supported flag is ``MSG_PEEK``, + all other flags are ignored. + :return: The string read from the Connection + """ + buf = _no_zero_allocator("char[]", bufsiz) + if flags is not None and flags & socket.MSG_PEEK: + result = _lib.SSL_peek(self._ssl, buf, bufsiz) + else: + result = _lib.SSL_read(self._ssl, buf, bufsiz) + self._raise_ssl_error(self._ssl, result) + return _ffi.buffer(buf, result)[:] + read = recv + + def recv_into(self, buffer, nbytes=None, flags=None): + """ + Receive data on the connection and copy it directly into the provided + buffer, rather than creating a new string. + + :param buffer: The buffer to copy into. + :param nbytes: (optional) The maximum number of bytes to read into the + buffer. If not present, defaults to the size of the buffer. If + larger than the size of the buffer, is reduced to the size of the + buffer. + :param flags: (optional) The only supported flag is ``MSG_PEEK``, + all other flags are ignored. + :return: The number of bytes read into the buffer. + """ + if nbytes is None: + nbytes = len(buffer) + else: + nbytes = min(nbytes, len(buffer)) + + # We need to create a temporary buffer. This is annoying, it would be + # better if we could pass memoryviews straight into the SSL_read call, + # but right now we can't. Revisit this if CFFI gets that ability. + buf = _no_zero_allocator("char[]", nbytes) + if flags is not None and flags & socket.MSG_PEEK: + result = _lib.SSL_peek(self._ssl, buf, nbytes) + else: + result = _lib.SSL_read(self._ssl, buf, nbytes) + self._raise_ssl_error(self._ssl, result) + + # This strange line is all to avoid a memory copy. The buffer protocol + # should allow us to assign a CFFI buffer to the LHS of this line, but + # on CPython 3.3+ that segfaults. As a workaround, we can temporarily + # wrap it in a memoryview. + buffer[:result] = memoryview(_ffi.buffer(buf, result)) + + return result + + def _handle_bio_errors(self, bio, result): + if _lib.BIO_should_retry(bio): + if _lib.BIO_should_read(bio): + raise WantReadError() + elif _lib.BIO_should_write(bio): + # TODO: This is untested. + raise WantWriteError() + elif _lib.BIO_should_io_special(bio): + # TODO: This is untested. I think io_special means the socket + # BIO has a not-yet connected socket. + raise ValueError("BIO_should_io_special") + else: + # TODO: This is untested. + raise ValueError("unknown bio failure") + else: + # TODO: This is untested. + _raise_current_error() + + def bio_read(self, bufsiz): + """ + If the Connection was created with a memory BIO, this method can be + used to read bytes from the write end of that memory BIO. Many + Connection methods will add bytes which must be read in this manner or + the buffer will eventually fill up and the Connection will be able to + take no further actions. + + :param bufsiz: The maximum number of bytes to read + :return: The string read. + """ + if self._from_ssl is None: + raise TypeError("Connection sock was not None") + + if not isinstance(bufsiz, integer_types): + raise TypeError("bufsiz must be an integer") + + buf = _no_zero_allocator("char[]", bufsiz) + result = _lib.BIO_read(self._from_ssl, buf, bufsiz) + if result <= 0: + self._handle_bio_errors(self._from_ssl, result) + + return _ffi.buffer(buf, result)[:] + + def bio_write(self, buf): + """ + If the Connection was created with a memory BIO, this method can be + used to add bytes to the read end of that memory BIO. The Connection + can then read the bytes (for example, in response to a call to + :meth:`recv`). + + :param buf: The string to put into the memory BIO. + :return: The number of bytes written + """ + buf = _text_to_bytes_and_warn("buf", buf) + + if self._into_ssl is None: + raise TypeError("Connection sock was not None") + + result = _lib.BIO_write(self._into_ssl, buf, len(buf)) + if result <= 0: + self._handle_bio_errors(self._into_ssl, result) + return result + + def renegotiate(self): + """ + Renegotiate the session. + + :return: True if the renegotiation can be started, False otherwise + :rtype: bool + """ + if not self.renegotiate_pending(): + _openssl_assert(_lib.SSL_renegotiate(self._ssl) == 1) + return True + return False + + def do_handshake(self): + """ + Perform an SSL handshake (usually called after :meth:`renegotiate` or + one of :meth:`set_accept_state` or :meth:`set_accept_state`). This can + raise the same exceptions as :meth:`send` and :meth:`recv`. + + :return: None. + """ + result = _lib.SSL_do_handshake(self._ssl) + self._raise_ssl_error(self._ssl, result) + + def renegotiate_pending(self): + """ + Check if there's a renegotiation in progress, it will return False once + a renegotiation is finished. + + :return: Whether there's a renegotiation in progress + :rtype: bool + """ + return _lib.SSL_renegotiate_pending(self._ssl) == 1 + + def total_renegotiations(self): + """ + Find out the total number of renegotiations. + + :return: The number of renegotiations. + :rtype: int + """ + return _lib.SSL_total_renegotiations(self._ssl) + + def connect(self, addr): + """ + Call the :meth:`connect` method of the underlying socket and set up SSL + on the socket, using the :class:`Context` object supplied to this + :class:`Connection` object at creation. + + :param addr: A remote address + :return: What the socket's connect method returns + """ + _lib.SSL_set_connect_state(self._ssl) + return self._socket.connect(addr) + + def connect_ex(self, addr): + """ + Call the :meth:`connect_ex` method of the underlying socket and set up + SSL on the socket, using the Context object supplied to this Connection + object at creation. Note that if the :meth:`connect_ex` method of the + socket doesn't return 0, SSL won't be initialized. + + :param addr: A remove address + :return: What the socket's connect_ex method returns + """ + connect_ex = self._socket.connect_ex + self.set_connect_state() + return connect_ex(addr) + + def accept(self): + """ + Call the :meth:`accept` method of the underlying socket and set up SSL + on the returned socket, using the Context object supplied to this + :class:`Connection` object at creation. + + :return: A *(conn, addr)* pair where *conn* is the new + :class:`Connection` object created, and *address* is as returned by + the socket's :meth:`accept`. + """ + client, addr = self._socket.accept() + conn = Connection(self._context, client) + conn.set_accept_state() + return (conn, addr) + + def bio_shutdown(self): + """ + If the Connection was created with a memory BIO, this method can be + used to indicate that *end of file* has been reached on the read end of + that memory BIO. + + :return: None + """ + if self._from_ssl is None: + raise TypeError("Connection sock was not None") + + _lib.BIO_set_mem_eof_return(self._into_ssl, 0) + + def shutdown(self): + """ + Send the shutdown message to the Connection. + + :return: True if the shutdown completed successfully (i.e. both sides + have sent closure alerts), False otherwise (in which case you + call :meth:`recv` or :meth:`send` when the connection becomes + readable/writeable). + """ + result = _lib.SSL_shutdown(self._ssl) + if result < 0: + self._raise_ssl_error(self._ssl, result) + elif result > 0: + return True + else: + return False + + def get_cipher_list(self): + """ + Retrieve the list of ciphers used by the Connection object. + + :return: A list of native cipher strings. + """ + ciphers = [] + for i in count(): + result = _lib.SSL_get_cipher_list(self._ssl, i) + if result == _ffi.NULL: + break + ciphers.append(_native(_ffi.string(result))) + return ciphers + + def get_client_ca_list(self): + """ + Get CAs whose certificates are suggested for client authentication. + + :return: If this is a server connection, the list of certificate + authorities that will be sent or has been sent to the client, as + controlled by this :class:`Connection`'s :class:`Context`. + + If this is a client connection, the list will be empty until the + connection with the server is established. + + .. versionadded:: 0.10 + """ + ca_names = _lib.SSL_get_client_CA_list(self._ssl) + if ca_names == _ffi.NULL: + # TODO: This is untested. + return [] + + result = [] + for i in range(_lib.sk_X509_NAME_num(ca_names)): + name = _lib.sk_X509_NAME_value(ca_names, i) + copy = _lib.X509_NAME_dup(name) + _openssl_assert(copy != _ffi.NULL) + + pyname = X509Name.__new__(X509Name) + pyname._name = _ffi.gc(copy, _lib.X509_NAME_free) + result.append(pyname) + return result + + def makefile(self, *args, **kwargs): + """ + The makefile() method is not implemented, since there is no dup + semantics for SSL connections + + :raise: NotImplementedError + """ + raise NotImplementedError( + "Cannot make file object of OpenSSL.SSL.Connection") + + def get_app_data(self): + """ + Retrieve application data as set by :meth:`set_app_data`. + + :return: The application data + """ + return self._app_data + + def set_app_data(self, data): + """ + Set application data + + :param data: The application data + :return: None + """ + self._app_data = data + + def get_shutdown(self): + """ + Get the shutdown state of the Connection. + + :return: The shutdown state, a bitvector of SENT_SHUTDOWN, + RECEIVED_SHUTDOWN. + """ + return _lib.SSL_get_shutdown(self._ssl) + + def set_shutdown(self, state): + """ + Set the shutdown state of the Connection. + + :param state: bitvector of SENT_SHUTDOWN, RECEIVED_SHUTDOWN. + :return: None + """ + if not isinstance(state, integer_types): + raise TypeError("state must be an integer") + + _lib.SSL_set_shutdown(self._ssl, state) + + def get_state_string(self): + """ + Retrieve a verbose string detailing the state of the Connection. + + :return: A string representing the state + :rtype: bytes + """ + return _ffi.string(_lib.SSL_state_string_long(self._ssl)) + + def server_random(self): + """ + Retrieve the random value used with the server hello message. + + :return: A string representing the state + """ + session = _lib.SSL_get_session(self._ssl) + if session == _ffi.NULL: + return None + length = _lib.SSL_get_server_random(self._ssl, _ffi.NULL, 0) + assert length > 0 + outp = _no_zero_allocator("unsigned char[]", length) + _lib.SSL_get_server_random(self._ssl, outp, length) + return _ffi.buffer(outp, length)[:] + + def client_random(self): + """ + Retrieve the random value used with the client hello message. + + :return: A string representing the state + """ + session = _lib.SSL_get_session(self._ssl) + if session == _ffi.NULL: + return None + + length = _lib.SSL_get_client_random(self._ssl, _ffi.NULL, 0) + assert length > 0 + outp = _no_zero_allocator("unsigned char[]", length) + _lib.SSL_get_client_random(self._ssl, outp, length) + return _ffi.buffer(outp, length)[:] + + def master_key(self): + """ + Retrieve the value of the master key for this session. + + :return: A string representing the state + """ + session = _lib.SSL_get_session(self._ssl) + if session == _ffi.NULL: + return None + + length = _lib.SSL_SESSION_get_master_key(session, _ffi.NULL, 0) + assert length > 0 + outp = _no_zero_allocator("unsigned char[]", length) + _lib.SSL_SESSION_get_master_key(session, outp, length) + return _ffi.buffer(outp, length)[:] + + def export_keying_material(self, label, olen, context=None): + """ + Obtain keying material for application use. + + :param: label - a disambiguating label string as described in RFC 5705 + :param: olen - the length of the exported key material in bytes + :param: context - a per-association context value + :return: the exported key material bytes or None + """ + outp = _no_zero_allocator("unsigned char[]", olen) + context_buf = _ffi.NULL + context_len = 0 + use_context = 0 + if context is not None: + context_buf = context + context_len = len(context) + use_context = 1 + success = _lib.SSL_export_keying_material(self._ssl, outp, olen, + label, len(label), + context_buf, context_len, + use_context) + _openssl_assert(success == 1) + return _ffi.buffer(outp, olen)[:] + + def sock_shutdown(self, *args, **kwargs): + """ + Call the :meth:`shutdown` method of the underlying socket. + See :manpage:`shutdown(2)`. + + :return: What the socket's shutdown() method returns + """ + return self._socket.shutdown(*args, **kwargs) + + def get_certificate(self): + """ + Retrieve the local certificate (if any) + + :return: The local certificate + """ + cert = _lib.SSL_get_certificate(self._ssl) + if cert != _ffi.NULL: + _lib.X509_up_ref(cert) + return X509._from_raw_x509_ptr(cert) + return None + + def get_peer_certificate(self): + """ + Retrieve the other side's certificate (if any) + + :return: The peer's certificate + """ + cert = _lib.SSL_get_peer_certificate(self._ssl) + if cert != _ffi.NULL: + return X509._from_raw_x509_ptr(cert) + return None + + def get_peer_cert_chain(self): + """ + Retrieve the other side's certificate (if any) + + :return: A list of X509 instances giving the peer's certificate chain, + or None if it does not have one. + """ + cert_stack = _lib.SSL_get_peer_cert_chain(self._ssl) + if cert_stack == _ffi.NULL: + return None + + result = [] + for i in range(_lib.sk_X509_num(cert_stack)): + # TODO could incref instead of dup here + cert = _lib.X509_dup(_lib.sk_X509_value(cert_stack, i)) + pycert = X509._from_raw_x509_ptr(cert) + result.append(pycert) + return result + + def want_read(self): + """ + Checks if more data has to be read from the transport layer to complete + an operation. + + :return: True iff more data has to be read + """ + return _lib.SSL_want_read(self._ssl) + + def want_write(self): + """ + Checks if there is data to write to the transport layer to complete an + operation. + + :return: True iff there is data to write + """ + return _lib.SSL_want_write(self._ssl) + + def set_accept_state(self): + """ + Set the connection to work in server mode. The handshake will be + handled automatically by read/write. + + :return: None + """ + _lib.SSL_set_accept_state(self._ssl) + + def set_connect_state(self): + """ + Set the connection to work in client mode. The handshake will be + handled automatically by read/write. + + :return: None + """ + _lib.SSL_set_connect_state(self._ssl) + + def get_session(self): + """ + Returns the Session currently used. + + :return: An instance of :class:`OpenSSL.SSL.Session` or + :obj:`None` if no session exists. + + .. versionadded:: 0.14 + """ + session = _lib.SSL_get1_session(self._ssl) + if session == _ffi.NULL: + return None + + pysession = Session.__new__(Session) + pysession._session = _ffi.gc(session, _lib.SSL_SESSION_free) + return pysession + + def set_session(self, session): + """ + Set the session to be used when the TLS/SSL connection is established. + + :param session: A Session instance representing the session to use. + :returns: None + + .. versionadded:: 0.14 + """ + if not isinstance(session, Session): + raise TypeError("session must be a Session instance") + + result = _lib.SSL_set_session(self._ssl, session._session) + if not result: + _raise_current_error() + + def _get_finished_message(self, function): + """ + Helper to implement :meth:`get_finished` and + :meth:`get_peer_finished`. + + :param function: Either :data:`SSL_get_finished`: or + :data:`SSL_get_peer_finished`. + + :return: :data:`None` if the desired message has not yet been + received, otherwise the contents of the message. + :rtype: :class:`bytes` or :class:`NoneType` + """ + # The OpenSSL documentation says nothing about what might happen if the + # count argument given is zero. Specifically, it doesn't say whether + # the output buffer may be NULL in that case or not. Inspection of the + # implementation reveals that it calls memcpy() unconditionally. + # Section 7.1.4, paragraph 1 of the C standard suggests that + # memcpy(NULL, source, 0) is not guaranteed to produce defined (let + # alone desirable) behavior (though it probably does on just about + # every implementation...) + # + # Allocate a tiny buffer to pass in (instead of just passing NULL as + # one might expect) for the initial call so as to be safe against this + # potentially undefined behavior. + empty = _ffi.new("char[]", 0) + size = function(self._ssl, empty, 0) + if size == 0: + # No Finished message so far. + return None + + buf = _no_zero_allocator("char[]", size) + function(self._ssl, buf, size) + return _ffi.buffer(buf, size)[:] + + def get_finished(self): + """ + Obtain the latest TLS Finished message that we sent. + + :return: The contents of the message or :obj:`None` if the TLS + handshake has not yet completed. + :rtype: :class:`bytes` or :class:`NoneType` + + .. versionadded:: 0.15 + """ + return self._get_finished_message(_lib.SSL_get_finished) + + def get_peer_finished(self): + """ + Obtain the latest TLS Finished message that we received from the peer. + + :return: The contents of the message or :obj:`None` if the TLS + handshake has not yet completed. + :rtype: :class:`bytes` or :class:`NoneType` + + .. versionadded:: 0.15 + """ + return self._get_finished_message(_lib.SSL_get_peer_finished) + + def get_cipher_name(self): + """ + Obtain the name of the currently used cipher. + + :returns: The name of the currently used cipher or :obj:`None` + if no connection has been established. + :rtype: :class:`unicode` or :class:`NoneType` + + .. versionadded:: 0.15 + """ + cipher = _lib.SSL_get_current_cipher(self._ssl) + if cipher == _ffi.NULL: + return None + else: + name = _ffi.string(_lib.SSL_CIPHER_get_name(cipher)) + return name.decode("utf-8") + + def get_cipher_bits(self): + """ + Obtain the number of secret bits of the currently used cipher. + + :returns: The number of secret bits of the currently used cipher + or :obj:`None` if no connection has been established. + :rtype: :class:`int` or :class:`NoneType` + + .. versionadded:: 0.15 + """ + cipher = _lib.SSL_get_current_cipher(self._ssl) + if cipher == _ffi.NULL: + return None + else: + return _lib.SSL_CIPHER_get_bits(cipher, _ffi.NULL) + + def get_cipher_version(self): + """ + Obtain the protocol version of the currently used cipher. + + :returns: The protocol name of the currently used cipher + or :obj:`None` if no connection has been established. + :rtype: :class:`unicode` or :class:`NoneType` + + .. versionadded:: 0.15 + """ + cipher = _lib.SSL_get_current_cipher(self._ssl) + if cipher == _ffi.NULL: + return None + else: + version = _ffi.string(_lib.SSL_CIPHER_get_version(cipher)) + return version.decode("utf-8") + + def get_protocol_version_name(self): + """ + Retrieve the protocol version of the current connection. + + :returns: The TLS version of the current connection, for example + the value for TLS 1.2 would be ``TLSv1.2``or ``Unknown`` + for connections that were not successfully established. + :rtype: :class:`unicode` + """ + version = _ffi.string(_lib.SSL_get_version(self._ssl)) + return version.decode("utf-8") + + def get_protocol_version(self): + """ + Retrieve the SSL or TLS protocol version of the current connection. + + :returns: The TLS version of the current connection. For example, + it will return ``0x769`` for connections made over TLS version 1. + :rtype: :class:`int` + """ + version = _lib.SSL_version(self._ssl) + return version + + @_requires_npn + def get_next_proto_negotiated(self): + """ + Get the protocol that was negotiated by NPN. + + :returns: A bytestring of the protocol name. If no protocol has been + negotiated yet, returns an empty string. + + .. versionadded:: 0.15 + """ + data = _ffi.new("unsigned char **") + data_len = _ffi.new("unsigned int *") + + _lib.SSL_get0_next_proto_negotiated(self._ssl, data, data_len) + + return _ffi.buffer(data[0], data_len[0])[:] + + @_requires_alpn + def set_alpn_protos(self, protos): + """ + Specify the client's ALPN protocol list. + + These protocols are offered to the server during protocol negotiation. + + :param protos: A list of the protocols to be offered to the server. + This list should be a Python list of bytestrings representing the + protocols to offer, e.g. ``[b'http/1.1', b'spdy/2']``. + """ + # Take the list of protocols and join them together, prefixing them + # with their lengths. + protostr = b''.join( + chain.from_iterable((int2byte(len(p)), p) for p in protos) + ) + + # Build a C string from the list. We don't need to save this off + # because OpenSSL immediately copies the data out. + input_str = _ffi.new("unsigned char[]", protostr) + _lib.SSL_set_alpn_protos(self._ssl, input_str, len(protostr)) + + @_requires_alpn + def get_alpn_proto_negotiated(self): + """ + Get the protocol that was negotiated by ALPN. + + :returns: A bytestring of the protocol name. If no protocol has been + negotiated yet, returns an empty string. + """ + data = _ffi.new("unsigned char **") + data_len = _ffi.new("unsigned int *") + + _lib.SSL_get0_alpn_selected(self._ssl, data, data_len) + + if not data_len: + return b'' + + return _ffi.buffer(data[0], data_len[0])[:] + + def request_ocsp(self): + """ + Called to request that the server sends stapled OCSP data, if + available. If this is not called on the client side then the server + will not send OCSP data. Should be used in conjunction with + :meth:`Context.set_ocsp_client_callback`. + """ + rc = _lib.SSL_set_tlsext_status_type( + self._ssl, _lib.TLSEXT_STATUSTYPE_ocsp + ) + _openssl_assert(rc == 1) + + +ConnectionType = deprecated( + Connection, __name__, + "ConnectionType has been deprecated, use Connection instead", + DeprecationWarning +) + +# This is similar to the initialization calls at the end of OpenSSL/crypto.py +# but is exercised mostly by the Context initializer. +_lib.SSL_library_init() diff --git a/venv/lib/python2.7/site-packages/OpenSSL/__init__.py b/venv/lib/python2.7/site-packages/OpenSSL/__init__.py new file mode 100644 index 0000000..810d00d --- /dev/null +++ b/venv/lib/python2.7/site-packages/OpenSSL/__init__.py @@ -0,0 +1,20 @@ +# Copyright (C) AB Strakt +# See LICENSE for details. + +""" +pyOpenSSL - A simple wrapper around the OpenSSL library +""" + +from OpenSSL import crypto, SSL +from OpenSSL.version import ( + __author__, __copyright__, __email__, __license__, __summary__, __title__, + __uri__, __version__, +) + + +__all__ = [ + "SSL", "crypto", + + "__author__", "__copyright__", "__email__", "__license__", "__summary__", + "__title__", "__uri__", "__version__", +] diff --git a/venv/lib/python2.7/site-packages/OpenSSL/_util.py b/venv/lib/python2.7/site-packages/OpenSSL/_util.py new file mode 100644 index 0000000..cf8b888 --- /dev/null +++ b/venv/lib/python2.7/site-packages/OpenSSL/_util.py @@ -0,0 +1,147 @@ +import sys +import warnings + +from six import PY3, binary_type, text_type + +from cryptography.hazmat.bindings.openssl.binding import Binding + + +binding = Binding() +binding.init_static_locks() +ffi = binding.ffi +lib = binding.lib + + +# This is a special CFFI allocator that does not bother to zero its memory +# after allocation. This has vastly better performance on large allocations and +# so should be used whenever we don't need the memory zeroed out. +no_zero_allocator = ffi.new_allocator(should_clear_after_alloc=False) + + +def text(charp): + """ + Get a native string type representing of the given CFFI ``char*`` object. + + :param charp: A C-style string represented using CFFI. + + :return: :class:`str` + """ + if not charp: + return "" + return native(ffi.string(charp)) + + +def exception_from_error_queue(exception_type): + """ + Convert an OpenSSL library failure into a Python exception. + + When a call to the native OpenSSL library fails, this is usually signalled + by the return value, and an error code is stored in an error queue + associated with the current thread. The err library provides functions to + obtain these error codes and textual error messages. + """ + errors = [] + + while True: + error = lib.ERR_get_error() + if error == 0: + break + errors.append(( + text(lib.ERR_lib_error_string(error)), + text(lib.ERR_func_error_string(error)), + text(lib.ERR_reason_error_string(error)))) + + raise exception_type(errors) + + +def make_assert(error): + """ + Create an assert function that uses :func:`exception_from_error_queue` to + raise an exception wrapped by *error*. + """ + def openssl_assert(ok): + """ + If *ok* is not True, retrieve the error from OpenSSL and raise it. + """ + if ok is not True: + exception_from_error_queue(error) + + return openssl_assert + + +def native(s): + """ + Convert :py:class:`bytes` or :py:class:`unicode` to the native + :py:class:`str` type, using UTF-8 encoding if conversion is necessary. + + :raise UnicodeError: The input string is not UTF-8 decodeable. + + :raise TypeError: The input is neither :py:class:`bytes` nor + :py:class:`unicode`. + """ + if not isinstance(s, (binary_type, text_type)): + raise TypeError("%r is neither bytes nor unicode" % s) + if PY3: + if isinstance(s, binary_type): + return s.decode("utf-8") + else: + if isinstance(s, text_type): + return s.encode("utf-8") + return s + + +def path_string(s): + """ + Convert a Python string to a :py:class:`bytes` string identifying the same + path and which can be passed into an OpenSSL API accepting a filename. + + :param s: An instance of :py:class:`bytes` or :py:class:`unicode`. + + :return: An instance of :py:class:`bytes`. + """ + if isinstance(s, binary_type): + return s + elif isinstance(s, text_type): + return s.encode(sys.getfilesystemencoding()) + else: + raise TypeError("Path must be represented as bytes or unicode string") + + +if PY3: + def byte_string(s): + return s.encode("charmap") +else: + def byte_string(s): + return s + + +# A marker object to observe whether some optional arguments are passed any +# value or not. +UNSPECIFIED = object() + +_TEXT_WARNING = ( + text_type.__name__ + " for {0} is no longer accepted, use bytes" +) + + +def text_to_bytes_and_warn(label, obj): + """ + If ``obj`` is text, emit a warning that it should be bytes instead and try + to convert it to bytes automatically. + + :param str label: The name of the parameter from which ``obj`` was taken + (so a developer can easily find the source of the problem and correct + it). + + :return: If ``obj`` is the text string type, a ``bytes`` object giving the + UTF-8 encoding of that text is returned. Otherwise, ``obj`` itself is + returned. + """ + if isinstance(obj, text_type): + warnings.warn( + _TEXT_WARNING.format(label), + category=DeprecationWarning, + stacklevel=3 + ) + return obj.encode('utf-8') + return obj diff --git a/venv/lib/python2.7/site-packages/OpenSSL/crypto.py b/venv/lib/python2.7/site-packages/OpenSSL/crypto.py new file mode 100644 index 0000000..adf03b4 --- /dev/null +++ b/venv/lib/python2.7/site-packages/OpenSSL/crypto.py @@ -0,0 +1,3123 @@ +import datetime + +from base64 import b16encode +from functools import partial +from operator import __eq__, __ne__, __lt__, __le__, __gt__, __ge__ + +from six import ( + integer_types as _integer_types, + text_type as _text_type, + PY3 as _PY3) + +from cryptography import x509 +from cryptography.hazmat.primitives.asymmetric import dsa, rsa +from cryptography.utils import deprecated + +from OpenSSL._util import ( + ffi as _ffi, + lib as _lib, + exception_from_error_queue as _exception_from_error_queue, + byte_string as _byte_string, + native as _native, + UNSPECIFIED as _UNSPECIFIED, + text_to_bytes_and_warn as _text_to_bytes_and_warn, + make_assert as _make_assert, +) + +__all__ = [ + 'FILETYPE_PEM', + 'FILETYPE_ASN1', + 'FILETYPE_TEXT', + 'TYPE_RSA', + 'TYPE_DSA', + 'Error', + 'PKey', + 'get_elliptic_curves', + 'get_elliptic_curve', + 'X509Name', + 'X509Extension', + 'X509Req', + 'X509', + 'X509StoreFlags', + 'X509Store', + 'X509StoreContextError', + 'X509StoreContext', + 'load_certificate', + 'dump_certificate', + 'dump_publickey', + 'dump_privatekey', + 'Revoked', + 'CRL', + 'PKCS7', + 'PKCS12', + 'NetscapeSPKI', + 'load_publickey', + 'load_privatekey', + 'dump_certificate_request', + 'load_certificate_request', + 'sign', + 'verify', + 'dump_crl', + 'load_crl', + 'load_pkcs7_data', + 'load_pkcs12' +] + +FILETYPE_PEM = _lib.SSL_FILETYPE_PEM +FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1 + +# TODO This was an API mistake. OpenSSL has no such constant. +FILETYPE_TEXT = 2 ** 16 - 1 + +TYPE_RSA = _lib.EVP_PKEY_RSA +TYPE_DSA = _lib.EVP_PKEY_DSA + + +class Error(Exception): + """ + An error occurred in an `OpenSSL.crypto` API. + """ + + +_raise_current_error = partial(_exception_from_error_queue, Error) +_openssl_assert = _make_assert(Error) + + +def _get_backend(): + """ + Importing the backend from cryptography has the side effect of activating + the osrandom engine. This mutates the global state of OpenSSL in the + process and causes issues for various programs that use subinterpreters or + embed Python. By putting the import in this function we can avoid + triggering this side effect unless _get_backend is called. + """ + from cryptography.hazmat.backends.openssl.backend import backend + return backend + + +def _untested_error(where): + """ + An OpenSSL API failed somehow. Additionally, the failure which was + encountered isn't one that's exercised by the test suite so future behavior + of pyOpenSSL is now somewhat less predictable. + """ + raise RuntimeError("Unknown %s failure" % (where,)) + + +def _new_mem_buf(buffer=None): + """ + Allocate a new OpenSSL memory BIO. + + Arrange for the garbage collector to clean it up automatically. + + :param buffer: None or some bytes to use to put into the BIO so that they + can be read out. + """ + if buffer is None: + bio = _lib.BIO_new(_lib.BIO_s_mem()) + free = _lib.BIO_free + else: + data = _ffi.new("char[]", buffer) + bio = _lib.BIO_new_mem_buf(data, len(buffer)) + + # Keep the memory alive as long as the bio is alive! + def free(bio, ref=data): + return _lib.BIO_free(bio) + + _openssl_assert(bio != _ffi.NULL) + + bio = _ffi.gc(bio, free) + return bio + + +def _bio_to_string(bio): + """ + Copy the contents of an OpenSSL BIO object into a Python byte string. + """ + result_buffer = _ffi.new('char**') + buffer_length = _lib.BIO_get_mem_data(bio, result_buffer) + return _ffi.buffer(result_buffer[0], buffer_length)[:] + + +def _set_asn1_time(boundary, when): + """ + The the time value of an ASN1 time object. + + @param boundary: An ASN1_TIME pointer (or an object safely + castable to that type) which will have its value set. + @param when: A string representation of the desired time value. + + @raise TypeError: If C{when} is not a L{bytes} string. + @raise ValueError: If C{when} does not represent a time in the required + format. + @raise RuntimeError: If the time value cannot be set for some other + (unspecified) reason. + """ + if not isinstance(when, bytes): + raise TypeError("when must be a byte string") + + set_result = _lib.ASN1_TIME_set_string(boundary, when) + if set_result == 0: + raise ValueError("Invalid string") + + +def _get_asn1_time(timestamp): + """ + Retrieve the time value of an ASN1 time object. + + @param timestamp: An ASN1_GENERALIZEDTIME* (or an object safely castable to + that type) from which the time value will be retrieved. + + @return: The time value from C{timestamp} as a L{bytes} string in a certain + format. Or C{None} if the object contains no time value. + """ + string_timestamp = _ffi.cast('ASN1_STRING*', timestamp) + if _lib.ASN1_STRING_length(string_timestamp) == 0: + return None + elif ( + _lib.ASN1_STRING_type(string_timestamp) == _lib.V_ASN1_GENERALIZEDTIME + ): + return _ffi.string(_lib.ASN1_STRING_data(string_timestamp)) + else: + generalized_timestamp = _ffi.new("ASN1_GENERALIZEDTIME**") + _lib.ASN1_TIME_to_generalizedtime(timestamp, generalized_timestamp) + if generalized_timestamp[0] == _ffi.NULL: + # This may happen: + # - if timestamp was not an ASN1_TIME + # - if allocating memory for the ASN1_GENERALIZEDTIME failed + # - if a copy of the time data from timestamp cannot be made for + # the newly allocated ASN1_GENERALIZEDTIME + # + # These are difficult to test. cffi enforces the ASN1_TIME type. + # Memory allocation failures are a pain to trigger + # deterministically. + _untested_error("ASN1_TIME_to_generalizedtime") + else: + string_timestamp = _ffi.cast( + "ASN1_STRING*", generalized_timestamp[0]) + string_data = _lib.ASN1_STRING_data(string_timestamp) + string_result = _ffi.string(string_data) + _lib.ASN1_GENERALIZEDTIME_free(generalized_timestamp[0]) + return string_result + + +class _X509NameInvalidator(object): + def __init__(self): + self._names = [] + + def add(self, name): + self._names.append(name) + + def clear(self): + for name in self._names: + # Breaks the object, but also prevents UAF! + del name._name + + +class PKey(object): + """ + A class representing an DSA or RSA public key or key pair. + """ + _only_public = False + _initialized = True + + def __init__(self): + pkey = _lib.EVP_PKEY_new() + self._pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free) + self._initialized = False + + def to_cryptography_key(self): + """ + Export as a ``cryptography`` key. + + :rtype: One of ``cryptography``'s `key interfaces`_. + + .. _key interfaces: https://cryptography.io/en/latest/hazmat/\ + primitives/asymmetric/rsa/#key-interfaces + + .. versionadded:: 16.1.0 + """ + backend = _get_backend() + if self._only_public: + return backend._evp_pkey_to_public_key(self._pkey) + else: + return backend._evp_pkey_to_private_key(self._pkey) + + @classmethod + def from_cryptography_key(cls, crypto_key): + """ + Construct based on a ``cryptography`` *crypto_key*. + + :param crypto_key: A ``cryptography`` key. + :type crypto_key: One of ``cryptography``'s `key interfaces`_. + + :rtype: PKey + + .. versionadded:: 16.1.0 + """ + pkey = cls() + if not isinstance(crypto_key, (rsa.RSAPublicKey, rsa.RSAPrivateKey, + dsa.DSAPublicKey, dsa.DSAPrivateKey)): + raise TypeError("Unsupported key type") + + pkey._pkey = crypto_key._evp_pkey + if isinstance(crypto_key, (rsa.RSAPublicKey, dsa.DSAPublicKey)): + pkey._only_public = True + pkey._initialized = True + return pkey + + def generate_key(self, type, bits): + """ + Generate a key pair of the given type, with the given number of bits. + + This generates a key "into" the this object. + + :param type: The key type. + :type type: :py:data:`TYPE_RSA` or :py:data:`TYPE_DSA` + :param bits: The number of bits. + :type bits: :py:data:`int` ``>= 0`` + :raises TypeError: If :py:data:`type` or :py:data:`bits` isn't + of the appropriate type. + :raises ValueError: If the number of bits isn't an integer of + the appropriate size. + :return: ``None`` + """ + if not isinstance(type, int): + raise TypeError("type must be an integer") + + if not isinstance(bits, int): + raise TypeError("bits must be an integer") + + # TODO Check error return + exponent = _lib.BN_new() + exponent = _ffi.gc(exponent, _lib.BN_free) + _lib.BN_set_word(exponent, _lib.RSA_F4) + + if type == TYPE_RSA: + if bits <= 0: + raise ValueError("Invalid number of bits") + + rsa = _lib.RSA_new() + + result = _lib.RSA_generate_key_ex(rsa, bits, exponent, _ffi.NULL) + _openssl_assert(result == 1) + + result = _lib.EVP_PKEY_assign_RSA(self._pkey, rsa) + _openssl_assert(result == 1) + + elif type == TYPE_DSA: + dsa = _lib.DSA_new() + _openssl_assert(dsa != _ffi.NULL) + + dsa = _ffi.gc(dsa, _lib.DSA_free) + res = _lib.DSA_generate_parameters_ex( + dsa, bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL + ) + _openssl_assert(res == 1) + + _openssl_assert(_lib.DSA_generate_key(dsa) == 1) + _openssl_assert(_lib.EVP_PKEY_set1_DSA(self._pkey, dsa) == 1) + else: + raise Error("No such key type") + + self._initialized = True + + def check(self): + """ + Check the consistency of an RSA private key. + + This is the Python equivalent of OpenSSL's ``RSA_check_key``. + + :return: ``True`` if key is consistent. + + :raise OpenSSL.crypto.Error: if the key is inconsistent. + + :raise TypeError: if the key is of a type which cannot be checked. + Only RSA keys can currently be checked. + """ + if self._only_public: + raise TypeError("public key only") + + if _lib.EVP_PKEY_type(self.type()) != _lib.EVP_PKEY_RSA: + raise TypeError("key type unsupported") + + rsa = _lib.EVP_PKEY_get1_RSA(self._pkey) + rsa = _ffi.gc(rsa, _lib.RSA_free) + result = _lib.RSA_check_key(rsa) + if result: + return True + _raise_current_error() + + def type(self): + """ + Returns the type of the key + + :return: The type of the key. + """ + return _lib.EVP_PKEY_id(self._pkey) + + def bits(self): + """ + Returns the number of bits of the key + + :return: The number of bits of the key. + """ + return _lib.EVP_PKEY_bits(self._pkey) + + +PKeyType = deprecated( + PKey, __name__, + "PKeyType has been deprecated, use PKey instead", + DeprecationWarning +) + + +class _EllipticCurve(object): + """ + A representation of a supported elliptic curve. + + @cvar _curves: :py:obj:`None` until an attempt is made to load the curves. + Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve` + instances each of which represents one curve supported by the system. + @type _curves: :py:type:`NoneType` or :py:type:`set` + """ + _curves = None + + if _PY3: + # This only necessary on Python 3. Morever, it is broken on Python 2. + def __ne__(self, other): + """ + Implement cooperation with the right-hand side argument of ``!=``. + + Python 3 seems to have dropped this cooperation in this very narrow + circumstance. + """ + if isinstance(other, _EllipticCurve): + return super(_EllipticCurve, self).__ne__(other) + return NotImplemented + + @classmethod + def _load_elliptic_curves(cls, lib): + """ + Get the curves supported by OpenSSL. + + :param lib: The OpenSSL library binding object. + + :return: A :py:type:`set` of ``cls`` instances giving the names of the + elliptic curves the underlying library supports. + """ + num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0) + builtin_curves = _ffi.new('EC_builtin_curve[]', num_curves) + # The return value on this call should be num_curves again. We + # could check it to make sure but if it *isn't* then.. what could + # we do? Abort the whole process, I suppose...? -exarkun + lib.EC_get_builtin_curves(builtin_curves, num_curves) + return set( + cls.from_nid(lib, c.nid) + for c in builtin_curves) + + @classmethod + def _get_elliptic_curves(cls, lib): + """ + Get, cache, and return the curves supported by OpenSSL. + + :param lib: The OpenSSL library binding object. + + :return: A :py:type:`set` of ``cls`` instances giving the names of the + elliptic curves the underlying library supports. + """ + if cls._curves is None: + cls._curves = cls._load_elliptic_curves(lib) + return cls._curves + + @classmethod + def from_nid(cls, lib, nid): + """ + Instantiate a new :py:class:`_EllipticCurve` associated with the given + OpenSSL NID. + + :param lib: The OpenSSL library binding object. + + :param nid: The OpenSSL NID the resulting curve object will represent. + This must be a curve NID (and not, for example, a hash NID) or + subsequent operations will fail in unpredictable ways. + :type nid: :py:class:`int` + + :return: The curve object. + """ + return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii")) + + def __init__(self, lib, nid, name): + """ + :param _lib: The :py:mod:`cryptography` binding instance used to + interface with OpenSSL. + + :param _nid: The OpenSSL NID identifying the curve this object + represents. + :type _nid: :py:class:`int` + + :param name: The OpenSSL short name identifying the curve this object + represents. + :type name: :py:class:`unicode` + """ + self._lib = lib + self._nid = nid + self.name = name + + def __repr__(self): + return "" % (self.name,) + + def _to_EC_KEY(self): + """ + Create a new OpenSSL EC_KEY structure initialized to use this curve. + + The structure is automatically garbage collected when the Python object + is garbage collected. + """ + key = self._lib.EC_KEY_new_by_curve_name(self._nid) + return _ffi.gc(key, _lib.EC_KEY_free) + + +def get_elliptic_curves(): + """ + Return a set of objects representing the elliptic curves supported in the + OpenSSL build in use. + + The curve objects have a :py:class:`unicode` ``name`` attribute by which + they identify themselves. + + The curve objects are useful as values for the argument accepted by + :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be + used for ECDHE key exchange. + """ + return _EllipticCurve._get_elliptic_curves(_lib) + + +def get_elliptic_curve(name): + """ + Return a single curve object selected by name. + + See :py:func:`get_elliptic_curves` for information about curve objects. + + :param name: The OpenSSL short name identifying the curve object to + retrieve. + :type name: :py:class:`unicode` + + If the named curve is not supported then :py:class:`ValueError` is raised. + """ + for curve in get_elliptic_curves(): + if curve.name == name: + return curve + raise ValueError("unknown curve name", name) + + +class X509Name(object): + """ + An X.509 Distinguished Name. + + :ivar countryName: The country of the entity. + :ivar C: Alias for :py:attr:`countryName`. + + :ivar stateOrProvinceName: The state or province of the entity. + :ivar ST: Alias for :py:attr:`stateOrProvinceName`. + + :ivar localityName: The locality of the entity. + :ivar L: Alias for :py:attr:`localityName`. + + :ivar organizationName: The organization name of the entity. + :ivar O: Alias for :py:attr:`organizationName`. + + :ivar organizationalUnitName: The organizational unit of the entity. + :ivar OU: Alias for :py:attr:`organizationalUnitName` + + :ivar commonName: The common name of the entity. + :ivar CN: Alias for :py:attr:`commonName`. + + :ivar emailAddress: The e-mail address of the entity. + """ + + def __init__(self, name): + """ + Create a new X509Name, copying the given X509Name instance. + + :param name: The name to copy. + :type name: :py:class:`X509Name` + """ + name = _lib.X509_NAME_dup(name._name) + self._name = _ffi.gc(name, _lib.X509_NAME_free) + + def __setattr__(self, name, value): + if name.startswith('_'): + return super(X509Name, self).__setattr__(name, value) + + # Note: we really do not want str subclasses here, so we do not use + # isinstance. + if type(name) is not str: + raise TypeError("attribute name must be string, not '%.200s'" % ( + type(value).__name__,)) + + nid = _lib.OBJ_txt2nid(_byte_string(name)) + if nid == _lib.NID_undef: + try: + _raise_current_error() + except Error: + pass + raise AttributeError("No such attribute") + + # If there's an old entry for this NID, remove it + for i in range(_lib.X509_NAME_entry_count(self._name)): + ent = _lib.X509_NAME_get_entry(self._name, i) + ent_obj = _lib.X509_NAME_ENTRY_get_object(ent) + ent_nid = _lib.OBJ_obj2nid(ent_obj) + if nid == ent_nid: + ent = _lib.X509_NAME_delete_entry(self._name, i) + _lib.X509_NAME_ENTRY_free(ent) + break + + if isinstance(value, _text_type): + value = value.encode('utf-8') + + add_result = _lib.X509_NAME_add_entry_by_NID( + self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0) + if not add_result: + _raise_current_error() + + def __getattr__(self, name): + """ + Find attribute. An X509Name object has the following attributes: + countryName (alias C), stateOrProvince (alias ST), locality (alias L), + organization (alias O), organizationalUnit (alias OU), commonName + (alias CN) and more... + """ + nid = _lib.OBJ_txt2nid(_byte_string(name)) + if nid == _lib.NID_undef: + # This is a bit weird. OBJ_txt2nid indicated failure, but it seems + # a lower level function, a2d_ASN1_OBJECT, also feels the need to + # push something onto the error queue. If we don't clean that up + # now, someone else will bump into it later and be quite confused. + # See lp#314814. + try: + _raise_current_error() + except Error: + pass + return super(X509Name, self).__getattr__(name) + + entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1) + if entry_index == -1: + return None + + entry = _lib.X509_NAME_get_entry(self._name, entry_index) + data = _lib.X509_NAME_ENTRY_get_data(entry) + + result_buffer = _ffi.new("unsigned char**") + data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data) + _openssl_assert(data_length >= 0) + + try: + result = _ffi.buffer( + result_buffer[0], data_length + )[:].decode('utf-8') + finally: + # XXX untested + _lib.OPENSSL_free(result_buffer[0]) + return result + + def _cmp(op): + def f(self, other): + if not isinstance(other, X509Name): + return NotImplemented + result = _lib.X509_NAME_cmp(self._name, other._name) + return op(result, 0) + return f + + __eq__ = _cmp(__eq__) + __ne__ = _cmp(__ne__) + + __lt__ = _cmp(__lt__) + __le__ = _cmp(__le__) + + __gt__ = _cmp(__gt__) + __ge__ = _cmp(__ge__) + + def __repr__(self): + """ + String representation of an X509Name + """ + result_buffer = _ffi.new("char[]", 512) + format_result = _lib.X509_NAME_oneline( + self._name, result_buffer, len(result_buffer)) + _openssl_assert(format_result != _ffi.NULL) + + return "" % ( + _native(_ffi.string(result_buffer)),) + + def hash(self): + """ + Return an integer representation of the first four bytes of the + MD5 digest of the DER representation of the name. + + This is the Python equivalent of OpenSSL's ``X509_NAME_hash``. + + :return: The (integer) hash of this name. + :rtype: :py:class:`int` + """ + return _lib.X509_NAME_hash(self._name) + + def der(self): + """ + Return the DER encoding of this name. + + :return: The DER encoded form of this name. + :rtype: :py:class:`bytes` + """ + result_buffer = _ffi.new('unsigned char**') + encode_result = _lib.i2d_X509_NAME(self._name, result_buffer) + _openssl_assert(encode_result >= 0) + + string_result = _ffi.buffer(result_buffer[0], encode_result)[:] + _lib.OPENSSL_free(result_buffer[0]) + return string_result + + def get_components(self): + """ + Returns the components of this name, as a sequence of 2-tuples. + + :return: The components of this name. + :rtype: :py:class:`list` of ``name, value`` tuples. + """ + result = [] + for i in range(_lib.X509_NAME_entry_count(self._name)): + ent = _lib.X509_NAME_get_entry(self._name, i) + + fname = _lib.X509_NAME_ENTRY_get_object(ent) + fval = _lib.X509_NAME_ENTRY_get_data(ent) + + nid = _lib.OBJ_obj2nid(fname) + name = _lib.OBJ_nid2sn(nid) + + result.append(( + _ffi.string(name), + _ffi.string( + _lib.ASN1_STRING_data(fval), + _lib.ASN1_STRING_length(fval)))) + + return result + + +X509NameType = deprecated( + X509Name, __name__, + "X509NameType has been deprecated, use X509Name instead", + DeprecationWarning +) + + +class X509Extension(object): + """ + An X.509 v3 certificate extension. + """ + + def __init__(self, type_name, critical, value, subject=None, issuer=None): + """ + Initializes an X509 extension. + + :param type_name: The name of the type of extension_ to create. + :type type_name: :py:data:`bytes` + + :param bool critical: A flag indicating whether this is a critical + extension. + + :param value: The value of the extension. + :type value: :py:data:`bytes` + + :param subject: Optional X509 certificate to use as subject. + :type subject: :py:class:`X509` + + :param issuer: Optional X509 certificate to use as issuer. + :type issuer: :py:class:`X509` + + .. _extension: https://www.openssl.org/docs/manmaster/man5/ + x509v3_config.html#STANDARD-EXTENSIONS + """ + ctx = _ffi.new("X509V3_CTX*") + + # A context is necessary for any extension which uses the r2i + # conversion method. That is, X509V3_EXT_nconf may segfault if passed + # a NULL ctx. Start off by initializing most of the fields to NULL. + _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0) + + # We have no configuration database - but perhaps we should (some + # extensions may require it). + _lib.X509V3_set_ctx_nodb(ctx) + + # Initialize the subject and issuer, if appropriate. ctx is a local, + # and as far as I can tell none of the X509V3_* APIs invoked here steal + # any references, so no need to mess with reference counts or + # duplicates. + if issuer is not None: + if not isinstance(issuer, X509): + raise TypeError("issuer must be an X509 instance") + ctx.issuer_cert = issuer._x509 + if subject is not None: + if not isinstance(subject, X509): + raise TypeError("subject must be an X509 instance") + ctx.subject_cert = subject._x509 + + if critical: + # There are other OpenSSL APIs which would let us pass in critical + # separately, but they're harder to use, and since value is already + # a pile of crappy junk smuggling a ton of utterly important + # structured data, what's the point of trying to avoid nasty stuff + # with strings? (However, X509V3_EXT_i2d in particular seems like + # it would be a better API to invoke. I do not know where to get + # the ext_struc it desires for its last parameter, though.) + value = b"critical," + value + + extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value) + if extension == _ffi.NULL: + _raise_current_error() + self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free) + + @property + def _nid(self): + return _lib.OBJ_obj2nid( + _lib.X509_EXTENSION_get_object(self._extension) + ) + + _prefixes = { + _lib.GEN_EMAIL: "email", + _lib.GEN_DNS: "DNS", + _lib.GEN_URI: "URI", + } + + def _subjectAltNameString(self): + names = _ffi.cast( + "GENERAL_NAMES*", _lib.X509V3_EXT_d2i(self._extension) + ) + + names = _ffi.gc(names, _lib.GENERAL_NAMES_free) + parts = [] + for i in range(_lib.sk_GENERAL_NAME_num(names)): + name = _lib.sk_GENERAL_NAME_value(names, i) + try: + label = self._prefixes[name.type] + except KeyError: + bio = _new_mem_buf() + _lib.GENERAL_NAME_print(bio, name) + parts.append(_native(_bio_to_string(bio))) + else: + value = _native( + _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:]) + parts.append(label + ":" + value) + return ", ".join(parts) + + def __str__(self): + """ + :return: a nice text representation of the extension + """ + if _lib.NID_subject_alt_name == self._nid: + return self._subjectAltNameString() + + bio = _new_mem_buf() + print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0) + _openssl_assert(print_result != 0) + + return _native(_bio_to_string(bio)) + + def get_critical(self): + """ + Returns the critical field of this X.509 extension. + + :return: The critical field. + """ + return _lib.X509_EXTENSION_get_critical(self._extension) + + def get_short_name(self): + """ + Returns the short type name of this X.509 extension. + + The result is a byte string such as :py:const:`b"basicConstraints"`. + + :return: The short type name. + :rtype: :py:data:`bytes` + + .. versionadded:: 0.12 + """ + obj = _lib.X509_EXTENSION_get_object(self._extension) + nid = _lib.OBJ_obj2nid(obj) + return _ffi.string(_lib.OBJ_nid2sn(nid)) + + def get_data(self): + """ + Returns the data of the X509 extension, encoded as ASN.1. + + :return: The ASN.1 encoded data of this X509 extension. + :rtype: :py:data:`bytes` + + .. versionadded:: 0.12 + """ + octet_result = _lib.X509_EXTENSION_get_data(self._extension) + string_result = _ffi.cast('ASN1_STRING*', octet_result) + char_result = _lib.ASN1_STRING_data(string_result) + result_length = _lib.ASN1_STRING_length(string_result) + return _ffi.buffer(char_result, result_length)[:] + + +X509ExtensionType = deprecated( + X509Extension, __name__, + "X509ExtensionType has been deprecated, use X509Extension instead", + DeprecationWarning +) + + +class X509Req(object): + """ + An X.509 certificate signing requests. + """ + + def __init__(self): + req = _lib.X509_REQ_new() + self._req = _ffi.gc(req, _lib.X509_REQ_free) + # Default to version 0. + self.set_version(0) + + def to_cryptography(self): + """ + Export as a ``cryptography`` certificate signing request. + + :rtype: ``cryptography.x509.CertificateSigningRequest`` + + .. versionadded:: 17.1.0 + """ + from cryptography.hazmat.backends.openssl.x509 import ( + _CertificateSigningRequest + ) + backend = _get_backend() + return _CertificateSigningRequest(backend, self._req) + + @classmethod + def from_cryptography(cls, crypto_req): + """ + Construct based on a ``cryptography`` *crypto_req*. + + :param crypto_req: A ``cryptography`` X.509 certificate signing request + :type crypto_req: ``cryptography.x509.CertificateSigningRequest`` + + :rtype: PKey + + .. versionadded:: 17.1.0 + """ + if not isinstance(crypto_req, x509.CertificateSigningRequest): + raise TypeError("Must be a certificate signing request") + + req = cls() + req._req = crypto_req._x509_req + return req + + def set_pubkey(self, pkey): + """ + Set the public key of the certificate signing request. + + :param pkey: The public key to use. + :type pkey: :py:class:`PKey` + + :return: ``None`` + """ + set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey) + _openssl_assert(set_result == 1) + + def get_pubkey(self): + """ + Get the public key of the certificate signing request. + + :return: The public key. + :rtype: :py:class:`PKey` + """ + pkey = PKey.__new__(PKey) + pkey._pkey = _lib.X509_REQ_get_pubkey(self._req) + _openssl_assert(pkey._pkey != _ffi.NULL) + pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free) + pkey._only_public = True + return pkey + + def set_version(self, version): + """ + Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate + request. + + :param int version: The version number. + :return: ``None`` + """ + set_result = _lib.X509_REQ_set_version(self._req, version) + _openssl_assert(set_result == 1) + + def get_version(self): + """ + Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate + request. + + :return: The value of the version subfield. + :rtype: :py:class:`int` + """ + return _lib.X509_REQ_get_version(self._req) + + def get_subject(self): + """ + Return the subject of this certificate signing request. + + This creates a new :class:`X509Name` that wraps the underlying subject + name field on the certificate signing request. Modifying it will modify + the underlying signing request, and will have the effect of modifying + any other :class:`X509Name` that refers to this subject. + + :return: The subject of this certificate signing request. + :rtype: :class:`X509Name` + """ + name = X509Name.__new__(X509Name) + name._name = _lib.X509_REQ_get_subject_name(self._req) + _openssl_assert(name._name != _ffi.NULL) + + # The name is owned by the X509Req structure. As long as the X509Name + # Python object is alive, keep the X509Req Python object alive. + name._owner = self + + return name + + def add_extensions(self, extensions): + """ + Add extensions to the certificate signing request. + + :param extensions: The X.509 extensions to add. + :type extensions: iterable of :py:class:`X509Extension` + :return: ``None`` + """ + stack = _lib.sk_X509_EXTENSION_new_null() + _openssl_assert(stack != _ffi.NULL) + + stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free) + + for ext in extensions: + if not isinstance(ext, X509Extension): + raise ValueError("One of the elements is not an X509Extension") + + # TODO push can fail (here and elsewhere) + _lib.sk_X509_EXTENSION_push(stack, ext._extension) + + add_result = _lib.X509_REQ_add_extensions(self._req, stack) + _openssl_assert(add_result == 1) + + def get_extensions(self): + """ + Get X.509 extensions in the certificate signing request. + + :return: The X.509 extensions in this request. + :rtype: :py:class:`list` of :py:class:`X509Extension` objects. + + .. versionadded:: 0.15 + """ + exts = [] + native_exts_obj = _lib.X509_REQ_get_extensions(self._req) + for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)): + ext = X509Extension.__new__(X509Extension) + ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i) + exts.append(ext) + return exts + + def sign(self, pkey, digest): + """ + Sign the certificate signing request with this key and digest type. + + :param pkey: The key pair to sign with. + :type pkey: :py:class:`PKey` + :param digest: The name of the message digest to use for the signature, + e.g. :py:data:`b"sha256"`. + :type digest: :py:class:`bytes` + :return: ``None`` + """ + if pkey._only_public: + raise ValueError("Key has only public part") + + if not pkey._initialized: + raise ValueError("Key is uninitialized") + + digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest)) + if digest_obj == _ffi.NULL: + raise ValueError("No such digest method") + + sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj) + _openssl_assert(sign_result > 0) + + def verify(self, pkey): + """ + Verifies the signature on this certificate signing request. + + :param PKey key: A public key. + + :return: ``True`` if the signature is correct. + :rtype: bool + + :raises OpenSSL.crypto.Error: If the signature is invalid or there is a + problem verifying the signature. + """ + if not isinstance(pkey, PKey): + raise TypeError("pkey must be a PKey instance") + + result = _lib.X509_REQ_verify(self._req, pkey._pkey) + if result <= 0: + _raise_current_error() + + return result + + +X509ReqType = deprecated( + X509Req, __name__, + "X509ReqType has been deprecated, use X509Req instead", + DeprecationWarning +) + + +class X509(object): + """ + An X.509 certificate. + """ + def __init__(self): + x509 = _lib.X509_new() + _openssl_assert(x509 != _ffi.NULL) + self._x509 = _ffi.gc(x509, _lib.X509_free) + + self._issuer_invalidator = _X509NameInvalidator() + self._subject_invalidator = _X509NameInvalidator() + + @classmethod + def _from_raw_x509_ptr(cls, x509): + cert = cls.__new__(cls) + cert._x509 = _ffi.gc(x509, _lib.X509_free) + cert._issuer_invalidator = _X509NameInvalidator() + cert._subject_invalidator = _X509NameInvalidator() + return cert + + def to_cryptography(self): + """ + Export as a ``cryptography`` certificate. + + :rtype: ``cryptography.x509.Certificate`` + + .. versionadded:: 17.1.0 + """ + from cryptography.hazmat.backends.openssl.x509 import _Certificate + backend = _get_backend() + return _Certificate(backend, self._x509) + + @classmethod + def from_cryptography(cls, crypto_cert): + """ + Construct based on a ``cryptography`` *crypto_cert*. + + :param crypto_key: A ``cryptography`` X.509 certificate. + :type crypto_key: ``cryptography.x509.Certificate`` + + :rtype: PKey + + .. versionadded:: 17.1.0 + """ + if not isinstance(crypto_cert, x509.Certificate): + raise TypeError("Must be a certificate") + + cert = cls() + cert._x509 = crypto_cert._x509 + return cert + + def set_version(self, version): + """ + Set the version number of the certificate. + + :param version: The version number of the certificate. + :type version: :py:class:`int` + + :return: ``None`` + """ + if not isinstance(version, int): + raise TypeError("version must be an integer") + + _lib.X509_set_version(self._x509, version) + + def get_version(self): + """ + Return the version number of the certificate. + + :return: The version number of the certificate. + :rtype: :py:class:`int` + """ + return _lib.X509_get_version(self._x509) + + def get_pubkey(self): + """ + Get the public key of the certificate. + + :return: The public key. + :rtype: :py:class:`PKey` + """ + pkey = PKey.__new__(PKey) + pkey._pkey = _lib.X509_get_pubkey(self._x509) + if pkey._pkey == _ffi.NULL: + _raise_current_error() + pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free) + pkey._only_public = True + return pkey + + def set_pubkey(self, pkey): + """ + Set the public key of the certificate. + + :param pkey: The public key. + :type pkey: :py:class:`PKey` + + :return: :py:data:`None` + """ + if not isinstance(pkey, PKey): + raise TypeError("pkey must be a PKey instance") + + set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey) + _openssl_assert(set_result == 1) + + def sign(self, pkey, digest): + """ + Sign the certificate with this key and digest type. + + :param pkey: The key to sign with. + :type pkey: :py:class:`PKey` + + :param digest: The name of the message digest to use. + :type digest: :py:class:`bytes` + + :return: :py:data:`None` + """ + if not isinstance(pkey, PKey): + raise TypeError("pkey must be a PKey instance") + + if pkey._only_public: + raise ValueError("Key only has public part") + + if not pkey._initialized: + raise ValueError("Key is uninitialized") + + evp_md = _lib.EVP_get_digestbyname(_byte_string(digest)) + if evp_md == _ffi.NULL: + raise ValueError("No such digest method") + + sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md) + _openssl_assert(sign_result > 0) + + def get_signature_algorithm(self): + """ + Return the signature algorithm used in the certificate. + + :return: The name of the algorithm. + :rtype: :py:class:`bytes` + + :raises ValueError: If the signature algorithm is undefined. + + .. versionadded:: 0.13 + """ + algor = _lib.X509_get0_tbs_sigalg(self._x509) + nid = _lib.OBJ_obj2nid(algor.algorithm) + if nid == _lib.NID_undef: + raise ValueError("Undefined signature algorithm") + return _ffi.string(_lib.OBJ_nid2ln(nid)) + + def digest(self, digest_name): + """ + Return the digest of the X509 object. + + :param digest_name: The name of the digest algorithm to use. + :type digest_name: :py:class:`bytes` + + :return: The digest of the object, formatted as + :py:const:`b":"`-delimited hex pairs. + :rtype: :py:class:`bytes` + """ + digest = _lib.EVP_get_digestbyname(_byte_string(digest_name)) + if digest == _ffi.NULL: + raise ValueError("No such digest method") + + result_buffer = _ffi.new("unsigned char[]", _lib.EVP_MAX_MD_SIZE) + result_length = _ffi.new("unsigned int[]", 1) + result_length[0] = len(result_buffer) + + digest_result = _lib.X509_digest( + self._x509, digest, result_buffer, result_length) + _openssl_assert(digest_result == 1) + + return b":".join([ + b16encode(ch).upper() for ch + in _ffi.buffer(result_buffer, result_length[0])]) + + def subject_name_hash(self): + """ + Return the hash of the X509 subject. + + :return: The hash of the subject. + :rtype: :py:class:`bytes` + """ + return _lib.X509_subject_name_hash(self._x509) + + def set_serial_number(self, serial): + """ + Set the serial number of the certificate. + + :param serial: The new serial number. + :type serial: :py:class:`int` + + :return: :py:data`None` + """ + if not isinstance(serial, _integer_types): + raise TypeError("serial must be an integer") + + hex_serial = hex(serial)[2:] + if not isinstance(hex_serial, bytes): + hex_serial = hex_serial.encode('ascii') + + bignum_serial = _ffi.new("BIGNUM**") + + # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like + # it. If bignum is still NULL after this call, then the return value + # is actually the result. I hope. -exarkun + small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial) + + if bignum_serial[0] == _ffi.NULL: + set_result = _lib.ASN1_INTEGER_set( + _lib.X509_get_serialNumber(self._x509), small_serial) + if set_result: + # TODO Not tested + _raise_current_error() + else: + asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL) + _lib.BN_free(bignum_serial[0]) + if asn1_serial == _ffi.NULL: + # TODO Not tested + _raise_current_error() + asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free) + set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial) + _openssl_assert(set_result == 1) + + def get_serial_number(self): + """ + Return the serial number of this certificate. + + :return: The serial number. + :rtype: int + """ + asn1_serial = _lib.X509_get_serialNumber(self._x509) + bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL) + try: + hex_serial = _lib.BN_bn2hex(bignum_serial) + try: + hexstring_serial = _ffi.string(hex_serial) + serial = int(hexstring_serial, 16) + return serial + finally: + _lib.OPENSSL_free(hex_serial) + finally: + _lib.BN_free(bignum_serial) + + def gmtime_adj_notAfter(self, amount): + """ + Adjust the time stamp on which the certificate stops being valid. + + :param int amount: The number of seconds by which to adjust the + timestamp. + :return: ``None`` + """ + if not isinstance(amount, int): + raise TypeError("amount must be an integer") + + notAfter = _lib.X509_get_notAfter(self._x509) + _lib.X509_gmtime_adj(notAfter, amount) + + def gmtime_adj_notBefore(self, amount): + """ + Adjust the timestamp on which the certificate starts being valid. + + :param amount: The number of seconds by which to adjust the timestamp. + :return: ``None`` + """ + if not isinstance(amount, int): + raise TypeError("amount must be an integer") + + notBefore = _lib.X509_get_notBefore(self._x509) + _lib.X509_gmtime_adj(notBefore, amount) + + def has_expired(self): + """ + Check whether the certificate has expired. + + :return: ``True`` if the certificate has expired, ``False`` otherwise. + :rtype: bool + """ + time_string = _native(self.get_notAfter()) + not_after = datetime.datetime.strptime(time_string, "%Y%m%d%H%M%SZ") + + return not_after < datetime.datetime.utcnow() + + def _get_boundary_time(self, which): + return _get_asn1_time(which(self._x509)) + + def get_notBefore(self): + """ + Get the timestamp at which the certificate starts being valid. + + The timestamp is formatted as an ASN.1 TIME:: + + YYYYMMDDhhmmssZ + + :return: A timestamp string, or ``None`` if there is none. + :rtype: bytes or NoneType + """ + return self._get_boundary_time(_lib.X509_get_notBefore) + + def _set_boundary_time(self, which, when): + return _set_asn1_time(which(self._x509), when) + + def set_notBefore(self, when): + """ + Set the timestamp at which the certificate starts being valid. + + The timestamp is formatted as an ASN.1 TIME:: + + YYYYMMDDhhmmssZ + + :param bytes when: A timestamp string. + :return: ``None`` + """ + return self._set_boundary_time(_lib.X509_get_notBefore, when) + + def get_notAfter(self): + """ + Get the timestamp at which the certificate stops being valid. + + The timestamp is formatted as an ASN.1 TIME:: + + YYYYMMDDhhmmssZ + + :return: A timestamp string, or ``None`` if there is none. + :rtype: bytes or NoneType + """ + return self._get_boundary_time(_lib.X509_get_notAfter) + + def set_notAfter(self, when): + """ + Set the timestamp at which the certificate stops being valid. + + The timestamp is formatted as an ASN.1 TIME:: + + YYYYMMDDhhmmssZ + + :param bytes when: A timestamp string. + :return: ``None`` + """ + return self._set_boundary_time(_lib.X509_get_notAfter, when) + + def _get_name(self, which): + name = X509Name.__new__(X509Name) + name._name = which(self._x509) + _openssl_assert(name._name != _ffi.NULL) + + # The name is owned by the X509 structure. As long as the X509Name + # Python object is alive, keep the X509 Python object alive. + name._owner = self + + return name + + def _set_name(self, which, name): + if not isinstance(name, X509Name): + raise TypeError("name must be an X509Name") + set_result = which(self._x509, name._name) + _openssl_assert(set_result == 1) + + def get_issuer(self): + """ + Return the issuer of this certificate. + + This creates a new :class:`X509Name` that wraps the underlying issuer + name field on the certificate. Modifying it will modify the underlying + certificate, and will have the effect of modifying any other + :class:`X509Name` that refers to this issuer. + + :return: The issuer of this certificate. + :rtype: :class:`X509Name` + """ + name = self._get_name(_lib.X509_get_issuer_name) + self._issuer_invalidator.add(name) + return name + + def set_issuer(self, issuer): + """ + Set the issuer of this certificate. + + :param issuer: The issuer. + :type issuer: :py:class:`X509Name` + + :return: ``None`` + """ + self._set_name(_lib.X509_set_issuer_name, issuer) + self._issuer_invalidator.clear() + + def get_subject(self): + """ + Return the subject of this certificate. + + This creates a new :class:`X509Name` that wraps the underlying subject + name field on the certificate. Modifying it will modify the underlying + certificate, and will have the effect of modifying any other + :class:`X509Name` that refers to this subject. + + :return: The subject of this certificate. + :rtype: :class:`X509Name` + """ + name = self._get_name(_lib.X509_get_subject_name) + self._subject_invalidator.add(name) + return name + + def set_subject(self, subject): + """ + Set the subject of this certificate. + + :param subject: The subject. + :type subject: :py:class:`X509Name` + + :return: ``None`` + """ + self._set_name(_lib.X509_set_subject_name, subject) + self._subject_invalidator.clear() + + def get_extension_count(self): + """ + Get the number of extensions on this certificate. + + :return: The number of extensions. + :rtype: :py:class:`int` + + .. versionadded:: 0.12 + """ + return _lib.X509_get_ext_count(self._x509) + + def add_extensions(self, extensions): + """ + Add extensions to the certificate. + + :param extensions: The extensions to add. + :type extensions: An iterable of :py:class:`X509Extension` objects. + :return: ``None`` + """ + for ext in extensions: + if not isinstance(ext, X509Extension): + raise ValueError("One of the elements is not an X509Extension") + + add_result = _lib.X509_add_ext(self._x509, ext._extension, -1) + if not add_result: + _raise_current_error() + + def get_extension(self, index): + """ + Get a specific extension of the certificate by index. + + Extensions on a certificate are kept in order. The index + parameter selects which extension will be returned. + + :param int index: The index of the extension to retrieve. + :return: The extension at the specified index. + :rtype: :py:class:`X509Extension` + :raises IndexError: If the extension index was out of bounds. + + .. versionadded:: 0.12 + """ + ext = X509Extension.__new__(X509Extension) + ext._extension = _lib.X509_get_ext(self._x509, index) + if ext._extension == _ffi.NULL: + raise IndexError("extension index out of bounds") + + extension = _lib.X509_EXTENSION_dup(ext._extension) + ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free) + return ext + + +X509Type = deprecated( + X509, __name__, + "X509Type has been deprecated, use X509 instead", + DeprecationWarning +) + + +class X509StoreFlags(object): + """ + Flags for X509 verification, used to change the behavior of + :class:`X509Store`. + + See `OpenSSL Verification Flags`_ for details. + + .. _OpenSSL Verification Flags: + https://www.openssl.org/docs/manmaster/man3/X509_VERIFY_PARAM_set_flags.html + """ + CRL_CHECK = _lib.X509_V_FLAG_CRL_CHECK + CRL_CHECK_ALL = _lib.X509_V_FLAG_CRL_CHECK_ALL + IGNORE_CRITICAL = _lib.X509_V_FLAG_IGNORE_CRITICAL + X509_STRICT = _lib.X509_V_FLAG_X509_STRICT + ALLOW_PROXY_CERTS = _lib.X509_V_FLAG_ALLOW_PROXY_CERTS + POLICY_CHECK = _lib.X509_V_FLAG_POLICY_CHECK + EXPLICIT_POLICY = _lib.X509_V_FLAG_EXPLICIT_POLICY + INHIBIT_MAP = _lib.X509_V_FLAG_INHIBIT_MAP + NOTIFY_POLICY = _lib.X509_V_FLAG_NOTIFY_POLICY + CHECK_SS_SIGNATURE = _lib.X509_V_FLAG_CHECK_SS_SIGNATURE + CB_ISSUER_CHECK = _lib.X509_V_FLAG_CB_ISSUER_CHECK + + +class X509Store(object): + """ + An X.509 store. + + An X.509 store is used to describe a context in which to verify a + certificate. A description of a context may include a set of certificates + to trust, a set of certificate revocation lists, verification flags and + more. + + An X.509 store, being only a description, cannot be used by itself to + verify a certificate. To carry out the actual verification process, see + :class:`X509StoreContext`. + """ + + def __init__(self): + store = _lib.X509_STORE_new() + self._store = _ffi.gc(store, _lib.X509_STORE_free) + + def add_cert(self, cert): + """ + Adds a trusted certificate to this store. + + Adding a certificate with this method adds this certificate as a + *trusted* certificate. + + :param X509 cert: The certificate to add to this store. + + :raises TypeError: If the certificate is not an :class:`X509`. + + :raises OpenSSL.crypto.Error: If OpenSSL was unhappy with your + certificate. + + :return: ``None`` if the certificate was added successfully. + """ + if not isinstance(cert, X509): + raise TypeError() + + _openssl_assert(_lib.X509_STORE_add_cert(self._store, cert._x509) != 0) + + def add_crl(self, crl): + """ + Add a certificate revocation list to this store. + + The certificate revocation lists added to a store will only be used if + the associated flags are configured to check certificate revocation + lists. + + .. versionadded:: 16.1.0 + + :param CRL crl: The certificate revocation list to add to this store. + :return: ``None`` if the certificate revocation list was added + successfully. + """ + _openssl_assert(_lib.X509_STORE_add_crl(self._store, crl._crl) != 0) + + def set_flags(self, flags): + """ + Set verification flags to this store. + + Verification flags can be combined by oring them together. + + .. note:: + + Setting a verification flag sometimes requires clients to add + additional information to the store, otherwise a suitable error will + be raised. + + For example, in setting flags to enable CRL checking a + suitable CRL must be added to the store otherwise an error will be + raised. + + .. versionadded:: 16.1.0 + + :param int flags: The verification flags to set on this store. + See :class:`X509StoreFlags` for available constants. + :return: ``None`` if the verification flags were successfully set. + """ + _openssl_assert(_lib.X509_STORE_set_flags(self._store, flags) != 0) + + def set_time(self, vfy_time): + """ + Set the time against which the certificates are verified. + + Normally the current time is used. + + .. note:: + + For example, you can determine if a certificate was valid at a given + time. + + .. versionadded:: 17.0.0 + + :param datetime vfy_time: The verification time to set on this store. + :return: ``None`` if the verification time was successfully set. + """ + param = _lib.X509_VERIFY_PARAM_new() + param = _ffi.gc(param, _lib.X509_VERIFY_PARAM_free) + + _lib.X509_VERIFY_PARAM_set_time(param, int(vfy_time.strftime('%s'))) + _openssl_assert(_lib.X509_STORE_set1_param(self._store, param) != 0) + + +X509StoreType = deprecated( + X509Store, __name__, + "X509StoreType has been deprecated, use X509Store instead", + DeprecationWarning +) + + +class X509StoreContextError(Exception): + """ + An exception raised when an error occurred while verifying a certificate + using `OpenSSL.X509StoreContext.verify_certificate`. + + :ivar certificate: The certificate which caused verificate failure. + :type certificate: :class:`X509` + """ + + def __init__(self, message, certificate): + super(X509StoreContextError, self).__init__(message) + self.certificate = certificate + + +class X509StoreContext(object): + """ + An X.509 store context. + + An X.509 store context is used to carry out the actual verification process + of a certificate in a described context. For describing such a context, see + :class:`X509Store`. + + :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this + instance. It is dynamically allocated and automatically garbage + collected. + :ivar _store: See the ``store`` ``__init__`` parameter. + :ivar _cert: See the ``certificate`` ``__init__`` parameter. + :param X509Store store: The certificates which will be trusted for the + purposes of any verifications. + :param X509 certificate: The certificate to be verified. + """ + + def __init__(self, store, certificate): + store_ctx = _lib.X509_STORE_CTX_new() + self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free) + self._store = store + self._cert = certificate + # Make the store context available for use after instantiating this + # class by initializing it now. Per testing, subsequent calls to + # :meth:`_init` have no adverse affect. + self._init() + + def _init(self): + """ + Set up the store context for a subsequent verification operation. + + Calling this method more than once without first calling + :meth:`_cleanup` will leak memory. + """ + ret = _lib.X509_STORE_CTX_init( + self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL + ) + if ret <= 0: + _raise_current_error() + + def _cleanup(self): + """ + Internally cleans up the store context. + + The store context can then be reused with a new call to :meth:`_init`. + """ + _lib.X509_STORE_CTX_cleanup(self._store_ctx) + + def _exception_from_context(self): + """ + Convert an OpenSSL native context error failure into a Python + exception. + + When a call to native OpenSSL X509_verify_cert fails, additional + information about the failure can be obtained from the store context. + """ + errors = [ + _lib.X509_STORE_CTX_get_error(self._store_ctx), + _lib.X509_STORE_CTX_get_error_depth(self._store_ctx), + _native(_ffi.string(_lib.X509_verify_cert_error_string( + _lib.X509_STORE_CTX_get_error(self._store_ctx)))), + ] + # A context error should always be associated with a certificate, so we + # expect this call to never return :class:`None`. + _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx) + _cert = _lib.X509_dup(_x509) + pycert = X509._from_raw_x509_ptr(_cert) + return X509StoreContextError(errors, pycert) + + def set_store(self, store): + """ + Set the context's X.509 store. + + .. versionadded:: 0.15 + + :param X509Store store: The store description which will be used for + the purposes of any *future* verifications. + """ + self._store = store + + def verify_certificate(self): + """ + Verify a certificate in a context. + + .. versionadded:: 0.15 + + :raises X509StoreContextError: If an error occurred when validating a + certificate in the context. Sets ``certificate`` attribute to + indicate which certificate caused the error. + """ + # Always re-initialize the store context in case + # :meth:`verify_certificate` is called multiple times. + # + # :meth:`_init` is called in :meth:`__init__` so _cleanup is called + # before _init to ensure memory is not leaked. + self._cleanup() + self._init() + ret = _lib.X509_verify_cert(self._store_ctx) + self._cleanup() + if ret <= 0: + raise self._exception_from_context() + + +def load_certificate(type, buffer): + """ + Load a certificate (X509) from the string *buffer* encoded with the + type *type*. + + :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1) + + :param bytes buffer: The buffer the certificate is stored in + + :return: The X509 object + """ + if isinstance(buffer, _text_type): + buffer = buffer.encode("ascii") + + bio = _new_mem_buf(buffer) + + if type == FILETYPE_PEM: + x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL) + elif type == FILETYPE_ASN1: + x509 = _lib.d2i_X509_bio(bio, _ffi.NULL) + else: + raise ValueError( + "type argument must be FILETYPE_PEM or FILETYPE_ASN1") + + if x509 == _ffi.NULL: + _raise_current_error() + + return X509._from_raw_x509_ptr(x509) + + +def dump_certificate(type, cert): + """ + Dump the certificate *cert* into a buffer string encoded with the type + *type*. + + :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or + FILETYPE_TEXT) + :param cert: The certificate to dump + :return: The buffer with the dumped certificate in + """ + bio = _new_mem_buf() + + if type == FILETYPE_PEM: + result_code = _lib.PEM_write_bio_X509(bio, cert._x509) + elif type == FILETYPE_ASN1: + result_code = _lib.i2d_X509_bio(bio, cert._x509) + elif type == FILETYPE_TEXT: + result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0) + else: + raise ValueError( + "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or " + "FILETYPE_TEXT") + + assert result_code == 1 + return _bio_to_string(bio) + + +def dump_publickey(type, pkey): + """ + Dump a public key to a buffer. + + :param type: The file type (one of :data:`FILETYPE_PEM` or + :data:`FILETYPE_ASN1`). + :param PKey pkey: The public key to dump + :return: The buffer with the dumped key in it. + :rtype: bytes + """ + bio = _new_mem_buf() + if type == FILETYPE_PEM: + write_bio = _lib.PEM_write_bio_PUBKEY + elif type == FILETYPE_ASN1: + write_bio = _lib.i2d_PUBKEY_bio + else: + raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1") + + result_code = write_bio(bio, pkey._pkey) + if result_code != 1: # pragma: no cover + _raise_current_error() + + return _bio_to_string(bio) + + +def dump_privatekey(type, pkey, cipher=None, passphrase=None): + """ + Dump the private key *pkey* into a buffer string encoded with the type + *type*. Optionally (if *type* is :const:`FILETYPE_PEM`) encrypting it + using *cipher* and *passphrase*. + + :param type: The file type (one of :const:`FILETYPE_PEM`, + :const:`FILETYPE_ASN1`, or :const:`FILETYPE_TEXT`) + :param PKey pkey: The PKey to dump + :param cipher: (optional) if encrypted PEM format, the cipher to use + :param passphrase: (optional) if encrypted PEM format, this can be either + the passphrase to use, or a callback for providing the passphrase. + + :return: The buffer with the dumped key in + :rtype: bytes + """ + bio = _new_mem_buf() + + if not isinstance(pkey, PKey): + raise TypeError("pkey must be a PKey") + + if cipher is not None: + if passphrase is None: + raise TypeError( + "if a value is given for cipher " + "one must also be given for passphrase") + cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher)) + if cipher_obj == _ffi.NULL: + raise ValueError("Invalid cipher name") + else: + cipher_obj = _ffi.NULL + + helper = _PassphraseHelper(type, passphrase) + if type == FILETYPE_PEM: + result_code = _lib.PEM_write_bio_PrivateKey( + bio, pkey._pkey, cipher_obj, _ffi.NULL, 0, + helper.callback, helper.callback_args) + helper.raise_if_problem() + elif type == FILETYPE_ASN1: + result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey) + elif type == FILETYPE_TEXT: + if _lib.EVP_PKEY_id(pkey._pkey) != _lib.EVP_PKEY_RSA: + raise TypeError("Only RSA keys are supported for FILETYPE_TEXT") + + rsa = _ffi.gc( + _lib.EVP_PKEY_get1_RSA(pkey._pkey), + _lib.RSA_free + ) + result_code = _lib.RSA_print(bio, rsa, 0) + else: + raise ValueError( + "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or " + "FILETYPE_TEXT") + + _openssl_assert(result_code != 0) + + return _bio_to_string(bio) + + +class Revoked(object): + """ + A certificate revocation. + """ + # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_ + # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches + # OCSP_crl_reason_str. We use the latter, just like the command line + # program. + _crl_reasons = [ + b"unspecified", + b"keyCompromise", + b"CACompromise", + b"affiliationChanged", + b"superseded", + b"cessationOfOperation", + b"certificateHold", + # b"removeFromCRL", + ] + + def __init__(self): + revoked = _lib.X509_REVOKED_new() + self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free) + + def set_serial(self, hex_str): + """ + Set the serial number. + + The serial number is formatted as a hexadecimal number encoded in + ASCII. + + :param bytes hex_str: The new serial number. + + :return: ``None`` + """ + bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free) + bignum_ptr = _ffi.new("BIGNUM**") + bignum_ptr[0] = bignum_serial + bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str) + if not bn_result: + raise ValueError("bad hex string") + + asn1_serial = _ffi.gc( + _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL), + _lib.ASN1_INTEGER_free) + _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial) + + def get_serial(self): + """ + Get the serial number. + + The serial number is formatted as a hexadecimal number encoded in + ASCII. + + :return: The serial number. + :rtype: bytes + """ + bio = _new_mem_buf() + + asn1_int = _lib.X509_REVOKED_get0_serialNumber(self._revoked) + _openssl_assert(asn1_int != _ffi.NULL) + result = _lib.i2a_ASN1_INTEGER(bio, asn1_int) + _openssl_assert(result >= 0) + return _bio_to_string(bio) + + def _delete_reason(self): + for i in range(_lib.X509_REVOKED_get_ext_count(self._revoked)): + ext = _lib.X509_REVOKED_get_ext(self._revoked, i) + obj = _lib.X509_EXTENSION_get_object(ext) + if _lib.OBJ_obj2nid(obj) == _lib.NID_crl_reason: + _lib.X509_EXTENSION_free(ext) + _lib.X509_REVOKED_delete_ext(self._revoked, i) + break + + def set_reason(self, reason): + """ + Set the reason of this revocation. + + If :data:`reason` is ``None``, delete the reason instead. + + :param reason: The reason string. + :type reason: :class:`bytes` or :class:`NoneType` + + :return: ``None`` + + .. seealso:: + + :meth:`all_reasons`, which gives you a list of all supported + reasons which you might pass to this method. + """ + if reason is None: + self._delete_reason() + elif not isinstance(reason, bytes): + raise TypeError("reason must be None or a byte string") + else: + reason = reason.lower().replace(b' ', b'') + reason_code = [r.lower() for r in self._crl_reasons].index(reason) + + new_reason_ext = _lib.ASN1_ENUMERATED_new() + _openssl_assert(new_reason_ext != _ffi.NULL) + new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free) + + set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code) + _openssl_assert(set_result != _ffi.NULL) + + self._delete_reason() + add_result = _lib.X509_REVOKED_add1_ext_i2d( + self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0) + _openssl_assert(add_result == 1) + + def get_reason(self): + """ + Get the reason of this revocation. + + :return: The reason, or ``None`` if there is none. + :rtype: bytes or NoneType + + .. seealso:: + + :meth:`all_reasons`, which gives you a list of all supported + reasons this method might return. + """ + for i in range(_lib.X509_REVOKED_get_ext_count(self._revoked)): + ext = _lib.X509_REVOKED_get_ext(self._revoked, i) + obj = _lib.X509_EXTENSION_get_object(ext) + if _lib.OBJ_obj2nid(obj) == _lib.NID_crl_reason: + bio = _new_mem_buf() + + print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0) + if not print_result: + print_result = _lib.M_ASN1_OCTET_STRING_print( + bio, _lib.X509_EXTENSION_get_data(ext) + ) + _openssl_assert(print_result != 0) + + return _bio_to_string(bio) + + def all_reasons(self): + """ + Return a list of all the supported reason strings. + + This list is a copy; modifying it does not change the supported reason + strings. + + :return: A list of reason strings. + :rtype: :class:`list` of :class:`bytes` + """ + return self._crl_reasons[:] + + def set_rev_date(self, when): + """ + Set the revocation timestamp. + + :param bytes when: The timestamp of the revocation, + as ASN.1 TIME. + :return: ``None`` + """ + dt = _lib.X509_REVOKED_get0_revocationDate(self._revoked) + return _set_asn1_time(dt, when) + + def get_rev_date(self): + """ + Get the revocation timestamp. + + :return: The timestamp of the revocation, as ASN.1 TIME. + :rtype: bytes + """ + dt = _lib.X509_REVOKED_get0_revocationDate(self._revoked) + return _get_asn1_time(dt) + + +class CRL(object): + """ + A certificate revocation list. + """ + + def __init__(self): + crl = _lib.X509_CRL_new() + self._crl = _ffi.gc(crl, _lib.X509_CRL_free) + + def to_cryptography(self): + """ + Export as a ``cryptography`` CRL. + + :rtype: ``cryptography.x509.CertificateRevocationList`` + + .. versionadded:: 17.1.0 + """ + from cryptography.hazmat.backends.openssl.x509 import ( + _CertificateRevocationList + ) + backend = _get_backend() + return _CertificateRevocationList(backend, self._crl) + + @classmethod + def from_cryptography(cls, crypto_crl): + """ + Construct based on a ``cryptography`` *crypto_crl*. + + :param crypto_crl: A ``cryptography`` certificate revocation list + :type crypto_crl: ``cryptography.x509.CertificateRevocationList`` + + :rtype: CRL + + .. versionadded:: 17.1.0 + """ + if not isinstance(crypto_crl, x509.CertificateRevocationList): + raise TypeError("Must be a certificate revocation list") + + crl = cls() + crl._crl = crypto_crl._x509_crl + return crl + + def get_revoked(self): + """ + Return the revocations in this certificate revocation list. + + These revocations will be provided by value, not by reference. + That means it's okay to mutate them: it won't affect this CRL. + + :return: The revocations in this CRL. + :rtype: :class:`tuple` of :class:`Revocation` + """ + results = [] + revoked_stack = _lib.X509_CRL_get_REVOKED(self._crl) + for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)): + revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i) + revoked_copy = _lib.Cryptography_X509_REVOKED_dup(revoked) + pyrev = Revoked.__new__(Revoked) + pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free) + results.append(pyrev) + if results: + return tuple(results) + + def add_revoked(self, revoked): + """ + Add a revoked (by value not reference) to the CRL structure + + This revocation will be added by value, not by reference. That + means it's okay to mutate it after adding: it won't affect + this CRL. + + :param Revoked revoked: The new revocation. + :return: ``None`` + """ + copy = _lib.Cryptography_X509_REVOKED_dup(revoked._revoked) + _openssl_assert(copy != _ffi.NULL) + + add_result = _lib.X509_CRL_add0_revoked(self._crl, copy) + _openssl_assert(add_result != 0) + + def get_issuer(self): + """ + Get the CRL's issuer. + + .. versionadded:: 16.1.0 + + :rtype: X509Name + """ + _issuer = _lib.X509_NAME_dup(_lib.X509_CRL_get_issuer(self._crl)) + _openssl_assert(_issuer != _ffi.NULL) + _issuer = _ffi.gc(_issuer, _lib.X509_NAME_free) + issuer = X509Name.__new__(X509Name) + issuer._name = _issuer + return issuer + + def set_version(self, version): + """ + Set the CRL version. + + .. versionadded:: 16.1.0 + + :param int version: The version of the CRL. + :return: ``None`` + """ + _openssl_assert(_lib.X509_CRL_set_version(self._crl, version) != 0) + + def _set_boundary_time(self, which, when): + return _set_asn1_time(which(self._crl), when) + + def set_lastUpdate(self, when): + """ + Set when the CRL was last updated. + + The timestamp is formatted as an ASN.1 TIME:: + + YYYYMMDDhhmmssZ + + .. versionadded:: 16.1.0 + + :param bytes when: A timestamp string. + :return: ``None`` + """ + return self._set_boundary_time(_lib.X509_CRL_get_lastUpdate, when) + + def set_nextUpdate(self, when): + """ + Set when the CRL will next be udpated. + + The timestamp is formatted as an ASN.1 TIME:: + + YYYYMMDDhhmmssZ + + .. versionadded:: 16.1.0 + + :param bytes when: A timestamp string. + :return: ``None`` + """ + return self._set_boundary_time(_lib.X509_CRL_get_nextUpdate, when) + + def sign(self, issuer_cert, issuer_key, digest): + """ + Sign the CRL. + + Signing a CRL enables clients to associate the CRL itself with an + issuer. Before a CRL is meaningful to other OpenSSL functions, it must + be signed by an issuer. + + This method implicitly sets the issuer's name based on the issuer + certificate and private key used to sign the CRL. + + .. versionadded:: 16.1.0 + + :param X509 issuer_cert: The issuer's certificate. + :param PKey issuer_key: The issuer's private key. + :param bytes digest: The digest method to sign the CRL with. + """ + digest_obj = _lib.EVP_get_digestbyname(digest) + _openssl_assert(digest_obj != _ffi.NULL) + _lib.X509_CRL_set_issuer_name( + self._crl, _lib.X509_get_subject_name(issuer_cert._x509)) + _lib.X509_CRL_sort(self._crl) + result = _lib.X509_CRL_sign(self._crl, issuer_key._pkey, digest_obj) + _openssl_assert(result != 0) + + def export(self, cert, key, type=FILETYPE_PEM, days=100, + digest=_UNSPECIFIED): + """ + Export the CRL as a string. + + :param X509 cert: The certificate used to sign the CRL. + :param PKey key: The key used to sign the CRL. + :param int type: The export format, either :data:`FILETYPE_PEM`, + :data:`FILETYPE_ASN1`, or :data:`FILETYPE_TEXT`. + :param int days: The number of days until the next update of this CRL. + :param bytes digest: The name of the message digest to use (eg + ``b"sha2566"``). + :rtype: bytes + """ + + if not isinstance(cert, X509): + raise TypeError("cert must be an X509 instance") + if not isinstance(key, PKey): + raise TypeError("key must be a PKey instance") + if not isinstance(type, int): + raise TypeError("type must be an integer") + + if digest is _UNSPECIFIED: + raise TypeError("digest must be provided") + + digest_obj = _lib.EVP_get_digestbyname(digest) + if digest_obj == _ffi.NULL: + raise ValueError("No such digest method") + + bio = _lib.BIO_new(_lib.BIO_s_mem()) + _openssl_assert(bio != _ffi.NULL) + + # A scratch time object to give different values to different CRL + # fields + sometime = _lib.ASN1_TIME_new() + _openssl_assert(sometime != _ffi.NULL) + + _lib.X509_gmtime_adj(sometime, 0) + _lib.X509_CRL_set_lastUpdate(self._crl, sometime) + + _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60) + _lib.X509_CRL_set_nextUpdate(self._crl, sometime) + + _lib.X509_CRL_set_issuer_name( + self._crl, _lib.X509_get_subject_name(cert._x509) + ) + + sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj) + if not sign_result: + _raise_current_error() + + return dump_crl(type, self) + + +CRLType = deprecated( + CRL, __name__, + "CRLType has been deprecated, use CRL instead", + DeprecationWarning +) + + +class PKCS7(object): + def type_is_signed(self): + """ + Check if this NID_pkcs7_signed object + + :return: True if the PKCS7 is of type signed + """ + return bool(_lib.PKCS7_type_is_signed(self._pkcs7)) + + def type_is_enveloped(self): + """ + Check if this NID_pkcs7_enveloped object + + :returns: True if the PKCS7 is of type enveloped + """ + return bool(_lib.PKCS7_type_is_enveloped(self._pkcs7)) + + def type_is_signedAndEnveloped(self): + """ + Check if this NID_pkcs7_signedAndEnveloped object + + :returns: True if the PKCS7 is of type signedAndEnveloped + """ + return bool(_lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7)) + + def type_is_data(self): + """ + Check if this NID_pkcs7_data object + + :return: True if the PKCS7 is of type data + """ + return bool(_lib.PKCS7_type_is_data(self._pkcs7)) + + def get_type_name(self): + """ + Returns the type name of the PKCS7 structure + + :return: A string with the typename + """ + nid = _lib.OBJ_obj2nid(self._pkcs7.type) + string_type = _lib.OBJ_nid2sn(nid) + return _ffi.string(string_type) + + +PKCS7Type = deprecated( + PKCS7, __name__, + "PKCS7Type has been deprecated, use PKCS7 instead", + DeprecationWarning +) + + +class PKCS12(object): + """ + A PKCS #12 archive. + """ + + def __init__(self): + self._pkey = None + self._cert = None + self._cacerts = None + self._friendlyname = None + + def get_certificate(self): + """ + Get the certificate in the PKCS #12 structure. + + :return: The certificate, or :py:const:`None` if there is none. + :rtype: :py:class:`X509` or :py:const:`None` + """ + return self._cert + + def set_certificate(self, cert): + """ + Set the certificate in the PKCS #12 structure. + + :param cert: The new certificate, or :py:const:`None` to unset it. + :type cert: :py:class:`X509` or :py:const:`None` + + :return: ``None`` + """ + if not isinstance(cert, X509): + raise TypeError("cert must be an X509 instance") + self._cert = cert + + def get_privatekey(self): + """ + Get the private key in the PKCS #12 structure. + + :return: The private key, or :py:const:`None` if there is none. + :rtype: :py:class:`PKey` + """ + return self._pkey + + def set_privatekey(self, pkey): + """ + Set the certificate portion of the PKCS #12 structure. + + :param pkey: The new private key, or :py:const:`None` to unset it. + :type pkey: :py:class:`PKey` or :py:const:`None` + + :return: ``None`` + """ + if not isinstance(pkey, PKey): + raise TypeError("pkey must be a PKey instance") + self._pkey = pkey + + def get_ca_certificates(self): + """ + Get the CA certificates in the PKCS #12 structure. + + :return: A tuple with the CA certificates in the chain, or + :py:const:`None` if there are none. + :rtype: :py:class:`tuple` of :py:class:`X509` or :py:const:`None` + """ + if self._cacerts is not None: + return tuple(self._cacerts) + + def set_ca_certificates(self, cacerts): + """ + Replace or set the CA certificates within the PKCS12 object. + + :param cacerts: The new CA certificates, or :py:const:`None` to unset + them. + :type cacerts: An iterable of :py:class:`X509` or :py:const:`None` + + :return: ``None`` + """ + if cacerts is None: + self._cacerts = None + else: + cacerts = list(cacerts) + for cert in cacerts: + if not isinstance(cert, X509): + raise TypeError( + "iterable must only contain X509 instances" + ) + self._cacerts = cacerts + + def set_friendlyname(self, name): + """ + Set the friendly name in the PKCS #12 structure. + + :param name: The new friendly name, or :py:const:`None` to unset. + :type name: :py:class:`bytes` or :py:const:`None` + + :return: ``None`` + """ + if name is None: + self._friendlyname = None + elif not isinstance(name, bytes): + raise TypeError( + "name must be a byte string or None (not %r)" % (name,) + ) + self._friendlyname = name + + def get_friendlyname(self): + """ + Get the friendly name in the PKCS# 12 structure. + + :returns: The friendly name, or :py:const:`None` if there is none. + :rtype: :py:class:`bytes` or :py:const:`None` + """ + return self._friendlyname + + def export(self, passphrase=None, iter=2048, maciter=1): + """ + Dump a PKCS12 object as a string. + + For more information, see the :c:func:`PKCS12_create` man page. + + :param passphrase: The passphrase used to encrypt the structure. Unlike + some other passphrase arguments, this *must* be a string, not a + callback. + :type passphrase: :py:data:`bytes` + + :param iter: Number of times to repeat the encryption step. + :type iter: :py:data:`int` + + :param maciter: Number of times to repeat the MAC step. + :type maciter: :py:data:`int` + + :return: The string representation of the PKCS #12 structure. + :rtype: + """ + passphrase = _text_to_bytes_and_warn("passphrase", passphrase) + + if self._cacerts is None: + cacerts = _ffi.NULL + else: + cacerts = _lib.sk_X509_new_null() + cacerts = _ffi.gc(cacerts, _lib.sk_X509_free) + for cert in self._cacerts: + _lib.sk_X509_push(cacerts, cert._x509) + + if passphrase is None: + passphrase = _ffi.NULL + + friendlyname = self._friendlyname + if friendlyname is None: + friendlyname = _ffi.NULL + + if self._pkey is None: + pkey = _ffi.NULL + else: + pkey = self._pkey._pkey + + if self._cert is None: + cert = _ffi.NULL + else: + cert = self._cert._x509 + + pkcs12 = _lib.PKCS12_create( + passphrase, friendlyname, pkey, cert, cacerts, + _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC, + _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC, + iter, maciter, 0) + if pkcs12 == _ffi.NULL: + _raise_current_error() + pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free) + + bio = _new_mem_buf() + _lib.i2d_PKCS12_bio(bio, pkcs12) + return _bio_to_string(bio) + + +PKCS12Type = deprecated( + PKCS12, __name__, + "PKCS12Type has been deprecated, use PKCS12 instead", + DeprecationWarning +) + + +class NetscapeSPKI(object): + """ + A Netscape SPKI object. + """ + + def __init__(self): + spki = _lib.NETSCAPE_SPKI_new() + self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free) + + def sign(self, pkey, digest): + """ + Sign the certificate request with this key and digest type. + + :param pkey: The private key to sign with. + :type pkey: :py:class:`PKey` + + :param digest: The message digest to use. + :type digest: :py:class:`bytes` + + :return: ``None`` + """ + if pkey._only_public: + raise ValueError("Key has only public part") + + if not pkey._initialized: + raise ValueError("Key is uninitialized") + + digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest)) + if digest_obj == _ffi.NULL: + raise ValueError("No such digest method") + + sign_result = _lib.NETSCAPE_SPKI_sign( + self._spki, pkey._pkey, digest_obj + ) + _openssl_assert(sign_result > 0) + + def verify(self, key): + """ + Verifies a signature on a certificate request. + + :param PKey key: The public key that signature is supposedly from. + + :return: ``True`` if the signature is correct. + :rtype: bool + + :raises OpenSSL.crypto.Error: If the signature is invalid, or there was + a problem verifying the signature. + """ + answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey) + if answer <= 0: + _raise_current_error() + return True + + def b64_encode(self): + """ + Generate a base64 encoded representation of this SPKI object. + + :return: The base64 encoded string. + :rtype: :py:class:`bytes` + """ + encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki) + result = _ffi.string(encoded) + _lib.OPENSSL_free(encoded) + return result + + def get_pubkey(self): + """ + Get the public key of this certificate. + + :return: The public key. + :rtype: :py:class:`PKey` + """ + pkey = PKey.__new__(PKey) + pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki) + _openssl_assert(pkey._pkey != _ffi.NULL) + pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free) + pkey._only_public = True + return pkey + + def set_pubkey(self, pkey): + """ + Set the public key of the certificate + + :param pkey: The public key + :return: ``None`` + """ + set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey) + _openssl_assert(set_result == 1) + + +NetscapeSPKIType = deprecated( + NetscapeSPKI, __name__, + "NetscapeSPKIType has been deprecated, use NetscapeSPKI instead", + DeprecationWarning +) + + +class _PassphraseHelper(object): + def __init__(self, type, passphrase, more_args=False, truncate=False): + if type != FILETYPE_PEM and passphrase is not None: + raise ValueError( + "only FILETYPE_PEM key format supports encryption" + ) + self._passphrase = passphrase + self._more_args = more_args + self._truncate = truncate + self._problems = [] + + @property + def callback(self): + if self._passphrase is None: + return _ffi.NULL + elif isinstance(self._passphrase, bytes): + return _ffi.NULL + elif callable(self._passphrase): + return _ffi.callback("pem_password_cb", self._read_passphrase) + else: + raise TypeError( + "Last argument must be a byte string or a callable." + ) + + @property + def callback_args(self): + if self._passphrase is None: + return _ffi.NULL + elif isinstance(self._passphrase, bytes): + return self._passphrase + elif callable(self._passphrase): + return _ffi.NULL + else: + raise TypeError( + "Last argument must be a byte string or a callable." + ) + + def raise_if_problem(self, exceptionType=Error): + if self._problems: + + # Flush the OpenSSL error queue + try: + _exception_from_error_queue(exceptionType) + except exceptionType: + pass + + raise self._problems.pop(0) + + def _read_passphrase(self, buf, size, rwflag, userdata): + try: + if self._more_args: + result = self._passphrase(size, rwflag, userdata) + else: + result = self._passphrase(rwflag) + if not isinstance(result, bytes): + raise ValueError("String expected") + if len(result) > size: + if self._truncate: + result = result[:size] + else: + raise ValueError( + "passphrase returned by callback is too long" + ) + for i in range(len(result)): + buf[i] = result[i:i + 1] + return len(result) + except Exception as e: + self._problems.append(e) + return 0 + + +def load_publickey(type, buffer): + """ + Load a public key from a buffer. + + :param type: The file type (one of :data:`FILETYPE_PEM`, + :data:`FILETYPE_ASN1`). + :param buffer: The buffer the key is stored in. + :type buffer: A Python string object, either unicode or bytestring. + :return: The PKey object. + :rtype: :class:`PKey` + """ + if isinstance(buffer, _text_type): + buffer = buffer.encode("ascii") + + bio = _new_mem_buf(buffer) + + if type == FILETYPE_PEM: + evp_pkey = _lib.PEM_read_bio_PUBKEY( + bio, _ffi.NULL, _ffi.NULL, _ffi.NULL) + elif type == FILETYPE_ASN1: + evp_pkey = _lib.d2i_PUBKEY_bio(bio, _ffi.NULL) + else: + raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1") + + if evp_pkey == _ffi.NULL: + _raise_current_error() + + pkey = PKey.__new__(PKey) + pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free) + pkey._only_public = True + return pkey + + +def load_privatekey(type, buffer, passphrase=None): + """ + Load a private key (PKey) from the string *buffer* encoded with the type + *type*. + + :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1) + :param buffer: The buffer the key is stored in + :param passphrase: (optional) if encrypted PEM format, this can be + either the passphrase to use, or a callback for + providing the passphrase. + + :return: The PKey object + """ + if isinstance(buffer, _text_type): + buffer = buffer.encode("ascii") + + bio = _new_mem_buf(buffer) + + helper = _PassphraseHelper(type, passphrase) + if type == FILETYPE_PEM: + evp_pkey = _lib.PEM_read_bio_PrivateKey( + bio, _ffi.NULL, helper.callback, helper.callback_args) + helper.raise_if_problem() + elif type == FILETYPE_ASN1: + evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL) + else: + raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1") + + if evp_pkey == _ffi.NULL: + _raise_current_error() + + pkey = PKey.__new__(PKey) + pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free) + return pkey + + +def dump_certificate_request(type, req): + """ + Dump the certificate request *req* into a buffer string encoded with the + type *type*. + + :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1) + :param req: The certificate request to dump + :return: The buffer with the dumped certificate request in + """ + bio = _new_mem_buf() + + if type == FILETYPE_PEM: + result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req) + elif type == FILETYPE_ASN1: + result_code = _lib.i2d_X509_REQ_bio(bio, req._req) + elif type == FILETYPE_TEXT: + result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0) + else: + raise ValueError( + "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or " + "FILETYPE_TEXT" + ) + + _openssl_assert(result_code != 0) + + return _bio_to_string(bio) + + +def load_certificate_request(type, buffer): + """ + Load a certificate request (X509Req) from the string *buffer* encoded with + the type *type*. + + :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1) + :param buffer: The buffer the certificate request is stored in + :return: The X509Req object + """ + if isinstance(buffer, _text_type): + buffer = buffer.encode("ascii") + + bio = _new_mem_buf(buffer) + + if type == FILETYPE_PEM: + req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL) + elif type == FILETYPE_ASN1: + req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL) + else: + raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1") + + _openssl_assert(req != _ffi.NULL) + + x509req = X509Req.__new__(X509Req) + x509req._req = _ffi.gc(req, _lib.X509_REQ_free) + return x509req + + +def sign(pkey, data, digest): + """ + Sign a data string using the given key and message digest. + + :param pkey: PKey to sign with + :param data: data to be signed + :param digest: message digest to use + :return: signature + + .. versionadded:: 0.11 + """ + data = _text_to_bytes_and_warn("data", data) + + digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest)) + if digest_obj == _ffi.NULL: + raise ValueError("No such digest method") + + md_ctx = _lib.Cryptography_EVP_MD_CTX_new() + md_ctx = _ffi.gc(md_ctx, _lib.Cryptography_EVP_MD_CTX_free) + + _lib.EVP_SignInit(md_ctx, digest_obj) + _lib.EVP_SignUpdate(md_ctx, data, len(data)) + + length = _lib.EVP_PKEY_size(pkey._pkey) + _openssl_assert(length > 0) + signature_buffer = _ffi.new("unsigned char[]", length) + signature_length = _ffi.new("unsigned int *") + final_result = _lib.EVP_SignFinal( + md_ctx, signature_buffer, signature_length, pkey._pkey) + _openssl_assert(final_result == 1) + + return _ffi.buffer(signature_buffer, signature_length[0])[:] + + +def verify(cert, signature, data, digest): + """ + Verify the signature for a data string. + + :param cert: signing certificate (X509 object) corresponding to the + private key which generated the signature. + :param signature: signature returned by sign function + :param data: data to be verified + :param digest: message digest to use + :return: ``None`` if the signature is correct, raise exception otherwise. + + .. versionadded:: 0.11 + """ + data = _text_to_bytes_and_warn("data", data) + + digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest)) + if digest_obj == _ffi.NULL: + raise ValueError("No such digest method") + + pkey = _lib.X509_get_pubkey(cert._x509) + _openssl_assert(pkey != _ffi.NULL) + pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free) + + md_ctx = _lib.Cryptography_EVP_MD_CTX_new() + md_ctx = _ffi.gc(md_ctx, _lib.Cryptography_EVP_MD_CTX_free) + + _lib.EVP_VerifyInit(md_ctx, digest_obj) + _lib.EVP_VerifyUpdate(md_ctx, data, len(data)) + verify_result = _lib.EVP_VerifyFinal( + md_ctx, signature, len(signature), pkey + ) + + if verify_result != 1: + _raise_current_error() + + +def dump_crl(type, crl): + """ + Dump a certificate revocation list to a buffer. + + :param type: The file type (one of ``FILETYPE_PEM``, ``FILETYPE_ASN1``, or + ``FILETYPE_TEXT``). + :param CRL crl: The CRL to dump. + + :return: The buffer with the CRL. + :rtype: bytes + """ + bio = _new_mem_buf() + + if type == FILETYPE_PEM: + ret = _lib.PEM_write_bio_X509_CRL(bio, crl._crl) + elif type == FILETYPE_ASN1: + ret = _lib.i2d_X509_CRL_bio(bio, crl._crl) + elif type == FILETYPE_TEXT: + ret = _lib.X509_CRL_print(bio, crl._crl) + else: + raise ValueError( + "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or " + "FILETYPE_TEXT") + + assert ret == 1 + return _bio_to_string(bio) + + +def load_crl(type, buffer): + """ + Load Certificate Revocation List (CRL) data from a string *buffer*. + *buffer* encoded with the type *type*. + + :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1) + :param buffer: The buffer the CRL is stored in + + :return: The PKey object + """ + if isinstance(buffer, _text_type): + buffer = buffer.encode("ascii") + + bio = _new_mem_buf(buffer) + + if type == FILETYPE_PEM: + crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL) + elif type == FILETYPE_ASN1: + crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL) + else: + raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1") + + if crl == _ffi.NULL: + _raise_current_error() + + result = CRL.__new__(CRL) + result._crl = _ffi.gc(crl, _lib.X509_CRL_free) + return result + + +def load_pkcs7_data(type, buffer): + """ + Load pkcs7 data from the string *buffer* encoded with the type + *type*. + + :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1) + :param buffer: The buffer with the pkcs7 data. + :return: The PKCS7 object + """ + if isinstance(buffer, _text_type): + buffer = buffer.encode("ascii") + + bio = _new_mem_buf(buffer) + + if type == FILETYPE_PEM: + pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL) + elif type == FILETYPE_ASN1: + pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL) + else: + raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1") + + if pkcs7 == _ffi.NULL: + _raise_current_error() + + pypkcs7 = PKCS7.__new__(PKCS7) + pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free) + return pypkcs7 + + +def load_pkcs12(buffer, passphrase=None): + """ + Load pkcs12 data from the string *buffer*. If the pkcs12 structure is + encrypted, a *passphrase* must be included. The MAC is always + checked and thus required. + + See also the man page for the C function :py:func:`PKCS12_parse`. + + :param buffer: The buffer the certificate is stored in + :param passphrase: (Optional) The password to decrypt the PKCS12 lump + :returns: The PKCS12 object + """ + passphrase = _text_to_bytes_and_warn("passphrase", passphrase) + + if isinstance(buffer, _text_type): + buffer = buffer.encode("ascii") + + bio = _new_mem_buf(buffer) + + # Use null passphrase if passphrase is None or empty string. With PKCS#12 + # password based encryption no password and a zero length password are two + # different things, but OpenSSL implementation will try both to figure out + # which one works. + if not passphrase: + passphrase = _ffi.NULL + + p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL) + if p12 == _ffi.NULL: + _raise_current_error() + p12 = _ffi.gc(p12, _lib.PKCS12_free) + + pkey = _ffi.new("EVP_PKEY**") + cert = _ffi.new("X509**") + cacerts = _ffi.new("Cryptography_STACK_OF_X509**") + + parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts) + if not parse_result: + _raise_current_error() + + cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free) + + # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the + # queue for no particular reason. This error isn't interesting to anyone + # outside this function. It's not even interesting to us. Get rid of it. + try: + _raise_current_error() + except Error: + pass + + if pkey[0] == _ffi.NULL: + pykey = None + else: + pykey = PKey.__new__(PKey) + pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free) + + if cert[0] == _ffi.NULL: + pycert = None + friendlyname = None + else: + pycert = X509._from_raw_x509_ptr(cert[0]) + + friendlyname_length = _ffi.new("int*") + friendlyname_buffer = _lib.X509_alias_get0( + cert[0], friendlyname_length + ) + friendlyname = _ffi.buffer( + friendlyname_buffer, friendlyname_length[0] + )[:] + if friendlyname_buffer == _ffi.NULL: + friendlyname = None + + pycacerts = [] + for i in range(_lib.sk_X509_num(cacerts)): + x509 = _lib.sk_X509_value(cacerts, i) + pycacert = X509._from_raw_x509_ptr(x509) + pycacerts.append(pycacert) + if not pycacerts: + pycacerts = None + + pkcs12 = PKCS12.__new__(PKCS12) + pkcs12._pkey = pykey + pkcs12._cert = pycert + pkcs12._cacerts = pycacerts + pkcs12._friendlyname = friendlyname + return pkcs12 + + +# There are no direct unit tests for this initialization. It is tested +# indirectly since it is necessary for functions like dump_privatekey when +# using encryption. +# +# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase +# and some other similar tests may fail without this (though they may not if +# the Python runtime has already done some initialization of the underlying +# OpenSSL library (and is linked against the same one that cryptography is +# using)). +_lib.OpenSSL_add_all_algorithms() + +# This is similar but exercised mainly by exception_from_error_queue. It calls +# both ERR_load_crypto_strings() and ERR_load_SSL_strings(). +_lib.SSL_load_error_strings() + + +# Set the default string mask to match OpenSSL upstream (since 2005) and +# RFC5280 recommendations. +_lib.ASN1_STRING_set_default_mask_asc(b'utf8only') diff --git a/venv/lib/python2.7/site-packages/OpenSSL/debug.py b/venv/lib/python2.7/site-packages/OpenSSL/debug.py new file mode 100644 index 0000000..0d37bf5 --- /dev/null +++ b/venv/lib/python2.7/site-packages/OpenSSL/debug.py @@ -0,0 +1,42 @@ +from __future__ import print_function + +import ssl +import sys + +import OpenSSL.SSL +import cffi +import cryptography + +from . import version + + +_env_info = u"""\ +pyOpenSSL: {pyopenssl} +cryptography: {cryptography} +cffi: {cffi} +cryptography's compiled against OpenSSL: {crypto_openssl_compile} +cryptography's linked OpenSSL: {crypto_openssl_link} +Pythons's OpenSSL: {python_openssl} +Python executable: {python} +Python version: {python_version} +Platform: {platform} +sys.path: {sys_path}""".format( + pyopenssl=version.__version__, + crypto_openssl_compile=OpenSSL._util.ffi.string( + OpenSSL._util.lib.OPENSSL_VERSION_TEXT, + ).decode("ascii"), + crypto_openssl_link=OpenSSL.SSL.SSLeay_version( + OpenSSL.SSL.SSLEAY_VERSION + ).decode("ascii"), + python_openssl=getattr(ssl, "OPENSSL_VERSION", "n/a"), + cryptography=cryptography.__version__, + cffi=cffi.__version__, + python=sys.executable, + python_version=sys.version, + platform=sys.platform, + sys_path=sys.path, +) + + +if __name__ == "__main__": + print(_env_info) diff --git a/venv/lib/python2.7/site-packages/OpenSSL/rand.py b/venv/lib/python2.7/site-packages/OpenSSL/rand.py new file mode 100644 index 0000000..d2c1767 --- /dev/null +++ b/venv/lib/python2.7/site-packages/OpenSSL/rand.py @@ -0,0 +1,40 @@ +""" +PRNG management routines, thin wrappers. +""" + +from OpenSSL._util import lib as _lib + + +def add(buffer, entropy): + """ + Mix bytes from *string* into the PRNG state. + + The *entropy* argument is (the lower bound of) an estimate of how much + randomness is contained in *string*, measured in bytes. + + For more information, see e.g. :rfc:`1750`. + + This function is only relevant if you are forking Python processes and + need to reseed the CSPRNG after fork. + + :param buffer: Buffer with random data. + :param entropy: The entropy (in bytes) measurement of the buffer. + + :return: :obj:`None` + """ + if not isinstance(buffer, bytes): + raise TypeError("buffer must be a byte string") + + if not isinstance(entropy, int): + raise TypeError("entropy must be an integer") + + _lib.RAND_add(buffer, len(buffer), entropy) + + +def status(): + """ + Check whether the PRNG has been seeded with enough data. + + :return: 1 if the PRNG is seeded enough, 0 otherwise. + """ + return _lib.RAND_status() diff --git a/venv/lib/python2.7/site-packages/OpenSSL/tsafe.py b/venv/lib/python2.7/site-packages/OpenSSL/tsafe.py new file mode 100644 index 0000000..f1c6f67 --- /dev/null +++ b/venv/lib/python2.7/site-packages/OpenSSL/tsafe.py @@ -0,0 +1,31 @@ +import warnings +from threading import RLock as _RLock + +from OpenSSL import SSL as _ssl + + +warnings.warn( + "OpenSSL.tsafe is deprecated and will be removed", + DeprecationWarning, stacklevel=3 +) + + +class Connection: + def __init__(self, *args): + self._ssl_conn = _ssl.Connection(*args) + self._lock = _RLock() + + for f in ('get_context', 'pending', 'send', 'write', 'recv', 'read', + 'renegotiate', 'bind', 'listen', 'connect', 'accept', + 'setblocking', 'fileno', 'shutdown', 'close', 'get_cipher_list', + 'getpeername', 'getsockname', 'getsockopt', 'setsockopt', + 'makefile', 'get_app_data', 'set_app_data', 'state_string', + 'sock_shutdown', 'get_peer_certificate', 'get_peer_cert_chain', + 'want_read', 'want_write', 'set_connect_state', + 'set_accept_state', 'connect_ex', 'sendall'): + exec("""def %s(self, *args): + self._lock.acquire() + try: + return self._ssl_conn.%s(*args) + finally: + self._lock.release()\n""" % (f, f)) diff --git a/venv/lib/python2.7/site-packages/OpenSSL/version.py b/venv/lib/python2.7/site-packages/OpenSSL/version.py new file mode 100644 index 0000000..4607bc4 --- /dev/null +++ b/venv/lib/python2.7/site-packages/OpenSSL/version.py @@ -0,0 +1,22 @@ +# Copyright (C) AB Strakt +# Copyright (C) Jean-Paul Calderone +# See LICENSE for details. + +""" +pyOpenSSL - A simple wrapper around the OpenSSL library +""" + +__all__ = [ + "__author__", "__copyright__", "__email__", "__license__", "__summary__", + "__title__", "__uri__", "__version__", +] + +__version__ = "18.0.0" + +__title__ = "pyOpenSSL" +__uri__ = "https://pyopenssl.org/" +__summary__ = "Python wrapper module around the OpenSSL library" +__author__ = "The pyOpenSSL developers" +__email__ = "cryptography-dev@python.org" +__license__ = "Apache License, Version 2.0" +__copyright__ = "Copyright 2001-2017 {0}".format(__author__) diff --git a/venv/lib/python2.7/site-packages/PyYAML-3.13.dist-info/INSTALLER b/venv/lib/python2.7/site-packages/PyYAML-3.13.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python2.7/site-packages/PyYAML-3.13.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python2.7/site-packages/PyYAML-3.13.dist-info/METADATA b/venv/lib/python2.7/site-packages/PyYAML-3.13.dist-info/METADATA new file mode 100644 index 0000000..e287f06 --- /dev/null +++ b/venv/lib/python2.7/site-packages/PyYAML-3.13.dist-info/METADATA @@ -0,0 +1,35 @@ +Metadata-Version: 2.1 +Name: PyYAML +Version: 3.13 +Summary: YAML parser and emitter for Python +Home-page: http://pyyaml.org/wiki/PyYAML +Author: Kirill Simonov +Author-email: xi@resolvent.net +License: MIT +Download-URL: http://pyyaml.org/download/pyyaml/PyYAML-3.13.tar.gz +Platform: Any +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Text Processing :: Markup + +YAML is a data serialization format designed for human readability +and interaction with scripting languages. PyYAML is a YAML parser +and emitter for Python. + +PyYAML features a complete YAML 1.1 parser, Unicode support, pickle +support, capable extension API, and sensible error messages. PyYAML +supports standard YAML tags and provides Python-specific tags that +allow to represent an arbitrary Python object. + +PyYAML is applicable for a broad range of tasks from complex +configuration files to object serialization and persistance. + diff --git a/venv/lib/python2.7/site-packages/PyYAML-3.13.dist-info/RECORD b/venv/lib/python2.7/site-packages/PyYAML-3.13.dist-info/RECORD new file mode 100644 index 0000000..f0c6c6a --- /dev/null +++ b/venv/lib/python2.7/site-packages/PyYAML-3.13.dist-info/RECORD @@ -0,0 +1,39 @@ +PyYAML-3.13.dist-info/METADATA,sha256=CYonKobrYoECdL2rhy8TUdOptU02BZL8BQaOGbxuudM,1424 +PyYAML-3.13.dist-info/RECORD,, +PyYAML-3.13.dist-info/WHEEL,sha256=THOELdoF0gz8Eu1fKvUoJv6AlhyCjQSuUxW0nm-XBW8,105 +PyYAML-3.13.dist-info/top_level.txt,sha256=rpj0IVMTisAjh_1vG3Ccf9v5jpCQwAz6cD1IVU5ZdhQ,11 +yaml/__init__.py,sha256=Qz7WIGATMtHvmu_vLmCcFTaiyZn5ptv2rsNGsdzlnbc,9776 +yaml/composer.py,sha256=pOjZ5afqNfH22WXyS6xlQCB2PbSrFPjK-qFPOEI76fw,4921 +yaml/constructor.py,sha256=S_Pux76-hgmgtJeJVtSvQ9ynmtEIR2jAx2ljAochKU0,25145 +yaml/cyaml.py,sha256=xK_IxkrRcetZeNwB_wzDAHYCWsumOFfsTlk3CeoM5kQ,3290 +yaml/dumper.py,sha256=ONPYNHirnLm-qCm-h9swnMWzZhncilexboIPRoNdcq4,2719 +yaml/emitter.py,sha256=Xya7zhTX3ykxMAdAgDIedejmLb1Q71W2G4yt4nTSMIM,43298 +yaml/error.py,sha256=7K-NdIv0qNKPKbnXxEg0L_b9K7nYDORr3rzm8_b-iBY,2559 +yaml/events.py,sha256=50_TksgQiE4up-lKo_V-nBy-tAIxkIPQxY5qDhKCeHw,2445 +yaml/loader.py,sha256=t_WLbw1-iWQ4KT_FUppJu30cFIU-l8NCb7bjoXJoV6A,1132 +yaml/nodes.py,sha256=gPKNj8pKCdh2d4gr3gIYINnPOaOxGhJAUiYhGRnPE84,1440 +yaml/parser.py,sha256=sgXahZA3DkySYnaC4D_zcl3l2y4Y5R40icWtdwkF_NE,25542 +yaml/reader.py,sha256=hKuxSbid1rSlfKBsshf5qaPwVduaCJA5t5S9Jum6CAA,6746 +yaml/representer.py,sha256=x3F9vDF4iiPit8sR8tgR-kjtotWTzH_Zv9moq0fMtlY,17711 +yaml/resolver.py,sha256=5Z3boiMikL6Qt6fS5Mt8fHym0GxbW7CMT2f2fnD1ZPQ,9122 +yaml/scanner.py,sha256=ft5i4fP9m0MrpKY9N8Xa24H1LqKhwGQXLG1Hd9gCSsk,52446 +yaml/serializer.py,sha256=tRsRwfu5E9fpLU7LY3vBQf2prt77hwnYlMt5dnBJLig,4171 +yaml/tokens.py,sha256=lTQIzSVw8Mg9wv459-TjiOQe6wVziqaRlqX2_89rp54,2573 +PyYAML-3.13.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +yaml/loader.pyc,, +yaml/__init__.pyc,, +yaml/reader.pyc,, +yaml/cyaml.pyc,, +yaml/resolver.pyc,, +yaml/constructor.pyc,, +yaml/scanner.pyc,, +yaml/dumper.pyc,, +yaml/serializer.pyc,, +yaml/nodes.pyc,, +yaml/events.pyc,, +yaml/representer.pyc,, +yaml/error.pyc,, +yaml/tokens.pyc,, +yaml/parser.pyc,, +yaml/composer.pyc,, +yaml/emitter.pyc,, diff --git a/venv/lib/python2.7/site-packages/PyYAML-3.13.dist-info/WHEEL b/venv/lib/python2.7/site-packages/PyYAML-3.13.dist-info/WHEEL new file mode 100644 index 0000000..eb11c88 --- /dev/null +++ b/venv/lib/python2.7/site-packages/PyYAML-3.13.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.31.1) +Root-Is-Purelib: false +Tag: cp27-cp27mu-linux_x86_64 + diff --git a/venv/lib/python2.7/site-packages/PyYAML-3.13.dist-info/top_level.txt b/venv/lib/python2.7/site-packages/PyYAML-3.13.dist-info/top_level.txt new file mode 100644 index 0000000..e6475e9 --- /dev/null +++ b/venv/lib/python2.7/site-packages/PyYAML-3.13.dist-info/top_level.txt @@ -0,0 +1,2 @@ +_yaml +yaml diff --git a/venv/lib/python2.7/site-packages/Werkzeug-0.14.1.dist-info/DESCRIPTION.rst b/venv/lib/python2.7/site-packages/Werkzeug-0.14.1.dist-info/DESCRIPTION.rst new file mode 100644 index 0000000..675f08d --- /dev/null +++ b/venv/lib/python2.7/site-packages/Werkzeug-0.14.1.dist-info/DESCRIPTION.rst @@ -0,0 +1,80 @@ +Werkzeug +======== + +Werkzeug is a comprehensive `WSGI`_ web application library. It began as +a simple collection of various utilities for WSGI applications and has +become one of the most advanced WSGI utility libraries. + +It includes: + +* An interactive debugger that allows inspecting stack traces and source + code in the browser with an interactive interpreter for any frame in + the stack. +* A full-featured request object with objects to interact with headers, + query args, form data, files, and cookies. +* A response object that can wrap other WSGI applications and handle + streaming data. +* A routing system for matching URLs to endpoints and generating URLs + for endpoints, with an extensible system for capturing variables from + URLs. +* HTTP utilities to handle entity tags, cache control, dates, user + agents, cookies, files, and more. +* A threaded WSGI server for use while developing applications locally. +* A test client for simulating HTTP requests during testing without + requiring running a server. + +Werkzeug is Unicode aware and doesn't enforce any dependencies. It is up +to the developer to choose a template engine, database adapter, and even +how to handle requests. It can be used to build all sorts of end user +applications such as blogs, wikis, or bulletin boards. + +`Flask`_ wraps Werkzeug, using it to handle the details of WSGI while +providing more structure and patterns for defining powerful +applications. + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + pip install -U Werkzeug + + +A Simple Example +---------------- + +.. code-block:: python + + from werkzeug.wrappers import Request, Response + + @Request.application + def application(request): + return Response('Hello, World!') + + if __name__ == '__main__': + from werkzeug.serving import run_simple + run_simple('localhost', 4000, application) + + +Links +----- + +* Website: https://www.palletsprojects.com/p/werkzeug/ +* Releases: https://pypi.org/project/Werkzeug/ +* Code: https://github.com/pallets/werkzeug +* Issue tracker: https://github.com/pallets/werkzeug/issues +* Test status: + + * Linux, Mac: https://travis-ci.org/pallets/werkzeug + * Windows: https://ci.appveyor.com/project/davidism/werkzeug + +* Test coverage: https://codecov.io/gh/pallets/werkzeug + +.. _WSGI: https://wsgi.readthedocs.io/en/latest/ +.. _Flask: https://www.palletsprojects.com/p/flask/ +.. _pip: https://pip.pypa.io/en/stable/quickstart/ + + diff --git a/venv/lib/python2.7/site-packages/Werkzeug-0.14.1.dist-info/INSTALLER b/venv/lib/python2.7/site-packages/Werkzeug-0.14.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python2.7/site-packages/Werkzeug-0.14.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python2.7/site-packages/Werkzeug-0.14.1.dist-info/LICENSE.txt b/venv/lib/python2.7/site-packages/Werkzeug-0.14.1.dist-info/LICENSE.txt new file mode 100644 index 0000000..1cc75bb --- /dev/null +++ b/venv/lib/python2.7/site-packages/Werkzeug-0.14.1.dist-info/LICENSE.txt @@ -0,0 +1,31 @@ +Copyright © 2007 by the Pallets team. + +Some rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/venv/lib/python2.7/site-packages/Werkzeug-0.14.1.dist-info/METADATA b/venv/lib/python2.7/site-packages/Werkzeug-0.14.1.dist-info/METADATA new file mode 100644 index 0000000..bfc3c4e --- /dev/null +++ b/venv/lib/python2.7/site-packages/Werkzeug-0.14.1.dist-info/METADATA @@ -0,0 +1,116 @@ +Metadata-Version: 2.0 +Name: Werkzeug +Version: 0.14.1 +Summary: The comprehensive WSGI web application library. +Home-page: https://www.palletsprojects.org/p/werkzeug/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +License: BSD +Description-Content-Type: UNKNOWN +Platform: any +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Provides-Extra: dev +Requires-Dist: coverage; extra == 'dev' +Requires-Dist: pytest; extra == 'dev' +Requires-Dist: sphinx; extra == 'dev' +Requires-Dist: tox; extra == 'dev' +Provides-Extra: termcolor +Requires-Dist: termcolor; extra == 'termcolor' +Provides-Extra: watchdog +Requires-Dist: watchdog; extra == 'watchdog' + +Werkzeug +======== + +Werkzeug is a comprehensive `WSGI`_ web application library. It began as +a simple collection of various utilities for WSGI applications and has +become one of the most advanced WSGI utility libraries. + +It includes: + +* An interactive debugger that allows inspecting stack traces and source + code in the browser with an interactive interpreter for any frame in + the stack. +* A full-featured request object with objects to interact with headers, + query args, form data, files, and cookies. +* A response object that can wrap other WSGI applications and handle + streaming data. +* A routing system for matching URLs to endpoints and generating URLs + for endpoints, with an extensible system for capturing variables from + URLs. +* HTTP utilities to handle entity tags, cache control, dates, user + agents, cookies, files, and more. +* A threaded WSGI server for use while developing applications locally. +* A test client for simulating HTTP requests during testing without + requiring running a server. + +Werkzeug is Unicode aware and doesn't enforce any dependencies. It is up +to the developer to choose a template engine, database adapter, and even +how to handle requests. It can be used to build all sorts of end user +applications such as blogs, wikis, or bulletin boards. + +`Flask`_ wraps Werkzeug, using it to handle the details of WSGI while +providing more structure and patterns for defining powerful +applications. + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + pip install -U Werkzeug + + +A Simple Example +---------------- + +.. code-block:: python + + from werkzeug.wrappers import Request, Response + + @Request.application + def application(request): + return Response('Hello, World!') + + if __name__ == '__main__': + from werkzeug.serving import run_simple + run_simple('localhost', 4000, application) + + +Links +----- + +* Website: https://www.palletsprojects.com/p/werkzeug/ +* Releases: https://pypi.org/project/Werkzeug/ +* Code: https://github.com/pallets/werkzeug +* Issue tracker: https://github.com/pallets/werkzeug/issues +* Test status: + + * Linux, Mac: https://travis-ci.org/pallets/werkzeug + * Windows: https://ci.appveyor.com/project/davidism/werkzeug + +* Test coverage: https://codecov.io/gh/pallets/werkzeug + +.. _WSGI: https://wsgi.readthedocs.io/en/latest/ +.. _Flask: https://www.palletsprojects.com/p/flask/ +.. _pip: https://pip.pypa.io/en/stable/quickstart/ + + diff --git a/venv/lib/python2.7/site-packages/Werkzeug-0.14.1.dist-info/RECORD b/venv/lib/python2.7/site-packages/Werkzeug-0.14.1.dist-info/RECORD new file mode 100644 index 0000000..60d1d40 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Werkzeug-0.14.1.dist-info/RECORD @@ -0,0 +1,97 @@ +Werkzeug-0.14.1.dist-info/DESCRIPTION.rst,sha256=rOCN36jwsWtWsTpqPG96z7FMilB5qI1CIARSKRuUmz8,2452 +Werkzeug-0.14.1.dist-info/LICENSE.txt,sha256=xndz_dD4m269AF9l_Xbl5V3tM1N3C1LoZC2PEPxWO-8,1534 +Werkzeug-0.14.1.dist-info/METADATA,sha256=FbfadrPdJNUWAxMOKxGUtHe5R3IDSBKYYmAz3FvI3uY,3872 +Werkzeug-0.14.1.dist-info/RECORD,, +Werkzeug-0.14.1.dist-info/WHEEL,sha256=GrqQvamwgBV4nLoJe0vhYRSWzWsx7xjlt74FT0SWYfE,110 +Werkzeug-0.14.1.dist-info/metadata.json,sha256=4489UTt6HBp2NQil95-pBkjU4Je93SMHvMxZ_rjOpqA,1452 +Werkzeug-0.14.1.dist-info/top_level.txt,sha256=QRyj2VjwJoQkrwjwFIOlB8Xg3r9un0NtqVHQF-15xaw,9 +werkzeug/__init__.py,sha256=NR0d4n_-U9BLVKlOISean3zUt2vBwhvK-AZE6M0sC0k,6842 +werkzeug/_compat.py,sha256=8c4U9o6A_TR9nKCcTbpZNxpqCXcXDVIbFawwKM2s92c,6311 +werkzeug/_internal.py,sha256=GhEyGMlsSz_tYjsDWO9TG35VN7304MM8gjKDrXLEdVc,13873 +werkzeug/_reloader.py,sha256=AyPphcOHPbu6qzW0UbrVvTDJdre5WgpxbhIJN_TqzUc,9264 +werkzeug/datastructures.py,sha256=3IgNKNqrz-ZjmAG7y3YgEYK-enDiMT_b652PsypWcYg,90080 +werkzeug/exceptions.py,sha256=3wp95Hqj9FqV8MdikV99JRcHse_fSMn27V8tgP5Hw2c,20505 +werkzeug/filesystem.py,sha256=hHWeWo_gqLMzTRfYt8-7n2wWcWUNTnDyudQDLOBEICE,2175 +werkzeug/formparser.py,sha256=mUuCwjzjb8_E4RzrAT2AioLuZSYpqR1KXTK6LScRYzA,21722 +werkzeug/http.py,sha256=RQg4MJuhRv2isNRiEh__Phh09ebpfT3Kuu_GfrZ54_c,40079 +werkzeug/local.py,sha256=QdQhWV5L8p1Y1CJ1CDStwxaUs24SuN5aebHwjVD08C8,14553 +werkzeug/posixemulation.py,sha256=xEF2Bxc-vUCPkiu4IbfWVd3LW7DROYAT-ExW6THqyzw,3519 +werkzeug/routing.py,sha256=2JVtdSgxKGeANy4Z_FP-dKESvKtkYGCZ1J2fARCLGCY,67214 +werkzeug/script.py,sha256=DwaVDcXdaOTffdNvlBdLitxWXjKaRVT32VbhDtljFPY,11365 +werkzeug/security.py,sha256=0m107exslz4QJLWQCpfQJ04z3re4eGHVggRvrQVAdWc,9193 +werkzeug/serving.py,sha256=A0flnIJHufdn2QJ9oeuHfrXwP3LzP8fn3rNW6hbxKUg,31926 +werkzeug/test.py,sha256=XmECSmnpASiYQTct4oMiWr0LT5jHWCtKqnpYKZd2ui8,36100 +werkzeug/testapp.py,sha256=3HQRW1sHZKXuAjCvFMet4KXtQG3loYTFnvn6LWt-4zI,9396 +werkzeug/urls.py,sha256=dUeLg2IeTm0WLmSvFeD4hBZWGdOs-uHudR5-t8n9zPo,36771 +werkzeug/useragents.py,sha256=BhYMf4cBTHyN4U0WsQedePIocmNlH_34C-UwqSThGCc,5865 +werkzeug/utils.py,sha256=BrY1j0DHQ8RTb0K1StIobKuMJhN9SQQkWEARbrh2qpk,22972 +werkzeug/websocket.py,sha256=PpSeDxXD_0UsPAa5hQhQNM6mxibeUgn8lA8eRqiS0vM,11344 +werkzeug/wrappers.py,sha256=kbyL_aFjxELwPgMwfNCYjKu-CR6kNkh-oO8wv3GXbk8,84511 +werkzeug/wsgi.py,sha256=1Nob-aeChWQf7MsiicO8RZt6J90iRzEcik44ev9Qu8s,49347 +werkzeug/contrib/__init__.py,sha256=f7PfttZhbrImqpr5Ezre8CXgwvcGUJK7zWNpO34WWrw,623 +werkzeug/contrib/atom.py,sha256=qqfJcfIn2RYY-3hO3Oz0aLq9YuNubcPQ_KZcNsDwVJo,15575 +werkzeug/contrib/cache.py,sha256=xBImHNj09BmX_7kC5NUCx8f_l4L8_O7zi0jCL21UZKE,32163 +werkzeug/contrib/fixers.py,sha256=gR06T-w71ur-tHQ_31kP_4jpOncPJ4Wc1dOqTvYusr8,10179 +werkzeug/contrib/iterio.py,sha256=RlqDvGhz0RneTpzE8dVc-yWCUv4nkPl1jEc_EDp2fH0,10814 +werkzeug/contrib/jsrouting.py,sha256=QTmgeDoKXvNK02KzXgx9lr3cAH6fAzpwF5bBdPNvJPs,8564 +werkzeug/contrib/limiter.py,sha256=iS8-ahPZ-JLRnmfIBzxpm7O_s3lPsiDMVWv7llAIDCI,1334 +werkzeug/contrib/lint.py,sha256=Mj9NeUN7s4zIUWeQOAVjrmtZIcl3Mm2yDe9BSIr9YGE,12558 +werkzeug/contrib/profiler.py,sha256=ISwCWvwVyGpDLRBRpLjo_qUWma6GXYBrTAco4PEQSHY,5151 +werkzeug/contrib/securecookie.py,sha256=uWMyHDHY3lkeBRiCSayGqWkAIy4a7xAbSE_Hln9ecqc,12196 +werkzeug/contrib/sessions.py,sha256=39LVNvLbm5JWpbxM79WC2l87MJFbqeISARjwYbkJatw,12577 +werkzeug/contrib/testtools.py,sha256=G9xN-qeihJlhExrIZMCahvQOIDxdL9NiX874jiiHFMs,2453 +werkzeug/contrib/wrappers.py,sha256=v7OYlz7wQtDlS9fey75UiRZ1IkUWqCpzbhsLy4k14Hw,10398 +werkzeug/debug/__init__.py,sha256=uSn9BqCZ5E3ySgpoZtundpROGsn-uYvZtSFiTfAX24M,17452 +werkzeug/debug/console.py,sha256=n3-dsKk1TsjnN-u4ZgmuWCU_HO0qw5IA7ttjhyyMM6I,5607 +werkzeug/debug/repr.py,sha256=bKqstDYGfECpeLerd48s_hxuqK4b6UWnjMu3d_DHO8I,9340 +werkzeug/debug/tbtools.py,sha256=rBudXCmkVdAKIcdhxANxgf09g6kQjJWW9_5bjSpr4OY,18451 +werkzeug/debug/shared/FONT_LICENSE,sha256=LwAVEI1oYnvXiNMT9SnCH_TaLCxCpeHziDrMg0gPkAI,4673 +werkzeug/debug/shared/console.png,sha256=bxax6RXXlvOij_KeqvSNX0ojJf83YbnZ7my-3Gx9w2A,507 +werkzeug/debug/shared/debugger.js,sha256=PKPVYuyO4SX1hkqLOwCLvmIEO5154WatFYaXE-zIfKI,6264 +werkzeug/debug/shared/jquery.js,sha256=7LkWEzqTdpEfELxcZZlS6wAx5Ff13zZ83lYO2_ujj7g,95957 +werkzeug/debug/shared/less.png,sha256=-4-kNRaXJSONVLahrQKUxMwXGm9R4OnZ9SxDGpHlIR4,191 +werkzeug/debug/shared/more.png,sha256=GngN7CioHQoV58rH6ojnkYi8c_qED2Aka5FO5UXrReY,200 +werkzeug/debug/shared/source.png,sha256=RoGcBTE4CyCB85GBuDGTFlAnUqxwTBiIfDqW15EpnUQ,818 +werkzeug/debug/shared/style.css,sha256=IEO0PC2pWmh2aEyGCaN--txuWsRCliuhlbEhPDFwh0A,6270 +werkzeug/debug/shared/ubuntu.ttf,sha256=1eaHFyepmy4FyDvjLVzpITrGEBu_CZYY94jE0nED1c0,70220 +Werkzeug-0.14.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +werkzeug/_reloader.pyc,, +werkzeug/filesystem.pyc,, +werkzeug/contrib/testtools.pyc,, +werkzeug/formparser.pyc,, +werkzeug/_compat.pyc,, +werkzeug/posixemulation.pyc,, +werkzeug/serving.pyc,, +werkzeug/contrib/__init__.pyc,, +werkzeug/contrib/iterio.pyc,, +werkzeug/test.pyc,, +werkzeug/contrib/limiter.pyc,, +werkzeug/debug/tbtools.pyc,, +werkzeug/contrib/sessions.pyc,, +werkzeug/local.pyc,, +werkzeug/utils.pyc,, +werkzeug/contrib/lint.pyc,, +werkzeug/security.pyc,, +werkzeug/contrib/cache.pyc,, +werkzeug/contrib/securecookie.pyc,, +werkzeug/script.pyc,, +werkzeug/routing.pyc,, +werkzeug/wrappers.pyc,, +werkzeug/contrib/jsrouting.pyc,, +werkzeug/contrib/fixers.pyc,, +werkzeug/contrib/profiler.pyc,, +werkzeug/debug/console.pyc,, +werkzeug/debug/__init__.pyc,, +werkzeug/wsgi.pyc,, +werkzeug/datastructures.pyc,, +werkzeug/http.pyc,, +werkzeug/urls.pyc,, +werkzeug/useragents.pyc,, +werkzeug/websocket.pyc,, +werkzeug/_internal.pyc,, +werkzeug/contrib/wrappers.pyc,, +werkzeug/exceptions.pyc,, +werkzeug/contrib/atom.pyc,, +werkzeug/__init__.pyc,, +werkzeug/testapp.pyc,, +werkzeug/debug/repr.pyc,, diff --git a/venv/lib/python2.7/site-packages/Werkzeug-0.14.1.dist-info/WHEEL b/venv/lib/python2.7/site-packages/Werkzeug-0.14.1.dist-info/WHEEL new file mode 100644 index 0000000..0de529b --- /dev/null +++ b/venv/lib/python2.7/site-packages/Werkzeug-0.14.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.26.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/lib/python2.7/site-packages/Werkzeug-0.14.1.dist-info/metadata.json b/venv/lib/python2.7/site-packages/Werkzeug-0.14.1.dist-info/metadata.json new file mode 100644 index 0000000..bca8d12 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Werkzeug-0.14.1.dist-info/metadata.json @@ -0,0 +1 @@ +{"generator": "bdist_wheel (0.26.0)", "summary": "The comprehensive WSGI web application library.", "classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules"], "description_content_type": "UNKNOWN", "extensions": {"python.details": {"project_urls": {"Home": "https://www.palletsprojects.org/p/werkzeug/"}, "contacts": [{"email": "armin.ronacher@active-4.com", "name": "Armin Ronacher", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst", "license": "LICENSE.txt"}}}, "license": "BSD", "metadata_version": "2.0", "name": "Werkzeug", "platform": "any", "extras": ["dev", "termcolor", "watchdog"], "run_requires": [{"requires": ["coverage", "pytest", "sphinx", "tox"], "extra": "dev"}, {"requires": ["termcolor"], "extra": "termcolor"}, {"requires": ["watchdog"], "extra": "watchdog"}], "version": "0.14.1"} \ No newline at end of file diff --git a/venv/lib/python2.7/site-packages/Werkzeug-0.14.1.dist-info/top_level.txt b/venv/lib/python2.7/site-packages/Werkzeug-0.14.1.dist-info/top_level.txt new file mode 100644 index 0000000..6fe8da8 --- /dev/null +++ b/venv/lib/python2.7/site-packages/Werkzeug-0.14.1.dist-info/top_level.txt @@ -0,0 +1 @@ +werkzeug diff --git a/venv/lib/python2.7/site-packages/_cffi_backend.so b/venv/lib/python2.7/site-packages/_cffi_backend.so new file mode 100755 index 0000000..7c699f1 Binary files /dev/null and b/venv/lib/python2.7/site-packages/_cffi_backend.so differ diff --git a/venv/lib/python2.7/site-packages/argh-0.26.2.dist-info/DESCRIPTION.rst b/venv/lib/python2.7/site-packages/argh-0.26.2.dist-info/DESCRIPTION.rst new file mode 100644 index 0000000..db8d16c --- /dev/null +++ b/venv/lib/python2.7/site-packages/argh-0.26.2.dist-info/DESCRIPTION.rst @@ -0,0 +1,272 @@ +Argh: The Natural CLI +===================== + +.. image:: https://img.shields.io/coveralls/neithere/argh.svg + :target: https://coveralls.io/r/neithere/argh + +.. image:: https://img.shields.io/travis/neithere/argh.svg + :target: https://travis-ci.org/neithere/argh + +.. image:: https://img.shields.io/pypi/format/argh.svg + :target: https://pypi.python.org/pypi/argh + +.. image:: https://img.shields.io/pypi/status/argh.svg + :target: https://pypi.python.org/pypi/argh + +.. image:: https://img.shields.io/pypi/v/argh.svg + :target: https://pypi.python.org/pypi/argh + +.. image:: https://img.shields.io/pypi/pyversions/argh.svg + :target: https://pypi.python.org/pypi/argh + +.. image:: https://img.shields.io/pypi/dd/argh.svg + :target: https://pypi.python.org/pypi/argh + +.. image:: https://readthedocs.org/projects/argh/badge/?version=stable + :target: http://argh.readthedocs.org/en/stable/ + +.. image:: https://readthedocs.org/projects/argh/badge/?version=latest + :target: http://argh.readthedocs.org/en/latest/ + +Building a command-line interface? Found yourself uttering "argh!" while +struggling with the API of `argparse`? Don't like the complexity but need +the power? + +.. epigraph:: + + Everything should be made as simple as possible, but no simpler. + + -- Albert Einstein (probably) + +`Argh` is a smart wrapper for `argparse`. `Argparse` is a very powerful tool; +`Argh` just makes it easy to use. + +In a nutshell +------------- + +`Argh`-powered applications are *simple* but *flexible*: + +:Modular: + Declaration of commands can be decoupled from assembling and dispatching; + +:Pythonic: + Commands are declared naturally, no complex API calls in most cases; + +:Reusable: + Commands are plain functions, can be used directly outside of CLI context; + +:Layered: + The complexity of code raises with requirements; + +:Transparent: + The full power of argparse is available whenever needed; + +:Namespaced: + Nested commands are a piece of cake, no messing with subparsers (though + they are of course used under the hood); + +:Term-Friendly: + Command output is processed with respect to stream encoding; + +:Unobtrusive: + `Argh` can dispatch a subset of pure-`argparse` code, and pure-`argparse` + code can update and dispatch a parser assembled with `Argh`; + +:DRY: + The amount of boilerplate code is minimal; among other things, `Argh` will: + + * infer command name from function name; + * infer arguments from function signature; + * infer argument type from the default value; + * infer argument action from the default value (for booleans); + * add an alias root command ``help`` for the ``--help`` argument. + +:NIH free: + `Argh` supports *completion*, *progress bars* and everything else by being + friendly to excellent 3rd-party libraries. No need to reinvent the wheel. + +Sounds good? Check the tutorial! + +Relation to argparse +-------------------- + +`Argh` is fully compatible with `argparse`. You can mix `Argh`-agnostic and +`Argh`-aware code. Just keep in mind that the dispatcher does some extra work +that a custom dispatcher may not do. + +Installation +------------ + +Using pip:: + + $ pip install argh + +Arch Linux (AUR):: + + $ yaourt python-argh + +Examples +-------- + +A very simple application with one command: + +.. code-block:: python + + import argh + + def main(): + return 'Hello world' + + argh.dispatch_command(main) + +Run it: + +.. code-block:: bash + + $ ./app.py + Hello world + +A potentially modular application with multiple commands: + +.. code-block:: python + + import argh + + # declaring: + + def echo(text): + "Returns given word as is." + return text + + def greet(name, greeting='Hello'): + "Greets the user with given name. The greeting is customizable." + return greeting + ', ' + name + + # assembling: + + parser = argh.ArghParser() + parser.add_commands([echo, greet]) + + # dispatching: + + if __name__ == '__main__': + parser.dispatch() + +Of course it works: + +.. code-block:: bash + + $ ./app.py greet Andy + Hello, Andy + + $ ./app.py greet Andy -g Arrrgh + Arrrgh, Andy + +Here's the auto-generated help for this application (note how the docstrings +are reused):: + + $ ./app.py help + + usage: app.py {echo,greet} ... + + positional arguments: + echo Returns given word as is. + greet Greets the user with given name. The greeting is customizable. + +...and for a specific command (an ordinary function signature is converted +to CLI arguments):: + + $ ./app.py help greet + + usage: app.py greet [-g GREETING] name + + Greets the user with given name. The greeting is customizable. + + positional arguments: + name + + optional arguments: + -g GREETING, --greeting GREETING 'Hello' + +(The help messages have been simplified a bit for brevity.) + +`Argh` easily maps plain Python functions to CLI. Sometimes this is not +enough; in these cases the powerful API of `argparse` is also available: + +.. code-block:: python + + @arg('text', default='hello world', nargs='+', help='The message') + def echo(text): + print text + +The approaches can be safely combined even up to this level: + +.. code-block:: python + + # adding help to `foo` which is in the function signature: + @arg('foo', help='blah') + # these are not in the signature so they go to **kwargs: + @arg('baz') + @arg('-q', '--quux') + # the function itself: + def cmd(foo, bar=1, *args, **kwargs): + yield foo + yield bar + yield ', '.join(args) + yield kwargs['baz'] + yield kwargs['quux'] + +Links +----- + +* `Project home page`_ (GitHub) +* `Documentation`_ (Read the Docs) +* `Package distribution`_ (PyPI) +* Questions, requests, bug reports, etc.: + + * `Issue tracker`_ (GitHub) + * `Mailing list`_ (subscribe to get important announcements) + * Direct e-mail (neithere at gmail com) + +.. _project home page: http://github.com/neithere/argh/ +.. _documentation: http://argh.readthedocs.org +.. _package distribution: http://pypi.python.org/pypi/argh +.. _issue tracker: http://github.com/neithere/argh/issues/ +.. _mailing list: http://groups.google.com/group/argh-users + +Author +------ + +Developed by Andrey Mikhaylenko since 2010. + +See file `AUTHORS` for a complete list of contributors to this library. + +Support +------- + +The fastest way to improve this project is to submit tested and documented +patches or detailed bug reports. + +Otherwise you can "flattr" me: |FlattrLink|_ + +.. _FlattrLink: https://flattr.com/submit/auto?user_id=neithere&url=http%3A%2F%2Fpypi.python.org%2Fpypi%2Fargh +.. |FlattrLink| image:: https://api.flattr.com/button/flattr-badge-large.png + :alt: Flattr the Argh project + +Licensing +--------- + +Argh is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published +by the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Argh 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with Argh. If not, see . + + diff --git a/venv/lib/python2.7/site-packages/argh-0.26.2.dist-info/INSTALLER b/venv/lib/python2.7/site-packages/argh-0.26.2.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python2.7/site-packages/argh-0.26.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python2.7/site-packages/argh-0.26.2.dist-info/METADATA b/venv/lib/python2.7/site-packages/argh-0.26.2.dist-info/METADATA new file mode 100644 index 0000000..64226d2 --- /dev/null +++ b/venv/lib/python2.7/site-packages/argh-0.26.2.dist-info/METADATA @@ -0,0 +1,300 @@ +Metadata-Version: 2.0 +Name: argh +Version: 0.26.2 +Summary: An unobtrusive argparse wrapper with natural syntax +Home-page: http://github.com/neithere/argh/ +Author: Andrey Mikhaylenko +Author-email: neithere@gmail.com +License: GNU Lesser General Public License (LGPL), Version 3 +Keywords: cli command line argparse optparse argument option +Platform: UNKNOWN +Classifier: Development Status :: 4 - Beta +Classifier: Environment :: Console +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: Information Technology +Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL) +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.2 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Software Development :: User Interfaces +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Provides: argh + +Argh: The Natural CLI +===================== + +.. image:: https://img.shields.io/coveralls/neithere/argh.svg + :target: https://coveralls.io/r/neithere/argh + +.. image:: https://img.shields.io/travis/neithere/argh.svg + :target: https://travis-ci.org/neithere/argh + +.. image:: https://img.shields.io/pypi/format/argh.svg + :target: https://pypi.python.org/pypi/argh + +.. image:: https://img.shields.io/pypi/status/argh.svg + :target: https://pypi.python.org/pypi/argh + +.. image:: https://img.shields.io/pypi/v/argh.svg + :target: https://pypi.python.org/pypi/argh + +.. image:: https://img.shields.io/pypi/pyversions/argh.svg + :target: https://pypi.python.org/pypi/argh + +.. image:: https://img.shields.io/pypi/dd/argh.svg + :target: https://pypi.python.org/pypi/argh + +.. image:: https://readthedocs.org/projects/argh/badge/?version=stable + :target: http://argh.readthedocs.org/en/stable/ + +.. image:: https://readthedocs.org/projects/argh/badge/?version=latest + :target: http://argh.readthedocs.org/en/latest/ + +Building a command-line interface? Found yourself uttering "argh!" while +struggling with the API of `argparse`? Don't like the complexity but need +the power? + +.. epigraph:: + + Everything should be made as simple as possible, but no simpler. + + -- Albert Einstein (probably) + +`Argh` is a smart wrapper for `argparse`. `Argparse` is a very powerful tool; +`Argh` just makes it easy to use. + +In a nutshell +------------- + +`Argh`-powered applications are *simple* but *flexible*: + +:Modular: + Declaration of commands can be decoupled from assembling and dispatching; + +:Pythonic: + Commands are declared naturally, no complex API calls in most cases; + +:Reusable: + Commands are plain functions, can be used directly outside of CLI context; + +:Layered: + The complexity of code raises with requirements; + +:Transparent: + The full power of argparse is available whenever needed; + +:Namespaced: + Nested commands are a piece of cake, no messing with subparsers (though + they are of course used under the hood); + +:Term-Friendly: + Command output is processed with respect to stream encoding; + +:Unobtrusive: + `Argh` can dispatch a subset of pure-`argparse` code, and pure-`argparse` + code can update and dispatch a parser assembled with `Argh`; + +:DRY: + The amount of boilerplate code is minimal; among other things, `Argh` will: + + * infer command name from function name; + * infer arguments from function signature; + * infer argument type from the default value; + * infer argument action from the default value (for booleans); + * add an alias root command ``help`` for the ``--help`` argument. + +:NIH free: + `Argh` supports *completion*, *progress bars* and everything else by being + friendly to excellent 3rd-party libraries. No need to reinvent the wheel. + +Sounds good? Check the tutorial! + +Relation to argparse +-------------------- + +`Argh` is fully compatible with `argparse`. You can mix `Argh`-agnostic and +`Argh`-aware code. Just keep in mind that the dispatcher does some extra work +that a custom dispatcher may not do. + +Installation +------------ + +Using pip:: + + $ pip install argh + +Arch Linux (AUR):: + + $ yaourt python-argh + +Examples +-------- + +A very simple application with one command: + +.. code-block:: python + + import argh + + def main(): + return 'Hello world' + + argh.dispatch_command(main) + +Run it: + +.. code-block:: bash + + $ ./app.py + Hello world + +A potentially modular application with multiple commands: + +.. code-block:: python + + import argh + + # declaring: + + def echo(text): + "Returns given word as is." + return text + + def greet(name, greeting='Hello'): + "Greets the user with given name. The greeting is customizable." + return greeting + ', ' + name + + # assembling: + + parser = argh.ArghParser() + parser.add_commands([echo, greet]) + + # dispatching: + + if __name__ == '__main__': + parser.dispatch() + +Of course it works: + +.. code-block:: bash + + $ ./app.py greet Andy + Hello, Andy + + $ ./app.py greet Andy -g Arrrgh + Arrrgh, Andy + +Here's the auto-generated help for this application (note how the docstrings +are reused):: + + $ ./app.py help + + usage: app.py {echo,greet} ... + + positional arguments: + echo Returns given word as is. + greet Greets the user with given name. The greeting is customizable. + +...and for a specific command (an ordinary function signature is converted +to CLI arguments):: + + $ ./app.py help greet + + usage: app.py greet [-g GREETING] name + + Greets the user with given name. The greeting is customizable. + + positional arguments: + name + + optional arguments: + -g GREETING, --greeting GREETING 'Hello' + +(The help messages have been simplified a bit for brevity.) + +`Argh` easily maps plain Python functions to CLI. Sometimes this is not +enough; in these cases the powerful API of `argparse` is also available: + +.. code-block:: python + + @arg('text', default='hello world', nargs='+', help='The message') + def echo(text): + print text + +The approaches can be safely combined even up to this level: + +.. code-block:: python + + # adding help to `foo` which is in the function signature: + @arg('foo', help='blah') + # these are not in the signature so they go to **kwargs: + @arg('baz') + @arg('-q', '--quux') + # the function itself: + def cmd(foo, bar=1, *args, **kwargs): + yield foo + yield bar + yield ', '.join(args) + yield kwargs['baz'] + yield kwargs['quux'] + +Links +----- + +* `Project home page`_ (GitHub) +* `Documentation`_ (Read the Docs) +* `Package distribution`_ (PyPI) +* Questions, requests, bug reports, etc.: + + * `Issue tracker`_ (GitHub) + * `Mailing list`_ (subscribe to get important announcements) + * Direct e-mail (neithere at gmail com) + +.. _project home page: http://github.com/neithere/argh/ +.. _documentation: http://argh.readthedocs.org +.. _package distribution: http://pypi.python.org/pypi/argh +.. _issue tracker: http://github.com/neithere/argh/issues/ +.. _mailing list: http://groups.google.com/group/argh-users + +Author +------ + +Developed by Andrey Mikhaylenko since 2010. + +See file `AUTHORS` for a complete list of contributors to this library. + +Support +------- + +The fastest way to improve this project is to submit tested and documented +patches or detailed bug reports. + +Otherwise you can "flattr" me: |FlattrLink|_ + +.. _FlattrLink: https://flattr.com/submit/auto?user_id=neithere&url=http%3A%2F%2Fpypi.python.org%2Fpypi%2Fargh +.. |FlattrLink| image:: https://api.flattr.com/button/flattr-badge-large.png + :alt: Flattr the Argh project + +Licensing +--------- + +Argh is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published +by the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Argh 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with Argh. If not, see . + + diff --git a/venv/lib/python2.7/site-packages/argh-0.26.2.dist-info/RECORD b/venv/lib/python2.7/site-packages/argh-0.26.2.dist-info/RECORD new file mode 100644 index 0000000..100c72b --- /dev/null +++ b/venv/lib/python2.7/site-packages/argh-0.26.2.dist-info/RECORD @@ -0,0 +1,31 @@ +argh/__init__.py,sha256=GemyWFY_3uaAOGEzxWtvU6trRx_s9Z5OaC7tS1Xaxn0,495 +argh/assembling.py,sha256=rHn8Qh5hKk4NhEgqA0NECja4ZnxkHM4ywMqKE5eJEVw,17555 +argh/compat.py,sha256=DThKad-IYxH-vz3DQDdObHOOwCOWvJH4H2rM4Iq_yZs,2834 +argh/completion.py,sha256=oxj9vfyI1WATZRnlwcc7m__-uwM3-Eqdi-WzR3wnMus,2943 +argh/constants.py,sha256=FpUSsGACMlGgZZuaqa79BwVROojE5ABJ2OQgkXS2e6A,3436 +argh/decorators.py,sha256=qAdU2Y2vQdIshrABdJoliNMSSOjetZN4EpkpZ3sQ0AM,6141 +argh/dispatching.py,sha256=5Bg22bf3MJZrvv3B4CtcLu_Nuq_RLLyBxkl4Vlvl4nw,12465 +argh/exceptions.py,sha256=x_UJbpOkdm-qfOdp1A4ERvPB0JkqL74GXTlXwqu6E-I,1545 +argh/helpers.py,sha256=SKAB5AQrmsXczTmL9QkzBJVlWE7zAGqwxhYvpU1menQ,2151 +argh/interaction.py,sha256=XKlTPo0lru_VYd2Jppm-LlZoW8oDVvSgqOyjPjsdzVM,2403 +argh/io.py,sha256=nfnyC53E_KYXJsCg3fEiNqHBqs-e2TC-x1KrkWVI3Vw,2986 +argh/utils.py,sha256=4yI6-_Q33m4vrthwVpFI3ZlIWGZ_bx7Tff7BGuEB1E4,1676 +argh-0.26.2.dist-info/DESCRIPTION.rst,sha256=lkRPNeZEMGOKCCfCGZ4_-2iPxLvQ3xyccMH7SUfEJ5Q,7304 +argh-0.26.2.dist-info/METADATA,sha256=opzH3aI3sMQFcRmdmcrFR14tZfX6eJYsY6fi9HhivYI,8557 +argh-0.26.2.dist-info/RECORD,, +argh-0.26.2.dist-info/WHEEL,sha256=o2k-Qa-RMNIJmUdIc7KU6VWR_ErNRbWNlxDIpl7lm34,110 +argh-0.26.2.dist-info/metadata.json,sha256=pbgTgagWaqB_H3oMqcB3xmA4mln1QBf-aAh-iGLHIUA,1408 +argh-0.26.2.dist-info/top_level.txt,sha256=KbRbUYCNA1IhMbo789mEq1eXr9-lhdgo1K6Ww_p7zM0,5 +argh-0.26.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +argh/constants.pyc,, +argh/dispatching.pyc,, +argh/interaction.pyc,, +argh/assembling.pyc,, +argh/exceptions.pyc,, +argh/io.pyc,, +argh/decorators.pyc,, +argh/compat.pyc,, +argh/__init__.pyc,, +argh/utils.pyc,, +argh/completion.pyc,, +argh/helpers.pyc,, diff --git a/venv/lib/python2.7/site-packages/argh-0.26.2.dist-info/WHEEL b/venv/lib/python2.7/site-packages/argh-0.26.2.dist-info/WHEEL new file mode 100644 index 0000000..8b6dd1b --- /dev/null +++ b/venv/lib/python2.7/site-packages/argh-0.26.2.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.29.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/lib/python2.7/site-packages/argh-0.26.2.dist-info/metadata.json b/venv/lib/python2.7/site-packages/argh-0.26.2.dist-info/metadata.json new file mode 100644 index 0000000..4b6e876 --- /dev/null +++ b/venv/lib/python2.7/site-packages/argh-0.26.2.dist-info/metadata.json @@ -0,0 +1 @@ +{"classifiers": ["Development Status :: 4 - Beta", "Environment :: Console", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: User Interfaces", "Topic :: Software Development :: Libraries :: Python Modules"], "extensions": {"python.details": {"contacts": [{"email": "neithere@gmail.com", "name": "Andrey Mikhaylenko", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "http://github.com/neithere/argh/"}}}, "generator": "bdist_wheel (0.29.0)", "keywords": ["cli", "command", "line", "argparse", "optparse", "argument", "option"], "license": "GNU Lesser General Public License (LGPL), Version 3", "metadata_version": "2.0", "name": "argh", "provides": "argh", "summary": "An unobtrusive argparse wrapper with natural syntax", "test_requires": [{"requires": ["iocapture", "mock", "pytest"]}], "version": "0.26.2"} \ No newline at end of file diff --git a/venv/lib/python2.7/site-packages/argh-0.26.2.dist-info/top_level.txt b/venv/lib/python2.7/site-packages/argh-0.26.2.dist-info/top_level.txt new file mode 100644 index 0000000..e795266 --- /dev/null +++ b/venv/lib/python2.7/site-packages/argh-0.26.2.dist-info/top_level.txt @@ -0,0 +1 @@ +argh diff --git a/venv/lib/python2.7/site-packages/argh/__init__.py b/venv/lib/python2.7/site-packages/argh/__init__.py new file mode 100644 index 0000000..481f1b4 --- /dev/null +++ b/venv/lib/python2.7/site-packages/argh/__init__.py @@ -0,0 +1,19 @@ +# coding: utf-8 +# +# Copyright © 2010—2014 Andrey Mikhaylenko and contributors +# +# This file is part of Argh. +# +# Argh is free software under terms of the GNU Lesser +# General Public License version 3 (LGPLv3) as published by the Free +# Software Foundation. See the file README.rst for copying conditions. +# +from .assembling import * +from .decorators import * +from .dispatching import * +from .exceptions import * +from .interaction import * +from .helpers import * + + +__version__ = '0.26.2' diff --git a/venv/lib/python2.7/site-packages/argh/assembling.py b/venv/lib/python2.7/site-packages/argh/assembling.py new file mode 100644 index 0000000..afe7ba7 --- /dev/null +++ b/venv/lib/python2.7/site-packages/argh/assembling.py @@ -0,0 +1,501 @@ +# coding: utf-8 +# +# Copyright © 2010—2014 Andrey Mikhaylenko and contributors +# +# This file is part of Argh. +# +# Argh is free software under terms of the GNU Lesser +# General Public License version 3 (LGPLv3) as published by the Free +# Software Foundation. See the file README.rst for copying conditions. +# +""" +Assembling +~~~~~~~~~~ + +Functions and classes to properly assemble your commands in a parser. +""" +import argparse +import sys +import warnings + +from argh.completion import COMPLETION_ENABLED +from argh.compat import OrderedDict +from argh.constants import ( + ATTR_ALIASES, + ATTR_ARGS, + ATTR_NAME, + ATTR_EXPECTS_NAMESPACE_OBJECT, + PARSER_FORMATTER, + DEFAULT_ARGUMENT_TEMPLATE, + DEST_FUNCTION, +) +from argh.utils import get_subparsers, get_arg_spec +from argh.exceptions import AssemblingError + + +__all__ = [ + 'SUPPORTS_ALIASES', + 'set_default_command', + 'add_commands', + 'add_subcommands', +] + + +def _check_support_aliases(): + p = argparse.ArgumentParser() + s = p.add_subparsers() + try: + s.add_parser('x', aliases=[]) + except TypeError: + return False + else: + return True + + +SUPPORTS_ALIASES = _check_support_aliases() +""" +Calculated on load. If `True`, current version of argparse supports +alternative command names (can be set via :func:`~argh.decorators.aliases`). +""" + + +def _get_args_from_signature(function): + if getattr(function, ATTR_EXPECTS_NAMESPACE_OBJECT, False): + return + + spec = get_arg_spec(function) + + defaults = dict(zip(*[reversed(x) for x in (spec.args, + spec.defaults or [])])) + defaults.update(getattr(spec, 'kwonlydefaults', None) or {}) + + kwonly = getattr(spec, 'kwonlyargs', []) + + if sys.version_info < (3,0): + annotations = {} + else: + annotations = dict((k,v) for k,v in function.__annotations__.items() + if isinstance(v, str)) + + # define the list of conflicting option strings + # (short forms, i.e. single-character ones) + chars = [a[0] for a in spec.args + kwonly] + char_counts = dict((char, chars.count(char)) for char in set(chars)) + conflicting_opts = tuple(char for char in char_counts + if 1 < char_counts[char]) + + for name in spec.args + kwonly: + flags = [] # name_or_flags + akwargs = {} # keyword arguments for add_argument() + + if name in annotations: + # help message: func(a : "b") -> add_argument("a", help="b") + akwargs.update(help=annotations.get(name)) + + if name in defaults or name in kwonly: + if name in defaults: + akwargs.update(default=defaults.get(name)) + else: + akwargs.update(required=True) + flags = ('-{0}'.format(name[0]), '--{0}'.format(name)) + if name.startswith(conflicting_opts): + # remove short name + flags = flags[1:] + + else: + # positional argument + flags = (name,) + + # cmd(foo_bar) -> add_argument('foo-bar') + flags = tuple(x.replace('_', '-') for x in flags) + + yield dict(option_strings=flags, **akwargs) + + if spec.varargs: + # *args + yield dict(option_strings=[spec.varargs], nargs='*') + + +def _guess(kwargs): + """ + Adds types, actions, etc. to given argument specification. + For example, ``default=3`` implies ``type=int``. + + :param arg: a :class:`argh.utils.Arg` instance + """ + guessed = {} + + # Parser actions that accept argument 'type' + TYPE_AWARE_ACTIONS = 'store', 'append' + + # guess type/action from default value + value = kwargs.get('default') + if value is not None: + if isinstance(value, bool): + if kwargs.get('action') is None: + # infer action from default value + guessed['action'] = 'store_false' if value else 'store_true' + elif kwargs.get('type') is None: + # infer type from default value + # (make sure that action handler supports this keyword) + if kwargs.get('action', 'store') in TYPE_AWARE_ACTIONS: + guessed['type'] = type(value) + + # guess type from choices (first item) + if kwargs.get('choices') and 'type' not in list(guessed) + list(kwargs): + guessed['type'] = type(kwargs['choices'][0]) + + return dict(kwargs, **guessed) + + +def _is_positional(args, prefix_chars='-'): + assert args + if 1 < len(args) or args[0][0].startswith(tuple(prefix_chars)): + return False + else: + return True + + +def _get_parser_param_kwargs(parser, argspec): + argspec = argspec.copy() # parser methods modify source data + args = argspec['option_strings'] + + if _is_positional(args, prefix_chars=parser.prefix_chars): + get_kwargs = parser._get_positional_kwargs + else: + get_kwargs = parser._get_optional_kwargs + + kwargs = get_kwargs(*args, **argspec) + + kwargs['dest'] = kwargs['dest'].replace('-', '_') + + return kwargs + + +def _get_dest(parser, argspec): + kwargs = _get_parser_param_kwargs(parser, argspec) + return kwargs['dest'] + + +def _require_support_for_default_command_with_subparsers(): + if sys.version_info < (3,4): + raise AssemblingError( + 'Argparse library bundled with this version of Python ' + 'does not support combining a default command with nested ones.') + + +def set_default_command(parser, function): + """ + Sets default command (i.e. a function) for given parser. + + If `parser.description` is empty and the function has a docstring, + it is used as the description. + + .. note:: + + An attempt to set default command to a parser which already has + subparsers (e.g. added with :func:`~argh.assembling.add_commands`) + results in a `AssemblingError`. + + .. note:: + + If there are both explicitly declared arguments (e.g. via + :func:`~argh.decorators.arg`) and ones inferred from the function + signature (e.g. via :func:`~argh.decorators.command`), declared ones + will be merged into inferred ones. If an argument does not conform + function signature, `AssemblingError` is raised. + + .. note:: + + If the parser was created with ``add_help=True`` (which is by default), + option name ``-h`` is silently removed from any argument. + + """ + if parser._subparsers: + _require_support_for_default_command_with_subparsers() + + spec = get_arg_spec(function) + + declared_args = getattr(function, ATTR_ARGS, []) + inferred_args = list(_get_args_from_signature(function)) + + if inferred_args and declared_args: + # We've got a mixture of declared and inferred arguments + + # a mapping of "dest" strings to argument declarations. + # + # * a "dest" string is a normalized form of argument name, i.e.: + # + # '-f', '--foo' → 'foo' + # 'foo-bar' → 'foo_bar' + # + # * argument declaration is a dictionary representing an argument; + # it is obtained either from _get_args_from_signature() or from + # an @arg decorator (as is). + # + dests = OrderedDict() + + for argspec in inferred_args: + dest = _get_parser_param_kwargs(parser, argspec)['dest'] + dests[dest] = argspec + + for declared_kw in declared_args: + # an argument is declared via decorator + dest = _get_dest(parser, declared_kw) + if dest in dests: + # the argument is already known from function signature + # + # now make sure that this declared arg conforms to the function + # signature and therefore only refines an inferred arg: + # + # @arg('my-foo') maps to func(my_foo) + # @arg('--my-bar') maps to func(my_bar=...) + + # either both arguments are positional or both are optional + decl_positional = _is_positional(declared_kw['option_strings']) + infr_positional = _is_positional(dests[dest]['option_strings']) + if decl_positional != infr_positional: + kinds = {True: 'positional', False: 'optional'} + raise AssemblingError( + '{func}: argument "{dest}" declared as {kind_i} ' + '(in function signature) and {kind_d} (via decorator)' + .format( + func=function.__name__, + dest=dest, + kind_i=kinds[infr_positional], + kind_d=kinds[decl_positional], + )) + + # merge explicit argument declaration into the inferred one + # (e.g. `help=...`) + dests[dest].update(**declared_kw) + else: + # the argument is not in function signature + varkw = getattr(spec, 'varkw', getattr(spec, 'keywords', [])) + if varkw: + # function accepts **kwargs; the argument goes into it + dests[dest] = declared_kw + else: + # there's no way we can map the argument declaration + # to function signature + xs = (dests[x]['option_strings'] for x in dests) + raise AssemblingError( + '{func}: argument {flags} does not fit ' + 'function signature: {sig}'.format( + flags=', '.join(declared_kw['option_strings']), + func=function.__name__, + sig=', '.join('/'.join(x) for x in xs))) + + # pack the modified data back into a list + inferred_args = dests.values() + + command_args = inferred_args or declared_args + + # add types, actions, etc. (e.g. default=3 implies type=int) + command_args = [_guess(x) for x in command_args] + + for draft in command_args: + draft = draft.copy() + if 'help' not in draft: + draft.update(help=DEFAULT_ARGUMENT_TEMPLATE) + dest_or_opt_strings = draft.pop('option_strings') + if parser.add_help and '-h' in dest_or_opt_strings: + dest_or_opt_strings = [x for x in dest_or_opt_strings if x != '-h'] + completer = draft.pop('completer', None) + try: + action = parser.add_argument(*dest_or_opt_strings, **draft) + if COMPLETION_ENABLED and completer: + action.completer = completer + except Exception as e: + raise type(e)('{func}: cannot add arg {args}: {msg}'.format( + args='/'.join(dest_or_opt_strings), func=function.__name__, msg=e)) + + if function.__doc__ and not parser.description: + parser.description = function.__doc__ + parser.set_defaults(**{ + DEST_FUNCTION: function, + }) + + +def add_commands(parser, functions, namespace=None, namespace_kwargs=None, + func_kwargs=None, + # deprecated args: + title=None, description=None, help=None): + """ + Adds given functions as commands to given parser. + + :param parser: + + an :class:`argparse.ArgumentParser` instance. + + :param functions: + + a list of functions. A subparser is created for each of them. + If the function is decorated with :func:`~argh.decorators.arg`, the + arguments are passed to :class:`argparse.ArgumentParser.add_argument`. + See also :func:`~argh.dispatching.dispatch` for requirements + concerning function signatures. The command name is inferred from the + function name. Note that the underscores in the name are replaced with + hyphens, i.e. function name "foo_bar" becomes command name "foo-bar". + + :param namespace: + + an optional string representing the group of commands. For example, if + a command named "hello" is added without the namespace, it will be + available as "prog.py hello"; if the namespace if specified as "greet", + then the command will be accessible as "prog.py greet hello". The + namespace itself is not callable, so "prog.py greet" will fail and only + display a help message. + + :param func_kwargs: + + a `dict` of keyword arguments to be passed to each nested ArgumentParser + instance created per command (i.e. per function). Members of this + dictionary have the highest priority, so a function's docstring is + overridden by a `help` in `func_kwargs` (if present). + + :param namespace_kwargs: + + a `dict` of keyword arguments to be passed to the nested ArgumentParser + instance under given `namespace`. + + Deprecated params that should be moved into `namespace_kwargs`: + + :param title: + + passed to :meth:`argparse.ArgumentParser.add_subparsers` as `title`. + + .. deprecated:: 0.26.0 + + Please use `namespace_kwargs` instead. + + :param description: + + passed to :meth:`argparse.ArgumentParser.add_subparsers` as + `description`. + + .. deprecated:: 0.26.0 + + Please use `namespace_kwargs` instead. + + :param help: + + passed to :meth:`argparse.ArgumentParser.add_subparsers` as `help`. + + .. deprecated:: 0.26.0 + + Please use `namespace_kwargs` instead. + + .. note:: + + This function modifies the parser object. Generally side effects are + bad practice but we don't seem to have any choice as ArgumentParser is + pretty opaque. + You may prefer :class:`~argh.helpers.ArghParser.add_commands` for a bit + more predictable API. + + .. note:: + + An attempt to add commands to a parser which already has a default + function (e.g. added with :func:`~argh.assembling.set_default_command`) + results in `AssemblingError`. + + """ + # FIXME "namespace" is a correct name but it clashes with the "namespace" + # that represents arguments (argparse.Namespace and our ArghNamespace). + # We should rename the argument here. + + if DEST_FUNCTION in parser._defaults: + _require_support_for_default_command_with_subparsers() + + namespace_kwargs = namespace_kwargs or {} + + # FIXME remove this by 1.0 + # + if title: + warnings.warn('argument `title` is deprecated in add_commands(),' + ' use `parser_kwargs` instead', DeprecationWarning) + namespace_kwargs['description'] = title + if help: + warnings.warn('argument `help` is deprecated in add_commands(),' + ' use `parser_kwargs` instead', DeprecationWarning) + namespace_kwargs['help'] = help + if description: + warnings.warn('argument `description` is deprecated in add_commands(),' + ' use `parser_kwargs` instead', DeprecationWarning) + namespace_kwargs['description'] = description + # + # / + + subparsers_action = get_subparsers(parser, create=True) + + if namespace: + # Make a nested parser and init a deeper _SubParsersAction under it. + + # Create a named group of commands. It will be listed along with + # root-level commands in ``app.py --help``; in that context its `title` + # can be used as a short description on the right side of its name. + # Normally `title` is shown above the list of commands + # in ``app.py my-namespace --help``. + subsubparser_kw = { + 'help': namespace_kwargs.get('title'), + } + subsubparser = subparsers_action.add_parser(namespace, **subsubparser_kw) + subparsers_action = subsubparser.add_subparsers(**namespace_kwargs) + else: + assert not namespace_kwargs, ('`parser_kwargs` only makes sense ' + 'with `namespace`.') + + for func in functions: + cmd_name, func_parser_kwargs = _extract_command_meta_from_func(func) + + # override any computed kwargs by manually supplied ones + if func_kwargs: + func_parser_kwargs.update(func_kwargs) + + # create and set up the parser for this command + command_parser = subparsers_action.add_parser(cmd_name, **func_parser_kwargs) + set_default_command(command_parser, func) + + +def _extract_command_meta_from_func(func): + # use explicitly defined name; if none, use function name (a_b → a-b) + cmd_name = getattr(func, ATTR_NAME, + func.__name__.replace('_','-')) + + func_parser_kwargs = { + + # add command help from function's docstring + 'help': func.__doc__, + + # set default formatter + 'formatter_class': PARSER_FORMATTER, + + } + + # try adding aliases for command name + if SUPPORTS_ALIASES: + func_parser_kwargs['aliases'] = getattr(func, ATTR_ALIASES, []) + + return cmd_name, func_parser_kwargs + + +def add_subcommands(parser, namespace, functions, **namespace_kwargs): + """ + A wrapper for :func:`add_commands`. + + These examples are equivalent:: + + add_commands(parser, [get, put], namespace='db', + namespace_kwargs={ + 'title': 'database commands', + 'help': 'CRUD for our silly database' + }) + + add_subcommands(parser, 'db', [get, put], + title='database commands', + help='CRUD for our silly database') + + """ + add_commands(parser, functions, namespace=namespace, + namespace_kwargs=namespace_kwargs) diff --git a/venv/lib/python2.7/site-packages/argh/compat.py b/venv/lib/python2.7/site-packages/argh/compat.py new file mode 100644 index 0000000..58c6a57 --- /dev/null +++ b/venv/lib/python2.7/site-packages/argh/compat.py @@ -0,0 +1,92 @@ +# originally inspired by "six" by Benjamin Peterson + +import inspect +import sys + + +if sys.version_info < (3,0): + text_type = unicode + binary_type = str + + import StringIO + StringIO = BytesIO = StringIO.StringIO +else: + text_type = str + binary_type = bytes + + import io + StringIO = io.StringIO + BytesIO = io.BytesIO + + +def getargspec_permissive(func): + """ + An `inspect.getargspec` with a relaxed sanity check to support Cython. + + Motivation: + + A Cython-compiled function is *not* an instance of Python's + types.FunctionType. That is the sanity check the standard Py2 + library uses in `inspect.getargspec()`. So, an exception is raised + when calling `argh.dispatch_command(cythonCompiledFunc)`. However, + the CyFunctions do have perfectly usable `.func_code` and + `.func_defaults` which is all `inspect.getargspec` needs. + + This function just copies `inspect.getargspec()` from the standard + library but relaxes the test to a more duck-typing one of having + both `.func_code` and `.func_defaults` attributes. + """ + if inspect.ismethod(func): + func = func.im_func + + # Py2 Stdlib uses isfunction(func) which is too strict for Cython-compiled + # functions though such have perfectly usable func_code, func_defaults. + if not (hasattr(func, "func_code") and hasattr(func, "func_defaults")): + raise TypeError('{!r} missing func_code or func_defaults'.format(func)) + + args, varargs, varkw = inspect.getargs(func.func_code) + return inspect.ArgSpec(args, varargs, varkw, func.func_defaults) + + +if sys.version_info < (3,0): + getargspec = getargspec_permissive +else: + # in Python 3 the basic getargspec doesn't support keyword-only arguments + # and annotations and raises ValueError if they are discovered + getargspec = inspect.getfullargspec + + +class _PrimitiveOrderedDict(dict): + """ + A poor man's OrderedDict replacement for compatibility with Python 2.6. + Implements only the basic features. May easily break if non-overloaded + methods are used. + """ + def __init__(self, *args, **kwargs): + super(_PrimitiveOrderedDict, self).__init__(*args, **kwargs) + self._seq = [] + + def __setitem__(self, key, value): + super(_PrimitiveOrderedDict, self).__setitem__(key, value) + if key not in self._seq: + self._seq.append(key) + + def __delitem__(self, key): + super(_PrimitiveOrderedDict, self).__delitem__(key) + idx = self._seq.index(key) + del self._seq[idx] + + def __iter__(self): + return iter(self._seq) + + def keys(self): + return list(self) + + def values(self): + return [self[k] for k in self] + + +try: + from collections import OrderedDict +except ImportError: + OrderedDict = _PrimitiveOrderedDict diff --git a/venv/lib/python2.7/site-packages/argh/completion.py b/venv/lib/python2.7/site-packages/argh/completion.py new file mode 100644 index 0000000..01b0818 --- /dev/null +++ b/venv/lib/python2.7/site-packages/argh/completion.py @@ -0,0 +1,94 @@ +# coding: utf-8 +# +# Copyright © 2010—2014 Andrey Mikhaylenko and contributors +# +# This file is part of Argh. +# +# Argh is free software under terms of the GNU Lesser +# General Public License version 3 (LGPLv3) as published by the Free +# Software Foundation. See the file README.rst for copying conditions. +# +""" +Shell completion +~~~~~~~~~~~~~~~~ + +Command and argument completion is a great way to reduce the number of +keystrokes and improve user experience. + +To display suggestions when you press :kbd:`tab`, a shell must obtain choices +from your program. It calls the program in a specific environment and expects +it to return a list of relevant choices. + +`Argparse` does not support completion out of the box. However, there are +3rd-party apps that do the job, such as argcomplete_ and +python-selfcompletion_. + +`Argh` supports only argcomplete_ which doesn't require subclassing +the parser and monkey-patches it instead. Combining `Argh` +with python-selfcompletion_ isn't much harder though: simply use +`SelfCompletingArgumentParser` instead of vanilla `ArgumentParser`. + +See installation details and gotchas in the documentation of the 3rd-party app +you've chosen for the completion backend. + +`Argh` automatically enables completion if argcomplete_ is available +(see :attr:`COMPLETION_ENABLED`). If completion is undesirable in given app by +design, it can be turned off by setting ``completion=False`` +in :func:`argh.dispatching.dispatch`. + +Note that you don't *have* to add completion via `Argh`; it doesn't matter +whether you let it do it for you or use the underlying API. + +.. _argcomplete: https://github.com/kislyuk/argcomplete +.. _python-selfcompletion: https://github.com/dbarnett/python-selfcompletion + +Argument-level completion +------------------------- + +Argcomplete_ supports custom "completers". The documentation suggests adding +the completer as an attribute of the argument parser action:: + + parser.add_argument("--env-var1").completer = EnvironCompleter + +However, this doesn't fit the normal `Argh`-assisted workflow. +It is recommended to use the :func:`~argh.decorators.arg` decorator:: + + @arg('--env-var1', completer=EnvironCompleter) + def func(...): + ... + +""" +import logging +import os + + +COMPLETION_ENABLED = False +""" +Dynamically set to `True` on load if argcomplete_ was successfully imported. +""" + +try: + import argcomplete +except ImportError: + pass +else: + COMPLETION_ENABLED = True + + +__all__ = ['autocomplete', 'COMPLETION_ENABLED'] + + +logger = logging.getLogger(__package__) + + +def autocomplete(parser): + """ + Adds support for shell completion via argcomplete_ by patching given + `argparse.ArgumentParser` (sub)class. + + If completion is not enabled, logs a debug-level message. + """ + if COMPLETION_ENABLED: + argcomplete.autocomplete(parser) + elif 'bash' in os.getenv('SHELL', ''): + logger.debug('Bash completion not available. Install argcomplete.') diff --git a/venv/lib/python2.7/site-packages/argh/constants.py b/venv/lib/python2.7/site-packages/argh/constants.py new file mode 100644 index 0000000..f295944 --- /dev/null +++ b/venv/lib/python2.7/site-packages/argh/constants.py @@ -0,0 +1,103 @@ +# coding: utf-8 +# +# Copyright © 2010—2014 Andrey Mikhaylenko and contributors +# +# This file is part of Argh. +# +# Argh is free software under terms of the GNU Lesser +# General Public License version 3 (LGPLv3) as published by the Free +# Software Foundation. See the file README.rst for copying conditions. +# +import argparse + +__all__ = ( + 'ATTR_NAME', 'ATTR_ALIASES', 'ATTR_ARGS', 'ATTR_WRAPPED_EXCEPTIONS', + 'ATTR_WRAPPED_EXCEPTIONS_PROCESSOR', 'ATTR_EXPECTS_NAMESPACE_OBJECT', + 'PARSER_FORMATTER', 'DEFAULT_ARGUMENT_TEMPLATE', 'DEST_FUNCTION', +) + + +# +# Names of function attributes where Argh stores command behaviour +# + +#: explicit command name (differing from function name) +ATTR_NAME = 'argh_name' + +#: alternative command names +ATTR_ALIASES = 'argh_aliases' + +#: declared arguments +ATTR_ARGS = 'argh_args' + +#: list of exception classes that should be wrapped and printed as results +ATTR_WRAPPED_EXCEPTIONS = 'argh_wrap_errors' + +#: a function to preprocess the exception object when it is wrapped +ATTR_WRAPPED_EXCEPTIONS_PROCESSOR = 'argh_wrap_errors_processor' + +#: forcing argparse.Namespace object instead of signature introspection +ATTR_EXPECTS_NAMESPACE_OBJECT = 'argh_expects_namespace_object' + +# +# Dest names in parser defaults +# + +#: dest name for a function mapped to given endpoint (goes to Namespace obj) +DEST_FUNCTION = 'function' + +# +# Other library-wide stuff +# + +class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter, + argparse.RawDescriptionHelpFormatter): + def _expand_help(self, action): + """ + This method is copied verbatim from ArgumentDefaultsHelpFormatter with + a couple of lines added just before the end. Reason: we need to + `repr()` default values instead of simply inserting them as is. + This helps notice, for example, an empty string as the default value; + moreover, it prevents breaking argparse due to logical quirks inside + of its formatters. + + Ideally this could be achieved by simply defining + :attr:`DEFAULT_ARGUMENT_TEMPLATE` as ``{default!r}`` but unfortunately + argparse only supports the old printf syntax. + """ + params = dict(vars(action), prog=self._prog) + for name in list(params): + if params[name] is argparse.SUPPRESS: + del params[name] + for name in list(params): + if hasattr(params[name], '__name__'): + params[name] = params[name].__name__ + if params.get('choices') is not None: + choices_str = ', '.join([str(c) for c in params['choices']]) + params['choices'] = choices_str + + # XXX this is added in Argh vs. argparse.ArgumentDefaultsHelpFormatter + # (avoiding empty strings, otherwise Argparse would die with + # an IndexError in _format_action) + # + if 'default' in params: + if params['default'] is None: + params['default'] = '-' + else: + params['default'] = repr(params['default']) + # + # / + + return self._get_help_string(action) % params + + +#: Default formatter to be used in implicitly instantiated ArgumentParser. +PARSER_FORMATTER = CustomFormatter + + +DEFAULT_ARGUMENT_TEMPLATE = '%(default)s' +""" +Default template of argument help message (see issue #64). +The template ``%(default)s`` is used by `argparse` to display the argument's +default value. +""" diff --git a/venv/lib/python2.7/site-packages/argh/decorators.py b/venv/lib/python2.7/site-packages/argh/decorators.py new file mode 100644 index 0000000..da176e6 --- /dev/null +++ b/venv/lib/python2.7/site-packages/argh/decorators.py @@ -0,0 +1,195 @@ +# coding: utf-8 +# +# Copyright © 2010—2014 Andrey Mikhaylenko and contributors +# +# This file is part of Argh. +# +# Argh is free software under terms of the GNU Lesser +# General Public License version 3 (LGPLv3) as published by the Free +# Software Foundation. See the file README.rst for copying conditions. +# +""" +Command decorators +~~~~~~~~~~~~~~~~~~ +""" +from argh.constants import (ATTR_ALIASES, ATTR_ARGS, ATTR_NAME, + ATTR_WRAPPED_EXCEPTIONS, + ATTR_WRAPPED_EXCEPTIONS_PROCESSOR, + ATTR_EXPECTS_NAMESPACE_OBJECT) + + +__all__ = ['aliases', 'named', 'arg', 'wrap_errors', 'expects_obj'] + + +def named(new_name): + """ + Sets given string as command name instead of the function name. + The string is used verbatim without further processing. + + Usage:: + + @named('load') + def do_load_some_stuff_and_keep_the_original_function_name(args): + ... + + The resulting command will be available only as ``load``. To add aliases + without renaming the command, check :func:`aliases`. + + .. versionadded:: 0.19 + """ + def wrapper(func): + setattr(func, ATTR_NAME, new_name) + return func + return wrapper + + +def aliases(*names): + """ + Defines alternative command name(s) for given function (along with its + original name). Usage:: + + @aliases('co', 'check') + def checkout(args): + ... + + The resulting command will be available as ``checkout``, ``check`` and ``co``. + + .. note:: + + This decorator only works with a recent version of argparse (see `Python + issue 9324`_ and `Python rev 4c0426`_). Such version ships with + **Python 3.2+** and may be available in other environments as a separate + package. Argh does not issue warnings and simply ignores aliases if + they are not supported. See :attr:`~argh.assembling.SUPPORTS_ALIASES`. + + .. _Python issue 9324: http://bugs.python.org/issue9324 + .. _Python rev 4c0426: http://hg.python.org/cpython/rev/4c0426261148/ + + .. versionadded:: 0.19 + """ + def wrapper(func): + setattr(func, ATTR_ALIASES, names) + return func + return wrapper + + +def arg(*args, **kwargs): + """ + Declares an argument for given function. Does not register the function + anywhere, nor does it modify the function in any way. + + The signature of the decorator matches that of + :meth:`argparse.ArgumentParser.add_argument`, only some keywords are not + required if they can be easily guessed (e.g. you don't have to specify type + or action when an `int` or `bool` default value is supplied). + + Typical use cases: + + - In combination with :func:`expects_obj` (which is not recommended); + - in combination with ordinary function signatures to add details that + cannot be expressed with that syntax (e.g. help message). + + Usage:: + + from argh import arg + + @arg('path', help='path to the file to load') + @arg('--format', choices=['yaml','json']) + @arg('-v', '--verbosity', choices=range(0,3), default=2) + def load(path, something=None, format='json', dry_run=False, verbosity=1): + loaders = {'json': json.load, 'yaml': yaml.load} + loader = loaders[args.format] + data = loader(args.path) + if not args.dry_run: + if verbosity < 1: + print('saving to the database') + put_to_database(data) + + In this example: + + - `path` declaration is extended with `help`; + - `format` declaration is extended with `choices`; + - `dry_run` declaration is not duplicated; + - `verbosity` is extended with `choices` and the default value is + overridden. (If both function signature and `@arg` define a default + value for an argument, `@arg` wins.) + + .. note:: + + It is recommended to avoid using this decorator unless there's no way + to tune the argument's behaviour or presentation using ordinary + function signatures. Readability counts, don't repeat yourself. + + """ + def wrapper(func): + declared_args = getattr(func, ATTR_ARGS, []) + # The innermost decorator is called first but appears last in the code. + # We need to preserve the expected order of positional arguments, so + # the outermost decorator inserts its value before the innermost's: + declared_args.insert(0, dict(option_strings=args, **kwargs)) + setattr(func, ATTR_ARGS, declared_args) + return func + return wrapper + + +def wrap_errors(errors=None, processor=None, *args): + """ + Decorator. Wraps given exceptions into + :class:`~argh.exceptions.CommandError`. Usage:: + + @wrap_errors([AssertionError]) + def foo(x=None, y=None): + assert x or y, 'x or y must be specified' + + If the assertion fails, its message will be correctly printed and the + stack hidden. This helps to avoid boilerplate code. + + :param errors: + A list of exception classes to catch. + :param processor: + A callable that expects the exception object and returns a string. + For example, this renders all wrapped errors in red colour:: + + from termcolor import colored + + def failure(err): + return colored(str(err), 'red') + + @wrap_errors(processor=failure) + def my_command(...): + ... + + """ + + def wrapper(func): + if errors: + setattr(func, ATTR_WRAPPED_EXCEPTIONS, errors) + + if processor: + setattr(func, ATTR_WRAPPED_EXCEPTIONS_PROCESSOR, processor) + + return func + return wrapper + + +def expects_obj(func): + """ + Marks given function as expecting a namespace object. + + Usage:: + + @arg('bar') + @arg('--quux', default=123) + @expects_obj + def foo(args): + yield args.bar, args.quux + + This is equivalent to:: + + def foo(bar, quux=123): + yield bar, quux + + In most cases you don't need this decorator. + """ + setattr(func, ATTR_EXPECTS_NAMESPACE_OBJECT, True) + return func diff --git a/venv/lib/python2.7/site-packages/argh/dispatching.py b/venv/lib/python2.7/site-packages/argh/dispatching.py new file mode 100644 index 0000000..78efc11 --- /dev/null +++ b/venv/lib/python2.7/site-packages/argh/dispatching.py @@ -0,0 +1,382 @@ +# coding: utf-8 +# +# Copyright © 2010—2014 Andrey Mikhaylenko and contributors +# +# This file is part of Argh. +# +# Argh is free software under terms of the GNU Lesser +# General Public License version 3 (LGPLv3) as published by the Free +# Software Foundation. See the file README.rst for copying conditions. +# +""" +Dispatching +~~~~~~~~~~~ +""" +import argparse +import sys +from types import GeneratorType + +from argh import compat, io +from argh.constants import ( + ATTR_WRAPPED_EXCEPTIONS, + ATTR_WRAPPED_EXCEPTIONS_PROCESSOR, + ATTR_EXPECTS_NAMESPACE_OBJECT, + PARSER_FORMATTER, + DEST_FUNCTION, +) +from argh.completion import autocomplete +from argh.assembling import add_commands, set_default_command +from argh.exceptions import DispatchingError, CommandError +from argh.utils import get_arg_spec + + +__all__ = ['dispatch', 'dispatch_command', 'dispatch_commands', + 'PARSER_FORMATTER', 'EntryPoint'] + + +class ArghNamespace(argparse.Namespace): + """ + A namespace object which collects the stack of functions (the + :attr:`~argh.constants.DEST_FUNCTION` arguments passed to it via + parser's defaults). + """ + def __init__(self, *args, **kw): + super(ArghNamespace, self).__init__(*args, **kw) + self._functions_stack = [] + + def __setattr__(self, k, v): + if k == DEST_FUNCTION: + # don't register the function under DEST_FUNCTION name. + # If `ArgumentParser.parse_known_args()` sees that we already have + # such attribute, it skips it. However, it goes from the topmost + # parser to subparsers. We need the function mapped to the + # subparser. So we fool the `ArgumentParser` and pretend that we + # didn't get a DEST_FUNCTION attribute; however, in fact we collect + # all its values in a stack. The last item in the stack would be + # the function mapped to the innermost parser — the one we need. + self._functions_stack.append(v) + else: + super(ArghNamespace, self).__setattr__(k, v) + + def get_function(self): + return self._functions_stack[-1] + + +def dispatch(parser, argv=None, add_help_command=True, + completion=True, pre_call=None, + output_file=sys.stdout, errors_file=sys.stderr, + raw_output=False, namespace=None, + skip_unknown_args=False): + """ + Parses given list of arguments using given parser, calls the relevant + function and prints the result. + + The target function should expect one positional argument: the + :class:`argparse.Namespace` object. However, if the function is decorated with + :func:`~argh.decorators.plain_signature`, the positional and named + arguments from the namespace object are passed to the function instead + of the object itself. + + :param parser: + + the ArgumentParser instance. + + :param argv: + + a list of strings representing the arguments. If `None`, ``sys.argv`` + is used instead. Default is `None`. + + :param add_help_command: + + if `True`, converts first positional argument "help" to a keyword + argument so that ``help foo`` becomes ``foo --help`` and displays usage + information for "foo". Default is `True`. + + :param output_file: + + A file-like object for output. If `None`, the resulting lines are + collected and returned as a string. Default is ``sys.stdout``. + + :param errors_file: + + Same as `output_file` but for ``sys.stderr``. + + :param raw_output: + + If `True`, results are written to the output file raw, without adding + whitespaces or newlines between yielded strings. Default is `False`. + + :param completion: + + If `True`, shell tab completion is enabled. Default is `True`. (You + will also need to install it.) See :mod:`argh.completion`. + + :param skip_unknown_args: + + If `True`, unknown arguments do not cause an error + (`ArgumentParser.parse_known_args` is used). + + :param namespace: + + An `argparse.Namespace`-like object. By default an + :class:`ArghNamespace` object is used. Please note that support for + combined default and nested functions may be broken if a different + type of object is forced. + + By default the exceptions are not wrapped and will propagate. The only + exception that is always wrapped is :class:`~argh.exceptions.CommandError` + which is interpreted as an expected event so the traceback is hidden. + You can also mark arbitrary exceptions as "wrappable" by using the + :func:`~argh.decorators.wrap_errors` decorator. + """ + if completion: + autocomplete(parser) + + if argv is None: + argv = sys.argv[1:] + + if add_help_command: + if argv and argv[0] == 'help': + argv.pop(0) + argv.append('--help') + + if skip_unknown_args: + parse_args = parser.parse_known_args + else: + parse_args = parser.parse_args + + if not namespace: + namespace = ArghNamespace() + + # this will raise SystemExit if parsing fails + namespace_obj = parse_args(argv, namespace=namespace) + + function = _get_function_from_namespace_obj(namespace_obj) + + if function: + lines = _execute_command(function, namespace_obj, errors_file, + pre_call=pre_call) + else: + # no commands declared, can't dispatch; display help message + lines = [parser.format_usage()] + + if output_file is None: + # user wants a string; we create an internal temporary file-like object + # and will return its contents as a string + if sys.version_info < (3,0): + f = compat.BytesIO() + else: + f = compat.StringIO() + else: + # normally this is stdout; can be any file + f = output_file + + for line in lines: + # print the line as soon as it is generated to ensure that it is + # displayed to the user before anything else happens, e.g. + # raw_input() is called + + io.dump(line, f) + if not raw_output: + # in most cases user wants one message per line + io.dump('\n', f) + + if output_file is None: + # user wanted a string; return contents of our temporary file-like obj + f.seek(0) + return f.read() + + +def _get_function_from_namespace_obj(namespace_obj): + if isinstance(namespace_obj, ArghNamespace): + # our special namespace object keeps the stack of assigned functions + try: + function = namespace_obj.get_function() + except (AttributeError, IndexError): + return None + else: + # a custom (probably vanilla) namespace object keeps the last assigned + # function; this may be wrong but at least something may work + if not hasattr(namespace_obj, DEST_FUNCTION): + return None + function = getattr(namespace_obj, DEST_FUNCTION) + + if not function or not hasattr(function, '__call__'): + return None + + return function + + +def _execute_command(function, namespace_obj, errors_file, pre_call=None): + """ + Assumes that `function` is a callable. Tries different approaches + to call it (with `namespace_obj` or with ordinary signature). + Yields the results line by line. + + If :class:`~argh.exceptions.CommandError` is raised, its message is + appended to the results (i.e. yielded by the generator as a string). + All other exceptions propagate unless marked as wrappable + by :func:`wrap_errors`. + """ + if pre_call: # XXX undocumented because I'm unsure if it's OK + # Actually used in real projects: + # * https://google.com/search?q=argh+dispatch+pre_call + # * https://github.com/neithere/argh/issues/63 + pre_call(namespace_obj) + + # the function is nested to catch certain exceptions (see below) + def _call(): + # Actually call the function + if getattr(function, ATTR_EXPECTS_NAMESPACE_OBJECT, False): + result = function(namespace_obj) + else: + # namespace -> dictionary + _flat_key = lambda key: key.replace('-', '_') + all_input = dict((_flat_key(k), v) + for k,v in vars(namespace_obj).items()) + + # filter the namespace variables so that only those expected + # by the actual function will pass + + spec = get_arg_spec(function) + + positional = [all_input[k] for k in spec.args] + kwonly = getattr(spec, 'kwonlyargs', []) + keywords = dict((k, all_input[k]) for k in kwonly) + + # *args + if spec.varargs: + positional += getattr(namespace_obj, spec.varargs) + + # **kwargs + varkw = getattr(spec, 'varkw', getattr(spec, 'keywords', [])) + if varkw: + not_kwargs = [DEST_FUNCTION] + spec.args + [spec.varargs] + kwonly + for k in vars(namespace_obj): + if k.startswith('_') or k in not_kwargs: + continue + keywords[k] = getattr(namespace_obj, k) + + result = function(*positional, **keywords) + + # Yield the results + if isinstance(result, (GeneratorType, list, tuple)): + # yield each line ASAP, convert CommandError message to a line + for line in result: + yield line + else: + # yield non-empty non-iterable result as a single line + if result is not None: + yield result + + wrappable_exceptions = [CommandError] + wrappable_exceptions += getattr(function, ATTR_WRAPPED_EXCEPTIONS, []) + + try: + result = _call() + for line in result: + yield line + except tuple(wrappable_exceptions) as e: + processor = getattr(function, ATTR_WRAPPED_EXCEPTIONS_PROCESSOR, + lambda e: '{0.__class__.__name__}: {0}'.format(e)) + + errors_file.write(compat.text_type(processor(e))) + errors_file.write('\n') + + +def dispatch_command(function, *args, **kwargs): + """ + A wrapper for :func:`dispatch` that creates a one-command parser. + Uses :attr:`PARSER_FORMATTER`. + + This:: + + dispatch_command(foo) + + ...is a shortcut for:: + + parser = ArgumentParser() + set_default_command(parser, foo) + dispatch(parser) + + This function can be also used as a decorator. + """ + parser = argparse.ArgumentParser(formatter_class=PARSER_FORMATTER) + set_default_command(parser, function) + dispatch(parser, *args, **kwargs) + + +def dispatch_commands(functions, *args, **kwargs): + """ + A wrapper for :func:`dispatch` that creates a parser, adds commands to + the parser and dispatches them. + Uses :attr:`PARSER_FORMATTER`. + + This:: + + dispatch_commands([foo, bar]) + + ...is a shortcut for:: + + parser = ArgumentParser() + add_commands(parser, [foo, bar]) + dispatch(parser) + + """ + parser = argparse.ArgumentParser(formatter_class=PARSER_FORMATTER) + add_commands(parser, functions) + dispatch(parser, *args, **kwargs) + + +class EntryPoint(object): + """ + An object to which functions can be attached and then dispatched. + + When called with an argument, the argument (a function) is registered + at this entry point as a command. + + When called without an argument, dispatching is triggered with all + previously registered commands. + + Usage:: + + from argh import EntryPoint + + app = EntryPoint('main', dict(description='This is a cool app')) + + @app + def ls(): + for i in range(10): + print i + + @app + def greet(): + print 'hello' + + if __name__ == '__main__': + app() + + """ + def __init__(self, name=None, parser_kwargs=None): + self.name = name or 'unnamed' + self.commands = [] + self.parser_kwargs = parser_kwargs or {} + + def __call__(self, f=None): + if f: + self._register_command(f) + return f + + return self._dispatch() + + def _register_command(self, f): + self.commands.append(f) + + def _dispatch(self): + if not self.commands: + raise DispatchingError('no commands for entry point "{0}"' + .format(self.name)) + + parser = argparse.ArgumentParser(**self.parser_kwargs) + add_commands(parser, self.commands) + dispatch(parser) diff --git a/venv/lib/python2.7/site-packages/argh/exceptions.py b/venv/lib/python2.7/site-packages/argh/exceptions.py new file mode 100644 index 0000000..e331826 --- /dev/null +++ b/venv/lib/python2.7/site-packages/argh/exceptions.py @@ -0,0 +1,56 @@ +# coding: utf-8 +# +# Copyright © 2010—2014 Andrey Mikhaylenko and contributors +# +# This file is part of Argh. +# +# Argh is free software under terms of the GNU Lesser +# General Public License version 3 (LGPLv3) as published by the Free +# Software Foundation. See the file README.rst for copying conditions. +# +""" +Exceptions +~~~~~~~~~~ +""" +class AssemblingError(Exception): + """ + Raised if the parser could not be configured due to malformed + or conflicting command declarations. + """ + + +class DispatchingError(Exception): + """ + Raised if the dispatching could not be completed due to misconfiguration + which could not be determined on an earlier stage. + """ + + +class CommandError(Exception): + """ + Intended to be raised from within a command. The dispatcher wraps this + exception by default and prints its message without traceback. + + Useful for print-and-exit tasks when you expect a failure and don't want + to startle the ordinary user by the cryptic output. + + Consider the following example:: + + def foo(args): + try: + ... + except KeyError as e: + print(u'Could not fetch item: {0}'.format(e)) + return + + It is exactly the same as:: + + def bar(args): + try: + ... + except KeyError as e: + raise CommandError(u'Could not fetch item: {0}'.format(e)) + + This exception can be safely used in both print-style and yield-style + commands (see :doc:`tutorial`). + """ diff --git a/venv/lib/python2.7/site-packages/argh/helpers.py b/venv/lib/python2.7/site-packages/argh/helpers.py new file mode 100644 index 0000000..3e626d8 --- /dev/null +++ b/venv/lib/python2.7/site-packages/argh/helpers.py @@ -0,0 +1,64 @@ +# coding: utf-8 +# +# Copyright © 2010—2014 Andrey Mikhaylenko and contributors +# +# This file is part of Argh. +# +# Argh is free software under terms of the GNU Lesser +# General Public License version 3 (LGPLv3) as published by the Free +# Software Foundation. See the file README.rst for copying conditions. +# +""" +Helpers +~~~~~~~ +""" +import argparse + +from argh.completion import autocomplete +from argh.assembling import add_commands, set_default_command +from argh.dispatching import PARSER_FORMATTER, ArghNamespace, dispatch + + +__all__ = ['ArghParser'] + + +class ArghParser(argparse.ArgumentParser): + """ + A subclass of :class:`ArgumentParser` with support for and a couple + of convenience methods. + + All methods are but wrappers for stand-alone functions + :func:`~argh.assembling.add_commands`, + :func:`~argh.completion.autocomplete` and + :func:`~argh.dispatching.dispatch`. + + Uses :attr:`~argh.dispatching.PARSER_FORMATTER`. + """ + def __init__(self, *args, **kwargs): + kwargs.setdefault('formatter_class', PARSER_FORMATTER) + super(ArghParser, self).__init__(*args, **kwargs) + + def set_default_command(self, *args, **kwargs): + "Wrapper for :func:`~argh.assembling.set_default_command`." + return set_default_command(self, *args, **kwargs) + + def add_commands(self, *args, **kwargs): + "Wrapper for :func:`~argh.assembling.add_commands`." + return add_commands(self, *args, **kwargs) + + def autocomplete(self): + "Wrapper for :func:`~argh.completion.autocomplete`." + return autocomplete(self) + + def dispatch(self, *args, **kwargs): + "Wrapper for :func:`~argh.dispatching.dispatch`." + return dispatch(self, *args, **kwargs) + + def parse_args(self, args=None, namespace=None): + """ + Wrapper for :meth:`argparse.ArgumentParser.parse_args`. If `namespace` + is not defined, :class:`argh.dispatching.ArghNamespace` is used. + This is required for functions to be properly used as commands. + """ + namespace = namespace or ArghNamespace() + return super(ArghParser, self).parse_args(args, namespace) diff --git a/venv/lib/python2.7/site-packages/argh/interaction.py b/venv/lib/python2.7/site-packages/argh/interaction.py new file mode 100644 index 0000000..f368ab4 --- /dev/null +++ b/venv/lib/python2.7/site-packages/argh/interaction.py @@ -0,0 +1,84 @@ +# coding: utf-8 +# +# Copyright © 2010—2014 Andrey Mikhaylenko and contributors +# +# This file is part of Argh. +# +# Argh is free software under terms of the GNU Lesser +# General Public License version 3 (LGPLv3) as published by the Free +# Software Foundation. See the file README.rst for copying conditions. +# +""" +Interaction +~~~~~~~~~~~ +""" +from argh.compat import text_type +from argh.io import safe_input + + +__all__ = ['confirm', 'safe_input'] + + +def confirm(action, default=None, skip=False): + """ + A shortcut for typical confirmation prompt. + + :param action: + + a string describing the action, e.g. "Apply changes". A question mark + will be appended. + + :param default: + + `bool` or `None`. Determines what happens when user hits :kbd:`Enter` + without typing in a choice. If `True`, default choice is "yes". If + `False`, it is "no". If `None` the prompt keeps reappearing until user + types in a choice (not necessarily acceptable) or until the number of + iteration reaches the limit. Default is `None`. + + :param skip: + + `bool`; if `True`, no interactive prompt is used and default choice is + returned (useful for batch mode). Default is `False`. + + Usage:: + + def delete(key, silent=False): + item = db.get(Item, args.key) + if confirm('Delete '+item.title, default=True, skip=silent): + item.delete() + print('Item deleted.') + else: + print('Operation cancelled.') + + Returns `None` on `KeyboardInterrupt` event. + """ + MAX_ITERATIONS = 3 + if skip: + return default + else: + defaults = { + None: ('y','n'), + True: ('Y','n'), + False: ('y','N'), + } + y, n = defaults[default] + prompt = text_type('{action}? ({y}/{n})').format(**locals()) + choice = None + try: + if default is None: + cnt = 1 + while not choice and cnt < MAX_ITERATIONS: + choice = safe_input(prompt) + cnt += 1 + else: + choice = safe_input(prompt) + except KeyboardInterrupt: + return None + if choice in ('yes', 'y', 'Y'): + return True + if choice in ('no', 'n', 'N'): + return False + if default is not None: + return default + return None diff --git a/venv/lib/python2.7/site-packages/argh/io.py b/venv/lib/python2.7/site-packages/argh/io.py new file mode 100644 index 0000000..35e9006 --- /dev/null +++ b/venv/lib/python2.7/site-packages/argh/io.py @@ -0,0 +1,105 @@ +# coding: utf-8 +# +# Copyright © 2010—2014 Andrey Mikhaylenko and contributors +# +# This file is part of Argh. +# +# Argh is free software under terms of the GNU Lesser +# General Public License version 3 (LGPLv3) as published by the Free +# Software Foundation. See the file README.rst for copying conditions. +# +""" +Output Processing +~~~~~~~~~~~~~~~~~ +""" +import locale +import sys + +from argh import compat + + +__all__ = ['dump', 'encode_output', 'safe_input'] + + +def _input(prompt): + # this function can be mocked up in tests + if sys.version_info < (3,0): + return raw_input(prompt) + else: + return input(prompt) + + +def safe_input(prompt): + """ + Prompts user for input. Correctly handles prompt message encoding. + """ + + if sys.version_info < (3,0): + if isinstance(prompt, compat.text_type): + # Python 2.x: unicode → bytes + encoding = locale.getpreferredencoding() or 'utf-8' + prompt = prompt.encode(encoding) + else: + if not isinstance(prompt, compat.text_type): + # Python 3.x: bytes → unicode + prompt = prompt.decode() + + return _input(prompt) + + +def encode_output(value, output_file): + """ + Encodes given value so it can be written to given file object. + + Value may be Unicode, binary string or any other data type. + + The exact behaviour depends on the Python version: + + Python 3.x + + `sys.stdout` is a `_io.TextIOWrapper` instance that accepts `str` + (unicode) and breaks on `bytes`. + + It is OK to simply assume that everything is Unicode unless special + handling is introduced in the client code. + + Thus, no additional processing is performed. + + Python 2.x + + `sys.stdout` is a file-like object that accepts `str` (bytes) + and breaks when `unicode` is passed to `sys.stdout.write()`. + + We can expect both Unicode and bytes. They need to be encoded so as + to match the file object encoding. + + The output is binary if the object doesn't explicitly require Unicode. + + """ + if sys.version_info > (3,0): + # Python 3: whatever → unicode + return compat.text_type(value) + else: + # Python 2: handle special cases + stream_encoding = getattr(output_file, 'encoding', None) + if stream_encoding: + if stream_encoding.upper() == 'UTF-8': + return compat.text_type(value) + else: + return value.encode(stream_encoding, 'ignore') + else: + # no explicit encoding requirements; force binary + if isinstance(value, compat.text_type): + # unicode → binary + return value.encode('utf-8') + else: + return str(value) + + +def dump(raw_data, output_file): + """ + Writes given line to given output file. + See :func:`encode_output` for details. + """ + data = encode_output(raw_data, output_file) + output_file.write(data) diff --git a/venv/lib/python2.7/site-packages/argh/utils.py b/venv/lib/python2.7/site-packages/argh/utils.py new file mode 100644 index 0000000..8650bb7 --- /dev/null +++ b/venv/lib/python2.7/site-packages/argh/utils.py @@ -0,0 +1,55 @@ +# coding: utf-8 +# +# Copyright © 2010—2014 Andrey Mikhaylenko and contributors +# +# This file is part of Argh. +# +# Argh is free software under terms of the GNU Lesser +# General Public License version 3 (LGPLv3) as published by the Free +# Software Foundation. See the file README.rst for copying conditions. +# +""" +Utilities +~~~~~~~~~ +""" +import argparse +import inspect + +from argh import compat + + +def get_subparsers(parser, create=False): + """ + Returns the :class:`argparse._SubParsersAction` instance for given + :class:`ArgumentParser` instance as would have been returned by + :meth:`ArgumentParser.add_subparsers`. The problem with the latter is that + it only works once and raises an exception on the second attempt, and the + public API seems to lack a method to get *existing* subparsers. + + :param create: + If `True`, creates the subparser if it does not exist. Default if + `False`. + + """ + # note that ArgumentParser._subparsers is *not* what is returned by + # ArgumentParser.add_subparsers(). + if parser._subparsers: + actions = [a for a in parser._actions + if isinstance(a, argparse._SubParsersAction)] + assert len(actions) == 1 + return actions[0] + else: + if create: + return parser.add_subparsers() + + +def get_arg_spec(function): + """ + Returns argument specification for given function. Omits special + arguments of instance methods (`self`) and static methods (usually `cls` + or something like this). + """ + spec = compat.getargspec(function) + if inspect.ismethod(function): + spec = spec._replace(args=spec.args[1:]) + return spec diff --git a/venv/lib/python2.7/site-packages/asn1crypto-0.24.0.dist-info/DESCRIPTION.rst b/venv/lib/python2.7/site-packages/asn1crypto-0.24.0.dist-info/DESCRIPTION.rst new file mode 100644 index 0000000..08533b5 --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto-0.24.0.dist-info/DESCRIPTION.rst @@ -0,0 +1,3 @@ +Docs for this project are maintained at https://github.com/wbond/asn1crypto#readme. + + diff --git a/venv/lib/python2.7/site-packages/asn1crypto-0.24.0.dist-info/INSTALLER b/venv/lib/python2.7/site-packages/asn1crypto-0.24.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto-0.24.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python2.7/site-packages/asn1crypto-0.24.0.dist-info/METADATA b/venv/lib/python2.7/site-packages/asn1crypto-0.24.0.dist-info/METADATA new file mode 100644 index 0000000..943af2b --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto-0.24.0.dist-info/METADATA @@ -0,0 +1,27 @@ +Metadata-Version: 2.0 +Name: asn1crypto +Version: 0.24.0 +Summary: Fast ASN.1 parser and serializer with definitions for private keys, public keys, certificates, CRL, OCSP, CMS, PKCS#3, PKCS#7, PKCS#8, PKCS#12, PKCS#5, X.509 and TSP +Home-page: https://github.com/wbond/asn1crypto +Author: wbond +Author-email: will@wbond.net +License: MIT +Description-Content-Type: UNKNOWN +Keywords: asn1 crypto pki x509 certificate rsa dsa ec dh +Platform: UNKNOWN +Classifier: Development Status :: 4 - Beta +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3.2 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Security :: Cryptography + +Docs for this project are maintained at https://github.com/wbond/asn1crypto#readme. + + diff --git a/venv/lib/python2.7/site-packages/asn1crypto-0.24.0.dist-info/RECORD b/venv/lib/python2.7/site-packages/asn1crypto-0.24.0.dist-info/RECORD new file mode 100644 index 0000000..8d9cca2 --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto-0.24.0.dist-info/RECORD @@ -0,0 +1,61 @@ +asn1crypto/__init__.py,sha256=d-HnaY-IU0N1aepUI9bYR11J2EGccGAN8kDvKMgGu78,209 +asn1crypto/_elliptic_curve.py,sha256=vdORN6l6XZyCQpA-9tdk71IrGLciAHEimOc5KsG7YNw,9419 +asn1crypto/_errors.py,sha256=YCCXkifzLkCnxo-iIO-oIWY-UuPZNbEai7z94ps8ck4,967 +asn1crypto/_ffi.py,sha256=Y4IhTLrLTxt7Xg5vcQFLAvH_Mq8xg3LTcmkIJn-G8eE,738 +asn1crypto/_inet.py,sha256=z2K8CKxSfEQ3d0UMIIgXw5NugKLZyRS__Cn10ivbiGM,4661 +asn1crypto/_int.py,sha256=I-INe1rHGsQfV6vndtD53fhyjsEOG5a6WoDY4w6M2B4,4618 +asn1crypto/_iri.py,sha256=5gG6VBG-tYAQT6lWnjvHRH-RvIStaeG_PxhyPLnL-KQ,8628 +asn1crypto/_ordereddict.py,sha256=5VAYLbxxEtfdZGKgjzINxlmNkYg9d_7JmZAFfr0EcAk,4533 +asn1crypto/_teletex_codec.py,sha256=LhDpkTprPaoc7UJ9i9uwnP-5Am00SVbHSQizPpCLpqE,5053 +asn1crypto/_types.py,sha256=OwsX30epv-ETI9eGrLW9GLqv0KeoiSRnJcjN92roqhQ,939 +asn1crypto/algos.py,sha256=zcJgP8VnZTT60ijR5-RPuhI9v4kcxrWgzv7_EjlZfW0,34095 +asn1crypto/cms.py,sha256=BOWS3bT33ZfmMpdL_yogG-3PwI2fbWEr1F7aw_5PFZo,25118 +asn1crypto/core.py,sha256=IDrq3cOH6xxc64nQcHr9LUdKvr2DU4ehd49I6k5XOcM,157260 +asn1crypto/crl.py,sha256=KJLuEn1IDJO19X4eLYhRyaM-ACnxKkimoGsyAnzGdgA,16104 +asn1crypto/csr.py,sha256=CP0tOGyHPEV3ZpnB7L4L9X-X1epD6TVixal6UAtTvLQ,2142 +asn1crypto/keys.py,sha256=fH9hBBq2buS378sKS8OYFHpRSQSOU2qCSnxqMeeGBHk,35185 +asn1crypto/ocsp.py,sha256=jF_F5-xwcATqxs-2Qpo9V83lhfDNYuZZTd4ODpKnyAM,17792 +asn1crypto/parser.py,sha256=pkyVS-BJk4mDTve0mZMUmrrUV_IHnQk9AvgtkEvfEKM,9149 +asn1crypto/pdf.py,sha256=HNybnna5WG2ftmb8Nx_T5reyLJ0E7hJXoj37DuLbpX0,2250 +asn1crypto/pem.py,sha256=s46r_KCQ9h1HENXMh4AGKTXesivQrKnWzU3-gok75uI,6145 +asn1crypto/pkcs12.py,sha256=q-KGfvaO72B8AfvolwsqhAQpjuqnkEczPddXYLBFUSE,4566 +asn1crypto/tsp.py,sha256=jpjpFmWBwX4GUVrYu9Gnk6YXRnzb-uVFvfaJSo-m_2Q,7827 +asn1crypto/util.py,sha256=m3dc7XtmQiq__uC0G2jcyHYkaJPsnm7KGAWiCXj-xio,18043 +asn1crypto/version.py,sha256=SqGlEZKUpqLOswcILajD1bITTOejwN3Jvlnw325hHjQ,154 +asn1crypto/x509.py,sha256=IGKOKTX3GWIsZhTtcpbcDkFWjpoTozNPlItYZ8pY8QA,92305 +asn1crypto/_perf/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +asn1crypto/_perf/_big_num_ctypes.py,sha256=bc1WXhoR08nB-l0mOutKldupcjybswWckOxquiXByx8,2027 +asn1crypto-0.24.0.dist-info/DESCRIPTION.rst,sha256=AKxcPr8A1r7Lgepi1zxda_bylQUpelEwT9VouCPpXFA,86 +asn1crypto-0.24.0.dist-info/METADATA,sha256=k2awXhDUj-10m5VIjPmW4_v1_g8IxusRxHuHmSikb-c,1132 +asn1crypto-0.24.0.dist-info/RECORD,, +asn1crypto-0.24.0.dist-info/WHEEL,sha256=GrqQvamwgBV4nLoJe0vhYRSWzWsx7xjlt74FT0SWYfE,110 +asn1crypto-0.24.0.dist-info/metadata.json,sha256=GWUZOttbqBGOXofIFkjNpPeItn-MlCQZLATLKFjoHL4,1177 +asn1crypto-0.24.0.dist-info/top_level.txt,sha256=z8-jF_Q-jgzGox7T2XYian3-yeptLS2I7MjoJLBaq1Y,11 +asn1crypto-0.24.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +asn1crypto/keys.pyc,, +asn1crypto/__init__.pyc,, +asn1crypto/pdf.pyc,, +asn1crypto/_int.pyc,, +asn1crypto/_inet.pyc,, +asn1crypto/_iri.pyc,, +asn1crypto/_ffi.pyc,, +asn1crypto/x509.pyc,, +asn1crypto/crl.pyc,, +asn1crypto/pem.pyc,, +asn1crypto/tsp.pyc,, +asn1crypto/_types.pyc,, +asn1crypto/parser.pyc,, +asn1crypto/_perf/_big_num_ctypes.pyc,, +asn1crypto/algos.pyc,, +asn1crypto/_elliptic_curve.pyc,, +asn1crypto/core.pyc,, +asn1crypto/cms.pyc,, +asn1crypto/_perf/__init__.pyc,, +asn1crypto/pkcs12.pyc,, +asn1crypto/csr.pyc,, +asn1crypto/_ordereddict.pyc,, +asn1crypto/ocsp.pyc,, +asn1crypto/util.pyc,, +asn1crypto/version.pyc,, +asn1crypto/_errors.pyc,, +asn1crypto/_teletex_codec.pyc,, diff --git a/venv/lib/python2.7/site-packages/asn1crypto-0.24.0.dist-info/WHEEL b/venv/lib/python2.7/site-packages/asn1crypto-0.24.0.dist-info/WHEEL new file mode 100644 index 0000000..0de529b --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto-0.24.0.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.26.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/lib/python2.7/site-packages/asn1crypto-0.24.0.dist-info/metadata.json b/venv/lib/python2.7/site-packages/asn1crypto-0.24.0.dist-info/metadata.json new file mode 100644 index 0000000..caa3c3a --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto-0.24.0.dist-info/metadata.json @@ -0,0 +1 @@ +{"generator": "bdist_wheel (0.26.0)", "summary": "Fast ASN.1 parser and serializer with definitions for private keys, public keys, certificates, CRL, OCSP, CMS, PKCS#3, PKCS#7, PKCS#8, PKCS#12, PKCS#5, X.509 and TSP", "classifiers": ["Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Security :: Cryptography"], "description_content_type": "UNKNOWN", "extensions": {"python.details": {"project_urls": {"Home": "https://github.com/wbond/asn1crypto"}, "contacts": [{"email": "will@wbond.net", "name": "wbond", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}}}, "keywords": ["asn1", "crypto", "pki", "x509", "certificate", "rsa", "dsa", "ec", "dh"], "license": "MIT", "metadata_version": "2.0", "name": "asn1crypto", "version": "0.24.0"} \ No newline at end of file diff --git a/venv/lib/python2.7/site-packages/asn1crypto-0.24.0.dist-info/top_level.txt b/venv/lib/python2.7/site-packages/asn1crypto-0.24.0.dist-info/top_level.txt new file mode 100644 index 0000000..35a704e --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto-0.24.0.dist-info/top_level.txt @@ -0,0 +1 @@ +asn1crypto diff --git a/venv/lib/python2.7/site-packages/asn1crypto/__init__.py b/venv/lib/python2.7/site-packages/asn1crypto/__init__.py new file mode 100644 index 0000000..afdeb43 --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/__init__.py @@ -0,0 +1,9 @@ +# coding: utf-8 +from __future__ import unicode_literals, division, absolute_import, print_function + +from .version import __version__, __version_info__ + +__all__ = [ + '__version__', + '__version_info__', +] diff --git a/venv/lib/python2.7/site-packages/asn1crypto/_elliptic_curve.py b/venv/lib/python2.7/site-packages/asn1crypto/_elliptic_curve.py new file mode 100644 index 0000000..8c0f12d --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/_elliptic_curve.py @@ -0,0 +1,314 @@ +# coding: utf-8 + +""" +Classes and objects to represent prime-field elliptic curves and points on them. +Exports the following items: + + - PrimeCurve() + - PrimePoint() + - SECP192R1_CURVE + - SECP192R1_BASE_POINT + - SECP224R1_CURVE + - SECP224R1_BASE_POINT + - SECP256R1_CURVE + - SECP256R1_BASE_POINT + - SECP384R1_CURVE + - SECP384R1_BASE_POINT + - SECP521R1_CURVE + - SECP521R1_BASE_POINT + +The curve constants are all PrimeCurve() objects and the base point constants +are all PrimePoint() objects. + +Some of the following source code is derived from +http://webpages.charter.net/curryfans/peter/downloads.html, but has been heavily +modified to fit into this projects lint settings. The original project license +is listed below: + +Copyright (c) 2014 Peter Pearson + +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. +""" + +from __future__ import unicode_literals, division, absolute_import, print_function + +from ._int import inverse_mod + + +class PrimeCurve(): + """ + Elliptic curve over a prime field. Characteristic two field curves are not + supported. + """ + + def __init__(self, p, a, b): + """ + The curve of points satisfying y^2 = x^3 + a*x + b (mod p) + + :param p: + The prime number as an integer + + :param a: + The component a as an integer + + :param b: + The component b as an integer + """ + + self.p = p + self.a = a + self.b = b + + def contains(self, point): + """ + :param point: + A Point object + + :return: + Boolean if the point is on this curve + """ + + y2 = point.y * point.y + x3 = point.x * point.x * point.x + return (y2 - (x3 + self.a * point.x + self.b)) % self.p == 0 + + +class PrimePoint(): + """ + A point on a prime-field elliptic curve + """ + + def __init__(self, curve, x, y, order=None): + """ + :param curve: + A PrimeCurve object + + :param x: + The x coordinate of the point as an integer + + :param y: + The y coordinate of the point as an integer + + :param order: + The order of the point, as an integer - optional + """ + + self.curve = curve + self.x = x + self.y = y + self.order = order + + # self.curve is allowed to be None only for INFINITY: + if self.curve: + if not self.curve.contains(self): + raise ValueError('Invalid EC point') + + if self.order: + if self * self.order != INFINITY: + raise ValueError('Invalid EC point') + + def __cmp__(self, other): + """ + :param other: + A PrimePoint object + + :return: + 0 if identical, 1 otherwise + """ + if self.curve == other.curve and self.x == other.x and self.y == other.y: + return 0 + else: + return 1 + + def __add__(self, other): + """ + :param other: + A PrimePoint object + + :return: + A PrimePoint object + """ + + # X9.62 B.3: + + if other == INFINITY: + return self + if self == INFINITY: + return other + assert self.curve == other.curve + if self.x == other.x: + if (self.y + other.y) % self.curve.p == 0: + return INFINITY + else: + return self.double() + + p = self.curve.p + + l_ = ((other.y - self.y) * inverse_mod(other.x - self.x, p)) % p + + x3 = (l_ * l_ - self.x - other.x) % p + y3 = (l_ * (self.x - x3) - self.y) % p + + return PrimePoint(self.curve, x3, y3) + + def __mul__(self, other): + """ + :param other: + An integer to multiple the Point by + + :return: + A PrimePoint object + """ + + def leftmost_bit(x): + assert x > 0 + result = 1 + while result <= x: + result = 2 * result + return result // 2 + + e = other + if self.order: + e = e % self.order + if e == 0: + return INFINITY + if self == INFINITY: + return INFINITY + assert e > 0 + + # From X9.62 D.3.2: + + e3 = 3 * e + negative_self = PrimePoint(self.curve, self.x, -self.y, self.order) + i = leftmost_bit(e3) // 2 + result = self + # print "Multiplying %s by %d (e3 = %d):" % ( self, other, e3 ) + while i > 1: + result = result.double() + if (e3 & i) != 0 and (e & i) == 0: + result = result + self + if (e3 & i) == 0 and (e & i) != 0: + result = result + negative_self + # print ". . . i = %d, result = %s" % ( i, result ) + i = i // 2 + + return result + + def __rmul__(self, other): + """ + :param other: + An integer to multiple the Point by + + :return: + A PrimePoint object + """ + + return self * other + + def double(self): + """ + :return: + A PrimePoint object that is twice this point + """ + + # X9.62 B.3: + + p = self.curve.p + a = self.curve.a + + l_ = ((3 * self.x * self.x + a) * inverse_mod(2 * self.y, p)) % p + + x3 = (l_ * l_ - 2 * self.x) % p + y3 = (l_ * (self.x - x3) - self.y) % p + + return PrimePoint(self.curve, x3, y3) + + +# This one point is the Point At Infinity for all purposes: +INFINITY = PrimePoint(None, None, None) + + +# NIST Curve P-192: +SECP192R1_CURVE = PrimeCurve( + 6277101735386680763835789423207666416083908700390324961279, + -3, + 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1 +) +SECP192R1_BASE_POINT = PrimePoint( + SECP192R1_CURVE, + 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012, + 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811, + 6277101735386680763835789423176059013767194773182842284081 +) + + +# NIST Curve P-224: +SECP224R1_CURVE = PrimeCurve( + 26959946667150639794667015087019630673557916260026308143510066298881, + -3, + 0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4 +) +SECP224R1_BASE_POINT = PrimePoint( + SECP224R1_CURVE, + 0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21, + 0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34, + 26959946667150639794667015087019625940457807714424391721682722368061 +) + + +# NIST Curve P-256: +SECP256R1_CURVE = PrimeCurve( + 115792089210356248762697446949407573530086143415290314195533631308867097853951, + -3, + 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b +) +SECP256R1_BASE_POINT = PrimePoint( + SECP256R1_CURVE, + 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296, + 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5, + 115792089210356248762697446949407573529996955224135760342422259061068512044369 +) + + +# NIST Curve P-384: +SECP384R1_CURVE = PrimeCurve( + 39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319, # noqa + -3, + 0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef +) +SECP384R1_BASE_POINT = PrimePoint( + SECP384R1_CURVE, + 0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7, + 0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f, + 39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942643 +) + + +# NIST Curve P-521: +SECP521R1_CURVE = PrimeCurve( + 6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151, # noqa + -3, + 0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00 # noqa +) +SECP521R1_BASE_POINT = PrimePoint( + SECP521R1_CURVE, + 0xc6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66, # noqa + 0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650, # noqa + 6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449 # noqa +) diff --git a/venv/lib/python2.7/site-packages/asn1crypto/_errors.py b/venv/lib/python2.7/site-packages/asn1crypto/_errors.py new file mode 100644 index 0000000..cc785a5 --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/_errors.py @@ -0,0 +1,45 @@ +# coding: utf-8 + +""" +Helper for formatting exception messages. Exports the following items: + + - unwrap() +""" + +from __future__ import unicode_literals, division, absolute_import, print_function + +import re +import textwrap + + +def unwrap(string, *params): + """ + Takes a multi-line string and does the following: + + - dedents + - converts newlines with text before and after into a single line + - strips leading and trailing whitespace + + :param string: + The string to format + + :param *params: + Params to interpolate into the string + + :return: + The formatted string + """ + + output = textwrap.dedent(string) + + # Unwrap lines, taking into account bulleted lists, ordered lists and + # underlines consisting of = signs + if output.find('\n') != -1: + output = re.sub('(?<=\\S)\n(?=[^ \n\t\\d\\*\\-=])', ' ', output) + + if params: + output = output % params + + output = output.strip() + + return output diff --git a/venv/lib/python2.7/site-packages/asn1crypto/_ffi.py b/venv/lib/python2.7/site-packages/asn1crypto/_ffi.py new file mode 100644 index 0000000..2a4f5bf --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/_ffi.py @@ -0,0 +1,45 @@ +# coding: utf-8 + +""" +FFI helper compatibility functions. Exports the following items: + + - LibraryNotFoundError + - FFIEngineError + - bytes_from_buffer() + - buffer_from_bytes() + - null() +""" + +from __future__ import unicode_literals, division, absolute_import, print_function + +from ctypes import create_string_buffer + + +def buffer_from_bytes(initializer): + return create_string_buffer(initializer) + + +def bytes_from_buffer(buffer, maxlen=None): + return buffer.raw + + +def null(): + return None + + +class LibraryNotFoundError(Exception): + + """ + An exception when trying to find a shared library + """ + + pass + + +class FFIEngineError(Exception): + + """ + An exception when trying to instantiate ctypes or cffi + """ + + pass diff --git a/venv/lib/python2.7/site-packages/asn1crypto/_inet.py b/venv/lib/python2.7/site-packages/asn1crypto/_inet.py new file mode 100644 index 0000000..045ba56 --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/_inet.py @@ -0,0 +1,170 @@ +# coding: utf-8 +from __future__ import unicode_literals, division, absolute_import, print_function + +import socket +import struct + +from ._errors import unwrap +from ._types import byte_cls, bytes_to_list, str_cls, type_name + + +def inet_ntop(address_family, packed_ip): + """ + Windows compatibility shim for socket.inet_ntop(). + + :param address_family: + socket.AF_INET for IPv4 or socket.AF_INET6 for IPv6 + + :param packed_ip: + A byte string of the network form of an IP address + + :return: + A unicode string of the IP address + """ + + if address_family not in set([socket.AF_INET, socket.AF_INET6]): + raise ValueError(unwrap( + ''' + address_family must be socket.AF_INET (%s) or socket.AF_INET6 (%s), + not %s + ''', + repr(socket.AF_INET), + repr(socket.AF_INET6), + repr(address_family) + )) + + if not isinstance(packed_ip, byte_cls): + raise TypeError(unwrap( + ''' + packed_ip must be a byte string, not %s + ''', + type_name(packed_ip) + )) + + required_len = 4 if address_family == socket.AF_INET else 16 + if len(packed_ip) != required_len: + raise ValueError(unwrap( + ''' + packed_ip must be %d bytes long - is %d + ''', + required_len, + len(packed_ip) + )) + + if address_family == socket.AF_INET: + return '%d.%d.%d.%d' % tuple(bytes_to_list(packed_ip)) + + octets = struct.unpack(b'!HHHHHHHH', packed_ip) + + runs_of_zero = {} + longest_run = 0 + zero_index = None + for i, octet in enumerate(octets + (-1,)): + if octet != 0: + if zero_index is not None: + length = i - zero_index + if length not in runs_of_zero: + runs_of_zero[length] = zero_index + longest_run = max(longest_run, length) + zero_index = None + elif zero_index is None: + zero_index = i + + hexed = [hex(o)[2:] for o in octets] + + if longest_run < 2: + return ':'.join(hexed) + + zero_start = runs_of_zero[longest_run] + zero_end = zero_start + longest_run + + return ':'.join(hexed[:zero_start]) + '::' + ':'.join(hexed[zero_end:]) + + +def inet_pton(address_family, ip_string): + """ + Windows compatibility shim for socket.inet_ntop(). + + :param address_family: + socket.AF_INET for IPv4 or socket.AF_INET6 for IPv6 + + :param ip_string: + A unicode string of an IP address + + :return: + A byte string of the network form of the IP address + """ + + if address_family not in set([socket.AF_INET, socket.AF_INET6]): + raise ValueError(unwrap( + ''' + address_family must be socket.AF_INET (%s) or socket.AF_INET6 (%s), + not %s + ''', + repr(socket.AF_INET), + repr(socket.AF_INET6), + repr(address_family) + )) + + if not isinstance(ip_string, str_cls): + raise TypeError(unwrap( + ''' + ip_string must be a unicode string, not %s + ''', + type_name(ip_string) + )) + + if address_family == socket.AF_INET: + octets = ip_string.split('.') + error = len(octets) != 4 + if not error: + ints = [] + for o in octets: + o = int(o) + if o > 255 or o < 0: + error = True + break + ints.append(o) + + if error: + raise ValueError(unwrap( + ''' + ip_string must be a dotted string with four integers in the + range of 0 to 255, got %s + ''', + repr(ip_string) + )) + + return struct.pack(b'!BBBB', *ints) + + error = False + omitted = ip_string.count('::') + if omitted > 1: + error = True + elif omitted == 0: + octets = ip_string.split(':') + error = len(octets) != 8 + else: + begin, end = ip_string.split('::') + begin_octets = begin.split(':') + end_octets = end.split(':') + missing = 8 - len(begin_octets) - len(end_octets) + octets = begin_octets + (['0'] * missing) + end_octets + + if not error: + ints = [] + for o in octets: + o = int(o, 16) + if o > 65535 or o < 0: + error = True + break + ints.append(o) + + return struct.pack(b'!HHHHHHHH', *ints) + + raise ValueError(unwrap( + ''' + ip_string must be a valid ipv6 string, got %s + ''', + repr(ip_string) + )) diff --git a/venv/lib/python2.7/site-packages/asn1crypto/_int.py b/venv/lib/python2.7/site-packages/asn1crypto/_int.py new file mode 100644 index 0000000..d0c2319 --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/_int.py @@ -0,0 +1,159 @@ +# coding: utf-8 + +""" +Function for calculating the modular inverse. Exports the following items: + + - inverse_mod() + +Source code is derived from +http://webpages.charter.net/curryfans/peter/downloads.html, but has been heavily +modified to fit into this projects lint settings. The original project license +is listed below: + +Copyright (c) 2014 Peter Pearson + +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. +""" + +from __future__ import unicode_literals, division, absolute_import, print_function + +import math +import platform + +from .util import int_to_bytes, int_from_bytes + +# First try to use ctypes with OpenSSL for better performance +try: + from ._ffi import ( + buffer_from_bytes, + bytes_from_buffer, + FFIEngineError, + LibraryNotFoundError, + null, + ) + + # Some versions of PyPy have segfault issues, so we just punt on PyPy + if platform.python_implementation() == 'PyPy': + raise EnvironmentError() + + try: + from ._perf._big_num_ctypes import libcrypto + + def inverse_mod(a, p): + """ + Compute the modular inverse of a (mod p) + + :param a: + An integer + + :param p: + An integer + + :return: + An integer + """ + + ctx = libcrypto.BN_CTX_new() + + a_bytes = int_to_bytes(abs(a)) + p_bytes = int_to_bytes(abs(p)) + + a_buf = buffer_from_bytes(a_bytes) + a_bn = libcrypto.BN_bin2bn(a_buf, len(a_bytes), null()) + if a < 0: + libcrypto.BN_set_negative(a_bn, 1) + + p_buf = buffer_from_bytes(p_bytes) + p_bn = libcrypto.BN_bin2bn(p_buf, len(p_bytes), null()) + if p < 0: + libcrypto.BN_set_negative(p_bn, 1) + + r_bn = libcrypto.BN_mod_inverse(null(), a_bn, p_bn, ctx) + r_len_bits = libcrypto.BN_num_bits(r_bn) + r_len = int(math.ceil(r_len_bits / 8)) + r_buf = buffer_from_bytes(r_len) + libcrypto.BN_bn2bin(r_bn, r_buf) + r_bytes = bytes_from_buffer(r_buf, r_len) + result = int_from_bytes(r_bytes) + + libcrypto.BN_free(a_bn) + libcrypto.BN_free(p_bn) + libcrypto.BN_free(r_bn) + libcrypto.BN_CTX_free(ctx) + + return result + except (LibraryNotFoundError, FFIEngineError): + raise EnvironmentError() + +# If there was an issue using ctypes or OpenSSL, we fall back to pure python +except (EnvironmentError, ImportError): + + def inverse_mod(a, p): + """ + Compute the modular inverse of a (mod p) + + :param a: + An integer + + :param p: + An integer + + :return: + An integer + """ + + if a < 0 or p <= a: + a = a % p + + # From Ferguson and Schneier, roughly: + + c, d = a, p + uc, vc, ud, vd = 1, 0, 0, 1 + while c != 0: + q, c, d = divmod(d, c) + (c,) + uc, vc, ud, vd = ud - q * uc, vd - q * vc, uc, vc + + # At this point, d is the GCD, and ud*a+vd*p = d. + # If d == 1, this means that ud is a inverse. + + assert d == 1 + if ud > 0: + return ud + else: + return ud + p + + +def fill_width(bytes_, width): + """ + Ensure a byte string representing a positive integer is a specific width + (in bytes) + + :param bytes_: + The integer byte string + + :param width: + The desired width as an integer + + :return: + A byte string of the width specified + """ + + while len(bytes_) < width: + bytes_ = b'\x00' + bytes_ + return bytes_ diff --git a/venv/lib/python2.7/site-packages/asn1crypto/_iri.py b/venv/lib/python2.7/site-packages/asn1crypto/_iri.py new file mode 100644 index 0000000..57ddd40 --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/_iri.py @@ -0,0 +1,288 @@ +# coding: utf-8 + +""" +Functions to convert unicode IRIs into ASCII byte string URIs and back. Exports +the following items: + + - iri_to_uri() + - uri_to_iri() +""" + +from __future__ import unicode_literals, division, absolute_import, print_function + +from encodings import idna # noqa +import codecs +import re +import sys + +from ._errors import unwrap +from ._types import byte_cls, str_cls, type_name, bytes_to_list, int_types + +if sys.version_info < (3,): + from urlparse import urlsplit, urlunsplit + from urllib import ( + quote as urlquote, + unquote as unquote_to_bytes, + ) + +else: + from urllib.parse import ( + quote as urlquote, + unquote_to_bytes, + urlsplit, + urlunsplit, + ) + + +def iri_to_uri(value): + """ + Normalizes and encodes a unicode IRI into an ASCII byte string URI + + :param value: + A unicode string of an IRI + + :return: + A byte string of the ASCII-encoded URI + """ + + if not isinstance(value, str_cls): + raise TypeError(unwrap( + ''' + value must be a unicode string, not %s + ''', + type_name(value) + )) + + scheme = None + # Python 2.6 doesn't split properly is the URL doesn't start with http:// or https:// + if sys.version_info < (2, 7) and not value.startswith('http://') and not value.startswith('https://'): + real_prefix = None + prefix_match = re.match('^[^:]*://', value) + if prefix_match: + real_prefix = prefix_match.group(0) + value = 'http://' + value[len(real_prefix):] + parsed = urlsplit(value) + if real_prefix: + value = real_prefix + value[7:] + scheme = _urlquote(real_prefix[:-3]) + else: + parsed = urlsplit(value) + + if scheme is None: + scheme = _urlquote(parsed.scheme) + hostname = parsed.hostname + if hostname is not None: + hostname = hostname.encode('idna') + # RFC 3986 allows userinfo to contain sub-delims + username = _urlquote(parsed.username, safe='!$&\'()*+,;=') + password = _urlquote(parsed.password, safe='!$&\'()*+,;=') + port = parsed.port + if port is not None: + port = str_cls(port).encode('ascii') + + netloc = b'' + if username is not None: + netloc += username + if password: + netloc += b':' + password + netloc += b'@' + if hostname is not None: + netloc += hostname + if port is not None: + default_http = scheme == b'http' and port == b'80' + default_https = scheme == b'https' and port == b'443' + if not default_http and not default_https: + netloc += b':' + port + + # RFC 3986 allows a path to contain sub-delims, plus "@" and ":" + path = _urlquote(parsed.path, safe='/!$&\'()*+,;=@:') + # RFC 3986 allows the query to contain sub-delims, plus "@", ":" , "/" and "?" + query = _urlquote(parsed.query, safe='/?!$&\'()*+,;=@:') + # RFC 3986 allows the fragment to contain sub-delims, plus "@", ":" , "/" and "?" + fragment = _urlquote(parsed.fragment, safe='/?!$&\'()*+,;=@:') + + if query is None and fragment is None and path == b'/': + path = None + + # Python 2.7 compat + if path is None: + path = '' + + output = urlunsplit((scheme, netloc, path, query, fragment)) + if isinstance(output, str_cls): + output = output.encode('latin1') + return output + + +def uri_to_iri(value): + """ + Converts an ASCII URI byte string into a unicode IRI + + :param value: + An ASCII-encoded byte string of the URI + + :return: + A unicode string of the IRI + """ + + if not isinstance(value, byte_cls): + raise TypeError(unwrap( + ''' + value must be a byte string, not %s + ''', + type_name(value) + )) + + parsed = urlsplit(value) + + scheme = parsed.scheme + if scheme is not None: + scheme = scheme.decode('ascii') + + username = _urlunquote(parsed.username, remap=[':', '@']) + password = _urlunquote(parsed.password, remap=[':', '@']) + hostname = parsed.hostname + if hostname: + hostname = hostname.decode('idna') + port = parsed.port + if port and not isinstance(port, int_types): + port = port.decode('ascii') + + netloc = '' + if username is not None: + netloc += username + if password: + netloc += ':' + password + netloc += '@' + if hostname is not None: + netloc += hostname + if port is not None: + netloc += ':' + str_cls(port) + + path = _urlunquote(parsed.path, remap=['/'], preserve=True) + query = _urlunquote(parsed.query, remap=['&', '='], preserve=True) + fragment = _urlunquote(parsed.fragment) + + return urlunsplit((scheme, netloc, path, query, fragment)) + + +def _iri_utf8_errors_handler(exc): + """ + Error handler for decoding UTF-8 parts of a URI into an IRI. Leaves byte + sequences encoded in %XX format, but as part of a unicode string. + + :param exc: + The UnicodeDecodeError exception + + :return: + A 2-element tuple of (replacement unicode string, integer index to + resume at) + """ + + bytes_as_ints = bytes_to_list(exc.object[exc.start:exc.end]) + replacements = ['%%%02x' % num for num in bytes_as_ints] + return (''.join(replacements), exc.end) + + +codecs.register_error('iriutf8', _iri_utf8_errors_handler) + + +def _urlquote(string, safe=''): + """ + Quotes a unicode string for use in a URL + + :param string: + A unicode string + + :param safe: + A unicode string of character to not encode + + :return: + None (if string is None) or an ASCII byte string of the quoted string + """ + + if string is None or string == '': + return None + + # Anything already hex quoted is pulled out of the URL and unquoted if + # possible + escapes = [] + if re.search('%[0-9a-fA-F]{2}', string): + # Try to unquote any percent values, restoring them if they are not + # valid UTF-8. Also, requote any safe chars since encoded versions of + # those are functionally different than the unquoted ones. + def _try_unescape(match): + byte_string = unquote_to_bytes(match.group(0)) + unicode_string = byte_string.decode('utf-8', 'iriutf8') + for safe_char in list(safe): + unicode_string = unicode_string.replace(safe_char, '%%%02x' % ord(safe_char)) + return unicode_string + string = re.sub('(?:%[0-9a-fA-F]{2})+', _try_unescape, string) + + # Once we have the minimal set of hex quoted values, removed them from + # the string so that they are not double quoted + def _extract_escape(match): + escapes.append(match.group(0).encode('ascii')) + return '\x00' + string = re.sub('%[0-9a-fA-F]{2}', _extract_escape, string) + + output = urlquote(string.encode('utf-8'), safe=safe.encode('utf-8')) + if not isinstance(output, byte_cls): + output = output.encode('ascii') + + # Restore the existing quoted values that we extracted + if len(escapes) > 0: + def _return_escape(_): + return escapes.pop(0) + output = re.sub(b'%00', _return_escape, output) + + return output + + +def _urlunquote(byte_string, remap=None, preserve=None): + """ + Unquotes a URI portion from a byte string into unicode using UTF-8 + + :param byte_string: + A byte string of the data to unquote + + :param remap: + A list of characters (as unicode) that should be re-mapped to a + %XX encoding. This is used when characters are not valid in part of a + URL. + + :param preserve: + A bool - indicates that the chars to be remapped if they occur in + non-hex form, should be preserved. E.g. / for URL path. + + :return: + A unicode string + """ + + if byte_string is None: + return byte_string + + if byte_string == b'': + return '' + + if preserve: + replacements = ['\x1A', '\x1C', '\x1D', '\x1E', '\x1F'] + preserve_unmap = {} + for char in remap: + replacement = replacements.pop(0) + preserve_unmap[replacement] = char + byte_string = byte_string.replace(char.encode('ascii'), replacement.encode('ascii')) + + byte_string = unquote_to_bytes(byte_string) + + if remap: + for char in remap: + byte_string = byte_string.replace(char.encode('ascii'), ('%%%02x' % ord(char)).encode('ascii')) + + output = byte_string.decode('utf-8', 'iriutf8') + + if preserve: + for replacement, original in preserve_unmap.items(): + output = output.replace(replacement, original) + + return output diff --git a/venv/lib/python2.7/site-packages/asn1crypto/_ordereddict.py b/venv/lib/python2.7/site-packages/asn1crypto/_ordereddict.py new file mode 100644 index 0000000..2f18ab5 --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/_ordereddict.py @@ -0,0 +1,135 @@ +# Copyright (c) 2009 Raymond Hettinger +# +# 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. + +import sys + +if not sys.version_info < (2, 7): + + from collections import OrderedDict + +else: + + from UserDict import DictMixin + + class OrderedDict(dict, DictMixin): + + def __init__(self, *args, **kwds): + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + try: + self.__end + except AttributeError: + self.clear() + self.update(*args, **kwds) + + def clear(self): + self.__end = end = [] + end += [None, end, end] # sentinel node for doubly linked list + self.__map = {} # key --> [key, prev, next] + dict.clear(self) + + def __setitem__(self, key, value): + if key not in self: + end = self.__end + curr = end[1] + curr[2] = end[1] = self.__map[key] = [key, curr, end] + dict.__setitem__(self, key, value) + + def __delitem__(self, key): + dict.__delitem__(self, key) + key, prev, next_ = self.__map.pop(key) + prev[2] = next_ + next_[1] = prev + + def __iter__(self): + end = self.__end + curr = end[2] + while curr is not end: + yield curr[0] + curr = curr[2] + + def __reversed__(self): + end = self.__end + curr = end[1] + while curr is not end: + yield curr[0] + curr = curr[1] + + def popitem(self, last=True): + if not self: + raise KeyError('dictionary is empty') + if last: + key = reversed(self).next() + else: + key = iter(self).next() + value = self.pop(key) + return key, value + + def __reduce__(self): + items = [[k, self[k]] for k in self] + tmp = self.__map, self.__end + del self.__map, self.__end + inst_dict = vars(self).copy() + self.__map, self.__end = tmp + if inst_dict: + return (self.__class__, (items,), inst_dict) + return self.__class__, (items,) + + def keys(self): + return list(self) + + setdefault = DictMixin.setdefault + update = DictMixin.update + pop = DictMixin.pop + values = DictMixin.values + items = DictMixin.items + iterkeys = DictMixin.iterkeys + itervalues = DictMixin.itervalues + iteritems = DictMixin.iteritems + + def __repr__(self): + if not self: + return '%s()' % (self.__class__.__name__,) + return '%s(%r)' % (self.__class__.__name__, self.items()) + + def copy(self): + return self.__class__(self) + + @classmethod + def fromkeys(cls, iterable, value=None): + d = cls() + for key in iterable: + d[key] = value + return d + + def __eq__(self, other): + if isinstance(other, OrderedDict): + if len(self) != len(other): + return False + for p, q in zip(self.items(), other.items()): + if p != q: + return False + return True + return dict.__eq__(self, other) + + def __ne__(self, other): + return not self == other diff --git a/venv/lib/python2.7/site-packages/asn1crypto/_perf/__init__.py b/venv/lib/python2.7/site-packages/asn1crypto/_perf/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python2.7/site-packages/asn1crypto/_perf/_big_num_ctypes.py b/venv/lib/python2.7/site-packages/asn1crypto/_perf/_big_num_ctypes.py new file mode 100644 index 0000000..8e37e9b --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/_perf/_big_num_ctypes.py @@ -0,0 +1,69 @@ +# coding: utf-8 + +""" +ctypes interface for BN_mod_inverse() function from OpenSSL. Exports the +following items: + + - libcrypto + - BN_bn2bin() + - BN_CTX_free() + - BN_CTX_new() + - BN_free() + - BN_mod_inverse() + - BN_new() + - BN_num_bits() + - BN_set_negative() + +Will raise asn1crypto._ffi.LibraryNotFoundError() if libcrypto can not be +found. Will raise asn1crypto._ffi.FFIEngineError() if there is an error +interfacing with libcrypto. +""" + +from __future__ import unicode_literals, division, absolute_import, print_function + +import sys + +from ctypes import CDLL, c_int, c_char_p, c_void_p +from ctypes.util import find_library + +from .._ffi import LibraryNotFoundError, FFIEngineError + + +try: + # On Python 2, the unicode string here may raise a UnicodeDecodeError as it + # tries to join a bytestring path to the unicode name "crypto" + libcrypto_path = find_library(b'crypto' if sys.version_info < (3,) else 'crypto') + if not libcrypto_path: + raise LibraryNotFoundError('The library libcrypto could not be found') + + libcrypto = CDLL(libcrypto_path) + + libcrypto.BN_new.argtypes = [] + libcrypto.BN_new.restype = c_void_p + + libcrypto.BN_bin2bn.argtypes = [c_char_p, c_int, c_void_p] + libcrypto.BN_bin2bn.restype = c_void_p + + libcrypto.BN_bn2bin.argtypes = [c_void_p, c_char_p] + libcrypto.BN_bn2bin.restype = c_int + + libcrypto.BN_set_negative.argtypes = [c_void_p, c_int] + libcrypto.BN_set_negative.restype = None + + libcrypto.BN_num_bits.argtypes = [c_void_p] + libcrypto.BN_num_bits.restype = c_int + + libcrypto.BN_free.argtypes = [c_void_p] + libcrypto.BN_free.restype = None + + libcrypto.BN_CTX_new.argtypes = [] + libcrypto.BN_CTX_new.restype = c_void_p + + libcrypto.BN_CTX_free.argtypes = [c_void_p] + libcrypto.BN_CTX_free.restype = None + + libcrypto.BN_mod_inverse.argtypes = [c_void_p, c_void_p, c_void_p, c_void_p] + libcrypto.BN_mod_inverse.restype = c_void_p + +except (AttributeError): + raise FFIEngineError('Error initializing ctypes') diff --git a/venv/lib/python2.7/site-packages/asn1crypto/_teletex_codec.py b/venv/lib/python2.7/site-packages/asn1crypto/_teletex_codec.py new file mode 100644 index 0000000..b5991aa --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/_teletex_codec.py @@ -0,0 +1,331 @@ +# coding: utf-8 + +""" +Implementation of the teletex T.61 codec. Exports the following items: + + - register() +""" + +from __future__ import unicode_literals, division, absolute_import, print_function + +import codecs + + +class TeletexCodec(codecs.Codec): + + def encode(self, input_, errors='strict'): + return codecs.charmap_encode(input_, errors, ENCODING_TABLE) + + def decode(self, input_, errors='strict'): + return codecs.charmap_decode(input_, errors, DECODING_TABLE) + + +class TeletexIncrementalEncoder(codecs.IncrementalEncoder): + + def encode(self, input_, final=False): + return codecs.charmap_encode(input_, self.errors, ENCODING_TABLE)[0] + + +class TeletexIncrementalDecoder(codecs.IncrementalDecoder): + + def decode(self, input_, final=False): + return codecs.charmap_decode(input_, self.errors, DECODING_TABLE)[0] + + +class TeletexStreamWriter(TeletexCodec, codecs.StreamWriter): + + pass + + +class TeletexStreamReader(TeletexCodec, codecs.StreamReader): + + pass + + +def teletex_search_function(name): + """ + Search function for teletex codec that is passed to codecs.register() + """ + + if name != 'teletex': + return None + + return codecs.CodecInfo( + name='teletex', + encode=TeletexCodec().encode, + decode=TeletexCodec().decode, + incrementalencoder=TeletexIncrementalEncoder, + incrementaldecoder=TeletexIncrementalDecoder, + streamreader=TeletexStreamReader, + streamwriter=TeletexStreamWriter, + ) + + +def register(): + """ + Registers the teletex codec + """ + + codecs.register(teletex_search_function) + + +# http://en.wikipedia.org/wiki/ITU_T.61 +DECODING_TABLE = ( + '\u0000' + '\u0001' + '\u0002' + '\u0003' + '\u0004' + '\u0005' + '\u0006' + '\u0007' + '\u0008' + '\u0009' + '\u000A' + '\u000B' + '\u000C' + '\u000D' + '\u000E' + '\u000F' + '\u0010' + '\u0011' + '\u0012' + '\u0013' + '\u0014' + '\u0015' + '\u0016' + '\u0017' + '\u0018' + '\u0019' + '\u001A' + '\u001B' + '\u001C' + '\u001D' + '\u001E' + '\u001F' + '\u0020' + '\u0021' + '\u0022' + '\ufffe' + '\ufffe' + '\u0025' + '\u0026' + '\u0027' + '\u0028' + '\u0029' + '\u002A' + '\u002B' + '\u002C' + '\u002D' + '\u002E' + '\u002F' + '\u0030' + '\u0031' + '\u0032' + '\u0033' + '\u0034' + '\u0035' + '\u0036' + '\u0037' + '\u0038' + '\u0039' + '\u003A' + '\u003B' + '\u003C' + '\u003D' + '\u003E' + '\u003F' + '\u0040' + '\u0041' + '\u0042' + '\u0043' + '\u0044' + '\u0045' + '\u0046' + '\u0047' + '\u0048' + '\u0049' + '\u004A' + '\u004B' + '\u004C' + '\u004D' + '\u004E' + '\u004F' + '\u0050' + '\u0051' + '\u0052' + '\u0053' + '\u0054' + '\u0055' + '\u0056' + '\u0057' + '\u0058' + '\u0059' + '\u005A' + '\u005B' + '\ufffe' + '\u005D' + '\ufffe' + '\u005F' + '\ufffe' + '\u0061' + '\u0062' + '\u0063' + '\u0064' + '\u0065' + '\u0066' + '\u0067' + '\u0068' + '\u0069' + '\u006A' + '\u006B' + '\u006C' + '\u006D' + '\u006E' + '\u006F' + '\u0070' + '\u0071' + '\u0072' + '\u0073' + '\u0074' + '\u0075' + '\u0076' + '\u0077' + '\u0078' + '\u0079' + '\u007A' + '\ufffe' + '\u007C' + '\ufffe' + '\ufffe' + '\u007F' + '\u0080' + '\u0081' + '\u0082' + '\u0083' + '\u0084' + '\u0085' + '\u0086' + '\u0087' + '\u0088' + '\u0089' + '\u008A' + '\u008B' + '\u008C' + '\u008D' + '\u008E' + '\u008F' + '\u0090' + '\u0091' + '\u0092' + '\u0093' + '\u0094' + '\u0095' + '\u0096' + '\u0097' + '\u0098' + '\u0099' + '\u009A' + '\u009B' + '\u009C' + '\u009D' + '\u009E' + '\u009F' + '\u00A0' + '\u00A1' + '\u00A2' + '\u00A3' + '\u0024' + '\u00A5' + '\u0023' + '\u00A7' + '\u00A4' + '\ufffe' + '\ufffe' + '\u00AB' + '\ufffe' + '\ufffe' + '\ufffe' + '\ufffe' + '\u00B0' + '\u00B1' + '\u00B2' + '\u00B3' + '\u00D7' + '\u00B5' + '\u00B6' + '\u00B7' + '\u00F7' + '\ufffe' + '\ufffe' + '\u00BB' + '\u00BC' + '\u00BD' + '\u00BE' + '\u00BF' + '\ufffe' + '\u0300' + '\u0301' + '\u0302' + '\u0303' + '\u0304' + '\u0306' + '\u0307' + '\u0308' + '\ufffe' + '\u030A' + '\u0327' + '\u0332' + '\u030B' + '\u0328' + '\u030C' + '\ufffe' + '\ufffe' + '\ufffe' + '\ufffe' + '\ufffe' + '\ufffe' + '\ufffe' + '\ufffe' + '\ufffe' + '\ufffe' + '\ufffe' + '\ufffe' + '\ufffe' + '\ufffe' + '\ufffe' + '\ufffe' + '\u2126' + '\u00C6' + '\u00D0' + '\u00AA' + '\u0126' + '\ufffe' + '\u0132' + '\u013F' + '\u0141' + '\u00D8' + '\u0152' + '\u00BA' + '\u00DE' + '\u0166' + '\u014A' + '\u0149' + '\u0138' + '\u00E6' + '\u0111' + '\u00F0' + '\u0127' + '\u0131' + '\u0133' + '\u0140' + '\u0142' + '\u00F8' + '\u0153' + '\u00DF' + '\u00FE' + '\u0167' + '\u014B' + '\ufffe' +) +ENCODING_TABLE = codecs.charmap_build(DECODING_TABLE) diff --git a/venv/lib/python2.7/site-packages/asn1crypto/_types.py b/venv/lib/python2.7/site-packages/asn1crypto/_types.py new file mode 100644 index 0000000..b9ca8cc --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/_types.py @@ -0,0 +1,46 @@ +# coding: utf-8 +from __future__ import unicode_literals, division, absolute_import, print_function + +import inspect +import sys + + +if sys.version_info < (3,): + str_cls = unicode # noqa + byte_cls = str + int_types = (int, long) # noqa + + def bytes_to_list(byte_string): + return [ord(b) for b in byte_string] + + chr_cls = chr + +else: + str_cls = str + byte_cls = bytes + int_types = int + + bytes_to_list = list + + def chr_cls(num): + return bytes([num]) + + +def type_name(value): + """ + Returns a user-readable name for the type of an object + + :param value: + A value to get the type name of + + :return: + A unicode string of the object's type name + """ + + if inspect.isclass(value): + cls = value + else: + cls = value.__class__ + if cls.__module__ in set(['builtins', '__builtin__']): + return cls.__name__ + return '%s.%s' % (cls.__module__, cls.__name__) diff --git a/venv/lib/python2.7/site-packages/asn1crypto/algos.py b/venv/lib/python2.7/site-packages/asn1crypto/algos.py new file mode 100644 index 0000000..c805433 --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/algos.py @@ -0,0 +1,1143 @@ +# coding: utf-8 + +""" +ASN.1 type classes for various algorithms using in various aspects of public +key cryptography. Exports the following items: + + - AlgorithmIdentifier() + - AnyAlgorithmIdentifier() + - DigestAlgorithm() + - DigestInfo() + - DSASignature() + - EncryptionAlgorithm() + - HmacAlgorithm() + - KdfAlgorithm() + - Pkcs5MacAlgorithm() + - SignedDigestAlgorithm() + +Other type classes are defined that help compose the types listed above. +""" + +from __future__ import unicode_literals, division, absolute_import, print_function + +from ._errors import unwrap +from ._int import fill_width +from .util import int_from_bytes, int_to_bytes +from .core import ( + Any, + Choice, + Integer, + Null, + ObjectIdentifier, + OctetString, + Sequence, + Void, +) + + +# Structures and OIDs in this file are pulled from +# https://tools.ietf.org/html/rfc3279, https://tools.ietf.org/html/rfc4055, +# https://tools.ietf.org/html/rfc5758, https://tools.ietf.org/html/rfc7292, +# http://www.emc.com/collateral/white-papers/h11302-pkcs5v2-1-password-based-cryptography-standard-wp.pdf + +class AlgorithmIdentifier(Sequence): + _fields = [ + ('algorithm', ObjectIdentifier), + ('parameters', Any, {'optional': True}), + ] + + +class _ForceNullParameters(object): + """ + Various structures based on AlgorithmIdentifier require that the parameters + field be core.Null() for certain OIDs. This mixin ensures that happens. + """ + + # The following attribute, plus the parameters spec callback and custom + # __setitem__ are all to handle a situation where parameters should not be + # optional and must be Null for certain OIDs. More info at + # https://tools.ietf.org/html/rfc4055#page-15 and + # https://tools.ietf.org/html/rfc4055#section-2.1 + _null_algos = set([ + '1.2.840.113549.1.1.1', # rsassa_pkcs1v15 / rsaes_pkcs1v15 / rsa + '1.2.840.113549.1.1.11', # sha256_rsa + '1.2.840.113549.1.1.12', # sha384_rsa + '1.2.840.113549.1.1.13', # sha512_rsa + '1.2.840.113549.1.1.14', # sha224_rsa + '1.3.14.3.2.26', # sha1 + '2.16.840.1.101.3.4.2.4', # sha224 + '2.16.840.1.101.3.4.2.1', # sha256 + '2.16.840.1.101.3.4.2.2', # sha384 + '2.16.840.1.101.3.4.2.3', # sha512 + ]) + + def _parameters_spec(self): + if self._oid_pair == ('algorithm', 'parameters'): + algo = self['algorithm'].native + if algo in self._oid_specs: + return self._oid_specs[algo] + + if self['algorithm'].dotted in self._null_algos: + return Null + + return None + + _spec_callbacks = { + 'parameters': _parameters_spec + } + + # We have to override this since the spec callback uses the value of + # algorithm to determine the parameter spec, however default values are + # assigned before setting a field, so a default value can't be based on + # another field value (unless it is a default also). Thus we have to + # manually check to see if the algorithm was set and parameters is unset, + # and then fix the value as appropriate. + def __setitem__(self, key, value): + res = super(_ForceNullParameters, self).__setitem__(key, value) + if key != 'algorithm': + return res + if self['algorithm'].dotted not in self._null_algos: + return res + if self['parameters'].__class__ != Void: + return res + self['parameters'] = Null() + return res + + +class HmacAlgorithmId(ObjectIdentifier): + _map = { + '1.3.14.3.2.10': 'des_mac', + '1.2.840.113549.2.7': 'sha1', + '1.2.840.113549.2.8': 'sha224', + '1.2.840.113549.2.9': 'sha256', + '1.2.840.113549.2.10': 'sha384', + '1.2.840.113549.2.11': 'sha512', + '1.2.840.113549.2.12': 'sha512_224', + '1.2.840.113549.2.13': 'sha512_256', + } + + +class HmacAlgorithm(Sequence): + _fields = [ + ('algorithm', HmacAlgorithmId), + ('parameters', Any, {'optional': True}), + ] + + +class DigestAlgorithmId(ObjectIdentifier): + _map = { + '1.2.840.113549.2.2': 'md2', + '1.2.840.113549.2.5': 'md5', + '1.3.14.3.2.26': 'sha1', + '2.16.840.1.101.3.4.2.4': 'sha224', + '2.16.840.1.101.3.4.2.1': 'sha256', + '2.16.840.1.101.3.4.2.2': 'sha384', + '2.16.840.1.101.3.4.2.3': 'sha512', + '2.16.840.1.101.3.4.2.5': 'sha512_224', + '2.16.840.1.101.3.4.2.6': 'sha512_256', + } + + +class DigestAlgorithm(_ForceNullParameters, Sequence): + _fields = [ + ('algorithm', DigestAlgorithmId), + ('parameters', Any, {'optional': True}), + ] + + +# This structure is what is signed with a SignedDigestAlgorithm +class DigestInfo(Sequence): + _fields = [ + ('digest_algorithm', DigestAlgorithm), + ('digest', OctetString), + ] + + +class MaskGenAlgorithmId(ObjectIdentifier): + _map = { + '1.2.840.113549.1.1.8': 'mgf1', + } + + +class MaskGenAlgorithm(Sequence): + _fields = [ + ('algorithm', MaskGenAlgorithmId), + ('parameters', Any, {'optional': True}), + ] + + _oid_pair = ('algorithm', 'parameters') + _oid_specs = { + 'mgf1': DigestAlgorithm + } + + +class TrailerField(Integer): + _map = { + 1: 'trailer_field_bc', + } + + +class RSASSAPSSParams(Sequence): + _fields = [ + ( + 'hash_algorithm', + DigestAlgorithm, + { + 'explicit': 0, + 'default': {'algorithm': 'sha1'}, + } + ), + ( + 'mask_gen_algorithm', + MaskGenAlgorithm, + { + 'explicit': 1, + 'default': { + 'algorithm': 'mgf1', + 'parameters': {'algorithm': 'sha1'}, + }, + } + ), + ( + 'salt_length', + Integer, + { + 'explicit': 2, + 'default': 20, + } + ), + ( + 'trailer_field', + TrailerField, + { + 'explicit': 3, + 'default': 'trailer_field_bc', + } + ), + ] + + +class SignedDigestAlgorithmId(ObjectIdentifier): + _map = { + '1.3.14.3.2.3': 'md5_rsa', + '1.3.14.3.2.29': 'sha1_rsa', + '1.3.14.7.2.3.1': 'md2_rsa', + '1.2.840.113549.1.1.2': 'md2_rsa', + '1.2.840.113549.1.1.4': 'md5_rsa', + '1.2.840.113549.1.1.5': 'sha1_rsa', + '1.2.840.113549.1.1.14': 'sha224_rsa', + '1.2.840.113549.1.1.11': 'sha256_rsa', + '1.2.840.113549.1.1.12': 'sha384_rsa', + '1.2.840.113549.1.1.13': 'sha512_rsa', + '1.2.840.113549.1.1.10': 'rsassa_pss', + '1.2.840.10040.4.3': 'sha1_dsa', + '1.3.14.3.2.13': 'sha1_dsa', + '1.3.14.3.2.27': 'sha1_dsa', + '2.16.840.1.101.3.4.3.1': 'sha224_dsa', + '2.16.840.1.101.3.4.3.2': 'sha256_dsa', + '1.2.840.10045.4.1': 'sha1_ecdsa', + '1.2.840.10045.4.3.1': 'sha224_ecdsa', + '1.2.840.10045.4.3.2': 'sha256_ecdsa', + '1.2.840.10045.4.3.3': 'sha384_ecdsa', + '1.2.840.10045.4.3.4': 'sha512_ecdsa', + # For when the digest is specified elsewhere in a Sequence + '1.2.840.113549.1.1.1': 'rsassa_pkcs1v15', + '1.2.840.10040.4.1': 'dsa', + '1.2.840.10045.4': 'ecdsa', + } + + _reverse_map = { + 'dsa': '1.2.840.10040.4.1', + 'ecdsa': '1.2.840.10045.4', + 'md2_rsa': '1.2.840.113549.1.1.2', + 'md5_rsa': '1.2.840.113549.1.1.4', + 'rsassa_pkcs1v15': '1.2.840.113549.1.1.1', + 'rsassa_pss': '1.2.840.113549.1.1.10', + 'sha1_dsa': '1.2.840.10040.4.3', + 'sha1_ecdsa': '1.2.840.10045.4.1', + 'sha1_rsa': '1.2.840.113549.1.1.5', + 'sha224_dsa': '2.16.840.1.101.3.4.3.1', + 'sha224_ecdsa': '1.2.840.10045.4.3.1', + 'sha224_rsa': '1.2.840.113549.1.1.14', + 'sha256_dsa': '2.16.840.1.101.3.4.3.2', + 'sha256_ecdsa': '1.2.840.10045.4.3.2', + 'sha256_rsa': '1.2.840.113549.1.1.11', + 'sha384_ecdsa': '1.2.840.10045.4.3.3', + 'sha384_rsa': '1.2.840.113549.1.1.12', + 'sha512_ecdsa': '1.2.840.10045.4.3.4', + 'sha512_rsa': '1.2.840.113549.1.1.13', + } + + +class SignedDigestAlgorithm(_ForceNullParameters, Sequence): + _fields = [ + ('algorithm', SignedDigestAlgorithmId), + ('parameters', Any, {'optional': True}), + ] + + _oid_pair = ('algorithm', 'parameters') + _oid_specs = { + 'rsassa_pss': RSASSAPSSParams, + } + + @property + def signature_algo(self): + """ + :return: + A unicode string of "rsassa_pkcs1v15", "rsassa_pss", "dsa" or + "ecdsa" + """ + + algorithm = self['algorithm'].native + + algo_map = { + 'md2_rsa': 'rsassa_pkcs1v15', + 'md5_rsa': 'rsassa_pkcs1v15', + 'sha1_rsa': 'rsassa_pkcs1v15', + 'sha224_rsa': 'rsassa_pkcs1v15', + 'sha256_rsa': 'rsassa_pkcs1v15', + 'sha384_rsa': 'rsassa_pkcs1v15', + 'sha512_rsa': 'rsassa_pkcs1v15', + 'rsassa_pkcs1v15': 'rsassa_pkcs1v15', + 'rsassa_pss': 'rsassa_pss', + 'sha1_dsa': 'dsa', + 'sha224_dsa': 'dsa', + 'sha256_dsa': 'dsa', + 'dsa': 'dsa', + 'sha1_ecdsa': 'ecdsa', + 'sha224_ecdsa': 'ecdsa', + 'sha256_ecdsa': 'ecdsa', + 'sha384_ecdsa': 'ecdsa', + 'sha512_ecdsa': 'ecdsa', + 'ecdsa': 'ecdsa', + } + if algorithm in algo_map: + return algo_map[algorithm] + + raise ValueError(unwrap( + ''' + Signature algorithm not known for %s + ''', + algorithm + )) + + @property + def hash_algo(self): + """ + :return: + A unicode string of "md2", "md5", "sha1", "sha224", "sha256", + "sha384", "sha512", "sha512_224", "sha512_256" + """ + + algorithm = self['algorithm'].native + + algo_map = { + 'md2_rsa': 'md2', + 'md5_rsa': 'md5', + 'sha1_rsa': 'sha1', + 'sha224_rsa': 'sha224', + 'sha256_rsa': 'sha256', + 'sha384_rsa': 'sha384', + 'sha512_rsa': 'sha512', + 'sha1_dsa': 'sha1', + 'sha224_dsa': 'sha224', + 'sha256_dsa': 'sha256', + 'sha1_ecdsa': 'sha1', + 'sha224_ecdsa': 'sha224', + 'sha256_ecdsa': 'sha256', + 'sha384_ecdsa': 'sha384', + 'sha512_ecdsa': 'sha512', + } + if algorithm in algo_map: + return algo_map[algorithm] + + if algorithm == 'rsassa_pss': + return self['parameters']['hash_algorithm']['algorithm'].native + + raise ValueError(unwrap( + ''' + Hash algorithm not known for %s + ''', + algorithm + )) + + +class Pbkdf2Salt(Choice): + _alternatives = [ + ('specified', OctetString), + ('other_source', AlgorithmIdentifier), + ] + + +class Pbkdf2Params(Sequence): + _fields = [ + ('salt', Pbkdf2Salt), + ('iteration_count', Integer), + ('key_length', Integer, {'optional': True}), + ('prf', HmacAlgorithm, {'default': {'algorithm': 'sha1'}}), + ] + + +class KdfAlgorithmId(ObjectIdentifier): + _map = { + '1.2.840.113549.1.5.12': 'pbkdf2' + } + + +class KdfAlgorithm(Sequence): + _fields = [ + ('algorithm', KdfAlgorithmId), + ('parameters', Any, {'optional': True}), + ] + _oid_pair = ('algorithm', 'parameters') + _oid_specs = { + 'pbkdf2': Pbkdf2Params + } + + +class DHParameters(Sequence): + """ + Original Name: DHParameter + Source: ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-3.asc section 9 + """ + + _fields = [ + ('p', Integer), + ('g', Integer), + ('private_value_length', Integer, {'optional': True}), + ] + + +class KeyExchangeAlgorithmId(ObjectIdentifier): + _map = { + '1.2.840.113549.1.3.1': 'dh', + } + + +class KeyExchangeAlgorithm(Sequence): + _fields = [ + ('algorithm', KeyExchangeAlgorithmId), + ('parameters', Any, {'optional': True}), + ] + _oid_pair = ('algorithm', 'parameters') + _oid_specs = { + 'dh': DHParameters, + } + + +class Rc2Params(Sequence): + _fields = [ + ('rc2_parameter_version', Integer, {'optional': True}), + ('iv', OctetString), + ] + + +class Rc5ParamVersion(Integer): + _map = { + 16: 'v1-0' + } + + +class Rc5Params(Sequence): + _fields = [ + ('version', Rc5ParamVersion), + ('rounds', Integer), + ('block_size_in_bits', Integer), + ('iv', OctetString, {'optional': True}), + ] + + +class Pbes1Params(Sequence): + _fields = [ + ('salt', OctetString), + ('iterations', Integer), + ] + + +class PSourceAlgorithmId(ObjectIdentifier): + _map = { + '1.2.840.113549.1.1.9': 'p_specified', + } + + +class PSourceAlgorithm(Sequence): + _fields = [ + ('algorithm', PSourceAlgorithmId), + ('parameters', Any, {'optional': True}), + ] + + _oid_pair = ('algorithm', 'parameters') + _oid_specs = { + 'p_specified': OctetString + } + + +class RSAESOAEPParams(Sequence): + _fields = [ + ( + 'hash_algorithm', + DigestAlgorithm, + { + 'explicit': 0, + 'default': {'algorithm': 'sha1'} + } + ), + ( + 'mask_gen_algorithm', + MaskGenAlgorithm, + { + 'explicit': 1, + 'default': { + 'algorithm': 'mgf1', + 'parameters': {'algorithm': 'sha1'} + } + } + ), + ( + 'p_source_algorithm', + PSourceAlgorithm, + { + 'explicit': 2, + 'default': { + 'algorithm': 'p_specified', + 'parameters': b'' + } + } + ), + ] + + +class DSASignature(Sequence): + """ + An ASN.1 class for translating between the OS crypto library's + representation of an (EC)DSA signature and the ASN.1 structure that is part + of various RFCs. + + Original Name: DSS-Sig-Value + Source: https://tools.ietf.org/html/rfc3279#section-2.2.2 + """ + + _fields = [ + ('r', Integer), + ('s', Integer), + ] + + @classmethod + def from_p1363(cls, data): + """ + Reads a signature from a byte string encoding accordint to IEEE P1363, + which is used by Microsoft's BCryptSignHash() function. + + :param data: + A byte string from BCryptSignHash() + + :return: + A DSASignature object + """ + + r = int_from_bytes(data[0:len(data) // 2]) + s = int_from_bytes(data[len(data) // 2:]) + return cls({'r': r, 's': s}) + + def to_p1363(self): + """ + Dumps a signature to a byte string compatible with Microsoft's + BCryptVerifySignature() function. + + :return: + A byte string compatible with BCryptVerifySignature() + """ + + r_bytes = int_to_bytes(self['r'].native) + s_bytes = int_to_bytes(self['s'].native) + + int_byte_length = max(len(r_bytes), len(s_bytes)) + r_bytes = fill_width(r_bytes, int_byte_length) + s_bytes = fill_width(s_bytes, int_byte_length) + + return r_bytes + s_bytes + + +class EncryptionAlgorithmId(ObjectIdentifier): + _map = { + '1.3.14.3.2.7': 'des', + '1.2.840.113549.3.7': 'tripledes_3key', + '1.2.840.113549.3.2': 'rc2', + '1.2.840.113549.3.9': 'rc5', + # From http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html#AES + '2.16.840.1.101.3.4.1.1': 'aes128_ecb', + '2.16.840.1.101.3.4.1.2': 'aes128_cbc', + '2.16.840.1.101.3.4.1.3': 'aes128_ofb', + '2.16.840.1.101.3.4.1.4': 'aes128_cfb', + '2.16.840.1.101.3.4.1.5': 'aes128_wrap', + '2.16.840.1.101.3.4.1.6': 'aes128_gcm', + '2.16.840.1.101.3.4.1.7': 'aes128_ccm', + '2.16.840.1.101.3.4.1.8': 'aes128_wrap_pad', + '2.16.840.1.101.3.4.1.21': 'aes192_ecb', + '2.16.840.1.101.3.4.1.22': 'aes192_cbc', + '2.16.840.1.101.3.4.1.23': 'aes192_ofb', + '2.16.840.1.101.3.4.1.24': 'aes192_cfb', + '2.16.840.1.101.3.4.1.25': 'aes192_wrap', + '2.16.840.1.101.3.4.1.26': 'aes192_gcm', + '2.16.840.1.101.3.4.1.27': 'aes192_ccm', + '2.16.840.1.101.3.4.1.28': 'aes192_wrap_pad', + '2.16.840.1.101.3.4.1.41': 'aes256_ecb', + '2.16.840.1.101.3.4.1.42': 'aes256_cbc', + '2.16.840.1.101.3.4.1.43': 'aes256_ofb', + '2.16.840.1.101.3.4.1.44': 'aes256_cfb', + '2.16.840.1.101.3.4.1.45': 'aes256_wrap', + '2.16.840.1.101.3.4.1.46': 'aes256_gcm', + '2.16.840.1.101.3.4.1.47': 'aes256_ccm', + '2.16.840.1.101.3.4.1.48': 'aes256_wrap_pad', + # From PKCS#5 + '1.2.840.113549.1.5.13': 'pbes2', + '1.2.840.113549.1.5.1': 'pbes1_md2_des', + '1.2.840.113549.1.5.3': 'pbes1_md5_des', + '1.2.840.113549.1.5.4': 'pbes1_md2_rc2', + '1.2.840.113549.1.5.6': 'pbes1_md5_rc2', + '1.2.840.113549.1.5.10': 'pbes1_sha1_des', + '1.2.840.113549.1.5.11': 'pbes1_sha1_rc2', + # From PKCS#12 + '1.2.840.113549.1.12.1.1': 'pkcs12_sha1_rc4_128', + '1.2.840.113549.1.12.1.2': 'pkcs12_sha1_rc4_40', + '1.2.840.113549.1.12.1.3': 'pkcs12_sha1_tripledes_3key', + '1.2.840.113549.1.12.1.4': 'pkcs12_sha1_tripledes_2key', + '1.2.840.113549.1.12.1.5': 'pkcs12_sha1_rc2_128', + '1.2.840.113549.1.12.1.6': 'pkcs12_sha1_rc2_40', + # PKCS#1 v2.2 + '1.2.840.113549.1.1.1': 'rsaes_pkcs1v15', + '1.2.840.113549.1.1.7': 'rsaes_oaep', + } + + +class EncryptionAlgorithm(_ForceNullParameters, Sequence): + _fields = [ + ('algorithm', EncryptionAlgorithmId), + ('parameters', Any, {'optional': True}), + ] + + _oid_pair = ('algorithm', 'parameters') + _oid_specs = { + 'des': OctetString, + 'tripledes_3key': OctetString, + 'rc2': Rc2Params, + 'rc5': Rc5Params, + 'aes128_cbc': OctetString, + 'aes192_cbc': OctetString, + 'aes256_cbc': OctetString, + 'aes128_ofb': OctetString, + 'aes192_ofb': OctetString, + 'aes256_ofb': OctetString, + # From PKCS#5 + 'pbes1_md2_des': Pbes1Params, + 'pbes1_md5_des': Pbes1Params, + 'pbes1_md2_rc2': Pbes1Params, + 'pbes1_md5_rc2': Pbes1Params, + 'pbes1_sha1_des': Pbes1Params, + 'pbes1_sha1_rc2': Pbes1Params, + # From PKCS#12 + 'pkcs12_sha1_rc4_128': Pbes1Params, + 'pkcs12_sha1_rc4_40': Pbes1Params, + 'pkcs12_sha1_tripledes_3key': Pbes1Params, + 'pkcs12_sha1_tripledes_2key': Pbes1Params, + 'pkcs12_sha1_rc2_128': Pbes1Params, + 'pkcs12_sha1_rc2_40': Pbes1Params, + # PKCS#1 v2.2 + 'rsaes_oaep': RSAESOAEPParams, + } + + @property + def kdf(self): + """ + Returns the name of the key derivation function to use. + + :return: + A unicode from of one of the following: "pbkdf1", "pbkdf2", + "pkcs12_kdf" + """ + + encryption_algo = self['algorithm'].native + + if encryption_algo == 'pbes2': + return self['parameters']['key_derivation_func']['algorithm'].native + + if encryption_algo.find('.') == -1: + if encryption_algo.find('_') != -1: + encryption_algo, _ = encryption_algo.split('_', 1) + + if encryption_algo == 'pbes1': + return 'pbkdf1' + + if encryption_algo == 'pkcs12': + return 'pkcs12_kdf' + + raise ValueError(unwrap( + ''' + Encryption algorithm "%s" does not have a registered key + derivation function + ''', + encryption_algo + )) + + raise ValueError(unwrap( + ''' + Unrecognized encryption algorithm "%s", can not determine key + derivation function + ''', + encryption_algo + )) + + @property + def kdf_hmac(self): + """ + Returns the HMAC algorithm to use with the KDF. + + :return: + A unicode string of one of the following: "md2", "md5", "sha1", + "sha224", "sha256", "sha384", "sha512" + """ + + encryption_algo = self['algorithm'].native + + if encryption_algo == 'pbes2': + return self['parameters']['key_derivation_func']['parameters']['prf']['algorithm'].native + + if encryption_algo.find('.') == -1: + if encryption_algo.find('_') != -1: + _, hmac_algo, _ = encryption_algo.split('_', 2) + return hmac_algo + + raise ValueError(unwrap( + ''' + Encryption algorithm "%s" does not have a registered key + derivation function + ''', + encryption_algo + )) + + raise ValueError(unwrap( + ''' + Unrecognized encryption algorithm "%s", can not determine key + derivation hmac algorithm + ''', + encryption_algo + )) + + @property + def kdf_salt(self): + """ + Returns the byte string to use as the salt for the KDF. + + :return: + A byte string + """ + + encryption_algo = self['algorithm'].native + + if encryption_algo == 'pbes2': + salt = self['parameters']['key_derivation_func']['parameters']['salt'] + + if salt.name == 'other_source': + raise ValueError(unwrap( + ''' + Can not determine key derivation salt - the + reserved-for-future-use other source salt choice was + specified in the PBKDF2 params structure + ''' + )) + + return salt.native + + if encryption_algo.find('.') == -1: + if encryption_algo.find('_') != -1: + return self['parameters']['salt'].native + + raise ValueError(unwrap( + ''' + Encryption algorithm "%s" does not have a registered key + derivation function + ''', + encryption_algo + )) + + raise ValueError(unwrap( + ''' + Unrecognized encryption algorithm "%s", can not determine key + derivation salt + ''', + encryption_algo + )) + + @property + def kdf_iterations(self): + """ + Returns the number of iterations that should be run via the KDF. + + :return: + An integer + """ + + encryption_algo = self['algorithm'].native + + if encryption_algo == 'pbes2': + return self['parameters']['key_derivation_func']['parameters']['iteration_count'].native + + if encryption_algo.find('.') == -1: + if encryption_algo.find('_') != -1: + return self['parameters']['iterations'].native + + raise ValueError(unwrap( + ''' + Encryption algorithm "%s" does not have a registered key + derivation function + ''', + encryption_algo + )) + + raise ValueError(unwrap( + ''' + Unrecognized encryption algorithm "%s", can not determine key + derivation iterations + ''', + encryption_algo + )) + + @property + def key_length(self): + """ + Returns the key length to pass to the cipher/kdf. The PKCS#5 spec does + not specify a way to store the RC5 key length, however this tends not + to be a problem since OpenSSL does not support RC5 in PKCS#8 and OS X + does not provide an RC5 cipher for use in the Security Transforms + library. + + :raises: + ValueError - when the key length can not be determined + + :return: + An integer representing the length in bytes + """ + + encryption_algo = self['algorithm'].native + + if encryption_algo[0:3] == 'aes': + return { + 'aes128_': 16, + 'aes192_': 24, + 'aes256_': 32, + }[encryption_algo[0:7]] + + cipher_lengths = { + 'des': 8, + 'tripledes_3key': 24, + } + + if encryption_algo in cipher_lengths: + return cipher_lengths[encryption_algo] + + if encryption_algo == 'rc2': + rc2_params = self['parameters'].parsed['encryption_scheme']['parameters'].parsed + rc2_parameter_version = rc2_params['rc2_parameter_version'].native + + # See page 24 of + # http://www.emc.com/collateral/white-papers/h11302-pkcs5v2-1-password-based-cryptography-standard-wp.pdf + encoded_key_bits_map = { + 160: 5, # 40-bit + 120: 8, # 64-bit + 58: 16, # 128-bit + } + + if rc2_parameter_version in encoded_key_bits_map: + return encoded_key_bits_map[rc2_parameter_version] + + if rc2_parameter_version >= 256: + return rc2_parameter_version + + if rc2_parameter_version is None: + return 4 # 32-bit default + + raise ValueError(unwrap( + ''' + Invalid RC2 parameter version found in EncryptionAlgorithm + parameters + ''' + )) + + if encryption_algo == 'pbes2': + key_length = self['parameters']['key_derivation_func']['parameters']['key_length'].native + if key_length is not None: + return key_length + + # If the KDF params don't specify the key size, we can infer it from + # the encryption scheme for all schemes except for RC5. However, in + # practical terms, neither OpenSSL or OS X support RC5 for PKCS#8 + # so it is unlikely to be an issue that is run into. + + return self['parameters']['encryption_scheme'].key_length + + if encryption_algo.find('.') == -1: + return { + 'pbes1_md2_des': 8, + 'pbes1_md5_des': 8, + 'pbes1_md2_rc2': 8, + 'pbes1_md5_rc2': 8, + 'pbes1_sha1_des': 8, + 'pbes1_sha1_rc2': 8, + 'pkcs12_sha1_rc4_128': 16, + 'pkcs12_sha1_rc4_40': 5, + 'pkcs12_sha1_tripledes_3key': 24, + 'pkcs12_sha1_tripledes_2key': 16, + 'pkcs12_sha1_rc2_128': 16, + 'pkcs12_sha1_rc2_40': 5, + }[encryption_algo] + + raise ValueError(unwrap( + ''' + Unrecognized encryption algorithm "%s" + ''', + encryption_algo + )) + + @property + def encryption_mode(self): + """ + Returns the name of the encryption mode to use. + + :return: + A unicode string from one of the following: "cbc", "ecb", "ofb", + "cfb", "wrap", "gcm", "ccm", "wrap_pad" + """ + + encryption_algo = self['algorithm'].native + + if encryption_algo[0:7] in set(['aes128_', 'aes192_', 'aes256_']): + return encryption_algo[7:] + + if encryption_algo[0:6] == 'pbes1_': + return 'cbc' + + if encryption_algo[0:7] == 'pkcs12_': + return 'cbc' + + if encryption_algo in set(['des', 'tripledes_3key', 'rc2', 'rc5']): + return 'cbc' + + if encryption_algo == 'pbes2': + return self['parameters']['encryption_scheme'].encryption_mode + + raise ValueError(unwrap( + ''' + Unrecognized encryption algorithm "%s" + ''', + encryption_algo + )) + + @property + def encryption_cipher(self): + """ + Returns the name of the symmetric encryption cipher to use. The key + length can be retrieved via the .key_length property to disabiguate + between different variations of TripleDES, AES, and the RC* ciphers. + + :return: + A unicode string from one of the following: "rc2", "rc5", "des", + "tripledes", "aes" + """ + + encryption_algo = self['algorithm'].native + + if encryption_algo[0:7] in set(['aes128_', 'aes192_', 'aes256_']): + return 'aes' + + if encryption_algo in set(['des', 'rc2', 'rc5']): + return encryption_algo + + if encryption_algo == 'tripledes_3key': + return 'tripledes' + + if encryption_algo == 'pbes2': + return self['parameters']['encryption_scheme'].encryption_cipher + + if encryption_algo.find('.') == -1: + return { + 'pbes1_md2_des': 'des', + 'pbes1_md5_des': 'des', + 'pbes1_md2_rc2': 'rc2', + 'pbes1_md5_rc2': 'rc2', + 'pbes1_sha1_des': 'des', + 'pbes1_sha1_rc2': 'rc2', + 'pkcs12_sha1_rc4_128': 'rc4', + 'pkcs12_sha1_rc4_40': 'rc4', + 'pkcs12_sha1_tripledes_3key': 'tripledes', + 'pkcs12_sha1_tripledes_2key': 'tripledes', + 'pkcs12_sha1_rc2_128': 'rc2', + 'pkcs12_sha1_rc2_40': 'rc2', + }[encryption_algo] + + raise ValueError(unwrap( + ''' + Unrecognized encryption algorithm "%s" + ''', + encryption_algo + )) + + @property + def encryption_block_size(self): + """ + Returns the block size of the encryption cipher, in bytes. + + :return: + An integer that is the block size in bytes + """ + + encryption_algo = self['algorithm'].native + + if encryption_algo[0:7] in set(['aes128_', 'aes192_', 'aes256_']): + return 16 + + cipher_map = { + 'des': 8, + 'tripledes_3key': 8, + 'rc2': 8, + } + if encryption_algo in cipher_map: + return cipher_map[encryption_algo] + + if encryption_algo == 'rc5': + return self['parameters'].parsed['block_size_in_bits'].native / 8 + + if encryption_algo == 'pbes2': + return self['parameters']['encryption_scheme'].encryption_block_size + + if encryption_algo.find('.') == -1: + return { + 'pbes1_md2_des': 8, + 'pbes1_md5_des': 8, + 'pbes1_md2_rc2': 8, + 'pbes1_md5_rc2': 8, + 'pbes1_sha1_des': 8, + 'pbes1_sha1_rc2': 8, + 'pkcs12_sha1_rc4_128': 0, + 'pkcs12_sha1_rc4_40': 0, + 'pkcs12_sha1_tripledes_3key': 8, + 'pkcs12_sha1_tripledes_2key': 8, + 'pkcs12_sha1_rc2_128': 8, + 'pkcs12_sha1_rc2_40': 8, + }[encryption_algo] + + raise ValueError(unwrap( + ''' + Unrecognized encryption algorithm "%s" + ''', + encryption_algo + )) + + @property + def encryption_iv(self): + """ + Returns the byte string of the initialization vector for the encryption + scheme. Only the PBES2 stores the IV in the params. For PBES1, the IV + is derived from the KDF and this property will return None. + + :return: + A byte string or None + """ + + encryption_algo = self['algorithm'].native + + if encryption_algo in set(['rc2', 'rc5']): + return self['parameters'].parsed['iv'].native + + # For DES/Triple DES and AES the IV is the entirety of the parameters + octet_string_iv_oids = set([ + 'des', + 'tripledes_3key', + 'aes128_cbc', + 'aes192_cbc', + 'aes256_cbc', + 'aes128_ofb', + 'aes192_ofb', + 'aes256_ofb', + ]) + if encryption_algo in octet_string_iv_oids: + return self['parameters'].native + + if encryption_algo == 'pbes2': + return self['parameters']['encryption_scheme'].encryption_iv + + # All of the PBES1 algos use their KDF to create the IV. For the pbkdf1, + # the KDF is told to generate a key that is an extra 8 bytes long, and + # that is used for the IV. For the PKCS#12 KDF, it is called with an id + # of 2 to generate the IV. In either case, we can't return the IV + # without knowing the user's password. + if encryption_algo.find('.') == -1: + return None + + raise ValueError(unwrap( + ''' + Unrecognized encryption algorithm "%s" + ''', + encryption_algo + )) + + +class Pbes2Params(Sequence): + _fields = [ + ('key_derivation_func', KdfAlgorithm), + ('encryption_scheme', EncryptionAlgorithm), + ] + + +class Pbmac1Params(Sequence): + _fields = [ + ('key_derivation_func', KdfAlgorithm), + ('message_auth_scheme', HmacAlgorithm), + ] + + +class Pkcs5MacId(ObjectIdentifier): + _map = { + '1.2.840.113549.1.5.14': 'pbmac1', + } + + +class Pkcs5MacAlgorithm(Sequence): + _fields = [ + ('algorithm', Pkcs5MacId), + ('parameters', Any), + ] + + _oid_pair = ('algorithm', 'parameters') + _oid_specs = { + 'pbmac1': Pbmac1Params, + } + + +EncryptionAlgorithm._oid_specs['pbes2'] = Pbes2Params + + +class AnyAlgorithmId(ObjectIdentifier): + _map = {} + + def _setup(self): + _map = self.__class__._map + for other_cls in (EncryptionAlgorithmId, SignedDigestAlgorithmId, DigestAlgorithmId): + for oid, name in other_cls._map.items(): + _map[oid] = name + + +class AnyAlgorithmIdentifier(_ForceNullParameters, Sequence): + _fields = [ + ('algorithm', AnyAlgorithmId), + ('parameters', Any, {'optional': True}), + ] + + _oid_pair = ('algorithm', 'parameters') + _oid_specs = {} + + def _setup(self): + Sequence._setup(self) + specs = self.__class__._oid_specs + for other_cls in (EncryptionAlgorithm, SignedDigestAlgorithm): + for oid, spec in other_cls._oid_specs.items(): + specs[oid] = spec diff --git a/venv/lib/python2.7/site-packages/asn1crypto/cms.py b/venv/lib/python2.7/site-packages/asn1crypto/cms.py new file mode 100644 index 0000000..9cad949 --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/cms.py @@ -0,0 +1,932 @@ +# coding: utf-8 + +""" +ASN.1 type classes for cryptographic message syntax (CMS). Structures are also +compatible with PKCS#7. Exports the following items: + + - AuthenticatedData() + - AuthEnvelopedData() + - CompressedData() + - ContentInfo() + - DigestedData() + - EncryptedData() + - EnvelopedData() + - SignedAndEnvelopedData() + - SignedData() + +Other type classes are defined that help compose the types listed above. + +Most CMS structures in the wild are formatted as ContentInfo encapsulating one of the other types. +""" + +from __future__ import unicode_literals, division, absolute_import, print_function + +try: + import zlib +except (ImportError): + zlib = None + +from .algos import ( + _ForceNullParameters, + DigestAlgorithm, + EncryptionAlgorithm, + HmacAlgorithm, + KdfAlgorithm, + SignedDigestAlgorithm, +) +from .core import ( + Any, + BitString, + Choice, + Enumerated, + GeneralizedTime, + Integer, + ObjectIdentifier, + OctetBitString, + OctetString, + ParsableOctetString, + Sequence, + SequenceOf, + SetOf, + UTCTime, + UTF8String, +) +from .crl import CertificateList +from .keys import PublicKeyInfo +from .ocsp import OCSPResponse +from .x509 import Attributes, Certificate, Extensions, GeneralName, GeneralNames, Name + + +# These structures are taken from +# ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-6.asc + +class ExtendedCertificateInfo(Sequence): + _fields = [ + ('version', Integer), + ('certificate', Certificate), + ('attributes', Attributes), + ] + + +class ExtendedCertificate(Sequence): + _fields = [ + ('extended_certificate_info', ExtendedCertificateInfo), + ('signature_algorithm', SignedDigestAlgorithm), + ('signature', OctetBitString), + ] + + +# These structures are taken from https://tools.ietf.org/html/rfc5652, +# https://tools.ietf.org/html/rfc5083, http://tools.ietf.org/html/rfc2315, +# https://tools.ietf.org/html/rfc5940, https://tools.ietf.org/html/rfc3274, +# https://tools.ietf.org/html/rfc3281 + + +class CMSVersion(Integer): + _map = { + 0: 'v0', + 1: 'v1', + 2: 'v2', + 3: 'v3', + 4: 'v4', + 5: 'v5', + } + + +class CMSAttributeType(ObjectIdentifier): + _map = { + '1.2.840.113549.1.9.3': 'content_type', + '1.2.840.113549.1.9.4': 'message_digest', + '1.2.840.113549.1.9.5': 'signing_time', + '1.2.840.113549.1.9.6': 'counter_signature', + # https://tools.ietf.org/html/rfc3161#page-20 + '1.2.840.113549.1.9.16.2.14': 'signature_time_stamp_token', + # https://tools.ietf.org/html/rfc6211#page-5 + '1.2.840.113549.1.9.52': 'cms_algorithm_protection', + } + + +class Time(Choice): + _alternatives = [ + ('utc_time', UTCTime), + ('generalized_time', GeneralizedTime), + ] + + +class ContentType(ObjectIdentifier): + _map = { + '1.2.840.113549.1.7.1': 'data', + '1.2.840.113549.1.7.2': 'signed_data', + '1.2.840.113549.1.7.3': 'enveloped_data', + '1.2.840.113549.1.7.4': 'signed_and_enveloped_data', + '1.2.840.113549.1.7.5': 'digested_data', + '1.2.840.113549.1.7.6': 'encrypted_data', + '1.2.840.113549.1.9.16.1.2': 'authenticated_data', + '1.2.840.113549.1.9.16.1.9': 'compressed_data', + '1.2.840.113549.1.9.16.1.23': 'authenticated_enveloped_data', + } + + +class CMSAlgorithmProtection(Sequence): + _fields = [ + ('digest_algorithm', DigestAlgorithm), + ('signature_algorithm', SignedDigestAlgorithm, {'implicit': 1, 'optional': True}), + ('mac_algorithm', HmacAlgorithm, {'implicit': 2, 'optional': True}), + ] + + +class SetOfContentType(SetOf): + _child_spec = ContentType + + +class SetOfOctetString(SetOf): + _child_spec = OctetString + + +class SetOfTime(SetOf): + _child_spec = Time + + +class SetOfAny(SetOf): + _child_spec = Any + + +class SetOfCMSAlgorithmProtection(SetOf): + _child_spec = CMSAlgorithmProtection + + +class CMSAttribute(Sequence): + _fields = [ + ('type', CMSAttributeType), + ('values', None), + ] + + _oid_specs = {} + + def _values_spec(self): + return self._oid_specs.get(self['type'].native, SetOfAny) + + _spec_callbacks = { + 'values': _values_spec + } + + +class CMSAttributes(SetOf): + _child_spec = CMSAttribute + + +class IssuerSerial(Sequence): + _fields = [ + ('issuer', GeneralNames), + ('serial', Integer), + ('issuer_uid', OctetBitString, {'optional': True}), + ] + + +class AttCertVersion(Integer): + _map = { + 0: 'v1', + 1: 'v2', + } + + +class AttCertSubject(Choice): + _alternatives = [ + ('base_certificate_id', IssuerSerial, {'explicit': 0}), + ('subject_name', GeneralNames, {'explicit': 1}), + ] + + +class AttCertValidityPeriod(Sequence): + _fields = [ + ('not_before_time', GeneralizedTime), + ('not_after_time', GeneralizedTime), + ] + + +class AttributeCertificateInfoV1(Sequence): + _fields = [ + ('version', AttCertVersion, {'default': 'v1'}), + ('subject', AttCertSubject), + ('issuer', GeneralNames), + ('signature', SignedDigestAlgorithm), + ('serial_number', Integer), + ('att_cert_validity_period', AttCertValidityPeriod), + ('attributes', Attributes), + ('issuer_unique_id', OctetBitString, {'optional': True}), + ('extensions', Extensions, {'optional': True}), + ] + + +class AttributeCertificateV1(Sequence): + _fields = [ + ('ac_info', AttributeCertificateInfoV1), + ('signature_algorithm', SignedDigestAlgorithm), + ('signature', OctetBitString), + ] + + +class DigestedObjectType(Enumerated): + _map = { + 0: 'public_key', + 1: 'public_key_cert', + 2: 'other_objy_types', + } + + +class ObjectDigestInfo(Sequence): + _fields = [ + ('digested_object_type', DigestedObjectType), + ('other_object_type_id', ObjectIdentifier, {'optional': True}), + ('digest_algorithm', DigestAlgorithm), + ('object_digest', OctetBitString), + ] + + +class Holder(Sequence): + _fields = [ + ('base_certificate_id', IssuerSerial, {'implicit': 0, 'optional': True}), + ('entity_name', GeneralNames, {'implicit': 1, 'optional': True}), + ('object_digest_info', ObjectDigestInfo, {'implicit': 2, 'optional': True}), + ] + + +class V2Form(Sequence): + _fields = [ + ('issuer_name', GeneralNames, {'optional': True}), + ('base_certificate_id', IssuerSerial, {'explicit': 0, 'optional': True}), + ('object_digest_info', ObjectDigestInfo, {'explicit': 1, 'optional': True}), + ] + + +class AttCertIssuer(Choice): + _alternatives = [ + ('v1_form', GeneralNames), + ('v2_form', V2Form, {'explicit': 0}), + ] + + +class IetfAttrValue(Choice): + _alternatives = [ + ('octets', OctetString), + ('oid', ObjectIdentifier), + ('string', UTF8String), + ] + + +class IetfAttrValues(SequenceOf): + _child_spec = IetfAttrValue + + +class IetfAttrSyntax(Sequence): + _fields = [ + ('policy_authority', GeneralNames, {'implicit': 0, 'optional': True}), + ('values', IetfAttrValues), + ] + + +class SetOfIetfAttrSyntax(SetOf): + _child_spec = IetfAttrSyntax + + +class SvceAuthInfo(Sequence): + _fields = [ + ('service', GeneralName), + ('ident', GeneralName), + ('auth_info', OctetString, {'optional': True}), + ] + + +class SetOfSvceAuthInfo(SetOf): + _child_spec = SvceAuthInfo + + +class RoleSyntax(Sequence): + _fields = [ + ('role_authority', GeneralNames, {'implicit': 0, 'optional': True}), + ('role_name', GeneralName, {'implicit': 1}), + ] + + +class SetOfRoleSyntax(SetOf): + _child_spec = RoleSyntax + + +class ClassList(BitString): + _map = { + 0: 'unmarked', + 1: 'unclassified', + 2: 'restricted', + 3: 'confidential', + 4: 'secret', + 5: 'top_secret', + } + + +class SecurityCategory(Sequence): + _fields = [ + ('type', ObjectIdentifier, {'implicit': 0}), + ('value', Any, {'implicit': 1}), + ] + + +class SetOfSecurityCategory(SetOf): + _child_spec = SecurityCategory + + +class Clearance(Sequence): + _fields = [ + ('policy_id', ObjectIdentifier, {'implicit': 0}), + ('class_list', ClassList, {'implicit': 1, 'default': 'unclassified'}), + ('security_categories', SetOfSecurityCategory, {'implicit': 2, 'optional': True}), + ] + + +class SetOfClearance(SetOf): + _child_spec = Clearance + + +class BigTime(Sequence): + _fields = [ + ('major', Integer), + ('fractional_seconds', Integer), + ('sign', Integer, {'optional': True}), + ] + + +class LeapData(Sequence): + _fields = [ + ('leap_time', BigTime), + ('action', Integer), + ] + + +class SetOfLeapData(SetOf): + _child_spec = LeapData + + +class TimingMetrics(Sequence): + _fields = [ + ('ntp_time', BigTime), + ('offset', BigTime), + ('delay', BigTime), + ('expiration', BigTime), + ('leap_event', SetOfLeapData, {'optional': True}), + ] + + +class SetOfTimingMetrics(SetOf): + _child_spec = TimingMetrics + + +class TimingPolicy(Sequence): + _fields = [ + ('policy_id', SequenceOf, {'spec': ObjectIdentifier}), + ('max_offset', BigTime, {'explicit': 0, 'optional': True}), + ('max_delay', BigTime, {'explicit': 1, 'optional': True}), + ] + + +class SetOfTimingPolicy(SetOf): + _child_spec = TimingPolicy + + +class AttCertAttributeType(ObjectIdentifier): + _map = { + '1.3.6.1.5.5.7.10.1': 'authentication_info', + '1.3.6.1.5.5.7.10.2': 'access_identity', + '1.3.6.1.5.5.7.10.3': 'charging_identity', + '1.3.6.1.5.5.7.10.4': 'group', + '2.5.4.72': 'role', + '2.5.4.55': 'clearance', + '1.3.6.1.4.1.601.10.4.1': 'timing_metrics', + '1.3.6.1.4.1.601.10.4.2': 'timing_policy', + } + + +class AttCertAttribute(Sequence): + _fields = [ + ('type', AttCertAttributeType), + ('values', None), + ] + + _oid_specs = { + 'authentication_info': SetOfSvceAuthInfo, + 'access_identity': SetOfSvceAuthInfo, + 'charging_identity': SetOfIetfAttrSyntax, + 'group': SetOfIetfAttrSyntax, + 'role': SetOfRoleSyntax, + 'clearance': SetOfClearance, + 'timing_metrics': SetOfTimingMetrics, + 'timing_policy': SetOfTimingPolicy, + } + + def _values_spec(self): + return self._oid_specs.get(self['type'].native, SetOfAny) + + _spec_callbacks = { + 'values': _values_spec + } + + +class AttCertAttributes(SequenceOf): + _child_spec = AttCertAttribute + + +class AttributeCertificateInfoV2(Sequence): + _fields = [ + ('version', AttCertVersion), + ('holder', Holder), + ('issuer', AttCertIssuer), + ('signature', SignedDigestAlgorithm), + ('serial_number', Integer), + ('att_cert_validity_period', AttCertValidityPeriod), + ('attributes', AttCertAttributes), + ('issuer_unique_id', OctetBitString, {'optional': True}), + ('extensions', Extensions, {'optional': True}), + ] + + +class AttributeCertificateV2(Sequence): + # Handle the situation where a V2 cert is encoded as V1 + _bad_tag = 1 + + _fields = [ + ('ac_info', AttributeCertificateInfoV2), + ('signature_algorithm', SignedDigestAlgorithm), + ('signature', OctetBitString), + ] + + +class OtherCertificateFormat(Sequence): + _fields = [ + ('other_cert_format', ObjectIdentifier), + ('other_cert', Any), + ] + + +class CertificateChoices(Choice): + _alternatives = [ + ('certificate', Certificate), + ('extended_certificate', ExtendedCertificate, {'implicit': 0}), + ('v1_attr_cert', AttributeCertificateV1, {'implicit': 1}), + ('v2_attr_cert', AttributeCertificateV2, {'implicit': 2}), + ('other', OtherCertificateFormat, {'implicit': 3}), + ] + + def validate(self, class_, tag, contents): + """ + Ensures that the class and tag specified exist as an alternative. This + custom version fixes parsing broken encodings there a V2 attribute + # certificate is encoded as a V1 + + :param class_: + The integer class_ from the encoded value header + + :param tag: + The integer tag from the encoded value header + + :param contents: + A byte string of the contents of the value - used when the object + is explicitly tagged + + :raises: + ValueError - when value is not a valid alternative + """ + + super(CertificateChoices, self).validate(class_, tag, contents) + if self._choice == 2: + if AttCertVersion.load(Sequence.load(contents)[0].dump()).native == 'v2': + self._choice = 3 + + +class CertificateSet(SetOf): + _child_spec = CertificateChoices + + +class ContentInfo(Sequence): + _fields = [ + ('content_type', ContentType), + ('content', Any, {'explicit': 0, 'optional': True}), + ] + + _oid_pair = ('content_type', 'content') + _oid_specs = {} + + +class SetOfContentInfo(SetOf): + _child_spec = ContentInfo + + +class EncapsulatedContentInfo(Sequence): + _fields = [ + ('content_type', ContentType), + ('content', ParsableOctetString, {'explicit': 0, 'optional': True}), + ] + + _oid_pair = ('content_type', 'content') + _oid_specs = {} + + +class IssuerAndSerialNumber(Sequence): + _fields = [ + ('issuer', Name), + ('serial_number', Integer), + ] + + +class SignerIdentifier(Choice): + _alternatives = [ + ('issuer_and_serial_number', IssuerAndSerialNumber), + ('subject_key_identifier', OctetString, {'implicit': 0}), + ] + + +class DigestAlgorithms(SetOf): + _child_spec = DigestAlgorithm + + +class CertificateRevocationLists(SetOf): + _child_spec = CertificateList + + +class SCVPReqRes(Sequence): + _fields = [ + ('request', ContentInfo, {'explicit': 0, 'optional': True}), + ('response', ContentInfo), + ] + + +class OtherRevInfoFormatId(ObjectIdentifier): + _map = { + '1.3.6.1.5.5.7.16.2': 'ocsp_response', + '1.3.6.1.5.5.7.16.4': 'scvp', + } + + +class OtherRevocationInfoFormat(Sequence): + _fields = [ + ('other_rev_info_format', OtherRevInfoFormatId), + ('other_rev_info', Any), + ] + + _oid_pair = ('other_rev_info_format', 'other_rev_info') + _oid_specs = { + 'ocsp_response': OCSPResponse, + 'scvp': SCVPReqRes, + } + + +class RevocationInfoChoice(Choice): + _alternatives = [ + ('crl', CertificateList), + ('other', OtherRevocationInfoFormat, {'implicit': 1}), + ] + + +class RevocationInfoChoices(SetOf): + _child_spec = RevocationInfoChoice + + +class SignerInfo(Sequence): + _fields = [ + ('version', CMSVersion), + ('sid', SignerIdentifier), + ('digest_algorithm', DigestAlgorithm), + ('signed_attrs', CMSAttributes, {'implicit': 0, 'optional': True}), + ('signature_algorithm', SignedDigestAlgorithm), + ('signature', OctetString), + ('unsigned_attrs', CMSAttributes, {'implicit': 1, 'optional': True}), + ] + + +class SignerInfos(SetOf): + _child_spec = SignerInfo + + +class SignedData(Sequence): + _fields = [ + ('version', CMSVersion), + ('digest_algorithms', DigestAlgorithms), + ('encap_content_info', None), + ('certificates', CertificateSet, {'implicit': 0, 'optional': True}), + ('crls', RevocationInfoChoices, {'implicit': 1, 'optional': True}), + ('signer_infos', SignerInfos), + ] + + def _encap_content_info_spec(self): + # If the encap_content_info is version v1, then this could be a PKCS#7 + # structure, or a CMS structure. CMS wraps the encoded value in an + # Octet String tag. + + # If the version is greater than 1, it is definite CMS + if self['version'].native != 'v1': + return EncapsulatedContentInfo + + # Otherwise, the ContentInfo spec from PKCS#7 will be compatible with + # CMS v1 (which only allows Data, an Octet String) and PKCS#7, which + # allows Any + return ContentInfo + + _spec_callbacks = { + 'encap_content_info': _encap_content_info_spec + } + + +class OriginatorInfo(Sequence): + _fields = [ + ('certs', CertificateSet, {'implicit': 0, 'optional': True}), + ('crls', RevocationInfoChoices, {'implicit': 1, 'optional': True}), + ] + + +class RecipientIdentifier(Choice): + _alternatives = [ + ('issuer_and_serial_number', IssuerAndSerialNumber), + ('subject_key_identifier', OctetString, {'implicit': 0}), + ] + + +class KeyEncryptionAlgorithmId(ObjectIdentifier): + _map = { + '1.2.840.113549.1.1.1': 'rsa', + '2.16.840.1.101.3.4.1.5': 'aes128_wrap', + '2.16.840.1.101.3.4.1.8': 'aes128_wrap_pad', + '2.16.840.1.101.3.4.1.25': 'aes192_wrap', + '2.16.840.1.101.3.4.1.28': 'aes192_wrap_pad', + '2.16.840.1.101.3.4.1.45': 'aes256_wrap', + '2.16.840.1.101.3.4.1.48': 'aes256_wrap_pad', + } + + +class KeyEncryptionAlgorithm(_ForceNullParameters, Sequence): + _fields = [ + ('algorithm', KeyEncryptionAlgorithmId), + ('parameters', Any, {'optional': True}), + ] + + +class KeyTransRecipientInfo(Sequence): + _fields = [ + ('version', CMSVersion), + ('rid', RecipientIdentifier), + ('key_encryption_algorithm', KeyEncryptionAlgorithm), + ('encrypted_key', OctetString), + ] + + +class OriginatorIdentifierOrKey(Choice): + _alternatives = [ + ('issuer_and_serial_number', IssuerAndSerialNumber), + ('subject_key_identifier', OctetString, {'implicit': 0}), + ('originator_key', PublicKeyInfo, {'implicit': 1}), + ] + + +class OtherKeyAttribute(Sequence): + _fields = [ + ('key_attr_id', ObjectIdentifier), + ('key_attr', Any), + ] + + +class RecipientKeyIdentifier(Sequence): + _fields = [ + ('subject_key_identifier', OctetString), + ('date', GeneralizedTime, {'optional': True}), + ('other', OtherKeyAttribute, {'optional': True}), + ] + + +class KeyAgreementRecipientIdentifier(Choice): + _alternatives = [ + ('issuer_and_serial_number', IssuerAndSerialNumber), + ('r_key_id', RecipientKeyIdentifier, {'implicit': 0}), + ] + + +class RecipientEncryptedKey(Sequence): + _fields = [ + ('rid', KeyAgreementRecipientIdentifier), + ('encrypted_key', OctetString), + ] + + +class RecipientEncryptedKeys(SequenceOf): + _child_spec = RecipientEncryptedKey + + +class KeyAgreeRecipientInfo(Sequence): + _fields = [ + ('version', CMSVersion), + ('originator', OriginatorIdentifierOrKey, {'explicit': 0}), + ('ukm', OctetString, {'explicit': 1, 'optional': True}), + ('key_encryption_algorithm', KeyEncryptionAlgorithm), + ('recipient_encrypted_keys', RecipientEncryptedKeys), + ] + + +class KEKIdentifier(Sequence): + _fields = [ + ('key_identifier', OctetString), + ('date', GeneralizedTime, {'optional': True}), + ('other', OtherKeyAttribute, {'optional': True}), + ] + + +class KEKRecipientInfo(Sequence): + _fields = [ + ('version', CMSVersion), + ('kekid', KEKIdentifier), + ('key_encryption_algorithm', KeyEncryptionAlgorithm), + ('encrypted_key', OctetString), + ] + + +class PasswordRecipientInfo(Sequence): + _fields = [ + ('version', CMSVersion), + ('key_derivation_algorithm', KdfAlgorithm, {'implicit': 0, 'optional': True}), + ('key_encryption_algorithm', KeyEncryptionAlgorithm), + ('encrypted_key', OctetString), + ] + + +class OtherRecipientInfo(Sequence): + _fields = [ + ('ori_type', ObjectIdentifier), + ('ori_value', Any), + ] + + +class RecipientInfo(Choice): + _alternatives = [ + ('ktri', KeyTransRecipientInfo), + ('kari', KeyAgreeRecipientInfo, {'implicit': 1}), + ('kekri', KEKRecipientInfo, {'implicit': 2}), + ('pwri', PasswordRecipientInfo, {'implicit': 3}), + ('ori', OtherRecipientInfo, {'implicit': 4}), + ] + + +class RecipientInfos(SetOf): + _child_spec = RecipientInfo + + +class EncryptedContentInfo(Sequence): + _fields = [ + ('content_type', ContentType), + ('content_encryption_algorithm', EncryptionAlgorithm), + ('encrypted_content', OctetString, {'implicit': 0, 'optional': True}), + ] + + +class EnvelopedData(Sequence): + _fields = [ + ('version', CMSVersion), + ('originator_info', OriginatorInfo, {'implicit': 0, 'optional': True}), + ('recipient_infos', RecipientInfos), + ('encrypted_content_info', EncryptedContentInfo), + ('unprotected_attrs', CMSAttributes, {'implicit': 1, 'optional': True}), + ] + + +class SignedAndEnvelopedData(Sequence): + _fields = [ + ('version', CMSVersion), + ('recipient_infos', RecipientInfos), + ('digest_algorithms', DigestAlgorithms), + ('encrypted_content_info', EncryptedContentInfo), + ('certificates', CertificateSet, {'implicit': 0, 'optional': True}), + ('crls', CertificateRevocationLists, {'implicit': 1, 'optional': True}), + ('signer_infos', SignerInfos), + ] + + +class DigestedData(Sequence): + _fields = [ + ('version', CMSVersion), + ('digest_algorithm', DigestAlgorithm), + ('encap_content_info', None), + ('digest', OctetString), + ] + + def _encap_content_info_spec(self): + # If the encap_content_info is version v1, then this could be a PKCS#7 + # structure, or a CMS structure. CMS wraps the encoded value in an + # Octet String tag. + + # If the version is greater than 1, it is definite CMS + if self['version'].native != 'v1': + return EncapsulatedContentInfo + + # Otherwise, the ContentInfo spec from PKCS#7 will be compatible with + # CMS v1 (which only allows Data, an Octet String) and PKCS#7, which + # allows Any + return ContentInfo + + _spec_callbacks = { + 'encap_content_info': _encap_content_info_spec + } + + +class EncryptedData(Sequence): + _fields = [ + ('version', CMSVersion), + ('encrypted_content_info', EncryptedContentInfo), + ('unprotected_attrs', CMSAttributes, {'implicit': 1, 'optional': True}), + ] + + +class AuthenticatedData(Sequence): + _fields = [ + ('version', CMSVersion), + ('originator_info', OriginatorInfo, {'implicit': 0, 'optional': True}), + ('recipient_infos', RecipientInfos), + ('mac_algorithm', HmacAlgorithm), + ('digest_algorithm', DigestAlgorithm, {'implicit': 1, 'optional': True}), + # This does not require the _spec_callbacks approach of SignedData and + # DigestedData since AuthenticatedData was not part of PKCS#7 + ('encap_content_info', EncapsulatedContentInfo), + ('auth_attrs', CMSAttributes, {'implicit': 2, 'optional': True}), + ('mac', OctetString), + ('unauth_attrs', CMSAttributes, {'implicit': 3, 'optional': True}), + ] + + +class AuthEnvelopedData(Sequence): + _fields = [ + ('version', CMSVersion), + ('originator_info', OriginatorInfo, {'implicit': 0, 'optional': True}), + ('recipient_infos', RecipientInfos), + ('auth_encrypted_content_info', EncryptedContentInfo), + ('auth_attrs', CMSAttributes, {'implicit': 1, 'optional': True}), + ('mac', OctetString), + ('unauth_attrs', CMSAttributes, {'implicit': 2, 'optional': True}), + ] + + +class CompressionAlgorithmId(ObjectIdentifier): + _map = { + '1.2.840.113549.1.9.16.3.8': 'zlib', + } + + +class CompressionAlgorithm(Sequence): + _fields = [ + ('algorithm', CompressionAlgorithmId), + ('parameters', Any, {'optional': True}), + ] + + +class CompressedData(Sequence): + _fields = [ + ('version', CMSVersion), + ('compression_algorithm', CompressionAlgorithm), + ('encap_content_info', EncapsulatedContentInfo), + ] + + _decompressed = None + + @property + def decompressed(self): + if self._decompressed is None: + if zlib is None: + raise SystemError('The zlib module is not available') + self._decompressed = zlib.decompress(self['encap_content_info']['content'].native) + return self._decompressed + + +ContentInfo._oid_specs = { + 'data': OctetString, + 'signed_data': SignedData, + 'enveloped_data': EnvelopedData, + 'signed_and_enveloped_data': SignedAndEnvelopedData, + 'digested_data': DigestedData, + 'encrypted_data': EncryptedData, + 'authenticated_data': AuthenticatedData, + 'compressed_data': CompressedData, + 'authenticated_enveloped_data': AuthEnvelopedData, +} + + +EncapsulatedContentInfo._oid_specs = { + 'signed_data': SignedData, + 'enveloped_data': EnvelopedData, + 'signed_and_enveloped_data': SignedAndEnvelopedData, + 'digested_data': DigestedData, + 'encrypted_data': EncryptedData, + 'authenticated_data': AuthenticatedData, + 'compressed_data': CompressedData, + 'authenticated_enveloped_data': AuthEnvelopedData, +} + + +CMSAttribute._oid_specs = { + 'content_type': SetOfContentType, + 'message_digest': SetOfOctetString, + 'signing_time': SetOfTime, + 'counter_signature': SignerInfos, + 'signature_time_stamp_token': SetOfContentInfo, + 'cms_algorithm_protection': SetOfCMSAlgorithmProtection, +} diff --git a/venv/lib/python2.7/site-packages/asn1crypto/core.py b/venv/lib/python2.7/site-packages/asn1crypto/core.py new file mode 100644 index 0000000..14a8203 --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/core.py @@ -0,0 +1,5242 @@ +# coding: utf-8 + +""" +ASN.1 type classes for universal types. Exports the following items: + + - load() + - Any() + - Asn1Value() + - BitString() + - BMPString() + - Boolean() + - CharacterString() + - Choice() + - EmbeddedPdv() + - Enumerated() + - GeneralizedTime() + - GeneralString() + - GraphicString() + - IA5String() + - InstanceOf() + - Integer() + - IntegerBitString() + - IntegerOctetString() + - Null() + - NumericString() + - ObjectDescriptor() + - ObjectIdentifier() + - OctetBitString() + - OctetString() + - PrintableString() + - Real() + - RelativeOid() + - Sequence() + - SequenceOf() + - Set() + - SetOf() + - TeletexString() + - UniversalString() + - UTCTime() + - UTF8String() + - VideotexString() + - VisibleString() + - VOID + - Void() + +Other type classes are defined that help compose the types listed above. +""" + +from __future__ import unicode_literals, division, absolute_import, print_function + +from datetime import datetime, timedelta +import binascii +import copy +import math +import re +import sys + +from . import _teletex_codec +from ._errors import unwrap +from ._ordereddict import OrderedDict +from ._types import type_name, str_cls, byte_cls, int_types, chr_cls +from .parser import _parse, _dump_header +from .util import int_to_bytes, int_from_bytes, timezone, extended_datetime + +if sys.version_info <= (3,): + from cStringIO import StringIO as BytesIO + + range = xrange # noqa + _PY2 = True + +else: + from io import BytesIO + + _PY2 = False + + +_teletex_codec.register() + + +CLASS_NUM_TO_NAME_MAP = { + 0: 'universal', + 1: 'application', + 2: 'context', + 3: 'private', +} + +CLASS_NAME_TO_NUM_MAP = { + 'universal': 0, + 'application': 1, + 'context': 2, + 'private': 3, + 0: 0, + 1: 1, + 2: 2, + 3: 3, +} + +METHOD_NUM_TO_NAME_MAP = { + 0: 'primitive', + 1: 'constructed', +} + + +_OID_RE = re.compile(r'^\d+(\.\d+)*$') + + +# A global tracker to ensure that _setup() is called for every class, even +# if is has been called for a parent class. This allows different _fields +# definitions for child classes. Without such a construct, the child classes +# would just see the parent class attributes and would use them. +_SETUP_CLASSES = {} + + +def load(encoded_data, strict=False): + """ + Loads a BER/DER-encoded byte string and construct a universal object based + on the tag value: + + - 1: Boolean + - 2: Integer + - 3: BitString + - 4: OctetString + - 5: Null + - 6: ObjectIdentifier + - 7: ObjectDescriptor + - 8: InstanceOf + - 9: Real + - 10: Enumerated + - 11: EmbeddedPdv + - 12: UTF8String + - 13: RelativeOid + - 16: Sequence, + - 17: Set + - 18: NumericString + - 19: PrintableString + - 20: TeletexString + - 21: VideotexString + - 22: IA5String + - 23: UTCTime + - 24: GeneralizedTime + - 25: GraphicString + - 26: VisibleString + - 27: GeneralString + - 28: UniversalString + - 29: CharacterString + - 30: BMPString + + :param encoded_data: + A byte string of BER or DER-encoded data + + :param strict: + A boolean indicating if trailing data should be forbidden - if so, a + ValueError will be raised when trailing data exists + + :raises: + ValueError - when strict is True and trailing data is present + ValueError - when the encoded value tag a tag other than listed above + ValueError - when the ASN.1 header length is longer than the data + TypeError - when encoded_data is not a byte string + + :return: + An instance of the one of the universal classes + """ + + return Asn1Value.load(encoded_data, strict=strict) + + +class Asn1Value(object): + """ + The basis of all ASN.1 values + """ + + # The integer 0 for primitive, 1 for constructed + method = None + + # An integer 0 through 3 - see CLASS_NUM_TO_NAME_MAP for value + class_ = None + + # An integer 1 or greater indicating the tag number + tag = None + + # An alternate tag allowed for this type - used for handling broken + # structures where a string value is encoded using an incorrect tag + _bad_tag = None + + # If the value has been implicitly tagged + implicit = False + + # If explicitly tagged, a tuple of 2-element tuples containing the + # class int and tag int, from innermost to outermost + explicit = None + + # The BER/DER header bytes + _header = None + + # Raw encoded value bytes not including class, method, tag, length header + contents = None + + # The BER/DER trailer bytes + _trailer = b'' + + # The native python representation of the value - this is not used by + # some classes since they utilize _bytes or _unicode + _native = None + + @classmethod + def load(cls, encoded_data, strict=False, **kwargs): + """ + Loads a BER/DER-encoded byte string using the current class as the spec + + :param encoded_data: + A byte string of BER or DER-encoded data + + :param strict: + A boolean indicating if trailing data should be forbidden - if so, a + ValueError will be raised when trailing data exists + + :return: + An instance of the current class + """ + + if not isinstance(encoded_data, byte_cls): + raise TypeError('encoded_data must be a byte string, not %s' % type_name(encoded_data)) + + spec = None + if cls.tag is not None: + spec = cls + + value, _ = _parse_build(encoded_data, spec=spec, spec_params=kwargs, strict=strict) + return value + + def __init__(self, explicit=None, implicit=None, no_explicit=False, tag_type=None, class_=None, tag=None, + optional=None, default=None, contents=None): + """ + The optional parameter is not used, but rather included so we don't + have to delete it from the parameter dictionary when passing as keyword + args + + :param explicit: + An int tag number for explicit tagging, or a 2-element tuple of + class and tag. + + :param implicit: + An int tag number for implicit tagging, or a 2-element tuple of + class and tag. + + :param no_explicit: + If explicit tagging info should be removed from this instance. + Used internally to allow contructing the underlying value that + has been wrapped in an explicit tag. + + :param tag_type: + None for normal values, or one of "implicit", "explicit" for tagged + values. Deprecated in favor of explicit and implicit params. + + :param class_: + The class for the value - defaults to "universal" if tag_type is + None, otherwise defaults to "context". Valid values include: + - "universal" + - "application" + - "context" + - "private" + Deprecated in favor of explicit and implicit params. + + :param tag: + The integer tag to override - usually this is used with tag_type or + class_. Deprecated in favor of explicit and implicit params. + + :param optional: + Dummy parameter that allows "optional" key in spec param dicts + + :param default: + The default value to use if the value is currently None + + :param contents: + A byte string of the encoded contents of the value + + :raises: + ValueError - when implicit, explicit, tag_type, class_ or tag are invalid values + """ + + try: + if self.__class__ not in _SETUP_CLASSES: + cls = self.__class__ + # Allow explicit to be specified as a simple 2-element tuple + # instead of requiring the user make a nested tuple + if cls.explicit is not None and isinstance(cls.explicit[0], int_types): + cls.explicit = (cls.explicit, ) + if hasattr(cls, '_setup'): + self._setup() + _SETUP_CLASSES[cls] = True + + # Normalize tagging values + if explicit is not None: + if isinstance(explicit, int_types): + if class_ is None: + class_ = 'context' + explicit = (class_, explicit) + # Prevent both explicit and tag_type == 'explicit' + if tag_type == 'explicit': + tag_type = None + tag = None + + if implicit is not None: + if isinstance(implicit, int_types): + if class_ is None: + class_ = 'context' + implicit = (class_, implicit) + # Prevent both implicit and tag_type == 'implicit' + if tag_type == 'implicit': + tag_type = None + tag = None + + # Convert old tag_type API to explicit/implicit params + if tag_type is not None: + if class_ is None: + class_ = 'context' + if tag_type == 'explicit': + explicit = (class_, tag) + elif tag_type == 'implicit': + implicit = (class_, tag) + else: + raise ValueError(unwrap( + ''' + tag_type must be one of "implicit", "explicit", not %s + ''', + repr(tag_type) + )) + + if explicit is not None: + # Ensure we have a tuple of 2-element tuples + if len(explicit) == 2 and isinstance(explicit[1], int_types): + explicit = (explicit, ) + for class_, tag in explicit: + invalid_class = None + if isinstance(class_, int_types): + if class_ not in CLASS_NUM_TO_NAME_MAP: + invalid_class = class_ + else: + if class_ not in CLASS_NAME_TO_NUM_MAP: + invalid_class = class_ + class_ = CLASS_NAME_TO_NUM_MAP[class_] + if invalid_class is not None: + raise ValueError(unwrap( + ''' + explicit class must be one of "universal", "application", + "context", "private", not %s + ''', + repr(invalid_class) + )) + if tag is not None: + if not isinstance(tag, int_types): + raise TypeError(unwrap( + ''' + explicit tag must be an integer, not %s + ''', + type_name(tag) + )) + if self.explicit is None: + self.explicit = ((class_, tag), ) + else: + self.explicit = self.explicit + ((class_, tag), ) + + elif implicit is not None: + class_, tag = implicit + if class_ not in CLASS_NAME_TO_NUM_MAP: + raise ValueError(unwrap( + ''' + implicit class must be one of "universal", "application", + "context", "private", not %s + ''', + repr(class_) + )) + if tag is not None: + if not isinstance(tag, int_types): + raise TypeError(unwrap( + ''' + implicit tag must be an integer, not %s + ''', + type_name(tag) + )) + self.class_ = CLASS_NAME_TO_NUM_MAP[class_] + self.tag = tag + self.implicit = True + else: + if class_ is not None: + if class_ not in CLASS_NUM_TO_NAME_MAP: + raise ValueError(unwrap( + ''' + class_ must be one of "universal", "application", + "context", "private", not %s + ''', + repr(class_) + )) + self.class_ = CLASS_NAME_TO_NUM_MAP[class_] + + if tag is not None: + self.tag = tag + + if no_explicit: + self.explicit = None + + if contents is not None: + self.contents = contents + + elif default is not None: + self.set(default) + + except (ValueError, TypeError) as e: + args = e.args[1:] + e.args = (e.args[0] + '\n while constructing %s' % type_name(self),) + args + raise e + + def __str__(self): + """ + Since str is different in Python 2 and 3, this calls the appropriate + method, __unicode__() or __bytes__() + + :return: + A unicode string + """ + + if _PY2: + return self.__bytes__() + else: + return self.__unicode__() + + def __repr__(self): + """ + :return: + A unicode string + """ + + if _PY2: + return '<%s %s b%s>' % (type_name(self), id(self), repr(self.dump())) + else: + return '<%s %s %s>' % (type_name(self), id(self), repr(self.dump())) + + def __bytes__(self): + """ + A fall-back method for print() in Python 2 + + :return: + A byte string of the output of repr() + """ + + return self.__repr__().encode('utf-8') + + def __unicode__(self): + """ + A fall-back method for print() in Python 3 + + :return: + A unicode string of the output of repr() + """ + + return self.__repr__() + + def _new_instance(self): + """ + Constructs a new copy of the current object, preserving any tagging + + :return: + An Asn1Value object + """ + + new_obj = self.__class__() + new_obj.class_ = self.class_ + new_obj.tag = self.tag + new_obj.implicit = self.implicit + new_obj.explicit = self.explicit + return new_obj + + def __copy__(self): + """ + Implements the copy.copy() interface + + :return: + A new shallow copy of the current Asn1Value object + """ + + new_obj = self._new_instance() + new_obj._copy(self, copy.copy) + return new_obj + + def __deepcopy__(self, memo): + """ + Implements the copy.deepcopy() interface + + :param memo: + A dict for memoization + + :return: + A new deep copy of the current Asn1Value object + """ + + new_obj = self._new_instance() + memo[id(self)] = new_obj + new_obj._copy(self, copy.deepcopy) + return new_obj + + def copy(self): + """ + Copies the object, preserving any special tagging from it + + :return: + An Asn1Value object + """ + + return copy.deepcopy(self) + + def retag(self, tagging, tag=None): + """ + Copies the object, applying a new tagging to it + + :param tagging: + A dict containing the keys "explicit" and "implicit". Legacy + API allows a unicode string of "implicit" or "explicit". + + :param tag: + A integer tag number. Only used when tagging is a unicode string. + + :return: + An Asn1Value object + """ + + # This is required to preserve the old API + if not isinstance(tagging, dict): + tagging = {tagging: tag} + new_obj = self.__class__(explicit=tagging.get('explicit'), implicit=tagging.get('implicit')) + new_obj._copy(self, copy.deepcopy) + return new_obj + + def untag(self): + """ + Copies the object, removing any special tagging from it + + :return: + An Asn1Value object + """ + + new_obj = self.__class__() + new_obj._copy(self, copy.deepcopy) + return new_obj + + def _copy(self, other, copy_func): + """ + Copies the contents of another Asn1Value object to itself + + :param object: + Another instance of the same class + + :param copy_func: + An reference of copy.copy() or copy.deepcopy() to use when copying + lists, dicts and objects + """ + + if self.__class__ != other.__class__: + raise TypeError(unwrap( + ''' + Can not copy values from %s object to %s object + ''', + type_name(other), + type_name(self) + )) + + self.contents = other.contents + self._native = copy_func(other._native) + + def debug(self, nest_level=1): + """ + Show the binary data and parsed data in a tree structure + """ + + prefix = ' ' * nest_level + + # This interacts with Any and moves the tag, implicit, explicit, _header, + # contents, _footer to the parsed value so duplicate data isn't present + has_parsed = hasattr(self, 'parsed') + + _basic_debug(prefix, self) + if has_parsed: + self.parsed.debug(nest_level + 2) + elif hasattr(self, 'chosen'): + self.chosen.debug(nest_level + 2) + else: + if _PY2 and isinstance(self.native, byte_cls): + print('%s Native: b%s' % (prefix, repr(self.native))) + else: + print('%s Native: %s' % (prefix, self.native)) + + def dump(self, force=False): + """ + Encodes the value using DER + + :param force: + If the encoded contents already exist, clear them and regenerate + to ensure they are in DER format instead of BER format + + :return: + A byte string of the DER-encoded value + """ + + contents = self.contents + + if self._header is None or force: + if isinstance(self, Constructable) and self._indefinite: + self.method = 0 + + header = _dump_header(self.class_, self.method, self.tag, self.contents) + + if self.explicit is not None: + for class_, tag in self.explicit: + header = _dump_header(class_, 1, tag, header + self.contents) + header + + self._header = header + self._trailer = b'' + + return self._header + contents + + +class ValueMap(): + """ + Basic functionality that allows for mapping values from ints or OIDs to + python unicode strings + """ + + # A dict from primitive value (int or OID) to unicode string. This needs + # to be defined in the source code + _map = None + + # A dict from unicode string to int/OID. This is automatically generated + # from _map the first time it is needed + _reverse_map = None + + def _setup(self): + """ + Generates _reverse_map from _map + """ + + cls = self.__class__ + if cls._map is None or cls._reverse_map is not None: + return + cls._reverse_map = {} + for key, value in cls._map.items(): + cls._reverse_map[value] = key + + +class Castable(object): + """ + A mixin to handle converting an object between different classes that + represent the same encoded value, but with different rules for converting + to and from native Python values + """ + + def cast(self, other_class): + """ + Converts the current object into an object of a different class. The + new class must use the ASN.1 encoding for the value. + + :param other_class: + The class to instantiate the new object from + + :return: + An instance of the type other_class + """ + + if other_class.tag != self.__class__.tag: + raise TypeError(unwrap( + ''' + Can not covert a value from %s object to %s object since they + use different tags: %d versus %d + ''', + type_name(other_class), + type_name(self), + other_class.tag, + self.__class__.tag + )) + + new_obj = other_class() + new_obj.class_ = self.class_ + new_obj.implicit = self.implicit + new_obj.explicit = self.explicit + new_obj._header = self._header + new_obj.contents = self.contents + new_obj._trailer = self._trailer + if isinstance(self, Constructable): + new_obj.method = self.method + new_obj._indefinite = self._indefinite + return new_obj + + +class Constructable(object): + """ + A mixin to handle string types that may be constructed from chunks + contained within an indefinite length BER-encoded container + """ + + # Instance attribute indicating if an object was indefinite + # length when parsed - affects parsing and dumping + _indefinite = False + + # Class attribute that indicates the offset into self.contents + # that contains the chunks of data to merge + _chunks_offset = 0 + + def _merge_chunks(self): + """ + :return: + A concatenation of the native values of the contained chunks + """ + + if not self._indefinite: + return self._as_chunk() + + pointer = self._chunks_offset + contents_len = len(self.contents) + output = None + + while pointer < contents_len: + # We pass the current class as the spec so content semantics are preserved + sub_value, pointer = _parse_build(self.contents, pointer, spec=self.__class__) + if output is None: + output = sub_value._merge_chunks() + else: + output += sub_value._merge_chunks() + + if output is None: + return self._as_chunk() + + return output + + def _as_chunk(self): + """ + A method to return a chunk of data that can be combined for + constructed method values + + :return: + A native Python value that can be added together. Examples include + byte strings, unicode strings or tuples. + """ + + if self._chunks_offset == 0: + return self.contents + return self.contents[self._chunks_offset:] + + def _copy(self, other, copy_func): + """ + Copies the contents of another Constructable object to itself + + :param object: + Another instance of the same class + + :param copy_func: + An reference of copy.copy() or copy.deepcopy() to use when copying + lists, dicts and objects + """ + + super(Constructable, self)._copy(other, copy_func) + self.method = other.method + self._indefinite = other._indefinite + + +class Void(Asn1Value): + """ + A representation of an optional value that is not present. Has .native + property and .dump() method to be compatible with other value classes. + """ + + contents = b'' + + def __eq__(self, other): + """ + :param other: + The other Primitive to compare to + + :return: + A boolean + """ + + return other.__class__ == self.__class__ + + def __nonzero__(self): + return False + + def __len__(self): + return 0 + + def __iter__(self): + return iter(()) + + @property + def native(self): + """ + The a native Python datatype representation of this value + + :return: + None + """ + + return None + + def dump(self, force=False): + """ + Encodes the value using DER + + :param force: + If the encoded contents already exist, clear them and regenerate + to ensure they are in DER format instead of BER format + + :return: + A byte string of the DER-encoded value + """ + + return b'' + + +VOID = Void() + + +class Any(Asn1Value): + """ + A value class that can contain any value, and allows for easy parsing of + the underlying encoded value using a spec. This is normally contained in + a Structure that has an ObjectIdentifier field and _oid_pair and _oid_specs + defined. + """ + + # The parsed value object + _parsed = None + + def __init__(self, value=None, **kwargs): + """ + Sets the value of the object before passing to Asn1Value.__init__() + + :param value: + An Asn1Value object that will be set as the parsed value + """ + + Asn1Value.__init__(self, **kwargs) + + try: + if value is not None: + if not isinstance(value, Asn1Value): + raise TypeError(unwrap( + ''' + value must be an instance of Asn1Value, not %s + ''', + type_name(value) + )) + + self._parsed = (value, value.__class__, None) + self.contents = value.dump() + + except (ValueError, TypeError) as e: + args = e.args[1:] + e.args = (e.args[0] + '\n while constructing %s' % type_name(self),) + args + raise e + + @property + def native(self): + """ + The a native Python datatype representation of this value + + :return: + The .native value from the parsed value object + """ + + if self._parsed is None: + self.parse() + + return self._parsed[0].native + + @property + def parsed(self): + """ + Returns the parsed object from .parse() + + :return: + The object returned by .parse() + """ + + if self._parsed is None: + self.parse() + + return self._parsed[0] + + def parse(self, spec=None, spec_params=None): + """ + Parses the contents generically, or using a spec with optional params + + :param spec: + A class derived from Asn1Value that defines what class_ and tag the + value should have, and the semantics of the encoded value. The + return value will be of this type. If omitted, the encoded value + will be decoded using the standard universal tag based on the + encoded tag number. + + :param spec_params: + A dict of params to pass to the spec object + + :return: + An object of the type spec, or if not present, a child of Asn1Value + """ + + if self._parsed is None or self._parsed[1:3] != (spec, spec_params): + try: + passed_params = spec_params or {} + _tag_type_to_explicit_implicit(passed_params) + if self.explicit is not None: + if 'explicit' in passed_params: + passed_params['explicit'] = self.explicit + passed_params['explicit'] + else: + passed_params['explicit'] = self.explicit + contents = self._header + self.contents + self._trailer + parsed_value, _ = _parse_build( + contents, + spec=spec, + spec_params=passed_params + ) + self._parsed = (parsed_value, spec, spec_params) + + # Once we've parsed the Any value, clear any attributes from this object + # since they are now duplicate + self.tag = None + self.explicit = None + self.implicit = False + self._header = b'' + self.contents = contents + self._trailer = b'' + + except (ValueError, TypeError) as e: + args = e.args[1:] + e.args = (e.args[0] + '\n while parsing %s' % type_name(self),) + args + raise e + return self._parsed[0] + + def _copy(self, other, copy_func): + """ + Copies the contents of another Any object to itself + + :param object: + Another instance of the same class + + :param copy_func: + An reference of copy.copy() or copy.deepcopy() to use when copying + lists, dicts and objects + """ + + super(Any, self)._copy(other, copy_func) + self._parsed = copy_func(other._parsed) + + def dump(self, force=False): + """ + Encodes the value using DER + + :param force: + If the encoded contents already exist, clear them and regenerate + to ensure they are in DER format instead of BER format + + :return: + A byte string of the DER-encoded value + """ + + if self._parsed is None: + self.parse() + + return self._parsed[0].dump(force=force) + + +class Choice(Asn1Value): + """ + A class to handle when a value may be one of several options + """ + + # The index in _alternatives of the validated alternative + _choice = None + + # The name of the chosen alternative + _name = None + + # The Asn1Value object for the chosen alternative + _parsed = None + + # A list of tuples in one of the following forms. + # + # Option 1, a unicode string field name and a value class + # + # ("name", Asn1ValueClass) + # + # Option 2, same as Option 1, but with a dict of class params + # + # ("name", Asn1ValueClass, {'explicit': 5}) + _alternatives = None + + # A dict that maps tuples of (class_, tag) to an index in _alternatives + _id_map = None + + # A dict that maps alternative names to an index in _alternatives + _name_map = None + + @classmethod + def load(cls, encoded_data, strict=False, **kwargs): + """ + Loads a BER/DER-encoded byte string using the current class as the spec + + :param encoded_data: + A byte string of BER or DER encoded data + + :param strict: + A boolean indicating if trailing data should be forbidden - if so, a + ValueError will be raised when trailing data exists + + :return: + A instance of the current class + """ + + if not isinstance(encoded_data, byte_cls): + raise TypeError('encoded_data must be a byte string, not %s' % type_name(encoded_data)) + + value, _ = _parse_build(encoded_data, spec=cls, spec_params=kwargs, strict=strict) + return value + + def _setup(self): + """ + Generates _id_map from _alternatives to allow validating contents + """ + + cls = self.__class__ + cls._id_map = {} + cls._name_map = {} + for index, info in enumerate(cls._alternatives): + if len(info) < 3: + info = info + ({},) + cls._alternatives[index] = info + id_ = _build_id_tuple(info[2], info[1]) + cls._id_map[id_] = index + cls._name_map[info[0]] = index + + def __init__(self, name=None, value=None, **kwargs): + """ + Checks to ensure implicit tagging is not being used since it is + incompatible with Choice, then forwards on to Asn1Value.__init__() + + :param name: + The name of the alternative to be set - used with value. + Alternatively this may be a dict with a single key being the name + and the value being the value, or a two-element tuple of the the + name and the value. + + :param value: + The alternative value to set - used with name + + :raises: + ValueError - when implicit param is passed (or legacy tag_type param is "implicit") + """ + + _tag_type_to_explicit_implicit(kwargs) + + Asn1Value.__init__(self, **kwargs) + + try: + if kwargs.get('implicit') is not None: + raise ValueError(unwrap( + ''' + The Choice type can not be implicitly tagged even if in an + implicit module - due to its nature any tagging must be + explicit + ''' + )) + + if name is not None: + if isinstance(name, dict): + if len(name) != 1: + raise ValueError(unwrap( + ''' + When passing a dict as the "name" argument to %s, + it must have a single key/value - however %d were + present + ''', + type_name(self), + len(name) + )) + name, value = list(name.items())[0] + + if isinstance(name, tuple): + if len(name) != 2: + raise ValueError(unwrap( + ''' + When passing a tuple as the "name" argument to %s, + it must have two elements, the name and value - + however %d were present + ''', + type_name(self), + len(name) + )) + value = name[1] + name = name[0] + + if name not in self._name_map: + raise ValueError(unwrap( + ''' + The name specified, "%s", is not a valid alternative + for %s + ''', + name, + type_name(self) + )) + + self._choice = self._name_map[name] + _, spec, params = self._alternatives[self._choice] + + if not isinstance(value, spec): + value = spec(value, **params) + else: + value = _fix_tagging(value, params) + self._parsed = value + + except (ValueError, TypeError) as e: + args = e.args[1:] + e.args = (e.args[0] + '\n while constructing %s' % type_name(self),) + args + raise e + + @property + def name(self): + """ + :return: + A unicode string of the field name of the chosen alternative + """ + if not self._name: + self._name = self._alternatives[self._choice][0] + return self._name + + def parse(self): + """ + Parses the detected alternative + + :return: + An Asn1Value object of the chosen alternative + """ + + if self._parsed is not None: + return self._parsed + + try: + _, spec, params = self._alternatives[self._choice] + self._parsed, _ = _parse_build(self.contents, spec=spec, spec_params=params) + except (ValueError, TypeError) as e: + args = e.args[1:] + e.args = (e.args[0] + '\n while parsing %s' % type_name(self),) + args + raise e + + @property + def chosen(self): + """ + :return: + An Asn1Value object of the chosen alternative + """ + + return self.parse() + + @property + def native(self): + """ + The a native Python datatype representation of this value + + :return: + The .native value from the contained value object + """ + + return self.chosen.native + + def validate(self, class_, tag, contents): + """ + Ensures that the class and tag specified exist as an alternative + + :param class_: + The integer class_ from the encoded value header + + :param tag: + The integer tag from the encoded value header + + :param contents: + A byte string of the contents of the value - used when the object + is explicitly tagged + + :raises: + ValueError - when value is not a valid alternative + """ + + id_ = (class_, tag) + + if self.explicit is not None: + if self.explicit[-1] != id_: + raise ValueError(unwrap( + ''' + %s was explicitly tagged, but the value provided does not + match the class and tag + ''', + type_name(self) + )) + + ((class_, _, tag, _, _, _), _) = _parse(contents, len(contents)) + id_ = (class_, tag) + + if id_ in self._id_map: + self._choice = self._id_map[id_] + return + + # This means the Choice was implicitly tagged + if self.class_ is not None and self.tag is not None: + if len(self._alternatives) > 1: + raise ValueError(unwrap( + ''' + %s was implicitly tagged, but more than one alternative + exists + ''', + type_name(self) + )) + if id_ == (self.class_, self.tag): + self._choice = 0 + return + + asn1 = self._format_class_tag(class_, tag) + asn1s = [self._format_class_tag(pair[0], pair[1]) for pair in self._id_map] + + raise ValueError(unwrap( + ''' + Value %s did not match the class and tag of any of the alternatives + in %s: %s + ''', + asn1, + type_name(self), + ', '.join(asn1s) + )) + + def _format_class_tag(self, class_, tag): + """ + :return: + A unicode string of a human-friendly representation of the class and tag + """ + + return '[%s %s]' % (CLASS_NUM_TO_NAME_MAP[class_].upper(), tag) + + def _copy(self, other, copy_func): + """ + Copies the contents of another Choice object to itself + + :param object: + Another instance of the same class + + :param copy_func: + An reference of copy.copy() or copy.deepcopy() to use when copying + lists, dicts and objects + """ + + super(Choice, self)._copy(other, copy_func) + self._choice = other._choice + self._name = other._name + self._parsed = copy_func(other._parsed) + + def dump(self, force=False): + """ + Encodes the value using DER + + :param force: + If the encoded contents already exist, clear them and regenerate + to ensure they are in DER format instead of BER format + + :return: + A byte string of the DER-encoded value + """ + + self.contents = self.chosen.dump(force=force) + if self._header is None or force: + self._header = b'' + if self.explicit is not None: + for class_, tag in self.explicit: + self._header = _dump_header(class_, 1, tag, self._header + self.contents) + self._header + return self._header + self.contents + + +class Concat(object): + """ + A class that contains two or more encoded child values concatentated + together. THIS IS NOT PART OF THE ASN.1 SPECIFICATION! This exists to handle + the x509.TrustedCertificate() class for OpenSSL certificates containing + extra information. + """ + + # A list of the specs of the concatenated values + _child_specs = None + + _children = None + + @classmethod + def load(cls, encoded_data, strict=False): + """ + Loads a BER/DER-encoded byte string using the current class as the spec + + :param encoded_data: + A byte string of BER or DER encoded data + + :param strict: + A boolean indicating if trailing data should be forbidden - if so, a + ValueError will be raised when trailing data exists + + :return: + A Concat object + """ + + return cls(contents=encoded_data, strict=strict) + + def __init__(self, value=None, contents=None, strict=False): + """ + :param value: + A native Python datatype to initialize the object value with + + :param contents: + A byte string of the encoded contents of the value + + :param strict: + A boolean indicating if trailing data should be forbidden - if so, a + ValueError will be raised when trailing data exists in contents + + :raises: + ValueError - when an error occurs with one of the children + TypeError - when an error occurs with one of the children + """ + + if contents is not None: + try: + contents_len = len(contents) + self._children = [] + + offset = 0 + for spec in self._child_specs: + if offset < contents_len: + child_value, offset = _parse_build(contents, pointer=offset, spec=spec) + else: + child_value = spec() + self._children.append(child_value) + + if strict and offset != contents_len: + extra_bytes = contents_len - offset + raise ValueError('Extra data - %d bytes of trailing data were provided' % extra_bytes) + + except (ValueError, TypeError) as e: + args = e.args[1:] + e.args = (e.args[0] + '\n while constructing %s' % type_name(self),) + args + raise e + + if value is not None: + if self._children is None: + self._children = [None] * len(self._child_specs) + for index, data in enumerate(value): + self.__setitem__(index, data) + + def __str__(self): + """ + Since str is different in Python 2 and 3, this calls the appropriate + method, __unicode__() or __bytes__() + + :return: + A unicode string + """ + + if _PY2: + return self.__bytes__() + else: + return self.__unicode__() + + def __bytes__(self): + """ + A byte string of the DER-encoded contents + """ + + return self.dump() + + def __unicode__(self): + """ + :return: + A unicode string + """ + + return repr(self) + + def __repr__(self): + """ + :return: + A unicode string + """ + + return '<%s %s %s>' % (type_name(self), id(self), repr(self.dump())) + + def __copy__(self): + """ + Implements the copy.copy() interface + + :return: + A new shallow copy of the Concat object + """ + + new_obj = self.__class__() + new_obj._copy(self, copy.copy) + return new_obj + + def __deepcopy__(self, memo): + """ + Implements the copy.deepcopy() interface + + :param memo: + A dict for memoization + + :return: + A new deep copy of the Concat object and all child objects + """ + + new_obj = self.__class__() + memo[id(self)] = new_obj + new_obj._copy(self, copy.deepcopy) + return new_obj + + def copy(self): + """ + Copies the object + + :return: + A Concat object + """ + + return copy.deepcopy(self) + + def _copy(self, other, copy_func): + """ + Copies the contents of another Concat object to itself + + :param object: + Another instance of the same class + + :param copy_func: + An reference of copy.copy() or copy.deepcopy() to use when copying + lists, dicts and objects + """ + + if self.__class__ != other.__class__: + raise TypeError(unwrap( + ''' + Can not copy values from %s object to %s object + ''', + type_name(other), + type_name(self) + )) + + self._children = copy_func(other._children) + + def debug(self, nest_level=1): + """ + Show the binary data and parsed data in a tree structure + """ + + prefix = ' ' * nest_level + print('%s%s Object #%s' % (prefix, type_name(self), id(self))) + print('%s Children:' % (prefix,)) + for child in self._children: + child.debug(nest_level + 2) + + def dump(self, force=False): + """ + Encodes the value using DER + + :param force: + If the encoded contents already exist, clear them and regenerate + to ensure they are in DER format instead of BER format + + :return: + A byte string of the DER-encoded value + """ + + contents = b'' + for child in self._children: + contents += child.dump(force=force) + return contents + + @property + def contents(self): + """ + :return: + A byte string of the DER-encoded contents of the children + """ + + return self.dump() + + def __len__(self): + """ + :return: + Integer + """ + + return len(self._children) + + def __getitem__(self, key): + """ + Allows accessing children by index + + :param key: + An integer of the child index + + :raises: + KeyError - when an index is invalid + + :return: + The Asn1Value object of the child specified + """ + + if key > len(self._child_specs) - 1 or key < 0: + raise KeyError(unwrap( + ''' + No child is definition for position %d of %s + ''', + key, + type_name(self) + )) + + return self._children[key] + + def __setitem__(self, key, value): + """ + Allows settings children by index + + :param key: + An integer of the child index + + :param value: + An Asn1Value object to set the child to + + :raises: + KeyError - when an index is invalid + ValueError - when the value is not an instance of Asn1Value + """ + + if key > len(self._child_specs) - 1 or key < 0: + raise KeyError(unwrap( + ''' + No child is defined for position %d of %s + ''', + key, + type_name(self) + )) + + if not isinstance(value, Asn1Value): + raise ValueError(unwrap( + ''' + Value for child %s of %s is not an instance of + asn1crypto.core.Asn1Value + ''', + key, + type_name(self) + )) + + self._children[key] = value + + def __iter__(self): + """ + :return: + An iterator of child values + """ + + return iter(self._children) + + +class Primitive(Asn1Value): + """ + Sets the class_ and method attributes for primitive, universal values + """ + + class_ = 0 + + method = 0 + + def __init__(self, value=None, default=None, contents=None, **kwargs): + """ + Sets the value of the object before passing to Asn1Value.__init__() + + :param value: + A native Python datatype to initialize the object value with + + :param default: + The default value if no value is specified + + :param contents: + A byte string of the encoded contents of the value + """ + + Asn1Value.__init__(self, **kwargs) + + try: + if contents is not None: + self.contents = contents + + elif value is not None: + self.set(value) + + elif default is not None: + self.set(default) + + except (ValueError, TypeError) as e: + args = e.args[1:] + e.args = (e.args[0] + '\n while constructing %s' % type_name(self),) + args + raise e + + def set(self, value): + """ + Sets the value of the object + + :param value: + A byte string + """ + + if not isinstance(value, byte_cls): + raise TypeError(unwrap( + ''' + %s value must be a byte string, not %s + ''', + type_name(self), + type_name(value) + )) + + self._native = value + self.contents = value + self._header = None + if self._trailer != b'': + self._trailer = b'' + + def dump(self, force=False): + """ + Encodes the value using DER + + :param force: + If the encoded contents already exist, clear them and regenerate + to ensure they are in DER format instead of BER format + + :return: + A byte string of the DER-encoded value + """ + + if force: + native = self.native + self.contents = None + self.set(native) + + return Asn1Value.dump(self) + + def __ne__(self, other): + return not self == other + + def __eq__(self, other): + """ + :param other: + The other Primitive to compare to + + :return: + A boolean + """ + + if not isinstance(other, Primitive): + return False + + if self.contents != other.contents: + return False + + # We compare class tag numbers since object tag numbers could be + # different due to implicit or explicit tagging + if self.__class__.tag != other.__class__.tag: + return False + + if self.__class__ == other.__class__ and self.contents == other.contents: + return True + + # If the objects share a common base class that is not too low-level + # then we can compare the contents + self_bases = (set(self.__class__.__bases__) | set([self.__class__])) - set([Asn1Value, Primitive, ValueMap]) + other_bases = (set(other.__class__.__bases__) | set([other.__class__])) - set([Asn1Value, Primitive, ValueMap]) + if self_bases | other_bases: + return self.contents == other.contents + + # When tagging is going on, do the extra work of constructing new + # objects to see if the dumped representation are the same + if self.implicit or self.explicit or other.implicit or other.explicit: + return self.untag().dump() == other.untag().dump() + + return self.dump() == other.dump() + + +class AbstractString(Constructable, Primitive): + """ + A base class for all strings that have a known encoding. In general, we do + not worry ourselves with confirming that the decoded values match a specific + set of characters, only that they are decoded into a Python unicode string + """ + + # The Python encoding name to use when decoding or encoded the contents + _encoding = 'latin1' + + # Instance attribute of (possibly-merged) unicode string + _unicode = None + + def set(self, value): + """ + Sets the value of the string + + :param value: + A unicode string + """ + + if not isinstance(value, str_cls): + raise TypeError(unwrap( + ''' + %s value must be a unicode string, not %s + ''', + type_name(self), + type_name(value) + )) + + self._unicode = value + self.contents = value.encode(self._encoding) + self._header = None + if self._indefinite: + self._indefinite = False + self.method = 0 + if self._trailer != b'': + self._trailer = b'' + + def __unicode__(self): + """ + :return: + A unicode string + """ + + if self.contents is None: + return '' + if self._unicode is None: + self._unicode = self._merge_chunks().decode(self._encoding) + return self._unicode + + def _copy(self, other, copy_func): + """ + Copies the contents of another AbstractString object to itself + + :param object: + Another instance of the same class + + :param copy_func: + An reference of copy.copy() or copy.deepcopy() to use when copying + lists, dicts and objects + """ + + super(AbstractString, self)._copy(other, copy_func) + self._unicode = other._unicode + + @property + def native(self): + """ + The a native Python datatype representation of this value + + :return: + A unicode string or None + """ + + if self.contents is None: + return None + + return self.__unicode__() + + +class Boolean(Primitive): + """ + Represents a boolean in both ASN.1 and Python + """ + + tag = 1 + + def set(self, value): + """ + Sets the value of the object + + :param value: + True, False or another value that works with bool() + """ + + self._native = bool(value) + self.contents = b'\x00' if not value else b'\xff' + self._header = None + if self._trailer != b'': + self._trailer = b'' + + # Python 2 + def __nonzero__(self): + """ + :return: + True or False + """ + return self.__bool__() + + def __bool__(self): + """ + :return: + True or False + """ + return self.contents != b'\x00' + + @property + def native(self): + """ + The a native Python datatype representation of this value + + :return: + True, False or None + """ + + if self.contents is None: + return None + + if self._native is None: + self._native = self.__bool__() + return self._native + + +class Integer(Primitive, ValueMap): + """ + Represents an integer in both ASN.1 and Python + """ + + tag = 2 + + def set(self, value): + """ + Sets the value of the object + + :param value: + An integer, or a unicode string if _map is set + + :raises: + ValueError - when an invalid value is passed + """ + + if isinstance(value, str_cls): + if self._map is None: + raise ValueError(unwrap( + ''' + %s value is a unicode string, but no _map provided + ''', + type_name(self) + )) + + if value not in self._reverse_map: + raise ValueError(unwrap( + ''' + %s value, %s, is not present in the _map + ''', + type_name(self), + value + )) + + value = self._reverse_map[value] + + elif not isinstance(value, int_types): + raise TypeError(unwrap( + ''' + %s value must be an integer or unicode string when a name_map + is provided, not %s + ''', + type_name(self), + type_name(value) + )) + + self._native = self._map[value] if self._map and value in self._map else value + + self.contents = int_to_bytes(value, signed=True) + self._header = None + if self._trailer != b'': + self._trailer = b'' + + def __int__(self): + """ + :return: + An integer + """ + return int_from_bytes(self.contents, signed=True) + + @property + def native(self): + """ + The a native Python datatype representation of this value + + :return: + An integer or None + """ + + if self.contents is None: + return None + + if self._native is None: + self._native = self.__int__() + if self._map is not None and self._native in self._map: + self._native = self._map[self._native] + return self._native + + +class BitString(Constructable, Castable, Primitive, ValueMap, object): + """ + Represents a bit string from ASN.1 as a Python tuple of 1s and 0s + """ + + tag = 3 + + _size = None + + # Used with _as_chunk() from Constructable + _chunk = None + _chunks_offset = 1 + + def _setup(self): + """ + Generates _reverse_map from _map + """ + + ValueMap._setup(self) + + cls = self.__class__ + if cls._map is not None: + cls._size = max(self._map.keys()) + 1 + + def set(self, value): + """ + Sets the value of the object + + :param value: + An integer or a tuple of integers 0 and 1 + + :raises: + ValueError - when an invalid value is passed + """ + + if isinstance(value, set): + if self._map is None: + raise ValueError(unwrap( + ''' + %s._map has not been defined + ''', + type_name(self) + )) + + bits = [0] * self._size + self._native = value + for index in range(0, self._size): + key = self._map.get(index) + if key is None: + continue + if key in value: + bits[index] = 1 + + value = ''.join(map(str_cls, bits)) + + elif value.__class__ == tuple: + if self._map is None: + self._native = value + else: + self._native = set() + for index, bit in enumerate(value): + if bit: + name = self._map.get(index, index) + self._native.add(name) + value = ''.join(map(str_cls, value)) + + else: + raise TypeError(unwrap( + ''' + %s value must be a tuple of ones and zeros or a set of unicode + strings, not %s + ''', + type_name(self), + type_name(value) + )) + + self._chunk = None + + if self._map is not None: + if len(value) > self._size: + raise ValueError(unwrap( + ''' + %s value must be at most %s bits long, specified was %s long + ''', + type_name(self), + self._size, + len(value) + )) + # A NamedBitList must have trailing zero bit truncated. See + # https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + # section 11.2, + # https://tools.ietf.org/html/rfc5280#page-134 and + # https://www.ietf.org/mail-archive/web/pkix/current/msg10443.html + value = value.rstrip('0') + size = len(value) + + size_mod = size % 8 + extra_bits = 0 + if size_mod != 0: + extra_bits = 8 - size_mod + value += '0' * extra_bits + + size_in_bytes = int(math.ceil(size / 8)) + + if extra_bits: + extra_bits_byte = int_to_bytes(extra_bits) + else: + extra_bits_byte = b'\x00' + + if value == '': + value_bytes = b'' + else: + value_bytes = int_to_bytes(int(value, 2)) + if len(value_bytes) != size_in_bytes: + value_bytes = (b'\x00' * (size_in_bytes - len(value_bytes))) + value_bytes + + self.contents = extra_bits_byte + value_bytes + self._header = None + if self._indefinite: + self._indefinite = False + self.method = 0 + if self._trailer != b'': + self._trailer = b'' + + def __getitem__(self, key): + """ + Retrieves a boolean version of one of the bits based on a name from the + _map + + :param key: + The unicode string of one of the bit names + + :raises: + ValueError - when _map is not set or the key name is invalid + + :return: + A boolean if the bit is set + """ + + is_int = isinstance(key, int_types) + if not is_int: + if not isinstance(self._map, dict): + raise ValueError(unwrap( + ''' + %s._map has not been defined + ''', + type_name(self) + )) + + if key not in self._reverse_map: + raise ValueError(unwrap( + ''' + %s._map does not contain an entry for "%s" + ''', + type_name(self), + key + )) + + if self._native is None: + self.native + + if self._map is None: + if len(self._native) >= key + 1: + return bool(self._native[key]) + return False + + if is_int: + key = self._map.get(key, key) + + return key in self._native + + def __setitem__(self, key, value): + """ + Sets one of the bits based on a name from the _map + + :param key: + The unicode string of one of the bit names + + :param value: + A boolean value + + :raises: + ValueError - when _map is not set or the key name is invalid + """ + + is_int = isinstance(key, int_types) + if not is_int: + if self._map is None: + raise ValueError(unwrap( + ''' + %s._map has not been defined + ''', + type_name(self) + )) + + if key not in self._reverse_map: + raise ValueError(unwrap( + ''' + %s._map does not contain an entry for "%s" + ''', + type_name(self), + key + )) + + if self._native is None: + self.native + + if self._map is None: + new_native = list(self._native) + max_key = len(new_native) - 1 + if key > max_key: + new_native.extend([0] * (key - max_key)) + new_native[key] = 1 if value else 0 + self._native = tuple(new_native) + + else: + if is_int: + key = self._map.get(key, key) + + if value: + if key not in self._native: + self._native.add(key) + else: + if key in self._native: + self._native.remove(key) + + self.set(self._native) + + def _as_chunk(self): + """ + Allows reconstructing indefinite length values + + :return: + A tuple of integers + """ + + extra_bits = int_from_bytes(self.contents[0:1]) + bit_string = '{0:b}'.format(int_from_bytes(self.contents[1:])) + byte_len = len(self.contents[1:]) + bit_len = len(bit_string) + + # Left-pad the bit string to a byte multiple to ensure we didn't + # lose any zero bits on the left + mod_bit_len = bit_len % 8 + if mod_bit_len != 0: + bit_string = ('0' * (8 - mod_bit_len)) + bit_string + bit_len = len(bit_string) + + if bit_len // 8 < byte_len: + missing_bytes = byte_len - (bit_len // 8) + bit_string = ('0' * (8 * missing_bytes)) + bit_string + + # Trim off the extra bits on the right used to fill the last byte + if extra_bits > 0: + bit_string = bit_string[0:0 - extra_bits] + + return tuple(map(int, tuple(bit_string))) + + @property + def native(self): + """ + The a native Python datatype representation of this value + + :return: + If a _map is set, a set of names, or if no _map is set, a tuple of + integers 1 and 0. None if no value. + """ + + # For BitString we default the value to be all zeros + if self.contents is None: + if self._map is None: + self.set(()) + else: + self.set(set()) + + if self._native is None: + bits = self._merge_chunks() + if self._map: + self._native = set() + for index, bit in enumerate(bits): + if bit: + name = self._map.get(index, index) + self._native.add(name) + else: + self._native = bits + return self._native + + +class OctetBitString(Constructable, Castable, Primitive): + """ + Represents a bit string in ASN.1 as a Python byte string + """ + + tag = 3 + + # Whenever dealing with octet-based bit strings, we really want the + # bytes, so we just ignore the unused bits portion since it isn't + # applicable to the current use case + # unused_bits = struct.unpack('>B', self.contents[0:1])[0] + _chunks_offset = 1 + + # Instance attribute of (possibly-merged) byte string + _bytes = None + + def set(self, value): + """ + Sets the value of the object + + :param value: + A byte string + + :raises: + ValueError - when an invalid value is passed + """ + + if not isinstance(value, byte_cls): + raise TypeError(unwrap( + ''' + %s value must be a byte string, not %s + ''', + type_name(self), + type_name(value) + )) + + self._bytes = value + # Set the unused bits to 0 + self.contents = b'\x00' + value + self._header = None + if self._indefinite: + self._indefinite = False + self.method = 0 + if self._trailer != b'': + self._trailer = b'' + + def __bytes__(self): + """ + :return: + A byte string + """ + + if self.contents is None: + return b'' + if self._bytes is None: + self._bytes = self._merge_chunks() + return self._bytes + + def _copy(self, other, copy_func): + """ + Copies the contents of another OctetBitString object to itself + + :param object: + Another instance of the same class + + :param copy_func: + An reference of copy.copy() or copy.deepcopy() to use when copying + lists, dicts and objects + """ + + super(OctetBitString, self)._copy(other, copy_func) + self._bytes = other._bytes + + @property + def native(self): + """ + The a native Python datatype representation of this value + + :return: + A byte string or None + """ + + if self.contents is None: + return None + + return self.__bytes__() + + +class IntegerBitString(Constructable, Castable, Primitive): + """ + Represents a bit string in ASN.1 as a Python integer + """ + + tag = 3 + + _chunks_offset = 1 + + def set(self, value): + """ + Sets the value of the object + + :param value: + An integer + + :raises: + ValueError - when an invalid value is passed + """ + + if not isinstance(value, int_types): + raise TypeError(unwrap( + ''' + %s value must be an integer, not %s + ''', + type_name(self), + type_name(value) + )) + + self._native = value + # Set the unused bits to 0 + self.contents = b'\x00' + int_to_bytes(value, signed=True) + self._header = None + if self._indefinite: + self._indefinite = False + self.method = 0 + if self._trailer != b'': + self._trailer = b'' + + def _as_chunk(self): + """ + Allows reconstructing indefinite length values + + :return: + A unicode string of bits - 1s and 0s + """ + + extra_bits = int_from_bytes(self.contents[0:1]) + bit_string = '{0:b}'.format(int_from_bytes(self.contents[1:])) + + # Ensure we have leading zeros since these chunks may be concatenated together + mod_bit_len = len(bit_string) % 8 + if mod_bit_len != 0: + bit_string = ('0' * (8 - mod_bit_len)) + bit_string + + if extra_bits > 0: + return bit_string[0:0 - extra_bits] + + return bit_string + + @property + def native(self): + """ + The a native Python datatype representation of this value + + :return: + An integer or None + """ + + if self.contents is None: + return None + + if self._native is None: + extra_bits = int_from_bytes(self.contents[0:1]) + # Fast path + if not self._indefinite and extra_bits == 0: + self._native = int_from_bytes(self.contents[1:]) + else: + if self._indefinite and extra_bits > 0: + raise ValueError('Constructed bit string has extra bits on indefinite container') + self._native = int(self._merge_chunks(), 2) + return self._native + + +class OctetString(Constructable, Castable, Primitive): + """ + Represents a byte string in both ASN.1 and Python + """ + + tag = 4 + + # Instance attribute of (possibly-merged) byte string + _bytes = None + + def set(self, value): + """ + Sets the value of the object + + :param value: + A byte string + """ + + if not isinstance(value, byte_cls): + raise TypeError(unwrap( + ''' + %s value must be a byte string, not %s + ''', + type_name(self), + type_name(value) + )) + + self._bytes = value + self.contents = value + self._header = None + if self._indefinite: + self._indefinite = False + self.method = 0 + if self._trailer != b'': + self._trailer = b'' + + def __bytes__(self): + """ + :return: + A byte string + """ + + if self.contents is None: + return b'' + if self._bytes is None: + self._bytes = self._merge_chunks() + return self._bytes + + def _copy(self, other, copy_func): + """ + Copies the contents of another OctetString object to itself + + :param object: + Another instance of the same class + + :param copy_func: + An reference of copy.copy() or copy.deepcopy() to use when copying + lists, dicts and objects + """ + + super(OctetString, self)._copy(other, copy_func) + self._bytes = other._bytes + + @property + def native(self): + """ + The a native Python datatype representation of this value + + :return: + A byte string or None + """ + + if self.contents is None: + return None + + return self.__bytes__() + + +class IntegerOctetString(Constructable, Castable, Primitive): + """ + Represents a byte string in ASN.1 as a Python integer + """ + + tag = 4 + + def set(self, value): + """ + Sets the value of the object + + :param value: + An integer + + :raises: + ValueError - when an invalid value is passed + """ + + if not isinstance(value, int_types): + raise TypeError(unwrap( + ''' + %s value must be an integer, not %s + ''', + type_name(self), + type_name(value) + )) + + self._native = value + self.contents = int_to_bytes(value, signed=False) + self._header = None + if self._indefinite: + self._indefinite = False + self.method = 0 + if self._trailer != b'': + self._trailer = b'' + + @property + def native(self): + """ + The a native Python datatype representation of this value + + :return: + An integer or None + """ + + if self.contents is None: + return None + + if self._native is None: + self._native = int_from_bytes(self._merge_chunks()) + return self._native + + +class ParsableOctetString(Constructable, Castable, Primitive): + + tag = 4 + + _parsed = None + + # Instance attribute of (possibly-merged) byte string + _bytes = None + + def __init__(self, value=None, parsed=None, **kwargs): + """ + Allows providing a parsed object that will be serialized to get the + byte string value + + :param value: + A native Python datatype to initialize the object value with + + :param parsed: + If value is None and this is an Asn1Value object, this will be + set as the parsed value, and the value will be obtained by calling + .dump() on this object. + """ + + set_parsed = False + if value is None and parsed is not None and isinstance(parsed, Asn1Value): + value = parsed.dump() + set_parsed = True + + Primitive.__init__(self, value=value, **kwargs) + + if set_parsed: + self._parsed = (parsed, parsed.__class__, None) + + def set(self, value): + """ + Sets the value of the object + + :param value: + A byte string + """ + + if not isinstance(value, byte_cls): + raise TypeError(unwrap( + ''' + %s value must be a byte string, not %s + ''', + type_name(self), + type_name(value) + )) + + self._bytes = value + self.contents = value + self._header = None + if self._indefinite: + self._indefinite = False + self.method = 0 + if self._trailer != b'': + self._trailer = b'' + + def parse(self, spec=None, spec_params=None): + """ + Parses the contents generically, or using a spec with optional params + + :param spec: + A class derived from Asn1Value that defines what class_ and tag the + value should have, and the semantics of the encoded value. The + return value will be of this type. If omitted, the encoded value + will be decoded using the standard universal tag based on the + encoded tag number. + + :param spec_params: + A dict of params to pass to the spec object + + :return: + An object of the type spec, or if not present, a child of Asn1Value + """ + + if self._parsed is None or self._parsed[1:3] != (spec, spec_params): + parsed_value, _ = _parse_build(self.__bytes__(), spec=spec, spec_params=spec_params) + self._parsed = (parsed_value, spec, spec_params) + return self._parsed[0] + + def __bytes__(self): + """ + :return: + A byte string + """ + + if self.contents is None: + return b'' + if self._bytes is None: + self._bytes = self._merge_chunks() + return self._bytes + + def _copy(self, other, copy_func): + """ + Copies the contents of another ParsableOctetString object to itself + + :param object: + Another instance of the same class + + :param copy_func: + An reference of copy.copy() or copy.deepcopy() to use when copying + lists, dicts and objects + """ + + super(ParsableOctetString, self)._copy(other, copy_func) + self._bytes = other._bytes + self._parsed = copy_func(other._parsed) + + @property + def native(self): + """ + The a native Python datatype representation of this value + + :return: + A byte string or None + """ + + if self.contents is None: + return None + + if self._parsed is not None: + return self._parsed[0].native + else: + return self.__bytes__() + + @property + def parsed(self): + """ + Returns the parsed object from .parse() + + :return: + The object returned by .parse() + """ + + if self._parsed is None: + self.parse() + + return self._parsed[0] + + def dump(self, force=False): + """ + Encodes the value using DER + + :param force: + If the encoded contents already exist, clear them and regenerate + to ensure they are in DER format instead of BER format + + :return: + A byte string of the DER-encoded value + """ + + if force: + if self._parsed is not None: + native = self.parsed.dump(force=force) + else: + native = self.native + self.contents = None + self.set(native) + + return Asn1Value.dump(self) + + +class ParsableOctetBitString(ParsableOctetString): + + tag = 3 + + # Whenever dealing with octet-based bit strings, we really want the + # bytes, so we just ignore the unused bits portion since it isn't + # applicable to the current use case + # unused_bits = struct.unpack('>B', self.contents[0:1])[0] + _chunks_offset = 1 + + def set(self, value): + """ + Sets the value of the object + + :param value: + A byte string + + :raises: + ValueError - when an invalid value is passed + """ + + if not isinstance(value, byte_cls): + raise TypeError(unwrap( + ''' + %s value must be a byte string, not %s + ''', + type_name(self), + type_name(value) + )) + + self._bytes = value + # Set the unused bits to 0 + self.contents = b'\x00' + value + self._header = None + if self._indefinite: + self._indefinite = False + self.method = 0 + if self._trailer != b'': + self._trailer = b'' + + +class Null(Primitive): + """ + Represents a null value in ASN.1 as None in Python + """ + + tag = 5 + + contents = b'' + + def set(self, value): + """ + Sets the value of the object + + :param value: + None + """ + + self.contents = b'' + + @property + def native(self): + """ + The a native Python datatype representation of this value + + :return: + None + """ + + return None + + +class ObjectIdentifier(Primitive, ValueMap): + """ + Represents an object identifier in ASN.1 as a Python unicode dotted + integer string + """ + + tag = 6 + + # A unicode string of the dotted form of the object identifier + _dotted = None + + @classmethod + def map(cls, value): + """ + Converts a dotted unicode string OID into a mapped unicode string + + :param value: + A dotted unicode string OID + + :raises: + ValueError - when no _map dict has been defined on the class + TypeError - when value is not a unicode string + + :return: + A mapped unicode string + """ + + if cls._map is None: + raise ValueError(unwrap( + ''' + %s._map has not been defined + ''', + type_name(cls) + )) + + if not isinstance(value, str_cls): + raise TypeError(unwrap( + ''' + value must be a unicode string, not %s + ''', + type_name(value) + )) + + return cls._map.get(value, value) + + @classmethod + def unmap(cls, value): + """ + Converts a mapped unicode string value into a dotted unicode string OID + + :param value: + A mapped unicode string OR dotted unicode string OID + + :raises: + ValueError - when no _map dict has been defined on the class or the value can't be unmapped + TypeError - when value is not a unicode string + + :return: + A dotted unicode string OID + """ + + if cls not in _SETUP_CLASSES: + cls()._setup() + _SETUP_CLASSES[cls] = True + + if cls._map is None: + raise ValueError(unwrap( + ''' + %s._map has not been defined + ''', + type_name(cls) + )) + + if not isinstance(value, str_cls): + raise TypeError(unwrap( + ''' + value must be a unicode string, not %s + ''', + type_name(value) + )) + + if value in cls._reverse_map: + return cls._reverse_map[value] + + if not _OID_RE.match(value): + raise ValueError(unwrap( + ''' + %s._map does not contain an entry for "%s" + ''', + type_name(cls), + value + )) + + return value + + def set(self, value): + """ + Sets the value of the object + + :param value: + A unicode string. May be a dotted integer string, or if _map is + provided, one of the mapped values. + + :raises: + ValueError - when an invalid value is passed + """ + + if not isinstance(value, str_cls): + raise TypeError(unwrap( + ''' + %s value must be a unicode string, not %s + ''', + type_name(self), + type_name(value) + )) + + self._native = value + + if self._map is not None: + if value in self._reverse_map: + value = self._reverse_map[value] + + self.contents = b'' + first = None + for index, part in enumerate(value.split('.')): + part = int(part) + + # The first two parts are merged into a single byte + if index == 0: + first = part + continue + elif index == 1: + part = (first * 40) + part + + encoded_part = chr_cls(0x7F & part) + part = part >> 7 + while part > 0: + encoded_part = chr_cls(0x80 | (0x7F & part)) + encoded_part + part = part >> 7 + self.contents += encoded_part + + self._header = None + if self._trailer != b'': + self._trailer = b'' + + def __unicode__(self): + """ + :return: + A unicode string + """ + + return self.dotted + + @property + def dotted(self): + """ + :return: + A unicode string of the object identifier in dotted notation, thus + ignoring any mapped value + """ + + if self._dotted is None: + output = [] + + part = 0 + for byte in self.contents: + if _PY2: + byte = ord(byte) + part = part * 128 + part += byte & 127 + # Last byte in subidentifier has the eighth bit set to 0 + if byte & 0x80 == 0: + if len(output) == 0: + output.append(str_cls(part // 40)) + output.append(str_cls(part % 40)) + else: + output.append(str_cls(part)) + part = 0 + + self._dotted = '.'.join(output) + return self._dotted + + @property + def native(self): + """ + The a native Python datatype representation of this value + + :return: + A unicode string or None. If _map is not defined, the unicode string + is a string of dotted integers. If _map is defined and the dotted + string is present in the _map, the mapped value is returned. + """ + + if self.contents is None: + return None + + if self._native is None: + self._native = self.dotted + if self._map is not None and self._native in self._map: + self._native = self._map[self._native] + return self._native + + +class ObjectDescriptor(Primitive): + """ + Represents an object descriptor from ASN.1 - no Python implementation + """ + + tag = 7 + + +class InstanceOf(Primitive): + """ + Represents an instance from ASN.1 - no Python implementation + """ + + tag = 8 + + +class Real(Primitive): + """ + Represents a real number from ASN.1 - no Python implementation + """ + + tag = 9 + + +class Enumerated(Integer): + """ + Represents a enumerated list of integers from ASN.1 as a Python + unicode string + """ + + tag = 10 + + def set(self, value): + """ + Sets the value of the object + + :param value: + An integer or a unicode string from _map + + :raises: + ValueError - when an invalid value is passed + """ + + if not isinstance(value, int_types) and not isinstance(value, str_cls): + raise TypeError(unwrap( + ''' + %s value must be an integer or a unicode string, not %s + ''', + type_name(self), + type_name(value) + )) + + if isinstance(value, str_cls): + if value not in self._reverse_map: + raise ValueError(unwrap( + ''' + %s value "%s" is not a valid value + ''', + type_name(self), + value + )) + + value = self._reverse_map[value] + + elif value not in self._map: + raise ValueError(unwrap( + ''' + %s value %s is not a valid value + ''', + type_name(self), + value + )) + + Integer.set(self, value) + + @property + def native(self): + """ + The a native Python datatype representation of this value + + :return: + A unicode string or None + """ + + if self.contents is None: + return None + + if self._native is None: + self._native = self._map[self.__int__()] + return self._native + + +class UTF8String(AbstractString): + """ + Represents a UTF-8 string from ASN.1 as a Python unicode string + """ + + tag = 12 + _encoding = 'utf-8' + + +class RelativeOid(ObjectIdentifier): + """ + Represents an object identifier in ASN.1 as a Python unicode dotted + integer string + """ + + tag = 13 + + +class Sequence(Asn1Value): + """ + Represents a sequence of fields from ASN.1 as a Python object with a + dict-like interface + """ + + tag = 16 + + class_ = 0 + method = 1 + + # A list of child objects, in order of _fields + children = None + + # Sequence overrides .contents to be a property so that the mutated state + # of child objects can be checked to ensure everything is up-to-date + _contents = None + + # Variable to track if the object has been mutated + _mutated = False + + # A list of tuples in one of the following forms. + # + # Option 1, a unicode string field name and a value class + # + # ("name", Asn1ValueClass) + # + # Option 2, same as Option 1, but with a dict of class params + # + # ("name", Asn1ValueClass, {'explicit': 5}) + _fields = [] + + # A dict with keys being the name of a field and the value being a unicode + # string of the method name on self to call to get the spec for that field + _spec_callbacks = None + + # A dict that maps unicode string field names to an index in _fields + _field_map = None + + # A list in the same order as _fields that has tuples in the form (class_, tag) + _field_ids = None + + # An optional 2-element tuple that defines the field names of an OID field + # and the field that the OID should be used to help decode. Works with the + # _oid_specs attribute. + _oid_pair = None + + # A dict with keys that are unicode string OID values and values that are + # Asn1Value classes to use for decoding a variable-type field. + _oid_specs = None + + # A 2-element tuple of the indexes in _fields of the OID and value fields + _oid_nums = None + + # Predetermined field specs to optimize away calls to _determine_spec() + _precomputed_specs = None + + def __init__(self, value=None, default=None, **kwargs): + """ + Allows setting field values before passing everything else along to + Asn1Value.__init__() + + :param value: + A native Python datatype to initialize the object value with + + :param default: + The default value if no value is specified + """ + + Asn1Value.__init__(self, **kwargs) + + check_existing = False + if value is None and default is not None: + check_existing = True + if self.children is None: + if self.contents is None: + check_existing = False + else: + self._parse_children() + value = default + + if value is not None: + try: + # Fields are iterated in definition order to allow things like + # OID-based specs. Otherwise sometimes the value would be processed + # before the OID field, resulting in invalid value object creation. + if self._fields: + keys = [info[0] for info in self._fields] + unused_keys = set(value.keys()) + else: + keys = value.keys() + unused_keys = set(keys) + + for key in keys: + # If we are setting defaults, but a real value has already + # been set for the field, then skip it + if check_existing: + index = self._field_map[key] + if index < len(self.children) and self.children[index] is not VOID: + if key in unused_keys: + unused_keys.remove(key) + continue + + if key in value: + self.__setitem__(key, value[key]) + unused_keys.remove(key) + + if len(unused_keys): + raise ValueError(unwrap( + ''' + One or more unknown fields was passed to the constructor + of %s: %s + ''', + type_name(self), + ', '.join(sorted(list(unused_keys))) + )) + + except (ValueError, TypeError) as e: + args = e.args[1:] + e.args = (e.args[0] + '\n while constructing %s' % type_name(self),) + args + raise e + + @property + def contents(self): + """ + :return: + A byte string of the DER-encoded contents of the sequence + """ + + if self.children is None: + return self._contents + + if self._is_mutated(): + self._set_contents() + + return self._contents + + @contents.setter + def contents(self, value): + """ + :param value: + A byte string of the DER-encoded contents of the sequence + """ + + self._contents = value + + def _is_mutated(self): + """ + :return: + A boolean - if the sequence or any children (recursively) have been + mutated + """ + + mutated = self._mutated + if self.children is not None: + for child in self.children: + if isinstance(child, Sequence) or isinstance(child, SequenceOf): + mutated = mutated or child._is_mutated() + + return mutated + + def _lazy_child(self, index): + """ + Builds a child object if the child has only been parsed into a tuple so far + """ + + child = self.children[index] + if child.__class__ == tuple: + child = self.children[index] = _build(*child) + return child + + def __len__(self): + """ + :return: + Integer + """ + # We inline this check to prevent method invocation each time + if self.children is None: + self._parse_children() + + return len(self.children) + + def __getitem__(self, key): + """ + Allows accessing fields by name or index + + :param key: + A unicode string of the field name, or an integer of the field index + + :raises: + KeyError - when a field name or index is invalid + + :return: + The Asn1Value object of the field specified + """ + + # We inline this check to prevent method invocation each time + if self.children is None: + self._parse_children() + + if not isinstance(key, int_types): + if key not in self._field_map: + raise KeyError(unwrap( + ''' + No field named "%s" defined for %s + ''', + key, + type_name(self) + )) + key = self._field_map[key] + + if key >= len(self.children): + raise KeyError(unwrap( + ''' + No field numbered %s is present in this %s + ''', + key, + type_name(self) + )) + + try: + return self._lazy_child(key) + + except (ValueError, TypeError) as e: + args = e.args[1:] + e.args = (e.args[0] + '\n while parsing %s' % type_name(self),) + args + raise e + + def __setitem__(self, key, value): + """ + Allows settings fields by name or index + + :param key: + A unicode string of the field name, or an integer of the field index + + :param value: + A native Python datatype to set the field value to. This method will + construct the appropriate Asn1Value object from _fields. + + :raises: + ValueError - when a field name or index is invalid + """ + + # We inline this check to prevent method invocation each time + if self.children is None: + self._parse_children() + + if not isinstance(key, int_types): + if key not in self._field_map: + raise KeyError(unwrap( + ''' + No field named "%s" defined for %s + ''', + key, + type_name(self) + )) + key = self._field_map[key] + + field_name, field_spec, value_spec, field_params, _ = self._determine_spec(key) + + new_value = self._make_value(field_name, field_spec, value_spec, field_params, value) + + invalid_value = False + if isinstance(new_value, Any): + invalid_value = new_value.parsed is None + elif isinstance(new_value, Choice): + invalid_value = new_value.chosen.contents is None + else: + invalid_value = new_value.contents is None + + if invalid_value: + raise ValueError(unwrap( + ''' + Value for field "%s" of %s is not set + ''', + field_name, + type_name(self) + )) + + self.children[key] = new_value + + if self._native is not None: + self._native[self._fields[key][0]] = self.children[key].native + self._mutated = True + + def __delitem__(self, key): + """ + Allows deleting optional or default fields by name or index + + :param key: + A unicode string of the field name, or an integer of the field index + + :raises: + ValueError - when a field name or index is invalid, or the field is not optional or defaulted + """ + + # We inline this check to prevent method invocation each time + if self.children is None: + self._parse_children() + + if not isinstance(key, int_types): + if key not in self._field_map: + raise KeyError(unwrap( + ''' + No field named "%s" defined for %s + ''', + key, + type_name(self) + )) + key = self._field_map[key] + + name, _, params = self._fields[key] + if not params or ('default' not in params and 'optional' not in params): + raise ValueError(unwrap( + ''' + Can not delete the value for the field "%s" of %s since it is + not optional or defaulted + ''', + name, + type_name(self) + )) + + if 'optional' in params: + self.children[key] = VOID + if self._native is not None: + self._native[name] = None + else: + self.__setitem__(key, None) + self._mutated = True + + def __iter__(self): + """ + :return: + An iterator of field key names + """ + + for info in self._fields: + yield info[0] + + def _set_contents(self, force=False): + """ + Updates the .contents attribute of the value with the encoded value of + all of the child objects + + :param force: + Ensure all contents are in DER format instead of possibly using + cached BER-encoded data + """ + + if self.children is None: + self._parse_children() + + contents = BytesIO() + for index, info in enumerate(self._fields): + child = self.children[index] + if child is None: + child_dump = b'' + elif child.__class__ == tuple: + if force: + child_dump = self._lazy_child(index).dump(force=force) + else: + child_dump = child[3] + child[4] + child[5] + else: + child_dump = child.dump(force=force) + # Skip values that are the same as the default + if info[2] and 'default' in info[2]: + default_value = info[1](**info[2]) + if default_value.dump() == child_dump: + continue + contents.write(child_dump) + self._contents = contents.getvalue() + + self._header = None + if self._trailer != b'': + self._trailer = b'' + + def _setup(self): + """ + Generates _field_map, _field_ids and _oid_nums for use in parsing + """ + + cls = self.__class__ + cls._field_map = {} + cls._field_ids = [] + cls._precomputed_specs = [] + for index, field in enumerate(cls._fields): + if len(field) < 3: + field = field + ({},) + cls._fields[index] = field + cls._field_map[field[0]] = index + cls._field_ids.append(_build_id_tuple(field[2], field[1])) + + if cls._oid_pair is not None: + cls._oid_nums = (cls._field_map[cls._oid_pair[0]], cls._field_map[cls._oid_pair[1]]) + + for index, field in enumerate(cls._fields): + has_callback = cls._spec_callbacks is not None and field[0] in cls._spec_callbacks + is_mapped_oid = cls._oid_nums is not None and cls._oid_nums[1] == index + if has_callback or is_mapped_oid: + cls._precomputed_specs.append(None) + else: + cls._precomputed_specs.append((field[0], field[1], field[1], field[2], None)) + + def _determine_spec(self, index): + """ + Determine how a value for a field should be constructed + + :param index: + The field number + + :return: + A tuple containing the following elements: + - unicode string of the field name + - Asn1Value class of the field spec + - Asn1Value class of the value spec + - None or dict of params to pass to the field spec + - None or Asn1Value class indicating the value spec was derived from an OID or a spec callback + """ + + name, field_spec, field_params = self._fields[index] + value_spec = field_spec + spec_override = None + + if self._spec_callbacks is not None and name in self._spec_callbacks: + callback = self._spec_callbacks[name] + spec_override = callback(self) + if spec_override: + # Allow a spec callback to specify both the base spec and + # the override, for situations such as OctetString and parse_as + if spec_override.__class__ == tuple and len(spec_override) == 2: + field_spec, value_spec = spec_override + if value_spec is None: + value_spec = field_spec + spec_override = None + # When no field spec is specified, use a single return value as that + elif field_spec is None: + field_spec = spec_override + value_spec = field_spec + spec_override = None + else: + value_spec = spec_override + + elif self._oid_nums is not None and self._oid_nums[1] == index: + oid = self._lazy_child(self._oid_nums[0]).native + if oid in self._oid_specs: + spec_override = self._oid_specs[oid] + value_spec = spec_override + + return (name, field_spec, value_spec, field_params, spec_override) + + def _make_value(self, field_name, field_spec, value_spec, field_params, value): + """ + Contructs an appropriate Asn1Value object for a field + + :param field_name: + A unicode string of the field name + + :param field_spec: + An Asn1Value class that is the field spec + + :param value_spec: + An Asn1Value class that is the vaue spec + + :param field_params: + None or a dict of params for the field spec + + :param value: + The value to construct an Asn1Value object from + + :return: + An instance of a child class of Asn1Value + """ + + if value is None and 'optional' in field_params: + return VOID + + specs_different = field_spec != value_spec + is_any = issubclass(field_spec, Any) + + if issubclass(value_spec, Choice): + if not isinstance(value, Asn1Value): + raise ValueError(unwrap( + ''' + Can not set a native python value to %s, which has the + choice type of %s - value must be an instance of Asn1Value + ''', + field_name, + type_name(value_spec) + )) + if not isinstance(value, value_spec): + wrapper = value_spec() + wrapper.validate(value.class_, value.tag, value.contents) + wrapper._parsed = value + new_value = wrapper + else: + new_value = value + + elif isinstance(value, field_spec): + new_value = value + if specs_different: + new_value.parse(value_spec) + + elif (not specs_different or is_any) and not isinstance(value, value_spec): + new_value = value_spec(value, **field_params) + + else: + if isinstance(value, value_spec): + new_value = value + else: + new_value = value_spec(value) + + # For when the field is OctetString or OctetBitString with embedded + # values we need to wrap the value in the field spec to get the + # appropriate encoded value. + if specs_different and not is_any: + wrapper = field_spec(value=new_value.dump(), **field_params) + wrapper._parsed = (new_value, new_value.__class__, None) + new_value = wrapper + + new_value = _fix_tagging(new_value, field_params) + + return new_value + + def _parse_children(self, recurse=False): + """ + Parses the contents and generates Asn1Value objects based on the + definitions from _fields. + + :param recurse: + If child objects that are Sequence or SequenceOf objects should + be recursively parsed + + :raises: + ValueError - when an error occurs parsing child objects + """ + + cls = self.__class__ + if self._contents is None: + if self._fields: + self.children = [VOID] * len(self._fields) + for index, (_, _, params) in enumerate(self._fields): + if 'default' in params: + if cls._precomputed_specs[index]: + field_name, field_spec, value_spec, field_params, _ = cls._precomputed_specs[index] + else: + field_name, field_spec, value_spec, field_params, _ = self._determine_spec(index) + self.children[index] = self._make_value(field_name, field_spec, value_spec, field_params, None) + return + + try: + self.children = [] + contents_length = len(self._contents) + child_pointer = 0 + field = 0 + field_len = len(self._fields) + parts = None + again = child_pointer < contents_length + while again: + if parts is None: + parts, child_pointer = _parse(self._contents, contents_length, pointer=child_pointer) + again = child_pointer < contents_length + + if field < field_len: + _, field_spec, value_spec, field_params, spec_override = ( + cls._precomputed_specs[field] or self._determine_spec(field)) + + # If the next value is optional or default, allow it to be absent + if field_params and ('optional' in field_params or 'default' in field_params): + if self._field_ids[field] != (parts[0], parts[2]) and field_spec != Any: + + # See if the value is a valid choice before assuming + # that we have a missing optional or default value + choice_match = False + if issubclass(field_spec, Choice): + try: + tester = field_spec(**field_params) + tester.validate(parts[0], parts[2], parts[4]) + choice_match = True + except (ValueError): + pass + + if not choice_match: + if 'optional' in field_params: + self.children.append(VOID) + else: + self.children.append(field_spec(**field_params)) + field += 1 + again = True + continue + + if field_spec is None or (spec_override and issubclass(field_spec, Any)): + field_spec = value_spec + spec_override = None + + if spec_override: + child = parts + (field_spec, field_params, value_spec) + else: + child = parts + (field_spec, field_params) + + # Handle situations where an optional or defaulted field definition is incorrect + elif field_len > 0 and field + 1 <= field_len: + missed_fields = [] + prev_field = field - 1 + while prev_field >= 0: + prev_field_info = self._fields[prev_field] + if len(prev_field_info) < 3: + break + if 'optional' in prev_field_info[2] or 'default' in prev_field_info[2]: + missed_fields.append(prev_field_info[0]) + prev_field -= 1 + plural = 's' if len(missed_fields) > 1 else '' + missed_field_names = ', '.join(missed_fields) + raise ValueError(unwrap( + ''' + Data for field %s (%s class, %s method, tag %s) does + not match the field definition%s of %s + ''', + field + 1, + CLASS_NUM_TO_NAME_MAP.get(parts[0]), + METHOD_NUM_TO_NAME_MAP.get(parts[1]), + parts[2], + plural, + missed_field_names + )) + + else: + child = parts + + if recurse: + child = _build(*child) + if isinstance(child, (Sequence, SequenceOf)): + child._parse_children(recurse=True) + + self.children.append(child) + field += 1 + parts = None + + index = len(self.children) + while index < field_len: + name, field_spec, field_params = self._fields[index] + if 'default' in field_params: + self.children.append(field_spec(**field_params)) + elif 'optional' in field_params: + self.children.append(VOID) + else: + raise ValueError(unwrap( + ''' + Field "%s" is missing from structure + ''', + name + )) + index += 1 + + except (ValueError, TypeError) as e: + args = e.args[1:] + e.args = (e.args[0] + '\n while parsing %s' % type_name(self),) + args + raise e + + def spec(self, field_name): + """ + Determines the spec to use for the field specified. Depending on how + the spec is determined (_oid_pair or _spec_callbacks), it may be + necessary to set preceding field values before calling this. Usually + specs, if dynamic, are controlled by a preceding ObjectIdentifier + field. + + :param field_name: + A unicode string of the field name to get the spec for + + :return: + A child class of asn1crypto.core.Asn1Value that the field must be + encoded using + """ + + if not isinstance(field_name, str_cls): + raise TypeError(unwrap( + ''' + field_name must be a unicode string, not %s + ''', + type_name(field_name) + )) + + if self._fields is None: + raise ValueError(unwrap( + ''' + Unable to retrieve spec for field %s in the class %s because + _fields has not been set + ''', + repr(field_name), + type_name(self) + )) + + index = self._field_map[field_name] + info = self._determine_spec(index) + + return info[2] + + @property + def native(self): + """ + The a native Python datatype representation of this value + + :return: + An OrderedDict or None. If an OrderedDict, all child values are + recursively converted to native representation also. + """ + + if self.contents is None: + return None + + if self._native is None: + if self.children is None: + self._parse_children(recurse=True) + try: + self._native = OrderedDict() + for index, child in enumerate(self.children): + if child.__class__ == tuple: + child = _build(*child) + self.children[index] = child + try: + name = self._fields[index][0] + except (IndexError): + name = str_cls(index) + self._native[name] = child.native + except (ValueError, TypeError) as e: + args = e.args[1:] + e.args = (e.args[0] + '\n while parsing %s' % type_name(self),) + args + raise e + return self._native + + def _copy(self, other, copy_func): + """ + Copies the contents of another Sequence object to itself + + :param object: + Another instance of the same class + + :param copy_func: + An reference of copy.copy() or copy.deepcopy() to use when copying + lists, dicts and objects + """ + + super(Sequence, self)._copy(other, copy_func) + if self.children is not None: + self.children = [] + for child in other.children: + if child.__class__ == tuple: + self.children.append(child) + else: + self.children.append(child.copy()) + + def debug(self, nest_level=1): + """ + Show the binary data and parsed data in a tree structure + """ + + if self.children is None: + self._parse_children() + + prefix = ' ' * nest_level + _basic_debug(prefix, self) + for field_name in self: + child = self._lazy_child(self._field_map[field_name]) + if child is not VOID: + print('%s Field "%s"' % (prefix, field_name)) + child.debug(nest_level + 3) + + def dump(self, force=False): + """ + Encodes the value using DER + + :param force: + If the encoded contents already exist, clear them and regenerate + to ensure they are in DER format instead of BER format + + :return: + A byte string of the DER-encoded value + """ + + if force: + self._set_contents(force=force) + + if self._fields and self.children is not None: + for index, (field_name, _, params) in enumerate(self._fields): + if self.children[index] is not VOID: + continue + if 'default' in params or 'optional' in params: + continue + raise ValueError(unwrap( + ''' + Field "%s" is missing from structure + ''', + field_name + )) + + return Asn1Value.dump(self) + + +class SequenceOf(Asn1Value): + """ + Represents a sequence (ordered) of a single type of values from ASN.1 as a + Python object with a list-like interface + """ + + tag = 16 + + class_ = 0 + method = 1 + + # A list of child objects + children = None + + # SequenceOf overrides .contents to be a property so that the mutated state + # of child objects can be checked to ensure everything is up-to-date + _contents = None + + # Variable to track if the object has been mutated + _mutated = False + + # An Asn1Value class to use when parsing children + _child_spec = None + + def __init__(self, value=None, default=None, contents=None, spec=None, **kwargs): + """ + Allows setting child objects and the _child_spec via the spec parameter + before passing everything else along to Asn1Value.__init__() + + :param value: + A native Python datatype to initialize the object value with + + :param default: + The default value if no value is specified + + :param contents: + A byte string of the encoded contents of the value + + :param spec: + A class derived from Asn1Value to use to parse children + """ + + if spec: + self._child_spec = spec + + Asn1Value.__init__(self, **kwargs) + + try: + if contents is not None: + self.contents = contents + else: + if value is None and default is not None: + value = default + + if value is not None: + for index, child in enumerate(value): + self.__setitem__(index, child) + + # Make sure a blank list is serialized + if self.contents is None: + self._set_contents() + + except (ValueError, TypeError) as e: + args = e.args[1:] + e.args = (e.args[0] + '\n while constructing %s' % type_name(self),) + args + raise e + + @property + def contents(self): + """ + :return: + A byte string of the DER-encoded contents of the sequence + """ + + if self.children is None: + return self._contents + + if self._is_mutated(): + self._set_contents() + + return self._contents + + @contents.setter + def contents(self, value): + """ + :param value: + A byte string of the DER-encoded contents of the sequence + """ + + self._contents = value + + def _is_mutated(self): + """ + :return: + A boolean - if the sequence or any children (recursively) have been + mutated + """ + + mutated = self._mutated + if self.children is not None: + for child in self.children: + if isinstance(child, Sequence) or isinstance(child, SequenceOf): + mutated = mutated or child._is_mutated() + + return mutated + + def _lazy_child(self, index): + """ + Builds a child object if the child has only been parsed into a tuple so far + """ + + child = self.children[index] + if child.__class__ == tuple: + child = _build(*child) + self.children[index] = child + return child + + def _make_value(self, value): + """ + Constructs a _child_spec value from a native Python data type, or + an appropriate Asn1Value object + + :param value: + A native Python value, or some child of Asn1Value + + :return: + An object of type _child_spec + """ + + if isinstance(value, self._child_spec): + new_value = value + + elif issubclass(self._child_spec, Any): + if isinstance(value, Asn1Value): + new_value = value + else: + raise ValueError(unwrap( + ''' + Can not set a native python value to %s where the + _child_spec is Any - value must be an instance of Asn1Value + ''', + type_name(self) + )) + + elif issubclass(self._child_spec, Choice): + if not isinstance(value, Asn1Value): + raise ValueError(unwrap( + ''' + Can not set a native python value to %s where the + _child_spec is the choice type %s - value must be an + instance of Asn1Value + ''', + type_name(self), + self._child_spec.__name__ + )) + if not isinstance(value, self._child_spec): + wrapper = self._child_spec() + wrapper.validate(value.class_, value.tag, value.contents) + wrapper._parsed = value + value = wrapper + new_value = value + + else: + return self._child_spec(value=value) + + params = {} + if self._child_spec.explicit: + params['explicit'] = self._child_spec.explicit + if self._child_spec.implicit: + params['implicit'] = (self._child_spec.class_, self._child_spec.tag) + return _fix_tagging(new_value, params) + + def __len__(self): + """ + :return: + An integer + """ + # We inline this checks to prevent method invocation each time + if self.children is None: + self._parse_children() + + return len(self.children) + + def __getitem__(self, key): + """ + Allows accessing children via index + + :param key: + Integer index of child + """ + + # We inline this checks to prevent method invocation each time + if self.children is None: + self._parse_children() + + return self._lazy_child(key) + + def __setitem__(self, key, value): + """ + Allows overriding a child via index + + :param key: + Integer index of child + + :param value: + Native python datatype that will be passed to _child_spec to create + new child object + """ + + # We inline this checks to prevent method invocation each time + if self.children is None: + self._parse_children() + + new_value = self._make_value(value) + + # If adding at the end, create a space for the new value + if key == len(self.children): + self.children.append(None) + if self._native is not None: + self._native.append(None) + + self.children[key] = new_value + + if self._native is not None: + self._native[key] = self.children[key].native + + self._mutated = True + + def __delitem__(self, key): + """ + Allows removing a child via index + + :param key: + Integer index of child + """ + + # We inline this checks to prevent method invocation each time + if self.children is None: + self._parse_children() + + self.children.pop(key) + if self._native is not None: + self._native.pop(key) + + self._mutated = True + + def __iter__(self): + """ + :return: + An iter() of child objects + """ + + # We inline this checks to prevent method invocation each time + if self.children is None: + self._parse_children() + + for index in range(0, len(self.children)): + yield self._lazy_child(index) + + def __contains__(self, item): + """ + :param item: + An object of the type cls._child_spec + + :return: + A boolean if the item is contained in this SequenceOf + """ + + if item is None or item is VOID: + return False + + if not isinstance(item, self._child_spec): + raise TypeError(unwrap( + ''' + Checking membership in %s is only available for instances of + %s, not %s + ''', + type_name(self), + type_name(self._child_spec), + type_name(item) + )) + + for child in self: + if child == item: + return True + + return False + + def append(self, value): + """ + Allows adding a child to the end of the sequence + + :param value: + Native python datatype that will be passed to _child_spec to create + new child object + """ + + # We inline this checks to prevent method invocation each time + if self.children is None: + self._parse_children() + + self.children.append(self._make_value(value)) + + if self._native is not None: + self._native.append(self.children[-1].native) + + self._mutated = True + + def _set_contents(self, force=False): + """ + Encodes all child objects into the contents for this object + + :param force: + Ensure all contents are in DER format instead of possibly using + cached BER-encoded data + """ + + if self.children is None: + self._parse_children() + + contents = BytesIO() + for child in self: + contents.write(child.dump(force=force)) + self._contents = contents.getvalue() + self._header = None + if self._trailer != b'': + self._trailer = b'' + + def _parse_children(self, recurse=False): + """ + Parses the contents and generates Asn1Value objects based on the + definitions from _child_spec. + + :param recurse: + If child objects that are Sequence or SequenceOf objects should + be recursively parsed + + :raises: + ValueError - when an error occurs parsing child objects + """ + + try: + self.children = [] + if self._contents is None: + return + contents_length = len(self._contents) + child_pointer = 0 + while child_pointer < contents_length: + parts, child_pointer = _parse(self._contents, contents_length, pointer=child_pointer) + if self._child_spec: + child = parts + (self._child_spec,) + else: + child = parts + if recurse: + child = _build(*child) + if isinstance(child, (Sequence, SequenceOf)): + child._parse_children(recurse=True) + self.children.append(child) + except (ValueError, TypeError) as e: + args = e.args[1:] + e.args = (e.args[0] + '\n while parsing %s' % type_name(self),) + args + raise e + + def spec(self): + """ + Determines the spec to use for child values. + + :return: + A child class of asn1crypto.core.Asn1Value that child values must be + encoded using + """ + + return self._child_spec + + @property + def native(self): + """ + The a native Python datatype representation of this value + + :return: + A list or None. If a list, all child values are recursively + converted to native representation also. + """ + + if self.contents is None: + return None + + if self._native is None: + if self.children is None: + self._parse_children(recurse=True) + try: + self._native = [child.native for child in self] + except (ValueError, TypeError) as e: + args = e.args[1:] + e.args = (e.args[0] + '\n while parsing %s' % type_name(self),) + args + raise e + return self._native + + def _copy(self, other, copy_func): + """ + Copies the contents of another SequenceOf object to itself + + :param object: + Another instance of the same class + + :param copy_func: + An reference of copy.copy() or copy.deepcopy() to use when copying + lists, dicts and objects + """ + + super(SequenceOf, self)._copy(other, copy_func) + if self.children is not None: + self.children = [] + for child in other.children: + if child.__class__ == tuple: + self.children.append(child) + else: + self.children.append(child.copy()) + + def debug(self, nest_level=1): + """ + Show the binary data and parsed data in a tree structure + """ + + if self.children is None: + self._parse_children() + + prefix = ' ' * nest_level + _basic_debug(prefix, self) + for child in self: + child.debug(nest_level + 1) + + def dump(self, force=False): + """ + Encodes the value using DER + + :param force: + If the encoded contents already exist, clear them and regenerate + to ensure they are in DER format instead of BER format + + :return: + A byte string of the DER-encoded value + """ + + if force: + self._set_contents(force=force) + + return Asn1Value.dump(self) + + +class Set(Sequence): + """ + Represents a set of fields (unordered) from ASN.1 as a Python object with a + dict-like interface + """ + + method = 1 + class_ = 0 + tag = 17 + + # A dict of 2-element tuples in the form (class_, tag) as keys and integers + # as values that are the index of the field in _fields + _field_ids = None + + def _setup(self): + """ + Generates _field_map, _field_ids and _oid_nums for use in parsing + """ + + cls = self.__class__ + cls._field_map = {} + cls._field_ids = {} + cls._precomputed_specs = [] + for index, field in enumerate(cls._fields): + if len(field) < 3: + field = field + ({},) + cls._fields[index] = field + cls._field_map[field[0]] = index + cls._field_ids[_build_id_tuple(field[2], field[1])] = index + + if cls._oid_pair is not None: + cls._oid_nums = (cls._field_map[cls._oid_pair[0]], cls._field_map[cls._oid_pair[1]]) + + for index, field in enumerate(cls._fields): + has_callback = cls._spec_callbacks is not None and field[0] in cls._spec_callbacks + is_mapped_oid = cls._oid_nums is not None and cls._oid_nums[1] == index + if has_callback or is_mapped_oid: + cls._precomputed_specs.append(None) + else: + cls._precomputed_specs.append((field[0], field[1], field[1], field[2], None)) + + def _parse_children(self, recurse=False): + """ + Parses the contents and generates Asn1Value objects based on the + definitions from _fields. + + :param recurse: + If child objects that are Sequence or SequenceOf objects should + be recursively parsed + + :raises: + ValueError - when an error occurs parsing child objects + """ + + cls = self.__class__ + if self._contents is None: + if self._fields: + self.children = [VOID] * len(self._fields) + for index, (_, _, params) in enumerate(self._fields): + if 'default' in params: + if cls._precomputed_specs[index]: + field_name, field_spec, value_spec, field_params, _ = cls._precomputed_specs[index] + else: + field_name, field_spec, value_spec, field_params, _ = self._determine_spec(index) + self.children[index] = self._make_value(field_name, field_spec, value_spec, field_params, None) + return + + try: + child_map = {} + contents_length = len(self.contents) + child_pointer = 0 + seen_field = 0 + while child_pointer < contents_length: + parts, child_pointer = _parse(self.contents, contents_length, pointer=child_pointer) + + id_ = (parts[0], parts[2]) + + field = self._field_ids.get(id_) + if field is None: + raise ValueError(unwrap( + ''' + Data for field %s (%s class, %s method, tag %s) does + not match any of the field definitions + ''', + seen_field, + CLASS_NUM_TO_NAME_MAP.get(parts[0]), + METHOD_NUM_TO_NAME_MAP.get(parts[1]), + parts[2], + )) + + _, field_spec, value_spec, field_params, spec_override = ( + cls._precomputed_specs[field] or self._determine_spec(field)) + + if field_spec is None or (spec_override and issubclass(field_spec, Any)): + field_spec = value_spec + spec_override = None + + if spec_override: + child = parts + (field_spec, field_params, value_spec) + else: + child = parts + (field_spec, field_params) + + if recurse: + child = _build(*child) + if isinstance(child, (Sequence, SequenceOf)): + child._parse_children(recurse=True) + + child_map[field] = child + seen_field += 1 + + total_fields = len(self._fields) + + for index in range(0, total_fields): + if index in child_map: + continue + + name, field_spec, value_spec, field_params, spec_override = ( + cls._precomputed_specs[index] or self._determine_spec(index)) + + if field_spec is None or (spec_override and issubclass(field_spec, Any)): + field_spec = value_spec + spec_override = None + + missing = False + + if not field_params: + missing = True + elif 'optional' not in field_params and 'default' not in field_params: + missing = True + elif 'optional' in field_params: + child_map[index] = VOID + elif 'default' in field_params: + child_map[index] = field_spec(**field_params) + + if missing: + raise ValueError(unwrap( + ''' + Missing required field "%s" from %s + ''', + name, + type_name(self) + )) + + self.children = [] + for index in range(0, total_fields): + self.children.append(child_map[index]) + + except (ValueError, TypeError) as e: + args = e.args[1:] + e.args = (e.args[0] + '\n while parsing %s' % type_name(self),) + args + raise e + + def _set_contents(self, force=False): + """ + Encodes all child objects into the contents for this object. + + This method is overridden because a Set needs to be encoded by + removing defaulted fields and then sorting the fields by tag. + + :param force: + Ensure all contents are in DER format instead of possibly using + cached BER-encoded data + """ + + if self.children is None: + self._parse_children() + + child_tag_encodings = [] + for index, child in enumerate(self.children): + child_encoding = child.dump(force=force) + + # Skip encoding defaulted children + name, spec, field_params = self._fields[index] + if 'default' in field_params: + if spec(**field_params).dump() == child_encoding: + continue + + child_tag_encodings.append((child.tag, child_encoding)) + child_tag_encodings.sort(key=lambda ct: ct[0]) + + self._contents = b''.join([ct[1] for ct in child_tag_encodings]) + self._header = None + if self._trailer != b'': + self._trailer = b'' + + +class SetOf(SequenceOf): + """ + Represents a set (unordered) of a single type of values from ASN.1 as a + Python object with a list-like interface + """ + + tag = 17 + + def _set_contents(self, force=False): + """ + Encodes all child objects into the contents for this object. + + This method is overridden because a SetOf needs to be encoded by + sorting the child encodings. + + :param force: + Ensure all contents are in DER format instead of possibly using + cached BER-encoded data + """ + + if self.children is None: + self._parse_children() + + child_encodings = [] + for child in self: + child_encodings.append(child.dump(force=force)) + + self._contents = b''.join(sorted(child_encodings)) + self._header = None + if self._trailer != b'': + self._trailer = b'' + + +class EmbeddedPdv(Sequence): + """ + A sequence structure + """ + + tag = 11 + + +class NumericString(AbstractString): + """ + Represents a numeric string from ASN.1 as a Python unicode string + """ + + tag = 18 + _encoding = 'latin1' + + +class PrintableString(AbstractString): + """ + Represents a printable string from ASN.1 as a Python unicode string + """ + + tag = 19 + _encoding = 'latin1' + + +class TeletexString(AbstractString): + """ + Represents a teletex string from ASN.1 as a Python unicode string + """ + + tag = 20 + _encoding = 'teletex' + + +class VideotexString(OctetString): + """ + Represents a videotex string from ASN.1 as a Python byte string + """ + + tag = 21 + + +class IA5String(AbstractString): + """ + Represents an IA5 string from ASN.1 as a Python unicode string + """ + + tag = 22 + _encoding = 'ascii' + + +class AbstractTime(AbstractString): + """ + Represents a time from ASN.1 as a Python datetime.datetime object + """ + + @property + def native(self): + """ + The a native Python datatype representation of this value + + :return: + A datetime.datetime object in the UTC timezone or None + """ + + if self.contents is None: + return None + + if self._native is None: + string = str_cls(self) + has_timezone = re.search('[-\\+]', string) + + # We don't know what timezone it is in, or it is UTC because of a Z + # suffix, so we just assume UTC + if not has_timezone: + string = string.rstrip('Z') + date = self._date_by_len(string) + self._native = date.replace(tzinfo=timezone.utc) + + else: + # Python 2 doesn't support the %z format code, so we have to manually + # process the timezone offset. + date = self._date_by_len(string[0:-5]) + + hours = int(string[-4:-2]) + minutes = int(string[-2:]) + delta = timedelta(hours=abs(hours), minutes=minutes) + if hours < 0: + date -= delta + else: + date += delta + + self._native = date.replace(tzinfo=timezone.utc) + + return self._native + + +class UTCTime(AbstractTime): + """ + Represents a UTC time from ASN.1 as a Python datetime.datetime object in UTC + """ + + tag = 23 + + def set(self, value): + """ + Sets the value of the object + + :param value: + A unicode string or a datetime.datetime object + + :raises: + ValueError - when an invalid value is passed + """ + + if isinstance(value, datetime): + value = value.strftime('%y%m%d%H%M%SZ') + if _PY2: + value = value.decode('ascii') + + AbstractString.set(self, value) + # Set it to None and let the class take care of converting the next + # time that .native is called + self._native = None + + def _date_by_len(self, string): + """ + Parses a date from a string based on its length + + :param string: + A unicode string to parse + + :return: + A datetime.datetime object or a unicode string + """ + + strlen = len(string) + + year_num = int(string[0:2]) + if year_num < 50: + prefix = '20' + else: + prefix = '19' + + if strlen == 10: + return datetime.strptime(prefix + string, '%Y%m%d%H%M') + + if strlen == 12: + return datetime.strptime(prefix + string, '%Y%m%d%H%M%S') + + return string + + +class GeneralizedTime(AbstractTime): + """ + Represents a generalized time from ASN.1 as a Python datetime.datetime + object or asn1crypto.util.extended_datetime object in UTC + """ + + tag = 24 + + def set(self, value): + """ + Sets the value of the object + + :param value: + A unicode string, a datetime.datetime object or an + asn1crypto.util.extended_datetime object + + :raises: + ValueError - when an invalid value is passed + """ + + if isinstance(value, (datetime, extended_datetime)): + value = value.strftime('%Y%m%d%H%M%SZ') + if _PY2: + value = value.decode('ascii') + + AbstractString.set(self, value) + # Set it to None and let the class take care of converting the next + # time that .native is called + self._native = None + + def _date_by_len(self, string): + """ + Parses a date from a string based on its length + + :param string: + A unicode string to parse + + :return: + A datetime.datetime object, asn1crypto.util.extended_datetime object or + a unicode string + """ + + strlen = len(string) + + date_format = None + if strlen == 10: + date_format = '%Y%m%d%H' + elif strlen == 12: + date_format = '%Y%m%d%H%M' + elif strlen == 14: + date_format = '%Y%m%d%H%M%S' + elif strlen == 18: + date_format = '%Y%m%d%H%M%S.%f' + + if date_format: + if len(string) >= 4 and string[0:4] == '0000': + # Year 2000 shares a calendar with year 0, and is supported natively + t = datetime.strptime('2000' + string[4:], date_format) + return extended_datetime( + 0, + t.month, + t.day, + t.hour, + t.minute, + t.second, + t.microsecond, + t.tzinfo + ) + return datetime.strptime(string, date_format) + + return string + + +class GraphicString(AbstractString): + """ + Represents a graphic string from ASN.1 as a Python unicode string + """ + + tag = 25 + # This is technically not correct since this type can contain any charset + _encoding = 'latin1' + + +class VisibleString(AbstractString): + """ + Represents a visible string from ASN.1 as a Python unicode string + """ + + tag = 26 + _encoding = 'latin1' + + +class GeneralString(AbstractString): + """ + Represents a general string from ASN.1 as a Python unicode string + """ + + tag = 27 + # This is technically not correct since this type can contain any charset + _encoding = 'latin1' + + +class UniversalString(AbstractString): + """ + Represents a universal string from ASN.1 as a Python unicode string + """ + + tag = 28 + _encoding = 'utf-32-be' + + +class CharacterString(AbstractString): + """ + Represents a character string from ASN.1 as a Python unicode string + """ + + tag = 29 + # This is technically not correct since this type can contain any charset + _encoding = 'latin1' + + +class BMPString(AbstractString): + """ + Represents a BMP string from ASN.1 as a Python unicode string + """ + + tag = 30 + _encoding = 'utf-16-be' + + +def _basic_debug(prefix, self): + """ + Prints out basic information about an Asn1Value object. Extracted for reuse + among different classes that customize the debug information. + + :param prefix: + A unicode string of spaces to prefix output line with + + :param self: + The object to print the debugging information about + """ + + print('%s%s Object #%s' % (prefix, type_name(self), id(self))) + if self._header: + print('%s Header: 0x%s' % (prefix, binascii.hexlify(self._header or b'').decode('utf-8'))) + + has_header = self.method is not None and self.class_ is not None and self.tag is not None + if has_header: + method_name = METHOD_NUM_TO_NAME_MAP.get(self.method) + class_name = CLASS_NUM_TO_NAME_MAP.get(self.class_) + + if self.explicit is not None: + for class_, tag in self.explicit: + print( + '%s %s tag %s (explicitly tagged)' % + ( + prefix, + CLASS_NUM_TO_NAME_MAP.get(class_), + tag + ) + ) + if has_header: + print('%s %s %s %s' % (prefix, method_name, class_name, self.tag)) + + elif self.implicit: + if has_header: + print('%s %s %s tag %s (implicitly tagged)' % (prefix, method_name, class_name, self.tag)) + + elif has_header: + print('%s %s %s tag %s' % (prefix, method_name, class_name, self.tag)) + + print('%s Data: 0x%s' % (prefix, binascii.hexlify(self.contents or b'').decode('utf-8'))) + + +def _tag_type_to_explicit_implicit(params): + """ + Converts old-style "tag_type" and "tag" params to "explicit" and "implicit" + + :param params: + A dict of parameters to convert from tag_type/tag to explicit/implicit + """ + + if 'tag_type' in params: + if params['tag_type'] == 'explicit': + params['explicit'] = (params.get('class', 2), params['tag']) + elif params['tag_type'] == 'implicit': + params['implicit'] = (params.get('class', 2), params['tag']) + del params['tag_type'] + del params['tag'] + if 'class' in params: + del params['class'] + + +def _fix_tagging(value, params): + """ + Checks if a value is properly tagged based on the spec, and re/untags as + necessary + + :param value: + An Asn1Value object + + :param params: + A dict of spec params + + :return: + An Asn1Value that is properly tagged + """ + + _tag_type_to_explicit_implicit(params) + + retag = False + if 'implicit' not in params: + if value.implicit is not False: + retag = True + else: + if isinstance(params['implicit'], tuple): + class_, tag = params['implicit'] + else: + tag = params['implicit'] + class_ = 'context' + if value.implicit is False: + retag = True + elif value.class_ != CLASS_NAME_TO_NUM_MAP[class_] or value.tag != tag: + retag = True + + if params.get('explicit') != value.explicit: + retag = True + + if retag: + return value.retag(params) + return value + + +def _build_id_tuple(params, spec): + """ + Builds a 2-element tuple used to identify fields by grabbing the class_ + and tag from an Asn1Value class and the params dict being passed to it + + :param params: + A dict of params to pass to spec + + :param spec: + An Asn1Value class + + :return: + A 2-element integer tuple in the form (class_, tag) + """ + + # Handle situations where the the spec is not known at setup time + if spec is None: + return (None, None) + + required_class = spec.class_ + required_tag = spec.tag + + _tag_type_to_explicit_implicit(params) + + if 'explicit' in params: + if isinstance(params['explicit'], tuple): + required_class, required_tag = params['explicit'] + else: + required_class = 2 + required_tag = params['explicit'] + elif 'implicit' in params: + if isinstance(params['implicit'], tuple): + required_class, required_tag = params['implicit'] + else: + required_class = 2 + required_tag = params['implicit'] + if required_class is not None and not isinstance(required_class, int_types): + required_class = CLASS_NAME_TO_NUM_MAP[required_class] + + required_class = params.get('class_', required_class) + required_tag = params.get('tag', required_tag) + + return (required_class, required_tag) + + +_UNIVERSAL_SPECS = { + 1: Boolean, + 2: Integer, + 3: BitString, + 4: OctetString, + 5: Null, + 6: ObjectIdentifier, + 7: ObjectDescriptor, + 8: InstanceOf, + 9: Real, + 10: Enumerated, + 11: EmbeddedPdv, + 12: UTF8String, + 13: RelativeOid, + 16: Sequence, + 17: Set, + 18: NumericString, + 19: PrintableString, + 20: TeletexString, + 21: VideotexString, + 22: IA5String, + 23: UTCTime, + 24: GeneralizedTime, + 25: GraphicString, + 26: VisibleString, + 27: GeneralString, + 28: UniversalString, + 29: CharacterString, + 30: BMPString +} + + +def _build(class_, method, tag, header, contents, trailer, spec=None, spec_params=None, nested_spec=None): + """ + Builds an Asn1Value object generically, or using a spec with optional params + + :param class_: + An integer representing the ASN.1 class + + :param method: + An integer representing the ASN.1 method + + :param tag: + An integer representing the ASN.1 tag + + :param header: + A byte string of the ASN.1 header (class, method, tag, length) + + :param contents: + A byte string of the ASN.1 value + + :param trailer: + A byte string of any ASN.1 trailer (only used by indefinite length encodings) + + :param spec: + A class derived from Asn1Value that defines what class_ and tag the + value should have, and the semantics of the encoded value. The + return value will be of this type. If omitted, the encoded value + will be decoded using the standard universal tag based on the + encoded tag number. + + :param spec_params: + A dict of params to pass to the spec object + + :param nested_spec: + For certain Asn1Value classes (such as OctetString and BitString), the + contents can be further parsed and interpreted as another Asn1Value. + This parameter controls the spec for that sub-parsing. + + :return: + An object of the type spec, or if not specified, a child of Asn1Value + """ + + if spec_params is not None: + _tag_type_to_explicit_implicit(spec_params) + + if header is None: + return VOID + + header_set = False + + # If an explicit specification was passed in, make sure it matches + if spec is not None: + # If there is explicit tagging and contents, we have to split + # the header and trailer off before we do the parsing + no_explicit = spec_params and 'no_explicit' in spec_params + if not no_explicit and (spec.explicit or (spec_params and 'explicit' in spec_params)): + if spec_params: + value = spec(**spec_params) + else: + value = spec() + original_explicit = value.explicit + explicit_info = reversed(original_explicit) + parsed_class = class_ + parsed_method = method + parsed_tag = tag + to_parse = contents + explicit_header = header + explicit_trailer = trailer or b'' + for expected_class, expected_tag in explicit_info: + if parsed_class != expected_class: + raise ValueError(unwrap( + ''' + Error parsing %s - explicitly-tagged class should have been + %s, but %s was found + ''', + type_name(value), + CLASS_NUM_TO_NAME_MAP.get(expected_class), + CLASS_NUM_TO_NAME_MAP.get(parsed_class, parsed_class) + )) + if parsed_method != 1: + raise ValueError(unwrap( + ''' + Error parsing %s - explicitly-tagged method should have + been %s, but %s was found + ''', + type_name(value), + METHOD_NUM_TO_NAME_MAP.get(1), + METHOD_NUM_TO_NAME_MAP.get(parsed_method, parsed_method) + )) + if parsed_tag != expected_tag: + raise ValueError(unwrap( + ''' + Error parsing %s - explicitly-tagged tag should have been + %s, but %s was found + ''', + type_name(value), + expected_tag, + parsed_tag + )) + info, _ = _parse(to_parse, len(to_parse)) + parsed_class, parsed_method, parsed_tag, parsed_header, to_parse, parsed_trailer = info + explicit_header += parsed_header + explicit_trailer = parsed_trailer + explicit_trailer + + value = _build(*info, spec=spec, spec_params={'no_explicit': True}) + value._header = explicit_header + value._trailer = explicit_trailer + value.explicit = original_explicit + header_set = True + else: + if spec_params: + value = spec(contents=contents, **spec_params) + else: + value = spec(contents=contents) + + if spec is Any: + pass + + elif isinstance(value, Choice): + value.validate(class_, tag, contents) + try: + # Force parsing the Choice now + value.contents = header + value.contents + header = b'' + value.parse() + except (ValueError, TypeError) as e: + args = e.args[1:] + e.args = (e.args[0] + '\n while parsing %s' % type_name(value),) + args + raise e + + else: + if class_ != value.class_: + raise ValueError(unwrap( + ''' + Error parsing %s - class should have been %s, but %s was + found + ''', + type_name(value), + CLASS_NUM_TO_NAME_MAP.get(value.class_), + CLASS_NUM_TO_NAME_MAP.get(class_, class_) + )) + if method != value.method: + # Allow parsing a primitive method as constructed if the value + # is indefinite length. This is to allow parsing BER. + ber_indef = method == 1 and value.method == 0 and trailer == b'\x00\x00' + if not ber_indef or not isinstance(value, Constructable): + raise ValueError(unwrap( + ''' + Error parsing %s - method should have been %s, but %s was found + ''', + type_name(value), + METHOD_NUM_TO_NAME_MAP.get(value.method), + METHOD_NUM_TO_NAME_MAP.get(method, method) + )) + else: + value.method = method + value._indefinite = True + if tag != value.tag and tag != value._bad_tag: + raise ValueError(unwrap( + ''' + Error parsing %s - tag should have been %s, but %s was found + ''', + type_name(value), + value.tag, + tag + )) + + # For explicitly tagged, un-speced parsings, we use a generic container + # since we will be parsing the contents and discarding the outer object + # anyway a little further on + elif spec_params and 'explicit' in spec_params: + original_value = Asn1Value(contents=contents, **spec_params) + original_explicit = original_value.explicit + + to_parse = contents + explicit_header = header + explicit_trailer = trailer or b'' + for expected_class, expected_tag in reversed(original_explicit): + info, _ = _parse(to_parse, len(to_parse)) + _, _, _, parsed_header, to_parse, parsed_trailer = info + explicit_header += parsed_header + explicit_trailer = parsed_trailer + explicit_trailer + value = _build(*info, spec=spec, spec_params={'no_explicit': True}) + value._header = header + value._header + value._trailer += trailer or b'' + value.explicit = original_explicit + header_set = True + + # If no spec was specified, allow anything and just process what + # is in the input data + else: + if tag not in _UNIVERSAL_SPECS: + raise ValueError(unwrap( + ''' + Unknown element - %s class, %s method, tag %s + ''', + CLASS_NUM_TO_NAME_MAP.get(class_), + METHOD_NUM_TO_NAME_MAP.get(method), + tag + )) + + spec = _UNIVERSAL_SPECS[tag] + + value = spec(contents=contents, class_=class_) + ber_indef = method == 1 and value.method == 0 and trailer == b'\x00\x00' + if ber_indef and isinstance(value, Constructable): + value._indefinite = True + value.method = method + + if not header_set: + value._header = header + value._trailer = trailer or b'' + + # Destroy any default value that our contents have overwritten + value._native = None + + if nested_spec: + try: + value.parse(nested_spec) + except (ValueError, TypeError) as e: + args = e.args[1:] + e.args = (e.args[0] + '\n while parsing %s' % type_name(value),) + args + raise e + + return value + + +def _parse_build(encoded_data, pointer=0, spec=None, spec_params=None, strict=False): + """ + Parses a byte string generically, or using a spec with optional params + + :param encoded_data: + A byte string that contains BER-encoded data + + :param pointer: + The index in the byte string to parse from + + :param spec: + A class derived from Asn1Value that defines what class_ and tag the + value should have, and the semantics of the encoded value. The + return value will be of this type. If omitted, the encoded value + will be decoded using the standard universal tag based on the + encoded tag number. + + :param spec_params: + A dict of params to pass to the spec object + + :param strict: + A boolean indicating if trailing data should be forbidden - if so, a + ValueError will be raised when trailing data exists + + :return: + A 2-element tuple: + - 0: An object of the type spec, or if not specified, a child of Asn1Value + - 1: An integer indicating how many bytes were consumed + """ + + encoded_len = len(encoded_data) + info, new_pointer = _parse(encoded_data, encoded_len, pointer) + if strict and new_pointer != pointer + encoded_len: + extra_bytes = pointer + encoded_len - new_pointer + raise ValueError('Extra data - %d bytes of trailing data were provided' % extra_bytes) + return (_build(*info, spec=spec, spec_params=spec_params), new_pointer) diff --git a/venv/lib/python2.7/site-packages/asn1crypto/crl.py b/venv/lib/python2.7/site-packages/asn1crypto/crl.py new file mode 100644 index 0000000..84cb168 --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/crl.py @@ -0,0 +1,536 @@ +# coding: utf-8 + +""" +ASN.1 type classes for certificate revocation lists (CRL). Exports the +following items: + + - CertificateList() + +Other type classes are defined that help compose the types listed above. +""" + +from __future__ import unicode_literals, division, absolute_import, print_function + +import hashlib + +from .algos import SignedDigestAlgorithm +from .core import ( + Boolean, + Enumerated, + GeneralizedTime, + Integer, + ObjectIdentifier, + OctetBitString, + ParsableOctetString, + Sequence, + SequenceOf, +) +from .x509 import ( + AuthorityInfoAccessSyntax, + AuthorityKeyIdentifier, + CRLDistributionPoints, + DistributionPointName, + GeneralNames, + Name, + ReasonFlags, + Time, +) + + +# The structures in this file are taken from https://tools.ietf.org/html/rfc5280 + + +class Version(Integer): + _map = { + 0: 'v1', + 1: 'v2', + 2: 'v3', + } + + +class IssuingDistributionPoint(Sequence): + _fields = [ + ('distribution_point', DistributionPointName, {'explicit': 0, 'optional': True}), + ('only_contains_user_certs', Boolean, {'implicit': 1, 'default': False}), + ('only_contains_ca_certs', Boolean, {'implicit': 2, 'default': False}), + ('only_some_reasons', ReasonFlags, {'implicit': 3, 'optional': True}), + ('indirect_crl', Boolean, {'implicit': 4, 'default': False}), + ('only_contains_attribute_certs', Boolean, {'implicit': 5, 'default': False}), + ] + + +class TBSCertListExtensionId(ObjectIdentifier): + _map = { + '2.5.29.18': 'issuer_alt_name', + '2.5.29.20': 'crl_number', + '2.5.29.27': 'delta_crl_indicator', + '2.5.29.28': 'issuing_distribution_point', + '2.5.29.35': 'authority_key_identifier', + '2.5.29.46': 'freshest_crl', + '1.3.6.1.5.5.7.1.1': 'authority_information_access', + } + + +class TBSCertListExtension(Sequence): + _fields = [ + ('extn_id', TBSCertListExtensionId), + ('critical', Boolean, {'default': False}), + ('extn_value', ParsableOctetString), + ] + + _oid_pair = ('extn_id', 'extn_value') + _oid_specs = { + 'issuer_alt_name': GeneralNames, + 'crl_number': Integer, + 'delta_crl_indicator': Integer, + 'issuing_distribution_point': IssuingDistributionPoint, + 'authority_key_identifier': AuthorityKeyIdentifier, + 'freshest_crl': CRLDistributionPoints, + 'authority_information_access': AuthorityInfoAccessSyntax, + } + + +class TBSCertListExtensions(SequenceOf): + _child_spec = TBSCertListExtension + + +class CRLReason(Enumerated): + _map = { + 0: 'unspecified', + 1: 'key_compromise', + 2: 'ca_compromise', + 3: 'affiliation_changed', + 4: 'superseded', + 5: 'cessation_of_operation', + 6: 'certificate_hold', + 8: 'remove_from_crl', + 9: 'privilege_withdrawn', + 10: 'aa_compromise', + } + + @property + def human_friendly(self): + """ + :return: + A unicode string with revocation description that is suitable to + show to end-users. Starts with a lower case letter and phrased in + such a way that it makes sense after the phrase "because of" or + "due to". + """ + + return { + 'unspecified': 'an unspecified reason', + 'key_compromise': 'a compromised key', + 'ca_compromise': 'the CA being compromised', + 'affiliation_changed': 'an affiliation change', + 'superseded': 'certificate supersession', + 'cessation_of_operation': 'a cessation of operation', + 'certificate_hold': 'a certificate hold', + 'remove_from_crl': 'removal from the CRL', + 'privilege_withdrawn': 'privilege withdrawl', + 'aa_compromise': 'the AA being compromised', + }[self.native] + + +class CRLEntryExtensionId(ObjectIdentifier): + _map = { + '2.5.29.21': 'crl_reason', + '2.5.29.23': 'hold_instruction_code', + '2.5.29.24': 'invalidity_date', + '2.5.29.29': 'certificate_issuer', + } + + +class CRLEntryExtension(Sequence): + _fields = [ + ('extn_id', CRLEntryExtensionId), + ('critical', Boolean, {'default': False}), + ('extn_value', ParsableOctetString), + ] + + _oid_pair = ('extn_id', 'extn_value') + _oid_specs = { + 'crl_reason': CRLReason, + 'hold_instruction_code': ObjectIdentifier, + 'invalidity_date': GeneralizedTime, + 'certificate_issuer': GeneralNames, + } + + +class CRLEntryExtensions(SequenceOf): + _child_spec = CRLEntryExtension + + +class RevokedCertificate(Sequence): + _fields = [ + ('user_certificate', Integer), + ('revocation_date', Time), + ('crl_entry_extensions', CRLEntryExtensions, {'optional': True}), + ] + + _processed_extensions = False + _critical_extensions = None + _crl_reason_value = None + _invalidity_date_value = None + _certificate_issuer_value = None + _issuer_name = False + + def _set_extensions(self): + """ + Sets common named extensions to private attributes and creates a list + of critical extensions + """ + + self._critical_extensions = set() + + for extension in self['crl_entry_extensions']: + name = extension['extn_id'].native + attribute_name = '_%s_value' % name + if hasattr(self, attribute_name): + setattr(self, attribute_name, extension['extn_value'].parsed) + if extension['critical'].native: + self._critical_extensions.add(name) + + self._processed_extensions = True + + @property + def critical_extensions(self): + """ + Returns a set of the names (or OID if not a known extension) of the + extensions marked as critical + + :return: + A set of unicode strings + """ + + if not self._processed_extensions: + self._set_extensions() + return self._critical_extensions + + @property + def crl_reason_value(self): + """ + This extension indicates the reason that a certificate was revoked. + + :return: + None or a CRLReason object + """ + + if self._processed_extensions is False: + self._set_extensions() + return self._crl_reason_value + + @property + def invalidity_date_value(self): + """ + This extension indicates the suspected date/time the private key was + compromised or the certificate became invalid. This would usually be + before the revocation date, which is when the CA processed the + revocation. + + :return: + None or a GeneralizedTime object + """ + + if self._processed_extensions is False: + self._set_extensions() + return self._invalidity_date_value + + @property + def certificate_issuer_value(self): + """ + This extension indicates the issuer of the certificate in question, + and is used in indirect CRLs. CRL entries without this extension are + for certificates issued from the last seen issuer. + + :return: + None or an x509.GeneralNames object + """ + + if self._processed_extensions is False: + self._set_extensions() + return self._certificate_issuer_value + + @property + def issuer_name(self): + """ + :return: + None, or an asn1crypto.x509.Name object for the issuer of the cert + """ + + if self._issuer_name is False: + self._issuer_name = None + if self.certificate_issuer_value: + for general_name in self.certificate_issuer_value: + if general_name.name == 'directory_name': + self._issuer_name = general_name.chosen + break + return self._issuer_name + + +class RevokedCertificates(SequenceOf): + _child_spec = RevokedCertificate + + +class TbsCertList(Sequence): + _fields = [ + ('version', Version, {'optional': True}), + ('signature', SignedDigestAlgorithm), + ('issuer', Name), + ('this_update', Time), + ('next_update', Time, {'optional': True}), + ('revoked_certificates', RevokedCertificates, {'optional': True}), + ('crl_extensions', TBSCertListExtensions, {'explicit': 0, 'optional': True}), + ] + + +class CertificateList(Sequence): + _fields = [ + ('tbs_cert_list', TbsCertList), + ('signature_algorithm', SignedDigestAlgorithm), + ('signature', OctetBitString), + ] + + _processed_extensions = False + _critical_extensions = None + _issuer_alt_name_value = None + _crl_number_value = None + _delta_crl_indicator_value = None + _issuing_distribution_point_value = None + _authority_key_identifier_value = None + _freshest_crl_value = None + _authority_information_access_value = None + _issuer_cert_urls = None + _delta_crl_distribution_points = None + _sha1 = None + _sha256 = None + + def _set_extensions(self): + """ + Sets common named extensions to private attributes and creates a list + of critical extensions + """ + + self._critical_extensions = set() + + for extension in self['tbs_cert_list']['crl_extensions']: + name = extension['extn_id'].native + attribute_name = '_%s_value' % name + if hasattr(self, attribute_name): + setattr(self, attribute_name, extension['extn_value'].parsed) + if extension['critical'].native: + self._critical_extensions.add(name) + + self._processed_extensions = True + + @property + def critical_extensions(self): + """ + Returns a set of the names (or OID if not a known extension) of the + extensions marked as critical + + :return: + A set of unicode strings + """ + + if not self._processed_extensions: + self._set_extensions() + return self._critical_extensions + + @property + def issuer_alt_name_value(self): + """ + This extension allows associating one or more alternative names with + the issuer of the CRL. + + :return: + None or an x509.GeneralNames object + """ + + if self._processed_extensions is False: + self._set_extensions() + return self._issuer_alt_name_value + + @property + def crl_number_value(self): + """ + This extension adds a monotonically increasing number to the CRL and is + used to distinguish different versions of the CRL. + + :return: + None or an Integer object + """ + + if self._processed_extensions is False: + self._set_extensions() + return self._crl_number_value + + @property + def delta_crl_indicator_value(self): + """ + This extension indicates a CRL is a delta CRL, and contains the CRL + number of the base CRL that it is a delta from. + + :return: + None or an Integer object + """ + + if self._processed_extensions is False: + self._set_extensions() + return self._delta_crl_indicator_value + + @property + def issuing_distribution_point_value(self): + """ + This extension includes information about what types of revocations + and certificates are part of the CRL. + + :return: + None or an IssuingDistributionPoint object + """ + + if self._processed_extensions is False: + self._set_extensions() + return self._issuing_distribution_point_value + + @property + def authority_key_identifier_value(self): + """ + This extension helps in identifying the public key with which to + validate the authenticity of the CRL. + + :return: + None or an AuthorityKeyIdentifier object + """ + + if self._processed_extensions is False: + self._set_extensions() + return self._authority_key_identifier_value + + @property + def freshest_crl_value(self): + """ + This extension is used in complete CRLs to indicate where a delta CRL + may be located. + + :return: + None or a CRLDistributionPoints object + """ + + if self._processed_extensions is False: + self._set_extensions() + return self._freshest_crl_value + + @property + def authority_information_access_value(self): + """ + This extension is used to provide a URL with which to download the + certificate used to sign this CRL. + + :return: + None or an AuthorityInfoAccessSyntax object + """ + + if self._processed_extensions is False: + self._set_extensions() + return self._authority_information_access_value + + @property + def issuer(self): + """ + :return: + An asn1crypto.x509.Name object for the issuer of the CRL + """ + + return self['tbs_cert_list']['issuer'] + + @property + def authority_key_identifier(self): + """ + :return: + None or a byte string of the key_identifier from the authority key + identifier extension + """ + + if not self.authority_key_identifier_value: + return None + + return self.authority_key_identifier_value['key_identifier'].native + + @property + def issuer_cert_urls(self): + """ + :return: + A list of unicode strings that are URLs that should contain either + an individual DER-encoded X.509 certificate, or a DER-encoded CMS + message containing multiple certificates + """ + + if self._issuer_cert_urls is None: + self._issuer_cert_urls = [] + if self.authority_information_access_value: + for entry in self.authority_information_access_value: + if entry['access_method'].native == 'ca_issuers': + location = entry['access_location'] + if location.name != 'uniform_resource_identifier': + continue + url = location.native + if url.lower()[0:7] == 'http://': + self._issuer_cert_urls.append(url) + return self._issuer_cert_urls + + @property + def delta_crl_distribution_points(self): + """ + Returns delta CRL URLs - only applies to complete CRLs + + :return: + A list of zero or more DistributionPoint objects + """ + + if self._delta_crl_distribution_points is None: + self._delta_crl_distribution_points = [] + + if self.freshest_crl_value is not None: + for distribution_point in self.freshest_crl_value: + distribution_point_name = distribution_point['distribution_point'] + # RFC 5280 indicates conforming CA should not use the relative form + if distribution_point_name.name == 'name_relative_to_crl_issuer': + continue + # This library is currently only concerned with HTTP-based CRLs + for general_name in distribution_point_name.chosen: + if general_name.name == 'uniform_resource_identifier': + self._delta_crl_distribution_points.append(distribution_point) + + return self._delta_crl_distribution_points + + @property + def signature(self): + """ + :return: + A byte string of the signature + """ + + return self['signature'].native + + @property + def sha1(self): + """ + :return: + The SHA1 hash of the DER-encoded bytes of this certificate list + """ + + if self._sha1 is None: + self._sha1 = hashlib.sha1(self.dump()).digest() + return self._sha1 + + @property + def sha256(self): + """ + :return: + The SHA-256 hash of the DER-encoded bytes of this certificate list + """ + + if self._sha256 is None: + self._sha256 = hashlib.sha256(self.dump()).digest() + return self._sha256 diff --git a/venv/lib/python2.7/site-packages/asn1crypto/csr.py b/venv/lib/python2.7/site-packages/asn1crypto/csr.py new file mode 100644 index 0000000..7ea2848 --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/csr.py @@ -0,0 +1,96 @@ +# coding: utf-8 + +""" +ASN.1 type classes for certificate signing requests (CSR). Exports the +following items: + + - CertificatationRequest() + +Other type classes are defined that help compose the types listed above. +""" + +from __future__ import unicode_literals, division, absolute_import, print_function + +from .algos import SignedDigestAlgorithm +from .core import ( + Any, + Integer, + ObjectIdentifier, + OctetBitString, + Sequence, + SetOf, +) +from .keys import PublicKeyInfo +from .x509 import DirectoryString, Extensions, Name + + +# The structures in this file are taken from https://tools.ietf.org/html/rfc2986 +# and https://tools.ietf.org/html/rfc2985 + + +class Version(Integer): + _map = { + 0: 'v1', + } + + +class CSRAttributeType(ObjectIdentifier): + _map = { + '1.2.840.113549.1.9.7': 'challenge_password', + '1.2.840.113549.1.9.9': 'extended_certificate_attributes', + '1.2.840.113549.1.9.14': 'extension_request', + } + + +class SetOfDirectoryString(SetOf): + _child_spec = DirectoryString + + +class Attribute(Sequence): + _fields = [ + ('type', ObjectIdentifier), + ('values', SetOf, {'spec': Any}), + ] + + +class SetOfAttributes(SetOf): + _child_spec = Attribute + + +class SetOfExtensions(SetOf): + _child_spec = Extensions + + +class CRIAttribute(Sequence): + _fields = [ + ('type', CSRAttributeType), + ('values', Any), + ] + + _oid_pair = ('type', 'values') + _oid_specs = { + 'challenge_password': SetOfDirectoryString, + 'extended_certificate_attributes': SetOfAttributes, + 'extension_request': SetOfExtensions, + } + + +class CRIAttributes(SetOf): + _child_spec = CRIAttribute + + +class CertificationRequestInfo(Sequence): + _fields = [ + ('version', Version), + ('subject', Name), + ('subject_pk_info', PublicKeyInfo), + ('attributes', CRIAttributes, {'implicit': 0, 'optional': True}), + ] + + +class CertificationRequest(Sequence): + _fields = [ + ('certification_request_info', CertificationRequestInfo), + ('signature_algorithm', SignedDigestAlgorithm), + ('signature', OctetBitString), + ] diff --git a/venv/lib/python2.7/site-packages/asn1crypto/keys.py b/venv/lib/python2.7/site-packages/asn1crypto/keys.py new file mode 100644 index 0000000..9a09a31 --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/keys.py @@ -0,0 +1,1249 @@ +# coding: utf-8 + +""" +ASN.1 type classes for public and private keys. Exports the following items: + + - DSAPrivateKey() + - ECPrivateKey() + - EncryptedPrivateKeyInfo() + - PrivateKeyInfo() + - PublicKeyInfo() + - RSAPrivateKey() + - RSAPublicKey() + +Other type classes are defined that help compose the types listed above. +""" + +from __future__ import unicode_literals, division, absolute_import, print_function + +import hashlib +import math + +from ._elliptic_curve import ( + SECP192R1_BASE_POINT, + SECP224R1_BASE_POINT, + SECP256R1_BASE_POINT, + SECP384R1_BASE_POINT, + SECP521R1_BASE_POINT, + PrimeCurve, + PrimePoint, +) +from ._errors import unwrap +from ._types import type_name, str_cls, byte_cls +from .algos import _ForceNullParameters, DigestAlgorithm, EncryptionAlgorithm, RSAESOAEPParams +from .core import ( + Any, + Asn1Value, + BitString, + Choice, + Integer, + IntegerOctetString, + Null, + ObjectIdentifier, + OctetBitString, + OctetString, + ParsableOctetString, + ParsableOctetBitString, + Sequence, + SequenceOf, + SetOf, +) +from .util import int_from_bytes, int_to_bytes + + +class OtherPrimeInfo(Sequence): + """ + Source: https://tools.ietf.org/html/rfc3447#page-46 + """ + + _fields = [ + ('prime', Integer), + ('exponent', Integer), + ('coefficient', Integer), + ] + + +class OtherPrimeInfos(SequenceOf): + """ + Source: https://tools.ietf.org/html/rfc3447#page-46 + """ + + _child_spec = OtherPrimeInfo + + +class RSAPrivateKeyVersion(Integer): + """ + Original Name: Version + Source: https://tools.ietf.org/html/rfc3447#page-45 + """ + + _map = { + 0: 'two-prime', + 1: 'multi', + } + + +class RSAPrivateKey(Sequence): + """ + Source: https://tools.ietf.org/html/rfc3447#page-45 + """ + + _fields = [ + ('version', RSAPrivateKeyVersion), + ('modulus', Integer), + ('public_exponent', Integer), + ('private_exponent', Integer), + ('prime1', Integer), + ('prime2', Integer), + ('exponent1', Integer), + ('exponent2', Integer), + ('coefficient', Integer), + ('other_prime_infos', OtherPrimeInfos, {'optional': True}) + ] + + +class RSAPublicKey(Sequence): + """ + Source: https://tools.ietf.org/html/rfc3447#page-44 + """ + + _fields = [ + ('modulus', Integer), + ('public_exponent', Integer) + ] + + +class DSAPrivateKey(Sequence): + """ + The ASN.1 structure that OpenSSL uses to store a DSA private key that is + not part of a PKCS#8 structure. Reversed engineered from english-language + description on linked OpenSSL documentation page. + + Original Name: None + Source: https://www.openssl.org/docs/apps/dsa.html + """ + + _fields = [ + ('version', Integer), + ('p', Integer), + ('q', Integer), + ('g', Integer), + ('public_key', Integer), + ('private_key', Integer), + ] + + +class _ECPoint(): + """ + In both PublicKeyInfo and PrivateKeyInfo, the EC public key is a byte + string that is encoded as a bit string. This class adds convenience + methods for converting to and from the byte string to a pair of integers + that are the X and Y coordinates. + """ + + @classmethod + def from_coords(cls, x, y): + """ + Creates an ECPoint object from the X and Y integer coordinates of the + point + + :param x: + The X coordinate, as an integer + + :param y: + The Y coordinate, as an integer + + :return: + An ECPoint object + """ + + x_bytes = int(math.ceil(math.log(x, 2) / 8.0)) + y_bytes = int(math.ceil(math.log(y, 2) / 8.0)) + + num_bytes = max(x_bytes, y_bytes) + + byte_string = b'\x04' + byte_string += int_to_bytes(x, width=num_bytes) + byte_string += int_to_bytes(y, width=num_bytes) + + return cls(byte_string) + + def to_coords(self): + """ + Returns the X and Y coordinates for this EC point, as native Python + integers + + :return: + A 2-element tuple containing integers (X, Y) + """ + + data = self.native + first_byte = data[0:1] + + # Uncompressed + if first_byte == b'\x04': + remaining = data[1:] + field_len = len(remaining) // 2 + x = int_from_bytes(remaining[0:field_len]) + y = int_from_bytes(remaining[field_len:]) + return (x, y) + + if first_byte not in set([b'\x02', b'\x03']): + raise ValueError(unwrap( + ''' + Invalid EC public key - first byte is incorrect + ''' + )) + + raise ValueError(unwrap( + ''' + Compressed representations of EC public keys are not supported due + to patent US6252960 + ''' + )) + + +class ECPoint(OctetString, _ECPoint): + + pass + + +class ECPointBitString(OctetBitString, _ECPoint): + + pass + + +class SpecifiedECDomainVersion(Integer): + """ + Source: http://www.secg.org/sec1-v2.pdf page 104 + """ + _map = { + 1: 'ecdpVer1', + 2: 'ecdpVer2', + 3: 'ecdpVer3', + } + + +class FieldType(ObjectIdentifier): + """ + Original Name: None + Source: http://www.secg.org/sec1-v2.pdf page 101 + """ + + _map = { + '1.2.840.10045.1.1': 'prime_field', + '1.2.840.10045.1.2': 'characteristic_two_field', + } + + +class CharacteristicTwoBasis(ObjectIdentifier): + """ + Original Name: None + Source: http://www.secg.org/sec1-v2.pdf page 102 + """ + + _map = { + '1.2.840.10045.1.2.1.1': 'gn_basis', + '1.2.840.10045.1.2.1.2': 'tp_basis', + '1.2.840.10045.1.2.1.3': 'pp_basis', + } + + +class Pentanomial(Sequence): + """ + Source: http://www.secg.org/sec1-v2.pdf page 102 + """ + + _fields = [ + ('k1', Integer), + ('k2', Integer), + ('k3', Integer), + ] + + +class CharacteristicTwo(Sequence): + """ + Original Name: Characteristic-two + Source: http://www.secg.org/sec1-v2.pdf page 101 + """ + + _fields = [ + ('m', Integer), + ('basis', CharacteristicTwoBasis), + ('parameters', Any), + ] + + _oid_pair = ('basis', 'parameters') + _oid_specs = { + 'gn_basis': Null, + 'tp_basis': Integer, + 'pp_basis': Pentanomial, + } + + +class FieldID(Sequence): + """ + Source: http://www.secg.org/sec1-v2.pdf page 100 + """ + + _fields = [ + ('field_type', FieldType), + ('parameters', Any), + ] + + _oid_pair = ('field_type', 'parameters') + _oid_specs = { + 'prime_field': Integer, + 'characteristic_two_field': CharacteristicTwo, + } + + +class Curve(Sequence): + """ + Source: http://www.secg.org/sec1-v2.pdf page 104 + """ + + _fields = [ + ('a', OctetString), + ('b', OctetString), + ('seed', OctetBitString, {'optional': True}), + ] + + +class SpecifiedECDomain(Sequence): + """ + Source: http://www.secg.org/sec1-v2.pdf page 103 + """ + + _fields = [ + ('version', SpecifiedECDomainVersion), + ('field_id', FieldID), + ('curve', Curve), + ('base', ECPoint), + ('order', Integer), + ('cofactor', Integer, {'optional': True}), + ('hash', DigestAlgorithm, {'optional': True}), + ] + + +class NamedCurve(ObjectIdentifier): + """ + Various named curves + + Original Name: None + Source: https://tools.ietf.org/html/rfc3279#page-23, + https://tools.ietf.org/html/rfc5480#page-5 + """ + + _map = { + # https://tools.ietf.org/html/rfc3279#page-23 + '1.2.840.10045.3.0.1': 'c2pnb163v1', + '1.2.840.10045.3.0.2': 'c2pnb163v2', + '1.2.840.10045.3.0.3': 'c2pnb163v3', + '1.2.840.10045.3.0.4': 'c2pnb176w1', + '1.2.840.10045.3.0.5': 'c2tnb191v1', + '1.2.840.10045.3.0.6': 'c2tnb191v2', + '1.2.840.10045.3.0.7': 'c2tnb191v3', + '1.2.840.10045.3.0.8': 'c2onb191v4', + '1.2.840.10045.3.0.9': 'c2onb191v5', + '1.2.840.10045.3.0.10': 'c2pnb208w1', + '1.2.840.10045.3.0.11': 'c2tnb239v1', + '1.2.840.10045.3.0.12': 'c2tnb239v2', + '1.2.840.10045.3.0.13': 'c2tnb239v3', + '1.2.840.10045.3.0.14': 'c2onb239v4', + '1.2.840.10045.3.0.15': 'c2onb239v5', + '1.2.840.10045.3.0.16': 'c2pnb272w1', + '1.2.840.10045.3.0.17': 'c2pnb304w1', + '1.2.840.10045.3.0.18': 'c2tnb359v1', + '1.2.840.10045.3.0.19': 'c2pnb368w1', + '1.2.840.10045.3.0.20': 'c2tnb431r1', + '1.2.840.10045.3.1.2': 'prime192v2', + '1.2.840.10045.3.1.3': 'prime192v3', + '1.2.840.10045.3.1.4': 'prime239v1', + '1.2.840.10045.3.1.5': 'prime239v2', + '1.2.840.10045.3.1.6': 'prime239v3', + # https://tools.ietf.org/html/rfc5480#page-5 + '1.3.132.0.1': 'sect163k1', + '1.3.132.0.15': 'sect163r2', + '1.2.840.10045.3.1.1': 'secp192r1', + '1.3.132.0.33': 'secp224r1', + '1.3.132.0.26': 'sect233k1', + '1.2.840.10045.3.1.7': 'secp256r1', + '1.3.132.0.27': 'sect233r1', + '1.3.132.0.16': 'sect283k1', + '1.3.132.0.17': 'sect283r1', + '1.3.132.0.34': 'secp384r1', + '1.3.132.0.36': 'sect409k1', + '1.3.132.0.37': 'sect409r1', + '1.3.132.0.35': 'secp521r1', + '1.3.132.0.38': 'sect571k1', + '1.3.132.0.39': 'sect571r1', + } + + +class ECDomainParameters(Choice): + """ + Source: http://www.secg.org/sec1-v2.pdf page 102 + """ + + _alternatives = [ + ('specified', SpecifiedECDomain), + ('named', NamedCurve), + ('implicit_ca', Null), + ] + + +class ECPrivateKeyVersion(Integer): + """ + Original Name: None + Source: http://www.secg.org/sec1-v2.pdf page 108 + """ + + _map = { + 1: 'ecPrivkeyVer1', + } + + +class ECPrivateKey(Sequence): + """ + Source: http://www.secg.org/sec1-v2.pdf page 108 + """ + + _fields = [ + ('version', ECPrivateKeyVersion), + ('private_key', IntegerOctetString), + ('parameters', ECDomainParameters, {'explicit': 0, 'optional': True}), + ('public_key', ECPointBitString, {'explicit': 1, 'optional': True}), + ] + + +class DSAParams(Sequence): + """ + Parameters for a DSA public or private key + + Original Name: Dss-Parms + Source: https://tools.ietf.org/html/rfc3279#page-9 + """ + + _fields = [ + ('p', Integer), + ('q', Integer), + ('g', Integer), + ] + + +class Attribute(Sequence): + """ + Source: https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-X.501-198811-S!!PDF-E&type=items page 8 + """ + + _fields = [ + ('type', ObjectIdentifier), + ('values', SetOf, {'spec': Any}), + ] + + +class Attributes(SetOf): + """ + Source: https://tools.ietf.org/html/rfc5208#page-3 + """ + + _child_spec = Attribute + + +class PrivateKeyAlgorithmId(ObjectIdentifier): + """ + These OIDs for various public keys are reused when storing private keys + inside of a PKCS#8 structure + + Original Name: None + Source: https://tools.ietf.org/html/rfc3279 + """ + + _map = { + # https://tools.ietf.org/html/rfc3279#page-19 + '1.2.840.113549.1.1.1': 'rsa', + # https://tools.ietf.org/html/rfc3279#page-18 + '1.2.840.10040.4.1': 'dsa', + # https://tools.ietf.org/html/rfc3279#page-13 + '1.2.840.10045.2.1': 'ec', + } + + +class PrivateKeyAlgorithm(_ForceNullParameters, Sequence): + """ + Original Name: PrivateKeyAlgorithmIdentifier + Source: https://tools.ietf.org/html/rfc5208#page-3 + """ + + _fields = [ + ('algorithm', PrivateKeyAlgorithmId), + ('parameters', Any, {'optional': True}), + ] + + _oid_pair = ('algorithm', 'parameters') + _oid_specs = { + 'dsa': DSAParams, + 'ec': ECDomainParameters, + } + + +class PrivateKeyInfo(Sequence): + """ + Source: https://tools.ietf.org/html/rfc5208#page-3 + """ + + _fields = [ + ('version', Integer), + ('private_key_algorithm', PrivateKeyAlgorithm), + ('private_key', ParsableOctetString), + ('attributes', Attributes, {'implicit': 0, 'optional': True}), + ] + + def _private_key_spec(self): + algorithm = self['private_key_algorithm']['algorithm'].native + return { + 'rsa': RSAPrivateKey, + 'dsa': Integer, + 'ec': ECPrivateKey, + }[algorithm] + + _spec_callbacks = { + 'private_key': _private_key_spec + } + + _algorithm = None + _bit_size = None + _public_key = None + _fingerprint = None + + @classmethod + def wrap(cls, private_key, algorithm): + """ + Wraps a private key in a PrivateKeyInfo structure + + :param private_key: + A byte string or Asn1Value object of the private key + + :param algorithm: + A unicode string of "rsa", "dsa" or "ec" + + :return: + A PrivateKeyInfo object + """ + + if not isinstance(private_key, byte_cls) and not isinstance(private_key, Asn1Value): + raise TypeError(unwrap( + ''' + private_key must be a byte string or Asn1Value, not %s + ''', + type_name(private_key) + )) + + if algorithm == 'rsa': + if not isinstance(private_key, RSAPrivateKey): + private_key = RSAPrivateKey.load(private_key) + params = Null() + elif algorithm == 'dsa': + if not isinstance(private_key, DSAPrivateKey): + private_key = DSAPrivateKey.load(private_key) + params = DSAParams() + params['p'] = private_key['p'] + params['q'] = private_key['q'] + params['g'] = private_key['g'] + public_key = private_key['public_key'] + private_key = private_key['private_key'] + elif algorithm == 'ec': + if not isinstance(private_key, ECPrivateKey): + private_key = ECPrivateKey.load(private_key) + else: + private_key = private_key.copy() + params = private_key['parameters'] + del private_key['parameters'] + else: + raise ValueError(unwrap( + ''' + algorithm must be one of "rsa", "dsa", "ec", not %s + ''', + repr(algorithm) + )) + + private_key_algo = PrivateKeyAlgorithm() + private_key_algo['algorithm'] = PrivateKeyAlgorithmId(algorithm) + private_key_algo['parameters'] = params + + container = cls() + container._algorithm = algorithm + container['version'] = Integer(0) + container['private_key_algorithm'] = private_key_algo + container['private_key'] = private_key + + # Here we save the DSA public key if possible since it is not contained + # within the PKCS#8 structure for a DSA key + if algorithm == 'dsa': + container._public_key = public_key + + return container + + def _compute_public_key(self): + """ + Computes the public key corresponding to the current private key. + + :return: + For RSA keys, an RSAPublicKey object. For DSA keys, an Integer + object. For EC keys, an ECPointBitString. + """ + + if self.algorithm == 'dsa': + params = self['private_key_algorithm']['parameters'] + return Integer(pow( + params['g'].native, + self['private_key'].parsed.native, + params['p'].native + )) + + if self.algorithm == 'rsa': + key = self['private_key'].parsed + return RSAPublicKey({ + 'modulus': key['modulus'], + 'public_exponent': key['public_exponent'], + }) + + if self.algorithm == 'ec': + curve_type, details = self.curve + + if curve_type == 'implicit_ca': + raise ValueError(unwrap( + ''' + Unable to compute public key for EC key using Implicit CA + parameters + ''' + )) + + if curve_type == 'specified': + if details['field_id']['field_type'] == 'characteristic_two_field': + raise ValueError(unwrap( + ''' + Unable to compute public key for EC key over a + characteristic two field + ''' + )) + + curve = PrimeCurve( + details['field_id']['parameters'], + int_from_bytes(details['curve']['a']), + int_from_bytes(details['curve']['b']) + ) + base_x, base_y = self['private_key_algorithm']['parameters'].chosen['base'].to_coords() + base_point = PrimePoint(curve, base_x, base_y) + + elif curve_type == 'named': + if details not in ('secp192r1', 'secp224r1', 'secp256r1', 'secp384r1', 'secp521r1'): + raise ValueError(unwrap( + ''' + Unable to compute public key for EC named curve %s, + parameters not currently included + ''', + details + )) + + base_point = { + 'secp192r1': SECP192R1_BASE_POINT, + 'secp224r1': SECP224R1_BASE_POINT, + 'secp256r1': SECP256R1_BASE_POINT, + 'secp384r1': SECP384R1_BASE_POINT, + 'secp521r1': SECP521R1_BASE_POINT, + }[details] + + public_point = base_point * self['private_key'].parsed['private_key'].native + return ECPointBitString.from_coords(public_point.x, public_point.y) + + def unwrap(self): + """ + Unwraps the private key into an RSAPrivateKey, DSAPrivateKey or + ECPrivateKey object + + :return: + An RSAPrivateKey, DSAPrivateKey or ECPrivateKey object + """ + + if self.algorithm == 'rsa': + return self['private_key'].parsed + + if self.algorithm == 'dsa': + params = self['private_key_algorithm']['parameters'] + return DSAPrivateKey({ + 'version': 0, + 'p': params['p'], + 'q': params['q'], + 'g': params['g'], + 'public_key': self.public_key, + 'private_key': self['private_key'].parsed, + }) + + if self.algorithm == 'ec': + output = self['private_key'].parsed + output['parameters'] = self['private_key_algorithm']['parameters'] + output['public_key'] = self.public_key + return output + + @property + def curve(self): + """ + Returns information about the curve used for an EC key + + :raises: + ValueError - when the key is not an EC key + + :return: + A two-element tuple, with the first element being a unicode string + of "implicit_ca", "specified" or "named". If the first element is + "implicit_ca", the second is None. If "specified", the second is + an OrderedDict that is the native version of SpecifiedECDomain. If + "named", the second is a unicode string of the curve name. + """ + + if self.algorithm != 'ec': + raise ValueError(unwrap( + ''' + Only EC keys have a curve, this key is %s + ''', + self.algorithm.upper() + )) + + params = self['private_key_algorithm']['parameters'] + chosen = params.chosen + + if params.name == 'implicit_ca': + value = None + else: + value = chosen.native + + return (params.name, value) + + @property + def hash_algo(self): + """ + Returns the name of the family of hash algorithms used to generate a + DSA key + + :raises: + ValueError - when the key is not a DSA key + + :return: + A unicode string of "sha1" or "sha2" + """ + + if self.algorithm != 'dsa': + raise ValueError(unwrap( + ''' + Only DSA keys are generated using a hash algorithm, this key is + %s + ''', + self.algorithm.upper() + )) + + byte_len = math.log(self['private_key_algorithm']['parameters']['q'].native, 2) / 8 + + return 'sha1' if byte_len <= 20 else 'sha2' + + @property + def algorithm(self): + """ + :return: + A unicode string of "rsa", "dsa" or "ec" + """ + + if self._algorithm is None: + self._algorithm = self['private_key_algorithm']['algorithm'].native + return self._algorithm + + @property + def bit_size(self): + """ + :return: + The bit size of the private key, as an integer + """ + + if self._bit_size is None: + if self.algorithm == 'rsa': + prime = self['private_key'].parsed['modulus'].native + elif self.algorithm == 'dsa': + prime = self['private_key_algorithm']['parameters']['p'].native + elif self.algorithm == 'ec': + prime = self['private_key'].parsed['private_key'].native + self._bit_size = int(math.ceil(math.log(prime, 2))) + modulus = self._bit_size % 8 + if modulus != 0: + self._bit_size += 8 - modulus + return self._bit_size + + @property + def byte_size(self): + """ + :return: + The byte size of the private key, as an integer + """ + + return int(math.ceil(self.bit_size / 8)) + + @property + def public_key(self): + """ + :return: + If an RSA key, an RSAPublicKey object. If a DSA key, an Integer + object. If an EC key, an ECPointBitString object. + """ + + if self._public_key is None: + if self.algorithm == 'ec': + key = self['private_key'].parsed + if key['public_key']: + self._public_key = key['public_key'].untag() + else: + self._public_key = self._compute_public_key() + else: + self._public_key = self._compute_public_key() + + return self._public_key + + @property + def public_key_info(self): + """ + :return: + A PublicKeyInfo object derived from this private key. + """ + + return PublicKeyInfo({ + 'algorithm': { + 'algorithm': self.algorithm, + 'parameters': self['private_key_algorithm']['parameters'] + }, + 'public_key': self.public_key + }) + + @property + def fingerprint(self): + """ + Creates a fingerprint that can be compared with a public key to see if + the two form a pair. + + This fingerprint is not compatible with fingerprints generated by any + other software. + + :return: + A byte string that is a sha256 hash of selected components (based + on the key type) + """ + + if self._fingerprint is None: + params = self['private_key_algorithm']['parameters'] + key = self['private_key'].parsed + + if self.algorithm == 'rsa': + to_hash = '%d:%d' % ( + key['modulus'].native, + key['public_exponent'].native, + ) + + elif self.algorithm == 'dsa': + public_key = self.public_key + to_hash = '%d:%d:%d:%d' % ( + params['p'].native, + params['q'].native, + params['g'].native, + public_key.native, + ) + + elif self.algorithm == 'ec': + public_key = key['public_key'].native + if public_key is None: + public_key = self.public_key.native + + if params.name == 'named': + to_hash = '%s:' % params.chosen.native + to_hash = to_hash.encode('utf-8') + to_hash += public_key + + elif params.name == 'implicit_ca': + to_hash = public_key + + elif params.name == 'specified': + to_hash = '%s:' % params.chosen['field_id']['parameters'].native + to_hash = to_hash.encode('utf-8') + to_hash += b':' + params.chosen['curve']['a'].native + to_hash += b':' + params.chosen['curve']['b'].native + to_hash += public_key + + if isinstance(to_hash, str_cls): + to_hash = to_hash.encode('utf-8') + + self._fingerprint = hashlib.sha256(to_hash).digest() + + return self._fingerprint + + +class EncryptedPrivateKeyInfo(Sequence): + """ + Source: https://tools.ietf.org/html/rfc5208#page-4 + """ + + _fields = [ + ('encryption_algorithm', EncryptionAlgorithm), + ('encrypted_data', OctetString), + ] + + +# These structures are from https://tools.ietf.org/html/rfc3279 + +class ValidationParms(Sequence): + """ + Source: https://tools.ietf.org/html/rfc3279#page-10 + """ + + _fields = [ + ('seed', BitString), + ('pgen_counter', Integer), + ] + + +class DomainParameters(Sequence): + """ + Source: https://tools.ietf.org/html/rfc3279#page-10 + """ + + _fields = [ + ('p', Integer), + ('g', Integer), + ('q', Integer), + ('j', Integer, {'optional': True}), + ('validation_params', ValidationParms, {'optional': True}), + ] + + +class PublicKeyAlgorithmId(ObjectIdentifier): + """ + Original Name: None + Source: https://tools.ietf.org/html/rfc3279 + """ + + _map = { + # https://tools.ietf.org/html/rfc3279#page-19 + '1.2.840.113549.1.1.1': 'rsa', + # https://tools.ietf.org/html/rfc3447#page-47 + '1.2.840.113549.1.1.7': 'rsaes_oaep', + # https://tools.ietf.org/html/rfc3279#page-18 + '1.2.840.10040.4.1': 'dsa', + # https://tools.ietf.org/html/rfc3279#page-13 + '1.2.840.10045.2.1': 'ec', + # https://tools.ietf.org/html/rfc3279#page-10 + '1.2.840.10046.2.1': 'dh', + } + + +class PublicKeyAlgorithm(_ForceNullParameters, Sequence): + """ + Original Name: AlgorithmIdentifier + Source: https://tools.ietf.org/html/rfc5280#page-18 + """ + + _fields = [ + ('algorithm', PublicKeyAlgorithmId), + ('parameters', Any, {'optional': True}), + ] + + _oid_pair = ('algorithm', 'parameters') + _oid_specs = { + 'dsa': DSAParams, + 'ec': ECDomainParameters, + 'dh': DomainParameters, + 'rsaes_oaep': RSAESOAEPParams, + } + + +class PublicKeyInfo(Sequence): + """ + Original Name: SubjectPublicKeyInfo + Source: https://tools.ietf.org/html/rfc5280#page-17 + """ + + _fields = [ + ('algorithm', PublicKeyAlgorithm), + ('public_key', ParsableOctetBitString), + ] + + def _public_key_spec(self): + algorithm = self['algorithm']['algorithm'].native + return { + 'rsa': RSAPublicKey, + 'rsaes_oaep': RSAPublicKey, + 'dsa': Integer, + # We override the field spec with ECPoint so that users can easily + # decompose the byte string into the constituent X and Y coords + 'ec': (ECPointBitString, None), + 'dh': Integer, + }[algorithm] + + _spec_callbacks = { + 'public_key': _public_key_spec + } + + _algorithm = None + _bit_size = None + _fingerprint = None + _sha1 = None + _sha256 = None + + @classmethod + def wrap(cls, public_key, algorithm): + """ + Wraps a public key in a PublicKeyInfo structure + + :param public_key: + A byte string or Asn1Value object of the public key + + :param algorithm: + A unicode string of "rsa" + + :return: + A PublicKeyInfo object + """ + + if not isinstance(public_key, byte_cls) and not isinstance(public_key, Asn1Value): + raise TypeError(unwrap( + ''' + public_key must be a byte string or Asn1Value, not %s + ''', + type_name(public_key) + )) + + if algorithm != 'rsa': + raise ValueError(unwrap( + ''' + algorithm must "rsa", not %s + ''', + repr(algorithm) + )) + + algo = PublicKeyAlgorithm() + algo['algorithm'] = PublicKeyAlgorithmId(algorithm) + algo['parameters'] = Null() + + container = cls() + container['algorithm'] = algo + if isinstance(public_key, Asn1Value): + public_key = public_key.untag().dump() + container['public_key'] = ParsableOctetBitString(public_key) + + return container + + def unwrap(self): + """ + Unwraps an RSA public key into an RSAPublicKey object. Does not support + DSA or EC public keys since they do not have an unwrapped form. + + :return: + An RSAPublicKey object + """ + + if self.algorithm == 'rsa': + return self['public_key'].parsed + + key_type = self.algorithm.upper() + a_an = 'an' if key_type == 'EC' else 'a' + raise ValueError(unwrap( + ''' + Only RSA public keys may be unwrapped - this key is %s %s public + key + ''', + a_an, + key_type + )) + + @property + def curve(self): + """ + Returns information about the curve used for an EC key + + :raises: + ValueError - when the key is not an EC key + + :return: + A two-element tuple, with the first element being a unicode string + of "implicit_ca", "specified" or "named". If the first element is + "implicit_ca", the second is None. If "specified", the second is + an OrderedDict that is the native version of SpecifiedECDomain. If + "named", the second is a unicode string of the curve name. + """ + + if self.algorithm != 'ec': + raise ValueError(unwrap( + ''' + Only EC keys have a curve, this key is %s + ''', + self.algorithm.upper() + )) + + params = self['algorithm']['parameters'] + chosen = params.chosen + + if params.name == 'implicit_ca': + value = None + else: + value = chosen.native + + return (params.name, value) + + @property + def hash_algo(self): + """ + Returns the name of the family of hash algorithms used to generate a + DSA key + + :raises: + ValueError - when the key is not a DSA key + + :return: + A unicode string of "sha1" or "sha2" or None if no parameters are + present + """ + + if self.algorithm != 'dsa': + raise ValueError(unwrap( + ''' + Only DSA keys are generated using a hash algorithm, this key is + %s + ''', + self.algorithm.upper() + )) + + parameters = self['algorithm']['parameters'] + if parameters.native is None: + return None + + byte_len = math.log(parameters['q'].native, 2) / 8 + + return 'sha1' if byte_len <= 20 else 'sha2' + + @property + def algorithm(self): + """ + :return: + A unicode string of "rsa", "dsa" or "ec" + """ + + if self._algorithm is None: + self._algorithm = self['algorithm']['algorithm'].native + return self._algorithm + + @property + def bit_size(self): + """ + :return: + The bit size of the public key, as an integer + """ + + if self._bit_size is None: + if self.algorithm == 'ec': + self._bit_size = ((len(self['public_key'].native) - 1) / 2) * 8 + else: + if self.algorithm == 'rsa': + prime = self['public_key'].parsed['modulus'].native + elif self.algorithm == 'dsa': + prime = self['algorithm']['parameters']['p'].native + self._bit_size = int(math.ceil(math.log(prime, 2))) + modulus = self._bit_size % 8 + if modulus != 0: + self._bit_size += 8 - modulus + + return self._bit_size + + @property + def byte_size(self): + """ + :return: + The byte size of the public key, as an integer + """ + + return int(math.ceil(self.bit_size / 8)) + + @property + def sha1(self): + """ + :return: + The SHA1 hash of the DER-encoded bytes of this public key info + """ + + if self._sha1 is None: + self._sha1 = hashlib.sha1(byte_cls(self['public_key'])).digest() + return self._sha1 + + @property + def sha256(self): + """ + :return: + The SHA-256 hash of the DER-encoded bytes of this public key info + """ + + if self._sha256 is None: + self._sha256 = hashlib.sha256(byte_cls(self['public_key'])).digest() + return self._sha256 + + @property + def fingerprint(self): + """ + Creates a fingerprint that can be compared with a private key to see if + the two form a pair. + + This fingerprint is not compatible with fingerprints generated by any + other software. + + :return: + A byte string that is a sha256 hash of selected components (based + on the key type) + """ + + if self._fingerprint is None: + key_type = self['algorithm']['algorithm'].native + params = self['algorithm']['parameters'] + + if key_type == 'rsa': + key = self['public_key'].parsed + to_hash = '%d:%d' % ( + key['modulus'].native, + key['public_exponent'].native, + ) + + elif key_type == 'dsa': + key = self['public_key'].parsed + to_hash = '%d:%d:%d:%d' % ( + params['p'].native, + params['q'].native, + params['g'].native, + key.native, + ) + + elif key_type == 'ec': + key = self['public_key'] + + if params.name == 'named': + to_hash = '%s:' % params.chosen.native + to_hash = to_hash.encode('utf-8') + to_hash += key.native + + elif params.name == 'implicit_ca': + to_hash = key.native + + elif params.name == 'specified': + to_hash = '%s:' % params.chosen['field_id']['parameters'].native + to_hash = to_hash.encode('utf-8') + to_hash += b':' + params.chosen['curve']['a'].native + to_hash += b':' + params.chosen['curve']['b'].native + to_hash += key.native + + if isinstance(to_hash, str_cls): + to_hash = to_hash.encode('utf-8') + + self._fingerprint = hashlib.sha256(to_hash).digest() + + return self._fingerprint diff --git a/venv/lib/python2.7/site-packages/asn1crypto/ocsp.py b/venv/lib/python2.7/site-packages/asn1crypto/ocsp.py new file mode 100644 index 0000000..f18d8e8 --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/ocsp.py @@ -0,0 +1,652 @@ +# coding: utf-8 + +""" +ASN.1 type classes for the online certificate status protocol (OCSP). Exports +the following items: + + - OCSPRequest() + - OCSPResponse() + +Other type classes are defined that help compose the types listed above. +""" + +from __future__ import unicode_literals, division, absolute_import, print_function + +from .algos import DigestAlgorithm, SignedDigestAlgorithm +from .core import ( + Boolean, + Choice, + Enumerated, + GeneralizedTime, + IA5String, + Integer, + Null, + ObjectIdentifier, + OctetBitString, + OctetString, + ParsableOctetString, + Sequence, + SequenceOf, +) +from .crl import AuthorityInfoAccessSyntax, CRLReason +from .keys import PublicKeyAlgorithm +from .x509 import Certificate, GeneralName, GeneralNames, Name + + +# The structures in this file are taken from https://tools.ietf.org/html/rfc6960 + + +class Version(Integer): + _map = { + 0: 'v1' + } + + +class CertId(Sequence): + _fields = [ + ('hash_algorithm', DigestAlgorithm), + ('issuer_name_hash', OctetString), + ('issuer_key_hash', OctetString), + ('serial_number', Integer), + ] + + +class ServiceLocator(Sequence): + _fields = [ + ('issuer', Name), + ('locator', AuthorityInfoAccessSyntax), + ] + + +class RequestExtensionId(ObjectIdentifier): + _map = { + '1.3.6.1.5.5.7.48.1.7': 'service_locator', + } + + +class RequestExtension(Sequence): + _fields = [ + ('extn_id', RequestExtensionId), + ('critical', Boolean, {'default': False}), + ('extn_value', ParsableOctetString), + ] + + _oid_pair = ('extn_id', 'extn_value') + _oid_specs = { + 'service_locator': ServiceLocator, + } + + +class RequestExtensions(SequenceOf): + _child_spec = RequestExtension + + +class Request(Sequence): + _fields = [ + ('req_cert', CertId), + ('single_request_extensions', RequestExtensions, {'explicit': 0, 'optional': True}), + ] + + _processed_extensions = False + _critical_extensions = None + _service_locator_value = None + + def _set_extensions(self): + """ + Sets common named extensions to private attributes and creates a list + of critical extensions + """ + + self._critical_extensions = set() + + for extension in self['single_request_extensions']: + name = extension['extn_id'].native + attribute_name = '_%s_value' % name + if hasattr(self, attribute_name): + setattr(self, attribute_name, extension['extn_value'].parsed) + if extension['critical'].native: + self._critical_extensions.add(name) + + self._processed_extensions = True + + @property + def critical_extensions(self): + """ + Returns a set of the names (or OID if not a known extension) of the + extensions marked as critical + + :return: + A set of unicode strings + """ + + if not self._processed_extensions: + self._set_extensions() + return self._critical_extensions + + @property + def service_locator_value(self): + """ + This extension is used when communicating with an OCSP responder that + acts as a proxy for OCSP requests + + :return: + None or a ServiceLocator object + """ + + if self._processed_extensions is False: + self._set_extensions() + return self._service_locator_value + + +class Requests(SequenceOf): + _child_spec = Request + + +class ResponseType(ObjectIdentifier): + _map = { + '1.3.6.1.5.5.7.48.1.1': 'basic_ocsp_response', + } + + +class AcceptableResponses(SequenceOf): + _child_spec = ResponseType + + +class PreferredSignatureAlgorithm(Sequence): + _fields = [ + ('sig_identifier', SignedDigestAlgorithm), + ('cert_identifier', PublicKeyAlgorithm, {'optional': True}), + ] + + +class PreferredSignatureAlgorithms(SequenceOf): + _child_spec = PreferredSignatureAlgorithm + + +class TBSRequestExtensionId(ObjectIdentifier): + _map = { + '1.3.6.1.5.5.7.48.1.2': 'nonce', + '1.3.6.1.5.5.7.48.1.4': 'acceptable_responses', + '1.3.6.1.5.5.7.48.1.8': 'preferred_signature_algorithms', + } + + +class TBSRequestExtension(Sequence): + _fields = [ + ('extn_id', TBSRequestExtensionId), + ('critical', Boolean, {'default': False}), + ('extn_value', ParsableOctetString), + ] + + _oid_pair = ('extn_id', 'extn_value') + _oid_specs = { + 'nonce': OctetString, + 'acceptable_responses': AcceptableResponses, + 'preferred_signature_algorithms': PreferredSignatureAlgorithms, + } + + +class TBSRequestExtensions(SequenceOf): + _child_spec = TBSRequestExtension + + +class TBSRequest(Sequence): + _fields = [ + ('version', Version, {'explicit': 0, 'default': 'v1'}), + ('requestor_name', GeneralName, {'explicit': 1, 'optional': True}), + ('request_list', Requests), + ('request_extensions', TBSRequestExtensions, {'explicit': 2, 'optional': True}), + ] + + +class Certificates(SequenceOf): + _child_spec = Certificate + + +class Signature(Sequence): + _fields = [ + ('signature_algorithm', SignedDigestAlgorithm), + ('signature', OctetBitString), + ('certs', Certificates, {'explicit': 0, 'optional': True}), + ] + + +class OCSPRequest(Sequence): + _fields = [ + ('tbs_request', TBSRequest), + ('optional_signature', Signature, {'explicit': 0, 'optional': True}), + ] + + _processed_extensions = False + _critical_extensions = None + _nonce_value = None + _acceptable_responses_value = None + _preferred_signature_algorithms_value = None + + def _set_extensions(self): + """ + Sets common named extensions to private attributes and creates a list + of critical extensions + """ + + self._critical_extensions = set() + + for extension in self['tbs_request']['request_extensions']: + name = extension['extn_id'].native + attribute_name = '_%s_value' % name + if hasattr(self, attribute_name): + setattr(self, attribute_name, extension['extn_value'].parsed) + if extension['critical'].native: + self._critical_extensions.add(name) + + self._processed_extensions = True + + @property + def critical_extensions(self): + """ + Returns a set of the names (or OID if not a known extension) of the + extensions marked as critical + + :return: + A set of unicode strings + """ + + if not self._processed_extensions: + self._set_extensions() + return self._critical_extensions + + @property + def nonce_value(self): + """ + This extension is used to prevent replay attacks by including a unique, + random value with each request/response pair + + :return: + None or an OctetString object + """ + + if self._processed_extensions is False: + self._set_extensions() + return self._nonce_value + + @property + def acceptable_responses_value(self): + """ + This extension is used to allow the client and server to communicate + with alternative response formats other than just basic_ocsp_response, + although no other formats are defined in the standard. + + :return: + None or an AcceptableResponses object + """ + + if self._processed_extensions is False: + self._set_extensions() + return self._acceptable_responses_value + + @property + def preferred_signature_algorithms_value(self): + """ + This extension is used by the client to define what signature algorithms + are preferred, including both the hash algorithm and the public key + algorithm, with a level of detail down to even the public key algorithm + parameters, such as curve name. + + :return: + None or a PreferredSignatureAlgorithms object + """ + + if self._processed_extensions is False: + self._set_extensions() + return self._preferred_signature_algorithms_value + + +class OCSPResponseStatus(Enumerated): + _map = { + 0: 'successful', + 1: 'malformed_request', + 2: 'internal_error', + 3: 'try_later', + 5: 'sign_required', + 6: 'unauthorized', + } + + +class ResponderId(Choice): + _alternatives = [ + ('by_name', Name, {'explicit': 1}), + ('by_key', OctetString, {'explicit': 2}), + ] + + +class RevokedInfo(Sequence): + _fields = [ + ('revocation_time', GeneralizedTime), + ('revocation_reason', CRLReason, {'explicit': 0, 'optional': True}), + ] + + +class CertStatus(Choice): + _alternatives = [ + ('good', Null, {'implicit': 0}), + ('revoked', RevokedInfo, {'implicit': 1}), + ('unknown', Null, {'implicit': 2}), + ] + + +class CrlId(Sequence): + _fields = [ + ('crl_url', IA5String, {'explicit': 0, 'optional': True}), + ('crl_num', Integer, {'explicit': 1, 'optional': True}), + ('crl_time', GeneralizedTime, {'explicit': 2, 'optional': True}), + ] + + +class SingleResponseExtensionId(ObjectIdentifier): + _map = { + '1.3.6.1.5.5.7.48.1.3': 'crl', + '1.3.6.1.5.5.7.48.1.6': 'archive_cutoff', + # These are CRLEntryExtension values from + # https://tools.ietf.org/html/rfc5280 + '2.5.29.21': 'crl_reason', + '2.5.29.24': 'invalidity_date', + '2.5.29.29': 'certificate_issuer', + # https://tools.ietf.org/html/rfc6962.html#page-13 + '1.3.6.1.4.1.11129.2.4.5': 'signed_certificate_timestamp_list', + } + + +class SingleResponseExtension(Sequence): + _fields = [ + ('extn_id', SingleResponseExtensionId), + ('critical', Boolean, {'default': False}), + ('extn_value', ParsableOctetString), + ] + + _oid_pair = ('extn_id', 'extn_value') + _oid_specs = { + 'crl': CrlId, + 'archive_cutoff': GeneralizedTime, + 'crl_reason': CRLReason, + 'invalidity_date': GeneralizedTime, + 'certificate_issuer': GeneralNames, + 'signed_certificate_timestamp_list': OctetString, + } + + +class SingleResponseExtensions(SequenceOf): + _child_spec = SingleResponseExtension + + +class SingleResponse(Sequence): + _fields = [ + ('cert_id', CertId), + ('cert_status', CertStatus), + ('this_update', GeneralizedTime), + ('next_update', GeneralizedTime, {'explicit': 0, 'optional': True}), + ('single_extensions', SingleResponseExtensions, {'explicit': 1, 'optional': True}), + ] + + _processed_extensions = False + _critical_extensions = None + _crl_value = None + _archive_cutoff_value = None + _crl_reason_value = None + _invalidity_date_value = None + _certificate_issuer_value = None + + def _set_extensions(self): + """ + Sets common named extensions to private attributes and creates a list + of critical extensions + """ + + self._critical_extensions = set() + + for extension in self['single_extensions']: + name = extension['extn_id'].native + attribute_name = '_%s_value' % name + if hasattr(self, attribute_name): + setattr(self, attribute_name, extension['extn_value'].parsed) + if extension['critical'].native: + self._critical_extensions.add(name) + + self._processed_extensions = True + + @property + def critical_extensions(self): + """ + Returns a set of the names (or OID if not a known extension) of the + extensions marked as critical + + :return: + A set of unicode strings + """ + + if not self._processed_extensions: + self._set_extensions() + return self._critical_extensions + + @property + def crl_value(self): + """ + This extension is used to locate the CRL that a certificate's revocation + is contained within. + + :return: + None or a CrlId object + """ + + if self._processed_extensions is False: + self._set_extensions() + return self._crl_value + + @property + def archive_cutoff_value(self): + """ + This extension is used to indicate the date at which an archived + (historical) certificate status entry will no longer be available. + + :return: + None or a GeneralizedTime object + """ + + if self._processed_extensions is False: + self._set_extensions() + return self._archive_cutoff_value + + @property + def crl_reason_value(self): + """ + This extension indicates the reason that a certificate was revoked. + + :return: + None or a CRLReason object + """ + + if self._processed_extensions is False: + self._set_extensions() + return self._crl_reason_value + + @property + def invalidity_date_value(self): + """ + This extension indicates the suspected date/time the private key was + compromised or the certificate became invalid. This would usually be + before the revocation date, which is when the CA processed the + revocation. + + :return: + None or a GeneralizedTime object + """ + + if self._processed_extensions is False: + self._set_extensions() + return self._invalidity_date_value + + @property + def certificate_issuer_value(self): + """ + This extension indicates the issuer of the certificate in question. + + :return: + None or an x509.GeneralNames object + """ + + if self._processed_extensions is False: + self._set_extensions() + return self._certificate_issuer_value + + +class Responses(SequenceOf): + _child_spec = SingleResponse + + +class ResponseDataExtensionId(ObjectIdentifier): + _map = { + '1.3.6.1.5.5.7.48.1.2': 'nonce', + '1.3.6.1.5.5.7.48.1.9': 'extended_revoke', + } + + +class ResponseDataExtension(Sequence): + _fields = [ + ('extn_id', ResponseDataExtensionId), + ('critical', Boolean, {'default': False}), + ('extn_value', ParsableOctetString), + ] + + _oid_pair = ('extn_id', 'extn_value') + _oid_specs = { + 'nonce': OctetString, + 'extended_revoke': Null, + } + + +class ResponseDataExtensions(SequenceOf): + _child_spec = ResponseDataExtension + + +class ResponseData(Sequence): + _fields = [ + ('version', Version, {'explicit': 0, 'default': 'v1'}), + ('responder_id', ResponderId), + ('produced_at', GeneralizedTime), + ('responses', Responses), + ('response_extensions', ResponseDataExtensions, {'explicit': 1, 'optional': True}), + ] + + +class BasicOCSPResponse(Sequence): + _fields = [ + ('tbs_response_data', ResponseData), + ('signature_algorithm', SignedDigestAlgorithm), + ('signature', OctetBitString), + ('certs', Certificates, {'explicit': 0, 'optional': True}), + ] + + +class ResponseBytes(Sequence): + _fields = [ + ('response_type', ResponseType), + ('response', ParsableOctetString), + ] + + _oid_pair = ('response_type', 'response') + _oid_specs = { + 'basic_ocsp_response': BasicOCSPResponse, + } + + +class OCSPResponse(Sequence): + _fields = [ + ('response_status', OCSPResponseStatus), + ('response_bytes', ResponseBytes, {'explicit': 0, 'optional': True}), + ] + + _processed_extensions = False + _critical_extensions = None + _nonce_value = None + _extended_revoke_value = None + + def _set_extensions(self): + """ + Sets common named extensions to private attributes and creates a list + of critical extensions + """ + + self._critical_extensions = set() + + for extension in self['response_bytes']['response'].parsed['tbs_response_data']['response_extensions']: + name = extension['extn_id'].native + attribute_name = '_%s_value' % name + if hasattr(self, attribute_name): + setattr(self, attribute_name, extension['extn_value'].parsed) + if extension['critical'].native: + self._critical_extensions.add(name) + + self._processed_extensions = True + + @property + def critical_extensions(self): + """ + Returns a set of the names (or OID if not a known extension) of the + extensions marked as critical + + :return: + A set of unicode strings + """ + + if not self._processed_extensions: + self._set_extensions() + return self._critical_extensions + + @property + def nonce_value(self): + """ + This extension is used to prevent replay attacks on the request/response + exchange + + :return: + None or an OctetString object + """ + + if self._processed_extensions is False: + self._set_extensions() + return self._nonce_value + + @property + def extended_revoke_value(self): + """ + This extension is used to signal that the responder will return a + "revoked" status for non-issued certificates. + + :return: + None or a Null object (if present) + """ + + if self._processed_extensions is False: + self._set_extensions() + return self._extended_revoke_value + + @property + def basic_ocsp_response(self): + """ + A shortcut into the BasicOCSPResponse sequence + + :return: + None or an asn1crypto.ocsp.BasicOCSPResponse object + """ + + return self['response_bytes']['response'].parsed + + @property + def response_data(self): + """ + A shortcut into the parsed, ResponseData sequence + + :return: + None or an asn1crypto.ocsp.ResponseData object + """ + + return self['response_bytes']['response'].parsed['tbs_response_data'] diff --git a/venv/lib/python2.7/site-packages/asn1crypto/parser.py b/venv/lib/python2.7/site-packages/asn1crypto/parser.py new file mode 100644 index 0000000..07f53ab --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/parser.py @@ -0,0 +1,289 @@ +# coding: utf-8 + +""" +Functions for parsing and dumping using the ASN.1 DER encoding. Exports the +following items: + + - emit() + - parse() + - peek() + +Other type classes are defined that help compose the types listed above. +""" + +from __future__ import unicode_literals, division, absolute_import, print_function + +import sys + +from ._types import byte_cls, chr_cls, type_name +from .util import int_from_bytes, int_to_bytes + +_PY2 = sys.version_info <= (3,) +_INSUFFICIENT_DATA_MESSAGE = 'Insufficient data - %s bytes requested but only %s available' + + +def emit(class_, method, tag, contents): + """ + Constructs a byte string of an ASN.1 DER-encoded value + + This is typically not useful. Instead, use one of the standard classes from + asn1crypto.core, or construct a new class with specific fields, and call the + .dump() method. + + :param class_: + An integer ASN.1 class value: 0 (universal), 1 (application), + 2 (context), 3 (private) + + :param method: + An integer ASN.1 method value: 0 (primitive), 1 (constructed) + + :param tag: + An integer ASN.1 tag value + + :param contents: + A byte string of the encoded byte contents + + :return: + A byte string of the ASN.1 DER value (header and contents) + """ + + if not isinstance(class_, int): + raise TypeError('class_ must be an integer, not %s' % type_name(class_)) + + if class_ < 0 or class_ > 3: + raise ValueError('class_ must be one of 0, 1, 2 or 3, not %s' % class_) + + if not isinstance(method, int): + raise TypeError('method must be an integer, not %s' % type_name(method)) + + if method < 0 or method > 1: + raise ValueError('method must be 0 or 1, not %s' % method) + + if not isinstance(tag, int): + raise TypeError('tag must be an integer, not %s' % type_name(tag)) + + if tag < 0: + raise ValueError('tag must be greater than zero, not %s' % tag) + + if not isinstance(contents, byte_cls): + raise TypeError('contents must be a byte string, not %s' % type_name(contents)) + + return _dump_header(class_, method, tag, contents) + contents + + +def parse(contents, strict=False): + """ + Parses a byte string of ASN.1 BER/DER-encoded data. + + This is typically not useful. Instead, use one of the standard classes from + asn1crypto.core, or construct a new class with specific fields, and call the + .load() class method. + + :param contents: + A byte string of BER/DER-encoded data + + :param strict: + A boolean indicating if trailing data should be forbidden - if so, a + ValueError will be raised when trailing data exists + + :raises: + ValueError - when the contents do not contain an ASN.1 header or are truncated in some way + TypeError - when contents is not a byte string + + :return: + A 6-element tuple: + - 0: integer class (0 to 3) + - 1: integer method + - 2: integer tag + - 3: byte string header + - 4: byte string content + - 5: byte string trailer + """ + + if not isinstance(contents, byte_cls): + raise TypeError('contents must be a byte string, not %s' % type_name(contents)) + + contents_len = len(contents) + info, consumed = _parse(contents, contents_len) + if strict and consumed != contents_len: + raise ValueError('Extra data - %d bytes of trailing data were provided' % (contents_len - consumed)) + return info + + +def peek(contents): + """ + Parses a byte string of ASN.1 BER/DER-encoded data to find the length + + This is typically used to look into an encoded value to see how long the + next chunk of ASN.1-encoded data is. Primarily it is useful when a + value is a concatenation of multiple values. + + :param contents: + A byte string of BER/DER-encoded data + + :raises: + ValueError - when the contents do not contain an ASN.1 header or are truncated in some way + TypeError - when contents is not a byte string + + :return: + An integer with the number of bytes occupied by the ASN.1 value + """ + + if not isinstance(contents, byte_cls): + raise TypeError('contents must be a byte string, not %s' % type_name(contents)) + + info, consumed = _parse(contents, len(contents)) + return consumed + + +def _parse(encoded_data, data_len, pointer=0, lengths_only=False): + """ + Parses a byte string into component parts + + :param encoded_data: + A byte string that contains BER-encoded data + + :param data_len: + The integer length of the encoded data + + :param pointer: + The index in the byte string to parse from + + :param lengths_only: + A boolean to cause the call to return a 2-element tuple of the integer + number of bytes in the header and the integer number of bytes in the + contents. Internal use only. + + :return: + A 2-element tuple: + - 0: A tuple of (class_, method, tag, header, content, trailer) + - 1: An integer indicating how many bytes were consumed + """ + + if data_len < pointer + 2: + raise ValueError(_INSUFFICIENT_DATA_MESSAGE % (2, data_len - pointer)) + + start = pointer + first_octet = ord(encoded_data[pointer]) if _PY2 else encoded_data[pointer] + pointer += 1 + + tag = first_octet & 31 + # Base 128 length using 8th bit as continuation indicator + if tag == 31: + tag = 0 + while True: + num = ord(encoded_data[pointer]) if _PY2 else encoded_data[pointer] + pointer += 1 + tag *= 128 + tag += num & 127 + if num >> 7 == 0: + break + + length_octet = ord(encoded_data[pointer]) if _PY2 else encoded_data[pointer] + pointer += 1 + + if length_octet >> 7 == 0: + if lengths_only: + return (pointer, pointer + (length_octet & 127)) + contents_end = pointer + (length_octet & 127) + + else: + length_octets = length_octet & 127 + if length_octets: + pointer += length_octets + contents_end = pointer + int_from_bytes(encoded_data[pointer - length_octets:pointer], signed=False) + if lengths_only: + return (pointer, contents_end) + + else: + # To properly parse indefinite length values, we need to scan forward + # parsing headers until we find a value with a length of zero. If we + # just scanned looking for \x00\x00, nested indefinite length values + # would not work. + contents_end = pointer + # Unfortunately we need to understand the contents of the data to + # properly scan forward, which bleeds some representation info into + # the parser. This condition handles the unused bits byte in + # constructed bit strings. + if tag == 3: + contents_end += 1 + while contents_end < data_len: + sub_header_end, contents_end = _parse(encoded_data, data_len, contents_end, lengths_only=True) + if contents_end == sub_header_end and encoded_data[contents_end - 2:contents_end] == b'\x00\x00': + break + if lengths_only: + return (pointer, contents_end) + if contents_end > data_len: + raise ValueError(_INSUFFICIENT_DATA_MESSAGE % (contents_end, data_len)) + return ( + ( + first_octet >> 6, + (first_octet >> 5) & 1, + tag, + encoded_data[start:pointer], + encoded_data[pointer:contents_end - 2], + b'\x00\x00' + ), + contents_end + ) + + if contents_end > data_len: + raise ValueError(_INSUFFICIENT_DATA_MESSAGE % (contents_end, data_len)) + return ( + ( + first_octet >> 6, + (first_octet >> 5) & 1, + tag, + encoded_data[start:pointer], + encoded_data[pointer:contents_end], + b'' + ), + contents_end + ) + + +def _dump_header(class_, method, tag, contents): + """ + Constructs the header bytes for an ASN.1 object + + :param class_: + An integer ASN.1 class value: 0 (universal), 1 (application), + 2 (context), 3 (private) + + :param method: + An integer ASN.1 method value: 0 (primitive), 1 (constructed) + + :param tag: + An integer ASN.1 tag value + + :param contents: + A byte string of the encoded byte contents + + :return: + A byte string of the ASN.1 DER header + """ + + header = b'' + + id_num = 0 + id_num |= class_ << 6 + id_num |= method << 5 + + if tag >= 31: + header += chr_cls(id_num | 31) + while tag > 0: + continuation_bit = 0x80 if tag > 0x7F else 0 + header += chr_cls(continuation_bit | (tag & 0x7F)) + tag = tag >> 7 + else: + header += chr_cls(id_num | tag) + + length = len(contents) + if length <= 127: + header += chr_cls(length) + else: + length_bytes = int_to_bytes(length) + header += chr_cls(0x80 | len(length_bytes)) + header += length_bytes + + return header diff --git a/venv/lib/python2.7/site-packages/asn1crypto/pdf.py b/venv/lib/python2.7/site-packages/asn1crypto/pdf.py new file mode 100644 index 0000000..b72c886 --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/pdf.py @@ -0,0 +1,84 @@ +# coding: utf-8 + +""" +ASN.1 type classes for PDF signature structures. Adds extra oid mapping and +value parsing to asn1crypto.x509.Extension() and asn1crypto.xms.CMSAttribute(). +""" + +from __future__ import unicode_literals, division, absolute_import, print_function + +from .cms import CMSAttributeType, CMSAttribute +from .core import ( + Boolean, + Integer, + Null, + ObjectIdentifier, + OctetString, + Sequence, + SequenceOf, + SetOf, +) +from .crl import CertificateList +from .ocsp import OCSPResponse +from .x509 import ( + Extension, + ExtensionId, + GeneralName, + KeyPurposeId, +) + + +class AdobeArchiveRevInfo(Sequence): + _fields = [ + ('version', Integer) + ] + + +class AdobeTimestamp(Sequence): + _fields = [ + ('version', Integer), + ('location', GeneralName), + ('requires_auth', Boolean, {'optional': True, 'default': False}), + ] + + +class OtherRevInfo(Sequence): + _fields = [ + ('type', ObjectIdentifier), + ('value', OctetString), + ] + + +class SequenceOfCertificateList(SequenceOf): + _child_spec = CertificateList + + +class SequenceOfOCSPResponse(SequenceOf): + _child_spec = OCSPResponse + + +class SequenceOfOtherRevInfo(SequenceOf): + _child_spec = OtherRevInfo + + +class RevocationInfoArchival(Sequence): + _fields = [ + ('crl', SequenceOfCertificateList, {'explicit': 0, 'optional': True}), + ('ocsp', SequenceOfOCSPResponse, {'explicit': 1, 'optional': True}), + ('other_rev_info', SequenceOfOtherRevInfo, {'explicit': 2, 'optional': True}), + ] + + +class SetOfRevocationInfoArchival(SetOf): + _child_spec = RevocationInfoArchival + + +ExtensionId._map['1.2.840.113583.1.1.9.2'] = 'adobe_archive_rev_info' +ExtensionId._map['1.2.840.113583.1.1.9.1'] = 'adobe_timestamp' +ExtensionId._map['1.2.840.113583.1.1.10'] = 'adobe_ppklite_credential' +Extension._oid_specs['adobe_archive_rev_info'] = AdobeArchiveRevInfo +Extension._oid_specs['adobe_timestamp'] = AdobeTimestamp +Extension._oid_specs['adobe_ppklite_credential'] = Null +KeyPurposeId._map['1.2.840.113583.1.1.5'] = 'pdf_signing' +CMSAttributeType._map['1.2.840.113583.1.1.8'] = 'adobe_revocation_info_archival' +CMSAttribute._oid_specs['adobe_revocation_info_archival'] = SetOfRevocationInfoArchival diff --git a/venv/lib/python2.7/site-packages/asn1crypto/pem.py b/venv/lib/python2.7/site-packages/asn1crypto/pem.py new file mode 100644 index 0000000..511ea4b --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/pem.py @@ -0,0 +1,222 @@ +# coding: utf-8 + +""" +Encoding DER to PEM and decoding PEM to DER. Exports the following items: + + - armor() + - detect() + - unarmor() + +""" + +from __future__ import unicode_literals, division, absolute_import, print_function + +import base64 +import re +import sys + +from ._errors import unwrap +from ._types import type_name as _type_name, str_cls, byte_cls + +if sys.version_info < (3,): + from cStringIO import StringIO as BytesIO +else: + from io import BytesIO + + +def detect(byte_string): + """ + Detect if a byte string seems to contain a PEM-encoded block + + :param byte_string: + A byte string to look through + + :return: + A boolean, indicating if a PEM-encoded block is contained in the byte + string + """ + + if not isinstance(byte_string, byte_cls): + raise TypeError(unwrap( + ''' + byte_string must be a byte string, not %s + ''', + _type_name(byte_string) + )) + + return byte_string.find(b'-----BEGIN') != -1 or byte_string.find(b'---- BEGIN') != -1 + + +def armor(type_name, der_bytes, headers=None): + """ + Armors a DER-encoded byte string in PEM + + :param type_name: + A unicode string that will be capitalized and placed in the header + and footer of the block. E.g. "CERTIFICATE", "PRIVATE KEY", etc. This + will appear as "-----BEGIN CERTIFICATE-----" and + "-----END CERTIFICATE-----". + + :param der_bytes: + A byte string to be armored + + :param headers: + An OrderedDict of the header lines to write after the BEGIN line + + :return: + A byte string of the PEM block + """ + + if not isinstance(der_bytes, byte_cls): + raise TypeError(unwrap( + ''' + der_bytes must be a byte string, not %s + ''' % _type_name(der_bytes) + )) + + if not isinstance(type_name, str_cls): + raise TypeError(unwrap( + ''' + type_name must be a unicode string, not %s + ''', + _type_name(type_name) + )) + + type_name = type_name.upper().encode('ascii') + + output = BytesIO() + output.write(b'-----BEGIN ') + output.write(type_name) + output.write(b'-----\n') + if headers: + for key in headers: + output.write(key.encode('ascii')) + output.write(b': ') + output.write(headers[key].encode('ascii')) + output.write(b'\n') + output.write(b'\n') + b64_bytes = base64.b64encode(der_bytes) + b64_len = len(b64_bytes) + i = 0 + while i < b64_len: + output.write(b64_bytes[i:i + 64]) + output.write(b'\n') + i += 64 + output.write(b'-----END ') + output.write(type_name) + output.write(b'-----\n') + + return output.getvalue() + + +def _unarmor(pem_bytes): + """ + Convert a PEM-encoded byte string into one or more DER-encoded byte strings + + :param pem_bytes: + A byte string of the PEM-encoded data + + :raises: + ValueError - when the pem_bytes do not appear to be PEM-encoded bytes + + :return: + A generator of 3-element tuples in the format: (object_type, headers, + der_bytes). The object_type is a unicode string of what is between + "-----BEGIN " and "-----". Examples include: "CERTIFICATE", + "PUBLIC KEY", "PRIVATE KEY". The headers is a dict containing any lines + in the form "Name: Value" that are right after the begin line. + """ + + if not isinstance(pem_bytes, byte_cls): + raise TypeError(unwrap( + ''' + pem_bytes must be a byte string, not %s + ''', + _type_name(pem_bytes) + )) + + # Valid states include: "trash", "headers", "body" + state = 'trash' + headers = {} + base64_data = b'' + object_type = None + + found_start = False + found_end = False + + for line in pem_bytes.splitlines(False): + if line == b'': + continue + + if state == "trash": + # Look for a starting line since some CA cert bundle show the cert + # into in a parsed format above each PEM block + type_name_match = re.match(b'^(?:---- |-----)BEGIN ([A-Z0-9 ]+)(?: ----|-----)', line) + if not type_name_match: + continue + object_type = type_name_match.group(1).decode('ascii') + + found_start = True + state = 'headers' + continue + + if state == 'headers': + if line.find(b':') == -1: + state = 'body' + else: + decoded_line = line.decode('ascii') + name, value = decoded_line.split(':', 1) + headers[name] = value.strip() + continue + + if state == 'body': + if line[0:5] in (b'-----', b'---- '): + der_bytes = base64.b64decode(base64_data) + + yield (object_type, headers, der_bytes) + + state = 'trash' + headers = {} + base64_data = b'' + object_type = None + found_end = True + continue + + base64_data += line + + if not found_start or not found_end: + raise ValueError(unwrap( + ''' + pem_bytes does not appear to contain PEM-encoded data - no + BEGIN/END combination found + ''' + )) + + +def unarmor(pem_bytes, multiple=False): + """ + Convert a PEM-encoded byte string into a DER-encoded byte string + + :param pem_bytes: + A byte string of the PEM-encoded data + + :param multiple: + If True, function will return a generator + + :raises: + ValueError - when the pem_bytes do not appear to be PEM-encoded bytes + + :return: + A 3-element tuple (object_name, headers, der_bytes). The object_name is + a unicode string of what is between "-----BEGIN " and "-----". Examples + include: "CERTIFICATE", "PUBLIC KEY", "PRIVATE KEY". The headers is a + dict containing any lines in the form "Name: Value" that are right + after the begin line. + """ + + generator = _unarmor(pem_bytes) + + if not multiple: + return next(generator) + + return generator diff --git a/venv/lib/python2.7/site-packages/asn1crypto/pkcs12.py b/venv/lib/python2.7/site-packages/asn1crypto/pkcs12.py new file mode 100644 index 0000000..7ebcefe --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/pkcs12.py @@ -0,0 +1,193 @@ +# coding: utf-8 + +""" +ASN.1 type classes for PKCS#12 files. Exports the following items: + + - CertBag() + - CrlBag() + - Pfx() + - SafeBag() + - SecretBag() + +Other type classes are defined that help compose the types listed above. +""" + +from __future__ import unicode_literals, division, absolute_import, print_function + +from .algos import DigestInfo +from .cms import ContentInfo, SignedData +from .core import ( + Any, + BMPString, + Integer, + ObjectIdentifier, + OctetString, + ParsableOctetString, + Sequence, + SequenceOf, + SetOf, +) +from .keys import PrivateKeyInfo, EncryptedPrivateKeyInfo +from .x509 import Certificate, KeyPurposeId + + +# The structures in this file are taken from https://tools.ietf.org/html/rfc7292 + +class MacData(Sequence): + _fields = [ + ('mac', DigestInfo), + ('mac_salt', OctetString), + ('iterations', Integer, {'default': 1}), + ] + + +class Version(Integer): + _map = { + 3: 'v3' + } + + +class AttributeType(ObjectIdentifier): + _map = { + # https://tools.ietf.org/html/rfc2985#page-18 + '1.2.840.113549.1.9.20': 'friendly_name', + '1.2.840.113549.1.9.21': 'local_key_id', + # https://support.microsoft.com/en-us/kb/287547 + '1.3.6.1.4.1.311.17.1': 'microsoft_local_machine_keyset', + # https://github.com/frohoff/jdk8u-dev-jdk/blob/master/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java + # this is a set of OIDs, representing key usage, the usual value is a SET of one element OID 2.5.29.37.0 + '2.16.840.1.113894.746875.1.1': 'trusted_key_usage', + } + + +class SetOfAny(SetOf): + _child_spec = Any + + +class SetOfBMPString(SetOf): + _child_spec = BMPString + + +class SetOfOctetString(SetOf): + _child_spec = OctetString + + +class SetOfKeyPurposeId(SetOf): + _child_spec = KeyPurposeId + + +class Attribute(Sequence): + _fields = [ + ('type', AttributeType), + ('values', None), + ] + + _oid_specs = { + 'friendly_name': SetOfBMPString, + 'local_key_id': SetOfOctetString, + 'microsoft_csp_name': SetOfBMPString, + 'trusted_key_usage': SetOfKeyPurposeId, + } + + def _values_spec(self): + return self._oid_specs.get(self['type'].native, SetOfAny) + + _spec_callbacks = { + 'values': _values_spec + } + + +class Attributes(SetOf): + _child_spec = Attribute + + +class Pfx(Sequence): + _fields = [ + ('version', Version), + ('auth_safe', ContentInfo), + ('mac_data', MacData, {'optional': True}) + ] + + _authenticated_safe = None + + @property + def authenticated_safe(self): + if self._authenticated_safe is None: + content = self['auth_safe']['content'] + if isinstance(content, SignedData): + content = content['content_info']['content'] + self._authenticated_safe = AuthenticatedSafe.load(content.native) + return self._authenticated_safe + + +class AuthenticatedSafe(SequenceOf): + _child_spec = ContentInfo + + +class BagId(ObjectIdentifier): + _map = { + '1.2.840.113549.1.12.10.1.1': 'key_bag', + '1.2.840.113549.1.12.10.1.2': 'pkcs8_shrouded_key_bag', + '1.2.840.113549.1.12.10.1.3': 'cert_bag', + '1.2.840.113549.1.12.10.1.4': 'crl_bag', + '1.2.840.113549.1.12.10.1.5': 'secret_bag', + '1.2.840.113549.1.12.10.1.6': 'safe_contents', + } + + +class CertId(ObjectIdentifier): + _map = { + '1.2.840.113549.1.9.22.1': 'x509', + '1.2.840.113549.1.9.22.2': 'sdsi', + } + + +class CertBag(Sequence): + _fields = [ + ('cert_id', CertId), + ('cert_value', ParsableOctetString, {'explicit': 0}), + ] + + _oid_pair = ('cert_id', 'cert_value') + _oid_specs = { + 'x509': Certificate, + } + + +class CrlBag(Sequence): + _fields = [ + ('crl_id', ObjectIdentifier), + ('crl_value', OctetString, {'explicit': 0}), + ] + + +class SecretBag(Sequence): + _fields = [ + ('secret_type_id', ObjectIdentifier), + ('secret_value', OctetString, {'explicit': 0}), + ] + + +class SafeContents(SequenceOf): + pass + + +class SafeBag(Sequence): + _fields = [ + ('bag_id', BagId), + ('bag_value', Any, {'explicit': 0}), + ('bag_attributes', Attributes, {'optional': True}), + ] + + _oid_pair = ('bag_id', 'bag_value') + _oid_specs = { + 'key_bag': PrivateKeyInfo, + 'pkcs8_shrouded_key_bag': EncryptedPrivateKeyInfo, + 'cert_bag': CertBag, + 'crl_bag': CrlBag, + 'secret_bag': SecretBag, + 'safe_contents': SafeContents + } + + +SafeContents._child_spec = SafeBag diff --git a/venv/lib/python2.7/site-packages/asn1crypto/tsp.py b/venv/lib/python2.7/site-packages/asn1crypto/tsp.py new file mode 100644 index 0000000..bd40810 --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/tsp.py @@ -0,0 +1,310 @@ +# coding: utf-8 + +""" +ASN.1 type classes for the time stamp protocol (TSP). Exports the following +items: + + - TimeStampReq() + - TimeStampResp() + +Also adds TimeStampedData() support to asn1crypto.cms.ContentInfo(), +TimeStampedData() and TSTInfo() support to +asn1crypto.cms.EncapsulatedContentInfo() and some oids and value parsers to +asn1crypto.cms.CMSAttribute(). + +Other type classes are defined that help compose the types listed above. +""" + +from __future__ import unicode_literals, division, absolute_import, print_function + +from .algos import DigestAlgorithm +from .cms import ( + CMSAttribute, + CMSAttributeType, + ContentInfo, + ContentType, + EncapsulatedContentInfo, +) +from .core import ( + Any, + BitString, + Boolean, + Choice, + GeneralizedTime, + IA5String, + Integer, + ObjectIdentifier, + OctetString, + Sequence, + SequenceOf, + SetOf, + UTF8String, +) +from .crl import CertificateList +from .x509 import ( + Attributes, + CertificatePolicies, + GeneralName, + GeneralNames, +) + + +# The structures in this file are based on https://tools.ietf.org/html/rfc3161, +# https://tools.ietf.org/html/rfc4998, https://tools.ietf.org/html/rfc5544, +# https://tools.ietf.org/html/rfc5035, https://tools.ietf.org/html/rfc2634 + +class Version(Integer): + _map = { + 0: 'v0', + 1: 'v1', + 2: 'v2', + 3: 'v3', + 4: 'v4', + 5: 'v5', + } + + +class MessageImprint(Sequence): + _fields = [ + ('hash_algorithm', DigestAlgorithm), + ('hashed_message', OctetString), + ] + + +class Accuracy(Sequence): + _fields = [ + ('seconds', Integer, {'optional': True}), + ('millis', Integer, {'implicit': 0, 'optional': True}), + ('micros', Integer, {'implicit': 1, 'optional': True}), + ] + + +class Extension(Sequence): + _fields = [ + ('extn_id', ObjectIdentifier), + ('critical', Boolean, {'default': False}), + ('extn_value', OctetString), + ] + + +class Extensions(SequenceOf): + _child_spec = Extension + + +class TSTInfo(Sequence): + _fields = [ + ('version', Version), + ('policy', ObjectIdentifier), + ('message_imprint', MessageImprint), + ('serial_number', Integer), + ('gen_time', GeneralizedTime), + ('accuracy', Accuracy, {'optional': True}), + ('ordering', Boolean, {'default': False}), + ('nonce', Integer, {'optional': True}), + ('tsa', GeneralName, {'explicit': 0, 'optional': True}), + ('extensions', Extensions, {'implicit': 1, 'optional': True}), + ] + + +class TimeStampReq(Sequence): + _fields = [ + ('version', Version), + ('message_imprint', MessageImprint), + ('req_policy', ObjectIdentifier, {'optional': True}), + ('nonce', Integer, {'optional': True}), + ('cert_req', Boolean, {'default': False}), + ('extensions', Extensions, {'implicit': 0, 'optional': True}), + ] + + +class PKIStatus(Integer): + _map = { + 0: 'granted', + 1: 'granted_with_mods', + 2: 'rejection', + 3: 'waiting', + 4: 'revocation_warning', + 5: 'revocation_notification', + } + + +class PKIFreeText(SequenceOf): + _child_spec = UTF8String + + +class PKIFailureInfo(BitString): + _map = { + 0: 'bad_alg', + 2: 'bad_request', + 5: 'bad_data_format', + 14: 'time_not_available', + 15: 'unaccepted_policy', + 16: 'unaccepted_extensions', + 17: 'add_info_not_available', + 25: 'system_failure', + } + + +class PKIStatusInfo(Sequence): + _fields = [ + ('status', PKIStatus), + ('status_string', PKIFreeText, {'optional': True}), + ('fail_info', PKIFailureInfo, {'optional': True}), + ] + + +class TimeStampResp(Sequence): + _fields = [ + ('status', PKIStatusInfo), + ('time_stamp_token', ContentInfo), + ] + + +class MetaData(Sequence): + _fields = [ + ('hash_protected', Boolean), + ('file_name', UTF8String, {'optional': True}), + ('media_type', IA5String, {'optional': True}), + ('other_meta_data', Attributes, {'optional': True}), + ] + + +class TimeStampAndCRL(SequenceOf): + _fields = [ + ('time_stamp', EncapsulatedContentInfo), + ('crl', CertificateList, {'optional': True}), + ] + + +class TimeStampTokenEvidence(SequenceOf): + _child_spec = TimeStampAndCRL + + +class DigestAlgorithms(SequenceOf): + _child_spec = DigestAlgorithm + + +class EncryptionInfo(Sequence): + _fields = [ + ('encryption_info_type', ObjectIdentifier), + ('encryption_info_value', Any), + ] + + +class PartialHashtree(SequenceOf): + _child_spec = OctetString + + +class PartialHashtrees(SequenceOf): + _child_spec = PartialHashtree + + +class ArchiveTimeStamp(Sequence): + _fields = [ + ('digest_algorithm', DigestAlgorithm, {'implicit': 0, 'optional': True}), + ('attributes', Attributes, {'implicit': 1, 'optional': True}), + ('reduced_hashtree', PartialHashtrees, {'implicit': 2, 'optional': True}), + ('time_stamp', ContentInfo), + ] + + +class ArchiveTimeStampSequence(SequenceOf): + _child_spec = ArchiveTimeStamp + + +class EvidenceRecord(Sequence): + _fields = [ + ('version', Version), + ('digest_algorithms', DigestAlgorithms), + ('crypto_infos', Attributes, {'implicit': 0, 'optional': True}), + ('encryption_info', EncryptionInfo, {'implicit': 1, 'optional': True}), + ('archive_time_stamp_sequence', ArchiveTimeStampSequence), + ] + + +class OtherEvidence(Sequence): + _fields = [ + ('oe_type', ObjectIdentifier), + ('oe_value', Any), + ] + + +class Evidence(Choice): + _alternatives = [ + ('tst_evidence', TimeStampTokenEvidence, {'implicit': 0}), + ('ers_evidence', EvidenceRecord, {'implicit': 1}), + ('other_evidence', OtherEvidence, {'implicit': 2}), + ] + + +class TimeStampedData(Sequence): + _fields = [ + ('version', Version), + ('data_uri', IA5String, {'optional': True}), + ('meta_data', MetaData, {'optional': True}), + ('content', OctetString, {'optional': True}), + ('temporal_evidence', Evidence), + ] + + +class IssuerSerial(Sequence): + _fields = [ + ('issuer', GeneralNames), + ('serial_number', Integer), + ] + + +class ESSCertID(Sequence): + _fields = [ + ('cert_hash', OctetString), + ('issuer_serial', IssuerSerial, {'optional': True}), + ] + + +class ESSCertIDs(SequenceOf): + _child_spec = ESSCertID + + +class SigningCertificate(Sequence): + _fields = [ + ('certs', ESSCertIDs), + ('policies', CertificatePolicies, {'optional': True}), + ] + + +class SetOfSigningCertificates(SetOf): + _child_spec = SigningCertificate + + +class ESSCertIDv2(Sequence): + _fields = [ + ('hash_algorithm', DigestAlgorithm, {'default': {'algorithm': 'sha256'}}), + ('cert_hash', OctetString), + ('issuer_serial', IssuerSerial, {'optional': True}), + ] + + +class ESSCertIDv2s(SequenceOf): + _child_spec = ESSCertIDv2 + + +class SigningCertificateV2(Sequence): + _fields = [ + ('certs', ESSCertIDv2s), + ('policies', CertificatePolicies, {'optional': True}), + ] + + +class SetOfSigningCertificatesV2(SetOf): + _child_spec = SigningCertificateV2 + + +EncapsulatedContentInfo._oid_specs['tst_info'] = TSTInfo +EncapsulatedContentInfo._oid_specs['timestamped_data'] = TimeStampedData +ContentInfo._oid_specs['timestamped_data'] = TimeStampedData +ContentType._map['1.2.840.113549.1.9.16.1.4'] = 'tst_info' +ContentType._map['1.2.840.113549.1.9.16.1.31'] = 'timestamped_data' +CMSAttributeType._map['1.2.840.113549.1.9.16.2.12'] = 'signing_certificate' +CMSAttribute._oid_specs['signing_certificate'] = SetOfSigningCertificates +CMSAttributeType._map['1.2.840.113549.1.9.16.2.47'] = 'signing_certificate_v2' +CMSAttribute._oid_specs['signing_certificate_v2'] = SetOfSigningCertificatesV2 diff --git a/venv/lib/python2.7/site-packages/asn1crypto/util.py b/venv/lib/python2.7/site-packages/asn1crypto/util.py new file mode 100644 index 0000000..2e55ef8 --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/util.py @@ -0,0 +1,712 @@ +# coding: utf-8 + +""" +Miscellaneous data helpers, including functions for converting integers to and +from bytes and UTC timezone. Exports the following items: + + - OrderedDict() + - int_from_bytes() + - int_to_bytes() + - timezone.utc + - inet_ntop() + - inet_pton() + - uri_to_iri() + - iri_to_uri() +""" + +from __future__ import unicode_literals, division, absolute_import, print_function + +import math +import sys +from datetime import datetime, date, time + +from ._errors import unwrap +from ._iri import iri_to_uri, uri_to_iri # noqa +from ._ordereddict import OrderedDict # noqa +from ._types import type_name + +if sys.platform == 'win32': + from ._inet import inet_ntop, inet_pton +else: + from socket import inet_ntop, inet_pton # noqa + + +# Python 2 +if sys.version_info <= (3,): + + from datetime import timedelta, tzinfo + + py2 = True + + def int_to_bytes(value, signed=False, width=None): + """ + Converts an integer to a byte string + + :param value: + The integer to convert + + :param signed: + If the byte string should be encoded using two's complement + + :param width: + None == auto, otherwise an integer of the byte width for the return + value + + :return: + A byte string + """ + + # Handle negatives in two's complement + is_neg = False + if signed and value < 0: + is_neg = True + bits = int(math.ceil(len('%x' % abs(value)) / 2.0) * 8) + value = (value + (1 << bits)) % (1 << bits) + + hex_str = '%x' % value + if len(hex_str) & 1: + hex_str = '0' + hex_str + + output = hex_str.decode('hex') + + if signed and not is_neg and ord(output[0:1]) & 0x80: + output = b'\x00' + output + + if width is not None: + if is_neg: + pad_char = b'\xFF' + else: + pad_char = b'\x00' + output = (pad_char * (width - len(output))) + output + elif is_neg and ord(output[0:1]) & 0x80 == 0: + output = b'\xFF' + output + + return output + + def int_from_bytes(value, signed=False): + """ + Converts a byte string to an integer + + :param value: + The byte string to convert + + :param signed: + If the byte string should be interpreted using two's complement + + :return: + An integer + """ + + if value == b'': + return 0 + + num = long(value.encode("hex"), 16) # noqa + + if not signed: + return num + + # Check for sign bit and handle two's complement + if ord(value[0:1]) & 0x80: + bit_len = len(value) * 8 + return num - (1 << bit_len) + + return num + + class utc(tzinfo): # noqa + + def tzname(self, _): + return b'UTC+00:00' + + def utcoffset(self, _): + return timedelta(0) + + def dst(self, _): + return timedelta(0) + + class timezone(): # noqa + + utc = utc() + + +# Python 3 +else: + + from datetime import timezone # noqa + + py2 = False + + def int_to_bytes(value, signed=False, width=None): + """ + Converts an integer to a byte string + + :param value: + The integer to convert + + :param signed: + If the byte string should be encoded using two's complement + + :param width: + None == auto, otherwise an integer of the byte width for the return + value + + :return: + A byte string + """ + + if width is None: + if signed: + if value < 0: + bits_required = abs(value + 1).bit_length() + else: + bits_required = value.bit_length() + if bits_required % 8 == 0: + bits_required += 1 + else: + bits_required = value.bit_length() + width = math.ceil(bits_required / 8) or 1 + return value.to_bytes(width, byteorder='big', signed=signed) + + def int_from_bytes(value, signed=False): + """ + Converts a byte string to an integer + + :param value: + The byte string to convert + + :param signed: + If the byte string should be interpreted using two's complement + + :return: + An integer + """ + + return int.from_bytes(value, 'big', signed=signed) + + +_DAYS_PER_MONTH_YEAR_0 = { + 1: 31, + 2: 29, # Year 0 was a leap year + 3: 31, + 4: 30, + 5: 31, + 6: 30, + 7: 31, + 8: 31, + 9: 30, + 10: 31, + 11: 30, + 12: 31 +} + + +class extended_date(object): + """ + A datetime.date-like object that can represent the year 0. This is just + to handle 0000-01-01 found in some certificates. + """ + + year = None + month = None + day = None + + def __init__(self, year, month, day): + """ + :param year: + The integer 0 + + :param month: + An integer from 1 to 12 + + :param day: + An integer from 1 to 31 + """ + + if year != 0: + raise ValueError('year must be 0') + + if month < 1 or month > 12: + raise ValueError('month is out of range') + + if day < 0 or day > _DAYS_PER_MONTH_YEAR_0[month]: + raise ValueError('day is out of range') + + self.year = year + self.month = month + self.day = day + + def _format(self, format): + """ + Performs strftime(), always returning a unicode string + + :param format: + A strftime() format string + + :return: + A unicode string of the formatted date + """ + + format = format.replace('%Y', '0000') + # Year 0 is 1BC and a leap year. Leap years repeat themselves + # every 28 years. Because of adjustments and the proleptic gregorian + # calendar, the simplest way to format is to substitute year 2000. + temp = date(2000, self.month, self.day) + if '%c' in format: + c_out = temp.strftime('%c') + # Handle full years + c_out = c_out.replace('2000', '0000') + c_out = c_out.replace('%', '%%') + format = format.replace('%c', c_out) + if '%x' in format: + x_out = temp.strftime('%x') + # Handle formats such as 08/16/2000 or 16.08.2000 + x_out = x_out.replace('2000', '0000') + x_out = x_out.replace('%', '%%') + format = format.replace('%x', x_out) + return temp.strftime(format) + + def isoformat(self): + """ + Formats the date as %Y-%m-%d + + :return: + The date formatted to %Y-%m-%d as a unicode string in Python 3 + and a byte string in Python 2 + """ + + return self.strftime('0000-%m-%d') + + def strftime(self, format): + """ + Formats the date using strftime() + + :param format: + The strftime() format string + + :return: + The formatted date as a unicode string in Python 3 and a byte + string in Python 2 + """ + + output = self._format(format) + if py2: + return output.encode('utf-8') + return output + + def replace(self, year=None, month=None, day=None): + """ + Returns a new datetime.date or asn1crypto.util.extended_date + object with the specified components replaced + + :return: + A datetime.date or asn1crypto.util.extended_date object + """ + + if year is None: + year = self.year + if month is None: + month = self.month + if day is None: + day = self.day + + if year > 0: + cls = date + else: + cls = extended_date + + return cls( + year, + month, + day + ) + + def __str__(self): + if py2: + return self.__bytes__() + else: + return self.__unicode__() + + def __bytes__(self): + return self.__unicode__().encode('utf-8') + + def __unicode__(self): + return self._format('%Y-%m-%d') + + def __eq__(self, other): + if not isinstance(other, self.__class__): + return False + return self.__cmp__(other) == 0 + + def __ne__(self, other): + return not self.__eq__(other) + + def _comparison_error(self, other): + raise TypeError(unwrap( + ''' + An asn1crypto.util.extended_date object can only be compared to + an asn1crypto.util.extended_date or datetime.date object, not %s + ''', + type_name(other) + )) + + def __cmp__(self, other): + if isinstance(other, date): + return -1 + + if not isinstance(other, self.__class__): + self._comparison_error(other) + + st = ( + self.year, + self.month, + self.day + ) + ot = ( + other.year, + other.month, + other.day + ) + + if st < ot: + return -1 + if st > ot: + return 1 + return 0 + + def __lt__(self, other): + return self.__cmp__(other) < 0 + + def __le__(self, other): + return self.__cmp__(other) <= 0 + + def __gt__(self, other): + return self.__cmp__(other) > 0 + + def __ge__(self, other): + return self.__cmp__(other) >= 0 + + +class extended_datetime(object): + """ + A datetime.datetime-like object that can represent the year 0. This is just + to handle 0000-01-01 found in some certificates. + """ + + year = None + month = None + day = None + hour = None + minute = None + second = None + microsecond = None + tzinfo = None + + def __init__(self, year, month, day, hour=0, minute=0, second=0, microsecond=0, tzinfo=None): + """ + :param year: + The integer 0 + + :param month: + An integer from 1 to 12 + + :param day: + An integer from 1 to 31 + + :param hour: + An integer from 0 to 23 + + :param minute: + An integer from 0 to 59 + + :param second: + An integer from 0 to 59 + + :param microsecond: + An integer from 0 to 999999 + """ + + if year != 0: + raise ValueError('year must be 0') + + if month < 1 or month > 12: + raise ValueError('month is out of range') + + if day < 0 or day > _DAYS_PER_MONTH_YEAR_0[month]: + raise ValueError('day is out of range') + + if hour < 0 or hour > 23: + raise ValueError('hour is out of range') + + if minute < 0 or minute > 59: + raise ValueError('minute is out of range') + + if second < 0 or second > 59: + raise ValueError('second is out of range') + + if microsecond < 0 or microsecond > 999999: + raise ValueError('microsecond is out of range') + + self.year = year + self.month = month + self.day = day + self.hour = hour + self.minute = minute + self.second = second + self.microsecond = microsecond + self.tzinfo = tzinfo + + def date(self): + """ + :return: + An asn1crypto.util.extended_date of the date + """ + + return extended_date(self.year, self.month, self.day) + + def time(self): + """ + :return: + A datetime.time object of the time + """ + + return time(self.hour, self.minute, self.second, self.microsecond, self.tzinfo) + + def utcoffset(self): + """ + :return: + None or a datetime.timedelta() of the offset from UTC + """ + + if self.tzinfo is None: + return None + return self.tzinfo.utcoffset(self.replace(year=2000)) + + def dst(self): + """ + :return: + None or a datetime.timedelta() of the daylight savings time offset + """ + + if self.tzinfo is None: + return None + return self.tzinfo.dst(self.replace(year=2000)) + + def tzname(self): + """ + :return: + None or the name of the timezone as a unicode string in Python 3 + and a byte string in Python 2 + """ + + if self.tzinfo is None: + return None + return self.tzinfo.tzname(self.replace(year=2000)) + + def _format(self, format): + """ + Performs strftime(), always returning a unicode string + + :param format: + A strftime() format string + + :return: + A unicode string of the formatted datetime + """ + + format = format.replace('%Y', '0000') + # Year 0 is 1BC and a leap year. Leap years repeat themselves + # every 28 years. Because of adjustments and the proleptic gregorian + # calendar, the simplest way to format is to substitute year 2000. + temp = datetime( + 2000, + self.month, + self.day, + self.hour, + self.minute, + self.second, + self.microsecond, + self.tzinfo + ) + if '%c' in format: + c_out = temp.strftime('%c') + # Handle full years + c_out = c_out.replace('2000', '0000') + c_out = c_out.replace('%', '%%') + format = format.replace('%c', c_out) + if '%x' in format: + x_out = temp.strftime('%x') + # Handle formats such as 08/16/2000 or 16.08.2000 + x_out = x_out.replace('2000', '0000') + x_out = x_out.replace('%', '%%') + format = format.replace('%x', x_out) + return temp.strftime(format) + + def isoformat(self, sep='T'): + """ + Formats the date as "%Y-%m-%d %H:%M:%S" with the sep param between the + date and time portions + + :param set: + A single character of the separator to place between the date and + time + + :return: + The formatted datetime as a unicode string in Python 3 and a byte + string in Python 2 + """ + + if self.microsecond == 0: + return self.strftime('0000-%%m-%%d%s%%H:%%M:%%S' % sep) + return self.strftime('0000-%%m-%%d%s%%H:%%M:%%S.%%f' % sep) + + def strftime(self, format): + """ + Formats the date using strftime() + + :param format: + The strftime() format string + + :return: + The formatted date as a unicode string in Python 3 and a byte + string in Python 2 + """ + + output = self._format(format) + if py2: + return output.encode('utf-8') + return output + + def replace(self, year=None, month=None, day=None, hour=None, minute=None, + second=None, microsecond=None, tzinfo=None): + """ + Returns a new datetime.datetime or asn1crypto.util.extended_datetime + object with the specified components replaced + + :return: + A datetime.datetime or asn1crypto.util.extended_datetime object + """ + + if year is None: + year = self.year + if month is None: + month = self.month + if day is None: + day = self.day + if hour is None: + hour = self.hour + if minute is None: + minute = self.minute + if second is None: + second = self.second + if microsecond is None: + microsecond = self.microsecond + if tzinfo is None: + tzinfo = self.tzinfo + + if year > 0: + cls = datetime + else: + cls = extended_datetime + + return cls( + year, + month, + day, + hour, + minute, + second, + microsecond, + tzinfo + ) + + def __str__(self): + if py2: + return self.__bytes__() + else: + return self.__unicode__() + + def __bytes__(self): + return self.__unicode__().encode('utf-8') + + def __unicode__(self): + format = '%Y-%m-%d %H:%M:%S' + if self.microsecond != 0: + format += '.%f' + return self._format(format) + + def __eq__(self, other): + if not isinstance(other, self.__class__): + return False + return self.__cmp__(other) == 0 + + def __ne__(self, other): + return not self.__eq__(other) + + def _comparison_error(self, other): + """ + Raises a TypeError about the other object not being suitable for + comparison + + :param other: + The object being compared to + """ + + raise TypeError(unwrap( + ''' + An asn1crypto.util.extended_datetime object can only be compared to + an asn1crypto.util.extended_datetime or datetime.datetime object, + not %s + ''', + type_name(other) + )) + + def __cmp__(self, other): + so = self.utcoffset() + oo = other.utcoffset() + + if (so is not None and oo is None) or (so is None and oo is not None): + raise TypeError("can't compare offset-naive and offset-aware datetimes") + + if isinstance(other, datetime): + return -1 + + if not isinstance(other, self.__class__): + self._comparison_error(other) + + st = ( + self.year, + self.month, + self.day, + self.hour, + self.minute, + self.second, + self.microsecond, + so + ) + ot = ( + other.year, + other.month, + other.day, + other.hour, + other.minute, + other.second, + other.microsecond, + oo + ) + + if st < ot: + return -1 + if st > ot: + return 1 + return 0 + + def __lt__(self, other): + return self.__cmp__(other) < 0 + + def __le__(self, other): + return self.__cmp__(other) <= 0 + + def __gt__(self, other): + return self.__cmp__(other) > 0 + + def __ge__(self, other): + return self.__cmp__(other) >= 0 diff --git a/venv/lib/python2.7/site-packages/asn1crypto/version.py b/venv/lib/python2.7/site-packages/asn1crypto/version.py new file mode 100644 index 0000000..2ce2408 --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/version.py @@ -0,0 +1,6 @@ +# coding: utf-8 +from __future__ import unicode_literals, division, absolute_import, print_function + + +__version__ = '0.24.0' +__version_info__ = (0, 24, 0) diff --git a/venv/lib/python2.7/site-packages/asn1crypto/x509.py b/venv/lib/python2.7/site-packages/asn1crypto/x509.py new file mode 100644 index 0000000..5a572a3 --- /dev/null +++ b/venv/lib/python2.7/site-packages/asn1crypto/x509.py @@ -0,0 +1,3002 @@ +# coding: utf-8 + +""" +ASN.1 type classes for X.509 certificates. Exports the following items: + + - Attributes() + - Certificate() + - Extensions() + - GeneralName() + - GeneralNames() + - Name() + +Other type classes are defined that help compose the types listed above. +""" + +from __future__ import unicode_literals, division, absolute_import, print_function + +from contextlib import contextmanager +from encodings import idna # noqa +import hashlib +import re +import socket +import stringprep +import sys +import unicodedata + +from ._errors import unwrap +from ._iri import iri_to_uri, uri_to_iri +from ._ordereddict import OrderedDict +from ._types import type_name, str_cls, bytes_to_list +from .algos import AlgorithmIdentifier, AnyAlgorithmIdentifier, DigestAlgorithm, SignedDigestAlgorithm +from .core import ( + Any, + BitString, + BMPString, + Boolean, + Choice, + Concat, + Enumerated, + GeneralizedTime, + GeneralString, + IA5String, + Integer, + Null, + NumericString, + ObjectIdentifier, + OctetBitString, + OctetString, + ParsableOctetString, + PrintableString, + Sequence, + SequenceOf, + Set, + SetOf, + TeletexString, + UniversalString, + UTCTime, + UTF8String, + VisibleString, + VOID, +) +from .keys import PublicKeyInfo +from .util import int_to_bytes, int_from_bytes, inet_ntop, inet_pton + + +# The structures in this file are taken from https://tools.ietf.org/html/rfc5280 +# and a few other supplementary sources, mostly due to extra supported +# extension and name OIDs + + +class DNSName(IA5String): + + _encoding = 'idna' + _bad_tag = 19 + + def __ne__(self, other): + return not self == other + + def __eq__(self, other): + """ + Equality as defined by https://tools.ietf.org/html/rfc5280#section-7.2 + + :param other: + Another DNSName object + + :return: + A boolean + """ + + if not isinstance(other, DNSName): + return False + + return self.__unicode__().lower() == other.__unicode__().lower() + + def set(self, value): + """ + Sets the value of the DNS name + + :param value: + A unicode string + """ + + if not isinstance(value, str_cls): + raise TypeError(unwrap( + ''' + %s value must be a unicode string, not %s + ''', + type_name(self), + type_name(value) + )) + + if value.startswith('.'): + encoded_value = b'.' + value[1:].encode(self._encoding) + else: + encoded_value = value.encode(self._encoding) + + self._unicode = value + self.contents = encoded_value + self._header = None + if self._trailer != b'': + self._trailer = b'' + + +class URI(IA5String): + + def set(self, value): + """ + Sets the value of the string + + :param value: + A unicode string + """ + + if not isinstance(value, str_cls): + raise TypeError(unwrap( + ''' + %s value must be a unicode string, not %s + ''', + type_name(self), + type_name(value) + )) + + self._unicode = value + self.contents = iri_to_uri(value) + self._header = None + if self._trailer != b'': + self._trailer = b'' + + def __ne__(self, other): + return not self == other + + def __eq__(self, other): + """ + Equality as defined by https://tools.ietf.org/html/rfc5280#section-7.4 + + :param other: + Another URI object + + :return: + A boolean + """ + + if not isinstance(other, URI): + return False + + return iri_to_uri(self.native) == iri_to_uri(other.native) + + def __unicode__(self): + """ + :return: + A unicode string + """ + + if self.contents is None: + return '' + if self._unicode is None: + self._unicode = uri_to_iri(self._merge_chunks()) + return self._unicode + + +class EmailAddress(IA5String): + + _contents = None + + # If the value has gone through the .set() method, thus normalizing it + _normalized = False + + @property + def contents(self): + """ + :return: + A byte string of the DER-encoded contents of the sequence + """ + + return self._contents + + @contents.setter + def contents(self, value): + """ + :param value: + A byte string of the DER-encoded contents of the sequence + """ + + self._normalized = False + self._contents = value + + def set(self, value): + """ + Sets the value of the string + + :param value: + A unicode string + """ + + if not isinstance(value, str_cls): + raise TypeError(unwrap( + ''' + %s value must be a unicode string, not %s + ''', + type_name(self), + type_name(value) + )) + + if value.find('@') != -1: + mailbox, hostname = value.rsplit('@', 1) + encoded_value = mailbox.encode('ascii') + b'@' + hostname.encode('idna') + else: + encoded_value = value.encode('ascii') + + self._normalized = True + self._unicode = value + self.contents = encoded_value + self._header = None + if self._trailer != b'': + self._trailer = b'' + + def __unicode__(self): + """ + :return: + A unicode string + """ + + if self._unicode is None: + contents = self._merge_chunks() + if contents.find(b'@') == -1: + self._unicode = contents.decode('ascii') + else: + mailbox, hostname = contents.rsplit(b'@', 1) + self._unicode = mailbox.decode('ascii') + '@' + hostname.decode('idna') + return self._unicode + + def __ne__(self, other): + return not self == other + + def __eq__(self, other): + """ + Equality as defined by https://tools.ietf.org/html/rfc5280#section-7.5 + + :param other: + Another EmailAddress object + + :return: + A boolean + """ + + if not isinstance(other, EmailAddress): + return False + + if not self._normalized: + self.set(self.native) + if not other._normalized: + other.set(other.native) + + if self._contents.find(b'@') == -1 or other._contents.find(b'@') == -1: + return self._contents == other._contents + + other_mailbox, other_hostname = other._contents.rsplit(b'@', 1) + mailbox, hostname = self._contents.rsplit(b'@', 1) + + if mailbox != other_mailbox: + return False + + if hostname.lower() != other_hostname.lower(): + return False + + return True + + +class IPAddress(OctetString): + def parse(self, spec=None, spec_params=None): + """ + This method is not applicable to IP addresses + """ + + raise ValueError(unwrap( + ''' + IP address values can not be parsed + ''' + )) + + def set(self, value): + """ + Sets the value of the object + + :param value: + A unicode string containing an IPv4 address, IPv4 address with CIDR, + an IPv6 address or IPv6 address with CIDR + """ + + if not isinstance(value, str_cls): + raise TypeError(unwrap( + ''' + %s value must be a unicode string, not %s + ''', + type_name(self), + type_name(value) + )) + + original_value = value + + has_cidr = value.find('/') != -1 + cidr = 0 + if has_cidr: + parts = value.split('/', 1) + value = parts[0] + cidr = int(parts[1]) + if cidr < 0: + raise ValueError(unwrap( + ''' + %s value contains a CIDR range less than 0 + ''', + type_name(self) + )) + + if value.find(':') != -1: + family = socket.AF_INET6 + if cidr > 128: + raise ValueError(unwrap( + ''' + %s value contains a CIDR range bigger than 128, the maximum + value for an IPv6 address + ''', + type_name(self) + )) + cidr_size = 128 + else: + family = socket.AF_INET + if cidr > 32: + raise ValueError(unwrap( + ''' + %s value contains a CIDR range bigger than 32, the maximum + value for an IPv4 address + ''', + type_name(self) + )) + cidr_size = 32 + + cidr_bytes = b'' + if has_cidr: + cidr_mask = '1' * cidr + cidr_mask += '0' * (cidr_size - len(cidr_mask)) + cidr_bytes = int_to_bytes(int(cidr_mask, 2)) + cidr_bytes = (b'\x00' * ((cidr_size // 8) - len(cidr_bytes))) + cidr_bytes + + self._native = original_value + self.contents = inet_pton(family, value) + cidr_bytes + self._bytes = self.contents + self._header = None + if self._trailer != b'': + self._trailer = b'' + + @property + def native(self): + """ + The a native Python datatype representation of this value + + :return: + A unicode string or None + """ + + if self.contents is None: + return None + + if self._native is None: + byte_string = self.__bytes__() + byte_len = len(byte_string) + cidr_int = None + if byte_len in set([32, 16]): + value = inet_ntop(socket.AF_INET6, byte_string[0:16]) + if byte_len > 16: + cidr_int = int_from_bytes(byte_string[16:]) + elif byte_len in set([8, 4]): + value = inet_ntop(socket.AF_INET, byte_string[0:4]) + if byte_len > 4: + cidr_int = int_from_bytes(byte_string[4:]) + if cidr_int is not None: + cidr_bits = '{0:b}'.format(cidr_int) + cidr = len(cidr_bits.rstrip('0')) + value = value + '/' + str_cls(cidr) + self._native = value + return self._native + + def __ne__(self, other): + return not self == other + + def __eq__(self, other): + """ + :param other: + Another IPAddress object + + :return: + A boolean + """ + + if not isinstance(other, IPAddress): + return False + + return self.__bytes__() == other.__bytes__() + + +class Attribute(Sequence): + _fields = [ + ('type', ObjectIdentifier), + ('values', SetOf, {'spec': Any}), + ] + + +class Attributes(SequenceOf): + _child_spec = Attribute + + +class KeyUsage(BitString): + _map = { + 0: 'digital_signature', + 1: 'non_repudiation', + 2: 'key_encipherment', + 3: 'data_encipherment', + 4: 'key_agreement', + 5: 'key_cert_sign', + 6: 'crl_sign', + 7: 'encipher_only', + 8: 'decipher_only', + } + + +class PrivateKeyUsagePeriod(Sequence): + _fields = [ + ('not_before', GeneralizedTime, {'implicit': 0, 'optional': True}), + ('not_after', GeneralizedTime, {'implicit': 1, 'optional': True}), + ] + + +class NotReallyTeletexString(TeletexString): + """ + OpenSSL (and probably some other libraries) puts ISO-8859-1 + into TeletexString instead of ITU T.61. We use Windows-1252 when + decoding since it is a superset of ISO-8859-1, and less likely to + cause encoding issues, but we stay strict with encoding to prevent + us from creating bad data. + """ + + _decoding_encoding = 'cp1252' + + def __unicode__(self): + """ + :return: + A unicode string + """ + + if self.contents is None: + return '' + if self._unicode is None: + self._unicode = self._merge_chunks().decode(self._decoding_encoding) + return self._unicode + + +@contextmanager +def strict_teletex(): + try: + NotReallyTeletexString._decoding_encoding = 'teletex' + yield + finally: + NotReallyTeletexString._decoding_encoding = 'cp1252' + + +class DirectoryString(Choice): + _alternatives = [ + ('teletex_string', NotReallyTeletexString), + ('printable_string', PrintableString), + ('universal_string', UniversalString), + ('utf8_string', UTF8String), + ('bmp_string', BMPString), + # This is an invalid/bad alternative, but some broken certs use it + ('ia5_string', IA5String), + ] + + +class NameType(ObjectIdentifier): + _map = { + '2.5.4.3': 'common_name', + '2.5.4.4': 'surname', + '2.5.4.5': 'serial_number', + '2.5.4.6': 'country_name', + '2.5.4.7': 'locality_name', + '2.5.4.8': 'state_or_province_name', + '2.5.4.9': 'street_address', + '2.5.4.10': 'organization_name', + '2.5.4.11': 'organizational_unit_name', + '2.5.4.12': 'title', + '2.5.4.15': 'business_category', + '2.5.4.17': 'postal_code', + '2.5.4.20': 'telephone_number', + '2.5.4.41': 'name', + '2.5.4.42': 'given_name', + '2.5.4.43': 'initials', + '2.5.4.44': 'generation_qualifier', + '2.5.4.45': 'unique_identifier', + '2.5.4.46': 'dn_qualifier', + '2.5.4.65': 'pseudonym', + '2.5.4.97': 'organization_identifier', + # https://www.trustedcomputinggroup.org/wp-content/uploads/Credential_Profile_EK_V2.0_R14_published.pdf + '2.23.133.2.1': 'tpm_manufacturer', + '2.23.133.2.2': 'tpm_model', + '2.23.133.2.3': 'tpm_version', + '2.23.133.2.4': 'platform_manufacturer', + '2.23.133.2.5': 'platform_model', + '2.23.133.2.6': 'platform_version', + # https://tools.ietf.org/html/rfc2985#page-26 + '1.2.840.113549.1.9.1': 'email_address', + # Page 10 of https://cabforum.org/wp-content/uploads/EV-V1_5_5.pdf + '1.3.6.1.4.1.311.60.2.1.1': 'incorporation_locality', + '1.3.6.1.4.1.311.60.2.1.2': 'incorporation_state_or_province', + '1.3.6.1.4.1.311.60.2.1.3': 'incorporation_country', + # https://tools.ietf.org/html/rfc2247#section-4 + '0.9.2342.19200300.100.1.25': 'domain_component', + # http://www.alvestrand.no/objectid/0.2.262.1.10.7.20.html + '0.2.262.1.10.7.20': 'name_distinguisher', + } + + # This order is largely based on observed order seen in EV certs from + # Symantec and DigiCert. Some of the uncommon name-related fields are + # just placed in what seems like a reasonable order. + preferred_order = [ + 'incorporation_country', + 'incorporation_state_or_province', + 'incorporation_locality', + 'business_category', + 'serial_number', + 'country_name', + 'postal_code', + 'state_or_province_name', + 'locality_name', + 'street_address', + 'organization_name', + 'organizational_unit_name', + 'title', + 'common_name', + 'initials', + 'generation_qualifier', + 'surname', + 'given_name', + 'name', + 'pseudonym', + 'dn_qualifier', + 'telephone_number', + 'email_address', + 'domain_component', + 'name_distinguisher', + 'organization_identifier', + 'tpm_manufacturer', + 'tpm_model', + 'tpm_version', + 'platform_manufacturer', + 'platform_model', + 'platform_version', + ] + + @classmethod + def preferred_ordinal(cls, attr_name): + """ + Returns an ordering value for a particular attribute key. + + Unrecognized attributes and OIDs will be sorted lexically at the end. + + :return: + An orderable value. + + """ + + attr_name = cls.map(attr_name) + if attr_name in cls.preferred_order: + ordinal = cls.preferred_order.index(attr_name) + else: + ordinal = len(cls.preferred_order) + + return (ordinal, attr_name) + + @property + def human_friendly(self): + """ + :return: + A human-friendly unicode string to display to users + """ + + return { + 'common_name': 'Common Name', + 'surname': 'Surname', + 'serial_number': 'Serial Number', + 'country_name': 'Country', + 'locality_name': 'Locality', + 'state_or_province_name': 'State/Province', + 'street_address': 'Street Address', + 'organization_name': 'Organization', + 'organizational_unit_name': 'Organizational Unit', + 'title': 'Title', + 'business_category': 'Business Category', + 'postal_code': 'Postal Code', + 'telephone_number': 'Telephone Number', + 'name': 'Name', + 'given_name': 'Given Name', + 'initials': 'Initials', + 'generation_qualifier': 'Generation Qualifier', + 'unique_identifier': 'Unique Identifier', + 'dn_qualifier': 'DN Qualifier', + 'pseudonym': 'Pseudonym', + 'email_address': 'Email Address', + 'incorporation_locality': 'Incorporation Locality', + 'incorporation_state_or_province': 'Incorporation State/Province', + 'incorporation_country': 'Incorporation Country', + 'domain_component': 'Domain Component', + 'name_distinguisher': 'Name Distinguisher', + 'organization_identifier': 'Organization Identifier', + 'tpm_manufacturer': 'TPM Manufacturer', + 'tpm_model': 'TPM Model', + 'tpm_version': 'TPM Version', + 'platform_manufacturer': 'Platform Manufacturer', + 'platform_model': 'Platform Model', + 'platform_version': 'Platform Version', + }.get(self.native, self.native) + + +class NameTypeAndValue(Sequence): + _fields = [ + ('type', NameType), + ('value', Any), + ] + + _oid_pair = ('type', 'value') + _oid_specs = { + 'common_name': DirectoryString, + 'surname': DirectoryString, + 'serial_number': DirectoryString, + 'country_name': DirectoryString, + 'locality_name': DirectoryString, + 'state_or_province_name': DirectoryString, + 'street_address': DirectoryString, + 'organization_name': DirectoryString, + 'organizational_unit_name': DirectoryString, + 'title': DirectoryString, + 'business_category': DirectoryString, + 'postal_code': DirectoryString, + 'telephone_number': PrintableString, + 'name': DirectoryString, + 'given_name': DirectoryString, + 'initials': DirectoryString, + 'generation_qualifier': DirectoryString, + 'unique_identifier': OctetBitString, + 'dn_qualifier': DirectoryString, + 'pseudonym': DirectoryString, + # https://tools.ietf.org/html/rfc2985#page-26 + 'email_address': EmailAddress, + # Page 10 of https://cabforum.org/wp-content/uploads/EV-V1_5_5.pdf + 'incorporation_locality': DirectoryString, + 'incorporation_state_or_province': DirectoryString, + 'incorporation_country': DirectoryString, + 'domain_component': DNSName, + 'name_distinguisher': DirectoryString, + 'organization_identifier': DirectoryString, + 'tpm_manufacturer': UTF8String, + 'tpm_model': UTF8String, + 'tpm_version': UTF8String, + 'platform_manufacturer': UTF8String, + 'platform_model': UTF8String, + 'platform_version': UTF8String, + } + + _prepped = None + + @property + def prepped_value(self): + """ + Returns the value after being processed by the internationalized string + preparation as specified by RFC 5280 + + :return: + A unicode string + """ + + if self._prepped is None: + self._prepped = self._ldap_string_prep(self['value'].native) + return self._prepped + + def __ne__(self, other): + return not self == other + + def __eq__(self, other): + """ + Equality as defined by https://tools.ietf.org/html/rfc5280#section-7.1 + + :param other: + Another NameTypeAndValue object + + :return: + A boolean + """ + + if not isinstance(other, NameTypeAndValue): + return False + + if other['type'].native != self['type'].native: + return False + + return other.prepped_value == self.prepped_value + + def _ldap_string_prep(self, string): + """ + Implements the internationalized string preparation algorithm from + RFC 4518. https://tools.ietf.org/html/rfc4518#section-2 + + :param string: + A unicode string to prepare + + :return: + A prepared unicode string, ready for comparison + """ + + # Map step + string = re.sub('[\u00ad\u1806\u034f\u180b-\u180d\ufe0f-\uff00\ufffc]+', '', string) + string = re.sub('[\u0009\u000a\u000b\u000c\u000d\u0085]', ' ', string) + if sys.maxunicode == 0xffff: + # Some installs of Python 2.7 don't support 8-digit unicode escape + # ranges, so we have to break them into pieces + # Original was: \U0001D173-\U0001D17A and \U000E0020-\U000E007F + string = re.sub('\ud834[\udd73-\udd7a]|\udb40[\udc20-\udc7f]|\U000e0001', '', string) + else: + string = re.sub('[\U0001D173-\U0001D17A\U000E0020-\U000E007F\U000e0001]', '', string) + string = re.sub( + '[\u0000-\u0008\u000e-\u001f\u007f-\u0084\u0086-\u009f\u06dd\u070f\u180e\u200c-\u200f' + '\u202a-\u202e\u2060-\u2063\u206a-\u206f\ufeff\ufff9-\ufffb]+', + '', + string + ) + string = string.replace('\u200b', '') + string = re.sub('[\u00a0\u1680\u2000-\u200a\u2028-\u2029\u202f\u205f\u3000]', ' ', string) + + string = ''.join(map(stringprep.map_table_b2, string)) + + # Normalize step + string = unicodedata.normalize('NFKC', string) + + # Prohibit step + for char in string: + if stringprep.in_table_a1(char): + raise ValueError(unwrap( + ''' + X.509 Name objects may not contain unassigned code points + ''' + )) + + if stringprep.in_table_c8(char): + raise ValueError(unwrap( + ''' + X.509 Name objects may not contain change display or + zzzzdeprecated characters + ''' + )) + + if stringprep.in_table_c3(char): + raise ValueError(unwrap( + ''' + X.509 Name objects may not contain private use characters + ''' + )) + + if stringprep.in_table_c4(char): + raise ValueError(unwrap( + ''' + X.509 Name objects may not contain non-character code points + ''' + )) + + if stringprep.in_table_c5(char): + raise ValueError(unwrap( + ''' + X.509 Name objects may not contain surrogate code points + ''' + )) + + if char == '\ufffd': + raise ValueError(unwrap( + ''' + X.509 Name objects may not contain the replacement character + ''' + )) + + # Check bidirectional step - here we ensure that we are not mixing + # left-to-right and right-to-left text in the string + has_r_and_al_cat = False + has_l_cat = False + for char in string: + if stringprep.in_table_d1(char): + has_r_and_al_cat = True + elif stringprep.in_table_d2(char): + has_l_cat = True + + if has_r_and_al_cat: + first_is_r_and_al = stringprep.in_table_d1(string[0]) + last_is_r_and_al = stringprep.in_table_d1(string[-1]) + + if has_l_cat or not first_is_r_and_al or not last_is_r_and_al: + raise ValueError(unwrap( + ''' + X.509 Name object contains a malformed bidirectional + sequence + ''' + )) + + # Insignificant space handling step + string = ' ' + re.sub(' +', ' ', string).strip() + ' ' + + return string + + +class RelativeDistinguishedName(SetOf): + _child_spec = NameTypeAndValue + + @property + def hashable(self): + """ + :return: + A unicode string that can be used as a dict key or in a set + """ + + output = [] + values = self._get_values(self) + for key in sorted(values.keys()): + output.append('%s: %s' % (key, values[key])) + # Unit separator is used here since the normalization process for + # values moves any such character, and the keys are all dotted integers + # or under_score_words + return '\x1F'.join(output) + + def __ne__(self, other): + return not self == other + + def __eq__(self, other): + """ + Equality as defined by https://tools.ietf.org/html/rfc5280#section-7.1 + + :param other: + Another RelativeDistinguishedName object + + :return: + A boolean + """ + + if not isinstance(other, RelativeDistinguishedName): + return False + + if len(self) != len(other): + return False + + self_types = self._get_types(self) + other_types = self._get_types(other) + + if self_types != other_types: + return False + + self_values = self._get_values(self) + other_values = self._get_values(other) + + for type_name_ in self_types: + if self_values[type_name_] != other_values[type_name_]: + return False + + return True + + def _get_types(self, rdn): + """ + Returns a set of types contained in an RDN + + :param rdn: + A RelativeDistinguishedName object + + :return: + A set object with unicode strings of NameTypeAndValue type field + values + """ + + return set([ntv['type'].native for ntv in rdn]) + + def _get_values(self, rdn): + """ + Returns a dict of prepped values contained in an RDN + + :param rdn: + A RelativeDistinguishedName object + + :return: + A dict object with unicode strings of NameTypeAndValue value field + values that have been prepped for comparison + """ + + output = {} + [output.update([(ntv['type'].native, ntv.prepped_value)]) for ntv in rdn] + return output + + +class RDNSequence(SequenceOf): + _child_spec = RelativeDistinguishedName + + @property + def hashable(self): + """ + :return: + A unicode string that can be used as a dict key or in a set + """ + + # Record separator is used here since the normalization process for + # values moves any such character, and the keys are all dotted integers + # or under_score_words + return '\x1E'.join(rdn.hashable for rdn in self) + + def __ne__(self, other): + return not self == other + + def __eq__(self, other): + """ + Equality as defined by https://tools.ietf.org/html/rfc5280#section-7.1 + + :param other: + Another RDNSequence object + + :return: + A boolean + """ + + if not isinstance(other, RDNSequence): + return False + + if len(self) != len(other): + return False + + for index, self_rdn in enumerate(self): + if other[index] != self_rdn: + return False + + return True + + +class Name(Choice): + _alternatives = [ + ('', RDNSequence), + ] + + _human_friendly = None + _sha1 = None + _sha256 = None + + @classmethod + def build(cls, name_dict, use_printable=False): + """ + Creates a Name object from a dict of unicode string keys and values. + The keys should be from NameType._map, or a dotted-integer OID unicode + string. + + :param name_dict: + A dict of name information, e.g. {"common_name": "Will Bond", + "country_name": "US", "organization": "Codex Non Sufficit LC"} + + :param use_printable: + A bool - if PrintableString should be used for encoding instead of + UTF8String. This is for backwards compatibility with old software. + + :return: + An x509.Name object + """ + + rdns = [] + if not use_printable: + encoding_name = 'utf8_string' + encoding_class = UTF8String + else: + encoding_name = 'printable_string' + encoding_class = PrintableString + + # Sort the attributes according to NameType.preferred_order + name_dict = OrderedDict( + sorted( + name_dict.items(), + key=lambda item: NameType.preferred_ordinal(item[0]) + ) + ) + + for attribute_name, attribute_value in name_dict.items(): + attribute_name = NameType.map(attribute_name) + if attribute_name == 'email_address': + value = EmailAddress(attribute_value) + elif attribute_name == 'domain_component': + value = DNSName(attribute_value) + elif attribute_name in set(['dn_qualifier', 'country_name', 'serial_number']): + value = DirectoryString( + name='printable_string', + value=PrintableString(attribute_value) + ) + else: + value = DirectoryString( + name=encoding_name, + value=encoding_class(attribute_value) + ) + + rdns.append(RelativeDistinguishedName([ + NameTypeAndValue({ + 'type': attribute_name, + 'value': value + }) + ])) + + return cls(name='', value=RDNSequence(rdns)) + + @property + def hashable(self): + """ + :return: + A unicode string that can be used as a dict key or in a set + """ + + return self.chosen.hashable + + def __len__(self): + return len(self.chosen) + + def __ne__(self, other): + return not self == other + + def __eq__(self, other): + """ + Equality as defined by https://tools.ietf.org/html/rfc5280#section-7.1 + + :param other: + Another Name object + + :return: + A boolean + """ + + if not isinstance(other, Name): + return False + return self.chosen == other.chosen + + @property + def native(self): + if self._native is None: + self._native = OrderedDict() + for rdn in self.chosen.native: + for type_val in rdn: + field_name = type_val['type'] + if field_name in self._native: + existing = self._native[field_name] + if not isinstance(existing, list): + existing = self._native[field_name] = [existing] + existing.append(type_val['value']) + else: + self._native[field_name] = type_val['value'] + return self._native + + @property + def human_friendly(self): + """ + :return: + A human-friendly unicode string containing the parts of the name + """ + + if self._human_friendly is None: + data = OrderedDict() + last_field = None + for rdn in self.chosen: + for type_val in rdn: + field_name = type_val['type'].human_friendly + last_field = field_name + if field_name in data: + data[field_name] = [data[field_name]] + data[field_name].append(type_val['value']) + else: + data[field_name] = type_val['value'] + to_join = [] + keys = data.keys() + if last_field == 'Country': + keys = reversed(list(keys)) + for key in keys: + value = data[key] + native_value = self._recursive_humanize(value) + to_join.append('%s: %s' % (key, native_value)) + + has_comma = False + for element in to_join: + if element.find(',') != -1: + has_comma = True + break + + separator = ', ' if not has_comma else '; ' + self._human_friendly = separator.join(to_join[::-1]) + + return self._human_friendly + + def _recursive_humanize(self, value): + """ + Recursively serializes data compiled from the RDNSequence + + :param value: + An Asn1Value object, or a list of Asn1Value objects + + :return: + A unicode string + """ + + if isinstance(value, list): + return', '.join( + reversed([self._recursive_humanize(sub_value) for sub_value in value]) + ) + return value.native + + @property + def sha1(self): + """ + :return: + The SHA1 hash of the DER-encoded bytes of this name + """ + + if self._sha1 is None: + self._sha1 = hashlib.sha1(self.dump()).digest() + return self._sha1 + + @property + def sha256(self): + """ + :return: + The SHA-256 hash of the DER-encoded bytes of this name + """ + + if self._sha256 is None: + self._sha256 = hashlib.sha256(self.dump()).digest() + return self._sha256 + + +class AnotherName(Sequence): + _fields = [ + ('type_id', ObjectIdentifier), + ('value', Any, {'explicit': 0}), + ] + + +class CountryName(Choice): + class_ = 1 + tag = 1 + + _alternatives = [ + ('x121_dcc_code', NumericString), + ('iso_3166_alpha2_code', PrintableString), + ] + + +class AdministrationDomainName(Choice): + class_ = 1 + tag = 2 + + _alternatives = [ + ('numeric', NumericString), + ('printable', PrintableString), + ] + + +class PrivateDomainName(Choice): + _alternatives = [ + ('numeric', NumericString), + ('printable', PrintableString), + ] + + +class PersonalName(Set): + _fields = [ + ('surname', PrintableString, {'implicit': 0}), + ('given_name', PrintableString, {'implicit': 1, 'optional': True}), + ('initials', PrintableString, {'implicit': 2, 'optional': True}), + ('generation_qualifier', PrintableString, {'implicit': 3, 'optional': True}), + ] + + +class TeletexPersonalName(Set): + _fields = [ + ('surname', TeletexString, {'implicit': 0}), + ('given_name', TeletexString, {'implicit': 1, 'optional': True}), + ('initials', TeletexString, {'implicit': 2, 'optional': True}), + ('generation_qualifier', TeletexString, {'implicit': 3, 'optional': True}), + ] + + +class OrganizationalUnitNames(SequenceOf): + _child_spec = PrintableString + + +class TeletexOrganizationalUnitNames(SequenceOf): + _child_spec = TeletexString + + +class BuiltInStandardAttributes(Sequence): + _fields = [ + ('country_name', CountryName, {'optional': True}), + ('administration_domain_name', AdministrationDomainName, {'optional': True}), + ('network_address', NumericString, {'implicit': 0, 'optional': True}), + ('terminal_identifier', PrintableString, {'implicit': 1, 'optional': True}), + ('private_domain_name', PrivateDomainName, {'explicit': 2, 'optional': True}), + ('organization_name', PrintableString, {'implicit': 3, 'optional': True}), + ('numeric_user_identifier', NumericString, {'implicit': 4, 'optional': True}), + ('personal_name', PersonalName, {'implicit': 5, 'optional': True}), + ('organizational_unit_names', OrganizationalUnitNames, {'implicit': 6, 'optional': True}), + ] + + +class BuiltInDomainDefinedAttribute(Sequence): + _fields = [ + ('type', PrintableString), + ('value', PrintableString), + ] + + +class BuiltInDomainDefinedAttributes(SequenceOf): + _child_spec = BuiltInDomainDefinedAttribute + + +class TeletexDomainDefinedAttribute(Sequence): + _fields = [ + ('type', TeletexString), + ('value', TeletexString), + ] + + +class TeletexDomainDefinedAttributes(SequenceOf): + _child_spec = TeletexDomainDefinedAttribute + + +class PhysicalDeliveryCountryName(Choice): + _alternatives = [ + ('x121_dcc_code', NumericString), + ('iso_3166_alpha2_code', PrintableString), + ] + + +class PostalCode(Choice): + _alternatives = [ + ('numeric_code', NumericString), + ('printable_code', PrintableString), + ] + + +class PDSParameter(Set): + _fields = [ + ('printable_string', PrintableString, {'optional': True}), + ('teletex_string', TeletexString, {'optional': True}), + ] + + +class PrintableAddress(SequenceOf): + _child_spec = PrintableString + + +class UnformattedPostalAddress(Set): + _fields = [ + ('printable_address', PrintableAddress, {'optional': True}), + ('teletex_string', TeletexString, {'optional': True}), + ] + + +class E1634Address(Sequence): + _fields = [ + ('number', NumericString, {'implicit': 0}), + ('sub_address', NumericString, {'implicit': 1, 'optional': True}), + ] + + +class NAddresses(SetOf): + _child_spec = OctetString + + +class PresentationAddress(Sequence): + _fields = [ + ('p_selector', OctetString, {'explicit': 0, 'optional': True}), + ('s_selector', OctetString, {'explicit': 1, 'optional': True}), + ('t_selector', OctetString, {'explicit': 2, 'optional': True}), + ('n_addresses', NAddresses, {'explicit': 3}), + ] + + +class ExtendedNetworkAddress(Choice): + _alternatives = [ + ('e163_4_address', E1634Address), + ('psap_address', PresentationAddress, {'implicit': 0}) + ] + + +class TerminalType(Integer): + _map = { + 3: 'telex', + 4: 'teletex', + 5: 'g3_facsimile', + 6: 'g4_facsimile', + 7: 'ia5_terminal', + 8: 'videotex', + } + + +class ExtensionAttributeType(Integer): + _map = { + 1: 'common_name', + 2: 'teletex_common_name', + 3: 'teletex_organization_name', + 4: 'teletex_personal_name', + 5: 'teletex_organization_unit_names', + 6: 'teletex_domain_defined_attributes', + 7: 'pds_name', + 8: 'physical_delivery_country_name', + 9: 'postal_code', + 10: 'physical_delivery_office_name', + 11: 'physical_delivery_office_number', + 12: 'extension_of_address_components', + 13: 'physical_delivery_personal_name', + 14: 'physical_delivery_organization_name', + 15: 'extension_physical_delivery_address_components', + 16: 'unformatted_postal_address', + 17: 'street_address', + 18: 'post_office_box_address', + 19: 'poste_restante_address', + 20: 'unique_postal_name', + 21: 'local_postal_attributes', + 22: 'extended_network_address', + 23: 'terminal_type', + } + + +class ExtensionAttribute(Sequence): + _fields = [ + ('extension_attribute_type', ExtensionAttributeType, {'implicit': 0}), + ('extension_attribute_value', Any, {'explicit': 1}), + ] + + _oid_pair = ('extension_attribute_type', 'extension_attribute_value') + _oid_specs = { + 'common_name': PrintableString, + 'teletex_common_name': TeletexString, + 'teletex_organization_name': TeletexString, + 'teletex_personal_name': TeletexPersonalName, + 'teletex_organization_unit_names': TeletexOrganizationalUnitNames, + 'teletex_domain_defined_attributes': TeletexDomainDefinedAttributes, + 'pds_name': PrintableString, + 'physical_delivery_country_name': PhysicalDeliveryCountryName, + 'postal_code': PostalCode, + 'physical_delivery_office_name': PDSParameter, + 'physical_delivery_office_number': PDSParameter, + 'extension_of_address_components': PDSParameter, + 'physical_delivery_personal_name': PDSParameter, + 'physical_delivery_organization_name': PDSParameter, + 'extension_physical_delivery_address_components': PDSParameter, + 'unformatted_postal_address': UnformattedPostalAddress, + 'street_address': PDSParameter, + 'post_office_box_address': PDSParameter, + 'poste_restante_address': PDSParameter, + 'unique_postal_name': PDSParameter, + 'local_postal_attributes': PDSParameter, + 'extended_network_address': ExtendedNetworkAddress, + 'terminal_type': TerminalType, + } + + +class ExtensionAttributes(SequenceOf): + _child_spec = ExtensionAttribute + + +class ORAddress(Sequence): + _fields = [ + ('built_in_standard_attributes', BuiltInStandardAttributes), + ('built_in_domain_defined_attributes', BuiltInDomainDefinedAttributes, {'optional': True}), + ('extension_attributes', ExtensionAttributes, {'optional': True}), + ] + + +class EDIPartyName(Sequence): + _fields = [ + ('name_assigner', DirectoryString, {'implicit': 0, 'optional': True}), + ('party_name', DirectoryString, {'implicit': 1}), + ] + + +class GeneralName(Choice): + _alternatives = [ + ('other_name', AnotherName, {'implicit': 0}), + ('rfc822_name', EmailAddress, {'implicit': 1}), + ('dns_name', DNSName, {'implicit': 2}), + ('x400_address', ORAddress, {'implicit': 3}), + ('directory_name', Name, {'explicit': 4}), + ('edi_party_name', EDIPartyName, {'implicit': 5}), + ('uniform_resource_identifier', URI, {'implicit': 6}), + ('ip_address', IPAddress, {'implicit': 7}), + ('registered_id', ObjectIdentifier, {'implicit': 8}), + ] + + def __ne__(self, other): + return not self == other + + def __eq__(self, other): + """ + Does not support other_name, x400_address or edi_party_name + + :param other: + The other GeneralName to compare to + + :return: + A boolean + """ + + if self.name in ('other_name', 'x400_address', 'edi_party_name'): + raise ValueError(unwrap( + ''' + Comparison is not supported for GeneralName objects of + choice %s + ''', + self.name + )) + + if other.name in ('other_name', 'x400_address', 'edi_party_name'): + raise ValueError(unwrap( + ''' + Comparison is not supported for GeneralName objects of choice + %s''', + other.name + )) + + if self.name != other.name: + return False + + return self.chosen == other.chosen + + +class GeneralNames(SequenceOf): + _child_spec = GeneralName + + +class Time(Choice): + _alternatives = [ + ('utc_time', UTCTime), + ('general_time', GeneralizedTime), + ] + + +class Validity(Sequence): + _fields = [ + ('not_before', Time), + ('not_after', Time), + ] + + +class BasicConstraints(Sequence): + _fields = [ + ('ca', Boolean, {'default': False}), + ('path_len_constraint', Integer, {'optional': True}), + ] + + +class AuthorityKeyIdentifier(Sequence): + _fields = [ + ('key_identifier', OctetString, {'implicit': 0, 'optional': True}), + ('authority_cert_issuer', GeneralNames, {'implicit': 1, 'optional': True}), + ('authority_cert_serial_number', Integer, {'implicit': 2, 'optional': True}), + ] + + +class DistributionPointName(Choice): + _alternatives = [ + ('full_name', GeneralNames, {'implicit': 0}), + ('name_relative_to_crl_issuer', RelativeDistinguishedName, {'implicit': 1}), + ] + + +class ReasonFlags(BitString): + _map = { + 0: 'unused', + 1: 'key_compromise', + 2: 'ca_compromise', + 3: 'affiliation_changed', + 4: 'superseded', + 5: 'cessation_of_operation', + 6: 'certificate_hold', + 7: 'privilege_withdrawn', + 8: 'aa_compromise', + } + + +class GeneralSubtree(Sequence): + _fields = [ + ('base', GeneralName), + ('minimum', Integer, {'implicit': 0, 'default': 0}), + ('maximum', Integer, {'implicit': 1, 'optional': True}), + ] + + +class GeneralSubtrees(SequenceOf): + _child_spec = GeneralSubtree + + +class NameConstraints(Sequence): + _fields = [ + ('permitted_subtrees', GeneralSubtrees, {'implicit': 0, 'optional': True}), + ('excluded_subtrees', GeneralSubtrees, {'implicit': 1, 'optional': True}), + ] + + +class DistributionPoint(Sequence): + _fields = [ + ('distribution_point', DistributionPointName, {'explicit': 0, 'optional': True}), + ('reasons', ReasonFlags, {'implicit': 1, 'optional': True}), + ('crl_issuer', GeneralNames, {'implicit': 2, 'optional': True}), + ] + + _url = False + + @property + def url(self): + """ + :return: + None or a unicode string of the distribution point's URL + """ + + if self._url is False: + self._url = None + name = self['distribution_point'] + if name.name != 'full_name': + raise ValueError(unwrap( + ''' + CRL distribution points that are relative to the issuer are + not supported + ''' + )) + + for general_name in name.chosen: + if general_name.name == 'uniform_resource_identifier': + url = general_name.native + if url.lower().startswith(('http://', 'https://', 'ldap://', 'ldaps://')): + self._url = url + break + + return self._url + + +class CRLDistributionPoints(SequenceOf): + _child_spec = DistributionPoint + + +class DisplayText(Choice): + _alternatives = [ + ('ia5_string', IA5String), + ('visible_string', VisibleString), + ('bmp_string', BMPString), + ('utf8_string', UTF8String), + ] + + +class NoticeNumbers(SequenceOf): + _child_spec = Integer + + +class NoticeReference(Sequence): + _fields = [ + ('organization', DisplayText), + ('notice_numbers', NoticeNumbers), + ] + + +class UserNotice(Sequence): + _fields = [ + ('notice_ref', NoticeReference, {'optional': True}), + ('explicit_text', DisplayText, {'optional': True}), + ] + + +class PolicyQualifierId(ObjectIdentifier): + _map = { + '1.3.6.1.5.5.7.2.1': 'certification_practice_statement', + '1.3.6.1.5.5.7.2.2': 'user_notice', + } + + +class PolicyQualifierInfo(Sequence): + _fields = [ + ('policy_qualifier_id', PolicyQualifierId), + ('qualifier', Any), + ] + + _oid_pair = ('policy_qualifier_id', 'qualifier') + _oid_specs = { + 'certification_practice_statement': IA5String, + 'user_notice': UserNotice, + } + + +class PolicyQualifierInfos(SequenceOf): + _child_spec = PolicyQualifierInfo + + +class PolicyIdentifier(ObjectIdentifier): + _map = { + '2.5.29.32.0': 'any_policy', + } + + +class PolicyInformation(Sequence): + _fields = [ + ('policy_identifier', PolicyIdentifier), + ('policy_qualifiers', PolicyQualifierInfos, {'optional': True}) + ] + + +class CertificatePolicies(SequenceOf): + _child_spec = PolicyInformation + + +class PolicyMapping(Sequence): + _fields = [ + ('issuer_domain_policy', PolicyIdentifier), + ('subject_domain_policy', PolicyIdentifier), + ] + + +class PolicyMappings(SequenceOf): + _child_spec = PolicyMapping + + +class PolicyConstraints(Sequence): + _fields = [ + ('require_explicit_policy', Integer, {'implicit': 0, 'optional': True}), + ('inhibit_policy_mapping', Integer, {'implicit': 1, 'optional': True}), + ] + + +class KeyPurposeId(ObjectIdentifier): + _map = { + # https://tools.ietf.org/html/rfc5280#page-45 + '2.5.29.37.0': 'any_extended_key_usage', + '1.3.6.1.5.5.7.3.1': 'server_auth', + '1.3.6.1.5.5.7.3.2': 'client_auth', + '1.3.6.1.5.5.7.3.3': 'code_signing', + '1.3.6.1.5.5.7.3.4': 'email_protection', + '1.3.6.1.5.5.7.3.5': 'ipsec_end_system', + '1.3.6.1.5.5.7.3.6': 'ipsec_tunnel', + '1.3.6.1.5.5.7.3.7': 'ipsec_user', + '1.3.6.1.5.5.7.3.8': 'time_stamping', + '1.3.6.1.5.5.7.3.9': 'ocsp_signing', + # http://tools.ietf.org/html/rfc3029.html#page-9 + '1.3.6.1.5.5.7.3.10': 'dvcs', + # http://tools.ietf.org/html/rfc6268.html#page-16 + '1.3.6.1.5.5.7.3.13': 'eap_over_ppp', + '1.3.6.1.5.5.7.3.14': 'eap_over_lan', + # https://tools.ietf.org/html/rfc5055#page-76 + '1.3.6.1.5.5.7.3.15': 'scvp_server', + '1.3.6.1.5.5.7.3.16': 'scvp_client', + # https://tools.ietf.org/html/rfc4945#page-31 + '1.3.6.1.5.5.7.3.17': 'ipsec_ike', + # https://tools.ietf.org/html/rfc5415#page-38 + '1.3.6.1.5.5.7.3.18': 'capwap_ac', + '1.3.6.1.5.5.7.3.19': 'capwap_wtp', + # https://tools.ietf.org/html/rfc5924#page-8 + '1.3.6.1.5.5.7.3.20': 'sip_domain', + # https://tools.ietf.org/html/rfc6187#page-7 + '1.3.6.1.5.5.7.3.21': 'secure_shell_client', + '1.3.6.1.5.5.7.3.22': 'secure_shell_server', + # https://tools.ietf.org/html/rfc6494#page-7 + '1.3.6.1.5.5.7.3.23': 'send_router', + '1.3.6.1.5.5.7.3.24': 'send_proxied_router', + '1.3.6.1.5.5.7.3.25': 'send_owner', + '1.3.6.1.5.5.7.3.26': 'send_proxied_owner', + # https://tools.ietf.org/html/rfc6402#page-10 + '1.3.6.1.5.5.7.3.27': 'cmc_ca', + '1.3.6.1.5.5.7.3.28': 'cmc_ra', + '1.3.6.1.5.5.7.3.29': 'cmc_archive', + # https://tools.ietf.org/html/draft-ietf-sidr-bgpsec-pki-profiles-15#page-6 + '1.3.6.1.5.5.7.3.30': 'bgpspec_router', + # https://msdn.microsoft.com/en-us/library/windows/desktop/aa378132(v=vs.85).aspx + # and https://support.microsoft.com/en-us/kb/287547 + '1.3.6.1.4.1.311.10.3.1': 'microsoft_trust_list_signing', + '1.3.6.1.4.1.311.10.3.2': 'microsoft_time_stamp_signing', + '1.3.6.1.4.1.311.10.3.3': 'microsoft_server_gated', + '1.3.6.1.4.1.311.10.3.3.1': 'microsoft_serialized', + '1.3.6.1.4.1.311.10.3.4': 'microsoft_efs', + '1.3.6.1.4.1.311.10.3.4.1': 'microsoft_efs_recovery', + '1.3.6.1.4.1.311.10.3.5': 'microsoft_whql', + '1.3.6.1.4.1.311.10.3.6': 'microsoft_nt5', + '1.3.6.1.4.1.311.10.3.7': 'microsoft_oem_whql', + '1.3.6.1.4.1.311.10.3.8': 'microsoft_embedded_nt', + '1.3.6.1.4.1.311.10.3.9': 'microsoft_root_list_signer', + '1.3.6.1.4.1.311.10.3.10': 'microsoft_qualified_subordination', + '1.3.6.1.4.1.311.10.3.11': 'microsoft_key_recovery', + '1.3.6.1.4.1.311.10.3.12': 'microsoft_document_signing', + '1.3.6.1.4.1.311.10.3.13': 'microsoft_lifetime_signing', + '1.3.6.1.4.1.311.10.3.14': 'microsoft_mobile_device_software', + # https://support.microsoft.com/en-us/help/287547/object-ids-associated-with-microsoft-cryptography + '1.3.6.1.4.1.311.20.2.2': 'microsoft_smart_card_logon', + # https://opensource.apple.com/source + # - /Security/Security-57031.40.6/Security/libsecurity_keychain/lib/SecPolicy.cpp + # - /libsecurity_cssm/libsecurity_cssm-36064/lib/oidsalg.c + '1.2.840.113635.100.1.2': 'apple_x509_basic', + '1.2.840.113635.100.1.3': 'apple_ssl', + '1.2.840.113635.100.1.4': 'apple_local_cert_gen', + '1.2.840.113635.100.1.5': 'apple_csr_gen', + '1.2.840.113635.100.1.6': 'apple_revocation_crl', + '1.2.840.113635.100.1.7': 'apple_revocation_ocsp', + '1.2.840.113635.100.1.8': 'apple_smime', + '1.2.840.113635.100.1.9': 'apple_eap', + '1.2.840.113635.100.1.10': 'apple_software_update_signing', + '1.2.840.113635.100.1.11': 'apple_ipsec', + '1.2.840.113635.100.1.12': 'apple_ichat', + '1.2.840.113635.100.1.13': 'apple_resource_signing', + '1.2.840.113635.100.1.14': 'apple_pkinit_client', + '1.2.840.113635.100.1.15': 'apple_pkinit_server', + '1.2.840.113635.100.1.16': 'apple_code_signing', + '1.2.840.113635.100.1.17': 'apple_package_signing', + '1.2.840.113635.100.1.18': 'apple_id_validation', + '1.2.840.113635.100.1.20': 'apple_time_stamping', + '1.2.840.113635.100.1.21': 'apple_revocation', + '1.2.840.113635.100.1.22': 'apple_passbook_signing', + '1.2.840.113635.100.1.23': 'apple_mobile_store', + '1.2.840.113635.100.1.24': 'apple_escrow_service', + '1.2.840.113635.100.1.25': 'apple_profile_signer', + '1.2.840.113635.100.1.26': 'apple_qa_profile_signer', + '1.2.840.113635.100.1.27': 'apple_test_mobile_store', + '1.2.840.113635.100.1.28': 'apple_otapki_signer', + '1.2.840.113635.100.1.29': 'apple_test_otapki_signer', + '1.2.840.113625.100.1.30': 'apple_id_validation_record_signing_policy', + '1.2.840.113625.100.1.31': 'apple_smp_encryption', + '1.2.840.113625.100.1.32': 'apple_test_smp_encryption', + '1.2.840.113635.100.1.33': 'apple_server_authentication', + '1.2.840.113635.100.1.34': 'apple_pcs_escrow_service', + # http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.201-2.pdf + '2.16.840.1.101.3.6.8': 'piv_card_authentication', + '2.16.840.1.101.3.6.7': 'piv_content_signing', + # https://tools.ietf.org/html/rfc4556.html + '1.3.6.1.5.2.3.4': 'pkinit_kpclientauth', + '1.3.6.1.5.2.3.5': 'pkinit_kpkdc', + # https://www.adobe.com/devnet-docs/acrobatetk/tools/DigSig/changes.html + '1.2.840.113583.1.1.5': 'adobe_authentic_documents_trust', + # https://www.idmanagement.gov/wp-content/uploads/sites/1171/uploads/fpki-pivi-cert-profiles.pdf + '2.16.840.1.101.3.8.7': 'fpki_pivi_content_signing' + } + + +class ExtKeyUsageSyntax(SequenceOf): + _child_spec = KeyPurposeId + + +class AccessMethod(ObjectIdentifier): + _map = { + '1.3.6.1.5.5.7.48.1': 'ocsp', + '1.3.6.1.5.5.7.48.2': 'ca_issuers', + '1.3.6.1.5.5.7.48.3': 'time_stamping', + '1.3.6.1.5.5.7.48.5': 'ca_repository', + } + + +class AccessDescription(Sequence): + _fields = [ + ('access_method', AccessMethod), + ('access_location', GeneralName), + ] + + +class AuthorityInfoAccessSyntax(SequenceOf): + _child_spec = AccessDescription + + +class SubjectInfoAccessSyntax(SequenceOf): + _child_spec = AccessDescription + + +# https://tools.ietf.org/html/rfc7633 +class Features(SequenceOf): + _child_spec = Integer + + +class EntrustVersionInfo(Sequence): + _fields = [ + ('entrust_vers', GeneralString), + ('entrust_info_flags', BitString) + ] + + +class NetscapeCertificateType(BitString): + _map = { + 0: 'ssl_client', + 1: 'ssl_server', + 2: 'email', + 3: 'object_signing', + 4: 'reserved', + 5: 'ssl_ca', + 6: 'email_ca', + 7: 'object_signing_ca', + } + + +class Version(Integer): + _map = { + 0: 'v1', + 1: 'v2', + 2: 'v3', + } + + +class TPMSpecification(Sequence): + _fields = [ + ('family', UTF8String), + ('level', Integer), + ('revision', Integer), + ] + + +class SetOfTPMSpecification(SetOf): + _child_spec = TPMSpecification + + +class TCGSpecificationVersion(Sequence): + _fields = [ + ('major_version', Integer), + ('minor_version', Integer), + ('revision', Integer), + ] + + +class TCGPlatformSpecification(Sequence): + _fields = [ + ('version', TCGSpecificationVersion), + ('platform_class', OctetString), + ] + + +class SetOfTCGPlatformSpecification(SetOf): + _child_spec = TCGPlatformSpecification + + +class EKGenerationType(Enumerated): + _map = { + 0: 'internal', + 1: 'injected', + 2: 'internal_revocable', + 3: 'injected_revocable', + } + + +class EKGenerationLocation(Enumerated): + _map = { + 0: 'tpm_manufacturer', + 1: 'platform_manufacturer', + 2: 'ek_cert_signer', + } + + +class EKCertificateGenerationLocation(Enumerated): + _map = { + 0: 'tpm_manufacturer', + 1: 'platform_manufacturer', + 2: 'ek_cert_signer', + } + + +class EvaluationAssuranceLevel(Enumerated): + _map = { + 1: 'level1', + 2: 'level2', + 3: 'level3', + 4: 'level4', + 5: 'level5', + 6: 'level6', + 7: 'level7', + } + + +class EvaluationStatus(Enumerated): + _map = { + 0: 'designed_to_meet', + 1: 'evaluation_in_progress', + 2: 'evaluation_completed', + } + + +class StrengthOfFunction(Enumerated): + _map = { + 0: 'basic', + 1: 'medium', + 2: 'high', + } + + +class URIReference(Sequence): + _fields = [ + ('uniform_resource_identifier', IA5String), + ('hash_algorithm', DigestAlgorithm, {'optional': True}), + ('hash_value', BitString, {'optional': True}), + ] + + +class CommonCriteriaMeasures(Sequence): + _fields = [ + ('version', IA5String), + ('assurance_level', EvaluationAssuranceLevel), + ('evaluation_status', EvaluationStatus), + ('plus', Boolean, {'default': False}), + ('strengh_of_function', StrengthOfFunction, {'implicit': 0, 'optional': True}), + ('profile_oid', ObjectIdentifier, {'implicit': 1, 'optional': True}), + ('profile_url', URIReference, {'implicit': 2, 'optional': True}), + ('target_oid', ObjectIdentifier, {'implicit': 3, 'optional': True}), + ('target_uri', URIReference, {'implicit': 4, 'optional': True}), + ] + + +class SecurityLevel(Enumerated): + _map = { + 1: 'level1', + 2: 'level2', + 3: 'level3', + 4: 'level4', + } + + +class FIPSLevel(Sequence): + _fields = [ + ('version', IA5String), + ('level', SecurityLevel), + ('plus', Boolean, {'default': False}), + ] + + +class TPMSecurityAssertions(Sequence): + _fields = [ + ('version', Version, {'default': 'v1'}), + ('field_upgradable', Boolean, {'default': False}), + ('ek_generation_type', EKGenerationType, {'implicit': 0, 'optional': True}), + ('ek_generation_location', EKGenerationLocation, {'implicit': 1, 'optional': True}), + ('ek_certificate_generation_location', EKCertificateGenerationLocation, {'implicit': 2, 'optional': True}), + ('cc_info', CommonCriteriaMeasures, {'implicit': 3, 'optional': True}), + ('fips_level', FIPSLevel, {'implicit': 4, 'optional': True}), + ('iso_9000_certified', Boolean, {'implicit': 5, 'default': False}), + ('iso_9000_uri', IA5String, {'optional': True}), + ] + + +class SetOfTPMSecurityAssertions(SetOf): + _child_spec = TPMSecurityAssertions + + +class SubjectDirectoryAttributeId(ObjectIdentifier): + _map = { + # https://tools.ietf.org/html/rfc2256#page-11 + '2.5.4.52': 'supported_algorithms', + # https://www.trustedcomputinggroup.org/wp-content/uploads/Credential_Profile_EK_V2.0_R14_published.pdf + '2.23.133.2.16': 'tpm_specification', + '2.23.133.2.17': 'tcg_platform_specification', + '2.23.133.2.18': 'tpm_security_assertions', + # https://tools.ietf.org/html/rfc3739#page-18 + '1.3.6.1.5.5.7.9.1': 'pda_date_of_birth', + '1.3.6.1.5.5.7.9.2': 'pda_place_of_birth', + '1.3.6.1.5.5.7.9.3': 'pda_gender', + '1.3.6.1.5.5.7.9.4': 'pda_country_of_citizenship', + '1.3.6.1.5.5.7.9.5': 'pda_country_of_residence', + # https://holtstrom.com/michael/tools/asn1decoder.php + '1.2.840.113533.7.68.29': 'entrust_user_role', + } + + +class SetOfGeneralizedTime(SetOf): + _child_spec = GeneralizedTime + + +class SetOfDirectoryString(SetOf): + _child_spec = DirectoryString + + +class SetOfPrintableString(SetOf): + _child_spec = PrintableString + + +class SupportedAlgorithm(Sequence): + _fields = [ + ('algorithm_identifier', AnyAlgorithmIdentifier), + ('intended_usage', KeyUsage, {'explicit': 0, 'optional': True}), + ('intended_certificate_policies', CertificatePolicies, {'explicit': 1, 'optional': True}), + ] + + +class SetOfSupportedAlgorithm(SetOf): + _child_spec = SupportedAlgorithm + + +class SubjectDirectoryAttribute(Sequence): + _fields = [ + ('type', SubjectDirectoryAttributeId), + ('values', Any), + ] + + _oid_pair = ('type', 'values') + _oid_specs = { + 'supported_algorithms': SetOfSupportedAlgorithm, + 'tpm_specification': SetOfTPMSpecification, + 'tcg_platform_specification': SetOfTCGPlatformSpecification, + 'tpm_security_assertions': SetOfTPMSecurityAssertions, + 'pda_date_of_birth': SetOfGeneralizedTime, + 'pda_place_of_birth': SetOfDirectoryString, + 'pda_gender': SetOfPrintableString, + 'pda_country_of_citizenship': SetOfPrintableString, + 'pda_country_of_residence': SetOfPrintableString, + } + + def _values_spec(self): + type_ = self['type'].native + if type_ in self._oid_specs: + return self._oid_specs[type_] + return SetOf + + _spec_callbacks = { + 'values': _values_spec + } + + +class SubjectDirectoryAttributes(SequenceOf): + _child_spec = SubjectDirectoryAttribute + + +class ExtensionId(ObjectIdentifier): + _map = { + '2.5.29.9': 'subject_directory_attributes', + '2.5.29.14': 'key_identifier', + '2.5.29.15': 'key_usage', + '2.5.29.16': 'private_key_usage_period', + '2.5.29.17': 'subject_alt_name', + '2.5.29.18': 'issuer_alt_name', + '2.5.29.19': 'basic_constraints', + '2.5.29.30': 'name_constraints', + '2.5.29.31': 'crl_distribution_points', + '2.5.29.32': 'certificate_policies', + '2.5.29.33': 'policy_mappings', + '2.5.29.35': 'authority_key_identifier', + '2.5.29.36': 'policy_constraints', + '2.5.29.37': 'extended_key_usage', + '2.5.29.46': 'freshest_crl', + '2.5.29.54': 'inhibit_any_policy', + '1.3.6.1.5.5.7.1.1': 'authority_information_access', + '1.3.6.1.5.5.7.1.11': 'subject_information_access', + # https://tools.ietf.org/html/rfc7633 + '1.3.6.1.5.5.7.1.24': 'tls_feature', + '1.3.6.1.5.5.7.48.1.5': 'ocsp_no_check', + '1.2.840.113533.7.65.0': 'entrust_version_extension', + '2.16.840.1.113730.1.1': 'netscape_certificate_type', + # https://tools.ietf.org/html/rfc6962.html#page-14 + '1.3.6.1.4.1.11129.2.4.2': 'signed_certificate_timestamp_list', + } + + +class Extension(Sequence): + _fields = [ + ('extn_id', ExtensionId), + ('critical', Boolean, {'default': False}), + ('extn_value', ParsableOctetString), + ] + + _oid_pair = ('extn_id', 'extn_value') + _oid_specs = { + 'subject_directory_attributes': SubjectDirectoryAttributes, + 'key_identifier': OctetString, + 'key_usage': KeyUsage, + 'private_key_usage_period': PrivateKeyUsagePeriod, + 'subject_alt_name': GeneralNames, + 'issuer_alt_name': GeneralNames, + 'basic_constraints': BasicConstraints, + 'name_constraints': NameConstraints, + 'crl_distribution_points': CRLDistributionPoints, + 'certificate_policies': CertificatePolicies, + 'policy_mappings': PolicyMappings, + 'authority_key_identifier': AuthorityKeyIdentifier, + 'policy_constraints': PolicyConstraints, + 'extended_key_usage': ExtKeyUsageSyntax, + 'freshest_crl': CRLDistributionPoints, + 'inhibit_any_policy': Integer, + 'authority_information_access': AuthorityInfoAccessSyntax, + 'subject_information_access': SubjectInfoAccessSyntax, + 'tls_feature': Features, + 'ocsp_no_check': Null, + 'entrust_version_extension': EntrustVersionInfo, + 'netscape_certificate_type': NetscapeCertificateType, + 'signed_certificate_timestamp_list': OctetString, + } + + +class Extensions(SequenceOf): + _child_spec = Extension + + +class TbsCertificate(Sequence): + _fields = [ + ('version', Version, {'explicit': 0, 'default': 'v1'}), + ('serial_number', Integer), + ('signature', SignedDigestAlgorithm), + ('issuer', Name), + ('validity', Validity), + ('subject', Name), + ('subject_public_key_info', PublicKeyInfo), + ('issuer_unique_id', OctetBitString, {'implicit': 1, 'optional': True}), + ('subject_unique_id', OctetBitString, {'implicit': 2, 'optional': True}), + ('extensions', Extensions, {'explicit': 3, 'optional': True}), + ] + + +class Certificate(Sequence): + _fields = [ + ('tbs_certificate', TbsCertificate), + ('signature_algorithm', SignedDigestAlgorithm), + ('signature_value', OctetBitString), + ] + + _processed_extensions = False + _critical_extensions = None + _subject_directory_attributes = None + _key_identifier_value = None + _key_usage_value = None + _subject_alt_name_value = None + _issuer_alt_name_value = None + _basic_constraints_value = None + _name_constraints_value = None + _crl_distribution_points_value = None + _certificate_policies_value = None + _policy_mappings_value = None + _authority_key_identifier_value = None + _policy_constraints_value = None + _freshest_crl_value = None + _inhibit_any_policy_value = None + _extended_key_usage_value = None + _authority_information_access_value = None + _subject_information_access_value = None + _private_key_usage_period_value = None + _tls_feature_value = None + _ocsp_no_check_value = None + _issuer_serial = None + _authority_issuer_serial = False + _crl_distribution_points = None + _delta_crl_distribution_points = None + _valid_domains = None + _valid_ips = None + _self_issued = None + _self_signed = None + _sha1 = None + _sha256 = None + + def _set_extensions(self): + """ + Sets common named extensions to private attributes and creates a list + of critical extensions + """ + + self._critical_extensions = set() + + for extension in self['tbs_certificate']['extensions']: + name = extension['extn_id'].native + attribute_name = '_%s_value' % name + if hasattr(self, attribute_name): + setattr(self, attribute_name, extension['extn_value'].parsed) + if extension['critical'].native: + self._critical_extensions.add(name) + + self._processed_extensions = True + + @property + def critical_extensions(self): + """ + Returns a set of the names (or OID if not a known extension) of the + extensions marked as critical + + :return: + A set of unicode strings + """ + + if not self._processed_extensions: + self._set_extensions() + return self._critical_extensions + + @property + def private_key_usage_period_value(self): + """ + This extension is used to constrain the period over which the subject + private key may be used + + :return: + None or a PrivateKeyUsagePeriod object + """ + + if not self._processed_extensions: + self._set_extensions() + return self._private_key_usage_period_value + + @property + def subject_directory_attributes_value(self): + """ + This extension is used to contain additional identification attributes + about the subject. + + :return: + None or a SubjectDirectoryAttributes object + """ + + if not self._processed_extensions: + self._set_extensions() + return self._subject_directory_attributes + + @property + def key_identifier_value(self): + """ + This extension is used to help in creating certificate validation paths. + It contains an identifier that should generally, but is not guaranteed + to, be unique. + + :return: + None or an OctetString object + """ + + if not self._processed_extensions: + self._set_extensions() + return self._key_identifier_value + + @property + def key_usage_value(self): + """ + This extension is used to define the purpose of the public key + contained within the certificate. + + :return: + None or a KeyUsage + """ + + if not self._processed_extensions: + self._set_extensions() + return self._key_usage_value + + @property + def subject_alt_name_value(self): + """ + This extension allows for additional names to be associate with the + subject of the certificate. While it may contain a whole host of + possible names, it is usually used to allow certificates to be used + with multiple different domain names. + + :return: + None or a GeneralNames object + """ + + if not self._processed_extensions: + self._set_extensions() + return self._subject_alt_name_value + + @property + def issuer_alt_name_value(self): + """ + This extension allows associating one or more alternative names with + the issuer of the certificate. + + :return: + None or an x509.GeneralNames object + """ + + if not self._processed_extensions: + self._set_extensions() + return self._issuer_alt_name_value + + @property + def basic_constraints_value(self): + """ + This extension is used to determine if the subject of the certificate + is a CA, and if so, what the maximum number of intermediate CA certs + after this are, before an end-entity certificate is found. + + :return: + None or a BasicConstraints object + """ + + if not self._processed_extensions: + self._set_extensions() + return self._basic_constraints_value + + @property + def name_constraints_value(self): + """ + This extension is used in CA certificates, and is used to limit the + possible names of certificates issued. + + :return: + None or a NameConstraints object + """ + + if not self._processed_extensions: + self._set_extensions() + return self._name_constraints_value + + @property + def crl_distribution_points_value(self): + """ + This extension is used to help in locating the CRL for this certificate. + + :return: + None or a CRLDistributionPoints object + extension + """ + + if not self._processed_extensions: + self._set_extensions() + return self._crl_distribution_points_value + + @property + def certificate_policies_value(self): + """ + This extension defines policies in CA certificates under which + certificates may be issued. In end-entity certificates, the inclusion + of a policy indicates the issuance of the certificate follows the + policy. + + :return: + None or a CertificatePolicies object + """ + + if not self._processed_extensions: + self._set_extensions() + return self._certificate_policies_value + + @property + def policy_mappings_value(self): + """ + This extension allows mapping policy OIDs to other OIDs. This is used + to allow different policies to be treated as equivalent in the process + of validation. + + :return: + None or a PolicyMappings object + """ + + if not self._processed_extensions: + self._set_extensions() + return self._policy_mappings_value + + @property + def authority_key_identifier_value(self): + """ + This extension helps in identifying the public key with which to + validate the authenticity of the certificate. + + :return: + None or an AuthorityKeyIdentifier object + """ + + if not self._processed_extensions: + self._set_extensions() + return self._authority_key_identifier_value + + @property + def policy_constraints_value(self): + """ + This extension is used to control if policy mapping is allowed and + when policies are required. + + :return: + None or a PolicyConstraints object + """ + + if not self._processed_extensions: + self._set_extensions() + return self._policy_constraints_value + + @property + def freshest_crl_value(self): + """ + This extension is used to help locate any available delta CRLs + + :return: + None or an CRLDistributionPoints object + """ + + if not self._processed_extensions: + self._set_extensions() + return self._freshest_crl_value + + @property + def inhibit_any_policy_value(self): + """ + This extension is used to prevent mapping of the any policy to + specific requirements + + :return: + None or a Integer object + """ + + if not self._processed_extensions: + self._set_extensions() + return self._inhibit_any_policy_value + + @property + def extended_key_usage_value(self): + """ + This extension is used to define additional purposes for the public key + beyond what is contained in the basic constraints. + + :return: + None or an ExtKeyUsageSyntax object + """ + + if not self._processed_extensions: + self._set_extensions() + return self._extended_key_usage_value + + @property + def authority_information_access_value(self): + """ + This extension is used to locate the CA certificate used to sign this + certificate, or the OCSP responder for this certificate. + + :return: + None or an AuthorityInfoAccessSyntax object + """ + + if not self._processed_extensions: + self._set_extensions() + return self._authority_information_access_value + + @property + def subject_information_access_value(self): + """ + This extension is used to access information about the subject of this + certificate. + + :return: + None or a SubjectInfoAccessSyntax object + """ + + if not self._processed_extensions: + self._set_extensions() + return self._subject_information_access_value + + @property + def tls_feature_value(self): + """ + This extension is used to list the TLS features a server must respond + with if a client initiates a request supporting them. + + :return: + None or a Features object + """ + + if not self._processed_extensions: + self._set_extensions() + return self._tls_feature_value + + @property + def ocsp_no_check_value(self): + """ + This extension is used on certificates of OCSP responders, indicating + that revocation information for the certificate should never need to + be verified, thus preventing possible loops in path validation. + + :return: + None or a Null object (if present) + """ + + if not self._processed_extensions: + self._set_extensions() + return self._ocsp_no_check_value + + @property + def signature(self): + """ + :return: + A byte string of the signature + """ + + return self['signature_value'].native + + @property + def signature_algo(self): + """ + :return: + A unicode string of "rsassa_pkcs1v15", "rsassa_pss", "dsa", "ecdsa" + """ + + return self['signature_algorithm'].signature_algo + + @property + def hash_algo(self): + """ + :return: + A unicode string of "md2", "md5", "sha1", "sha224", "sha256", + "sha384", "sha512", "sha512_224", "sha512_256" + """ + + return self['signature_algorithm'].hash_algo + + @property + def public_key(self): + """ + :return: + The PublicKeyInfo object for this certificate + """ + + return self['tbs_certificate']['subject_public_key_info'] + + @property + def subject(self): + """ + :return: + The Name object for the subject of this certificate + """ + + return self['tbs_certificate']['subject'] + + @property + def issuer(self): + """ + :return: + The Name object for the issuer of this certificate + """ + + return self['tbs_certificate']['issuer'] + + @property + def serial_number(self): + """ + :return: + An integer of the certificate's serial number + """ + + return self['tbs_certificate']['serial_number'].native + + @property + def key_identifier(self): + """ + :return: + None or a byte string of the certificate's key identifier from the + key identifier extension + """ + + if not self.key_identifier_value: + return None + + return self.key_identifier_value.native + + @property + def issuer_serial(self): + """ + :return: + A byte string of the SHA-256 hash of the issuer concatenated with + the ascii character ":", concatenated with the serial number as + an ascii string + """ + + if self._issuer_serial is None: + self._issuer_serial = self.issuer.sha256 + b':' + str_cls(self.serial_number).encode('ascii') + return self._issuer_serial + + @property + def authority_key_identifier(self): + """ + :return: + None or a byte string of the key_identifier from the authority key + identifier extension + """ + + if not self.authority_key_identifier_value: + return None + + return self.authority_key_identifier_value['key_identifier'].native + + @property + def authority_issuer_serial(self): + """ + :return: + None or a byte string of the SHA-256 hash of the isser from the + authority key identifier extension concatenated with the ascii + character ":", concatenated with the serial number from the + authority key identifier extension as an ascii string + """ + + if self._authority_issuer_serial is False: + akiv = self.authority_key_identifier_value + if akiv and akiv['authority_cert_issuer'].native: + issuer = self.authority_key_identifier_value['authority_cert_issuer'][0].chosen + # We untag the element since it is tagged via being a choice from GeneralName + issuer = issuer.untag() + authority_serial = self.authority_key_identifier_value['authority_cert_serial_number'].native + self._authority_issuer_serial = issuer.sha256 + b':' + str_cls(authority_serial).encode('ascii') + else: + self._authority_issuer_serial = None + return self._authority_issuer_serial + + @property + def crl_distribution_points(self): + """ + Returns complete CRL URLs - does not include delta CRLs + + :return: + A list of zero or more DistributionPoint objects + """ + + if self._crl_distribution_points is None: + self._crl_distribution_points = self._get_http_crl_distribution_points(self.crl_distribution_points_value) + return self._crl_distribution_points + + @property + def delta_crl_distribution_points(self): + """ + Returns delta CRL URLs - does not include complete CRLs + + :return: + A list of zero or more DistributionPoint objects + """ + + if self._delta_crl_distribution_points is None: + self._delta_crl_distribution_points = self._get_http_crl_distribution_points(self.freshest_crl_value) + return self._delta_crl_distribution_points + + def _get_http_crl_distribution_points(self, crl_distribution_points): + """ + Fetches the DistributionPoint object for non-relative, HTTP CRLs + referenced by the certificate + + :param crl_distribution_points: + A CRLDistributionPoints object to grab the DistributionPoints from + + :return: + A list of zero or more DistributionPoint objects + """ + + output = [] + + if crl_distribution_points is None: + return [] + + for distribution_point in crl_distribution_points: + distribution_point_name = distribution_point['distribution_point'] + if distribution_point_name is VOID: + continue + # RFC 5280 indicates conforming CA should not use the relative form + if distribution_point_name.name == 'name_relative_to_crl_issuer': + continue + # This library is currently only concerned with HTTP-based CRLs + for general_name in distribution_point_name.chosen: + if general_name.name == 'uniform_resource_identifier': + output.append(distribution_point) + + return output + + @property + def ocsp_urls(self): + """ + :return: + A list of zero or more unicode strings of the OCSP URLs for this + cert + """ + + if not self.authority_information_access_value: + return [] + + output = [] + for entry in self.authority_information_access_value: + if entry['access_method'].native == 'ocsp': + location = entry['access_location'] + if location.name != 'uniform_resource_identifier': + continue + url = location.native + if url.lower().startswith(('http://', 'https://', 'ldap://', 'ldaps://')): + output.append(url) + return output + + @property + def valid_domains(self): + """ + :return: + A list of unicode strings of valid domain names for the certificate. + Wildcard certificates will have a domain in the form: *.example.com + """ + + if self._valid_domains is None: + self._valid_domains = [] + + # For the subject alt name extension, we can look at the name of + # the choice selected since it distinguishes between domain names, + # email addresses, IPs, etc + if self.subject_alt_name_value: + for general_name in self.subject_alt_name_value: + if general_name.name == 'dns_name' and general_name.native not in self._valid_domains: + self._valid_domains.append(general_name.native) + + # If there was no subject alt name extension, and the common name + # in the subject looks like a domain, that is considered the valid + # list. This is done because according to + # https://tools.ietf.org/html/rfc6125#section-6.4.4, the common + # name should not be used if the subject alt name is present. + else: + pattern = re.compile('^(\\*\\.)?(?:[a-zA-Z0-9](?:[a-zA-Z0-9\\-]*[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,}$') + for rdn in self.subject.chosen: + for name_type_value in rdn: + if name_type_value['type'].native == 'common_name': + value = name_type_value['value'].native + if pattern.match(value): + self._valid_domains.append(value) + + return self._valid_domains + + @property + def valid_ips(self): + """ + :return: + A list of unicode strings of valid IP addresses for the certificate + """ + + if self._valid_ips is None: + self._valid_ips = [] + + if self.subject_alt_name_value: + for general_name in self.subject_alt_name_value: + if general_name.name == 'ip_address': + self._valid_ips.append(general_name.native) + + return self._valid_ips + + @property + def ca(self): + """ + :return; + A boolean - if the certificate is marked as a CA + """ + + return self.basic_constraints_value and self.basic_constraints_value['ca'].native + + @property + def max_path_length(self): + """ + :return; + None or an integer of the maximum path length + """ + + if not self.ca: + return None + return self.basic_constraints_value['path_len_constraint'].native + + @property + def self_issued(self): + """ + :return: + A boolean - if the certificate is self-issued, as defined by RFC + 5280 + """ + + if self._self_issued is None: + self._self_issued = self.subject == self.issuer + return self._self_issued + + @property + def self_signed(self): + """ + :return: + A unicode string of "no" or "maybe". The "maybe" result will + be returned if the certificate issuer and subject are the same. + If a key identifier and authority key identifier are present, + they will need to match otherwise "no" will be returned. + + To verify is a certificate is truly self-signed, the signature + will need to be verified. See the certvalidator package for + one possible solution. + """ + + if self._self_signed is None: + self._self_signed = 'no' + if self.self_issued: + if self.key_identifier: + if not self.authority_key_identifier: + self._self_signed = 'maybe' + elif self.authority_key_identifier == self.key_identifier: + self._self_signed = 'maybe' + else: + self._self_signed = 'maybe' + return self._self_signed + + @property + def sha1(self): + """ + :return: + The SHA-1 hash of the DER-encoded bytes of this complete certificate + """ + + if self._sha1 is None: + self._sha1 = hashlib.sha1(self.dump()).digest() + return self._sha1 + + @property + def sha1_fingerprint(self): + """ + :return: + A unicode string of the SHA-1 hash, formatted using hex encoding + with a space between each pair of characters, all uppercase + """ + + return ' '.join('%02X' % c for c in bytes_to_list(self.sha1)) + + @property + def sha256(self): + """ + :return: + The SHA-256 hash of the DER-encoded bytes of this complete + certificate + """ + + if self._sha256 is None: + self._sha256 = hashlib.sha256(self.dump()).digest() + return self._sha256 + + @property + def sha256_fingerprint(self): + """ + :return: + A unicode string of the SHA-256 hash, formatted using hex encoding + with a space between each pair of characters, all uppercase + """ + + return ' '.join('%02X' % c for c in bytes_to_list(self.sha256)) + + def is_valid_domain_ip(self, domain_ip): + """ + Check if a domain name or IP address is valid according to the + certificate + + :param domain_ip: + A unicode string of a domain name or IP address + + :return: + A boolean - if the domain or IP is valid for the certificate + """ + + if not isinstance(domain_ip, str_cls): + raise TypeError(unwrap( + ''' + domain_ip must be a unicode string, not %s + ''', + type_name(domain_ip) + )) + + encoded_domain_ip = domain_ip.encode('idna').decode('ascii').lower() + + is_ipv6 = encoded_domain_ip.find(':') != -1 + is_ipv4 = not is_ipv6 and re.match('^\\d+\\.\\d+\\.\\d+\\.\\d+$', encoded_domain_ip) + is_domain = not is_ipv6 and not is_ipv4 + + # Handle domain name checks + if is_domain: + if not self.valid_domains: + return False + + domain_labels = encoded_domain_ip.split('.') + + for valid_domain in self.valid_domains: + encoded_valid_domain = valid_domain.encode('idna').decode('ascii').lower() + valid_domain_labels = encoded_valid_domain.split('.') + + # The domain must be equal in label length to match + if len(valid_domain_labels) != len(domain_labels): + continue + + if valid_domain_labels == domain_labels: + return True + + is_wildcard = self._is_wildcard_domain(encoded_valid_domain) + if is_wildcard and self._is_wildcard_match(domain_labels, valid_domain_labels): + return True + + return False + + # Handle IP address checks + if not self.valid_ips: + return False + + family = socket.AF_INET if is_ipv4 else socket.AF_INET6 + normalized_ip = inet_pton(family, encoded_domain_ip) + + for valid_ip in self.valid_ips: + valid_family = socket.AF_INET if valid_ip.find('.') != -1 else socket.AF_INET6 + normalized_valid_ip = inet_pton(valid_family, valid_ip) + + if normalized_valid_ip == normalized_ip: + return True + + return False + + def _is_wildcard_domain(self, domain): + """ + Checks if a domain is a valid wildcard according to + https://tools.ietf.org/html/rfc6125#section-6.4.3 + + :param domain: + A unicode string of the domain name, where any U-labels from an IDN + have been converted to A-labels + + :return: + A boolean - if the domain is a valid wildcard domain + """ + + # The * character must be present for a wildcard match, and if there is + # most than one, it is an invalid wildcard specification + if domain.count('*') != 1: + return False + + labels = domain.lower().split('.') + + if not labels: + return False + + # Wildcards may only appear in the left-most label + if labels[0].find('*') == -1: + return False + + # Wildcards may not be embedded in an A-label from an IDN + if labels[0][0:4] == 'xn--': + return False + + return True + + def _is_wildcard_match(self, domain_labels, valid_domain_labels): + """ + Determines if the labels in a domain are a match for labels from a + wildcard valid domain name + + :param domain_labels: + A list of unicode strings, with A-label form for IDNs, of the labels + in the domain name to check + + :param valid_domain_labels: + A list of unicode strings, with A-label form for IDNs, of the labels + in a wildcard domain pattern + + :return: + A boolean - if the domain matches the valid domain + """ + + first_domain_label = domain_labels[0] + other_domain_labels = domain_labels[1:] + + wildcard_label = valid_domain_labels[0] + other_valid_domain_labels = valid_domain_labels[1:] + + # The wildcard is only allowed in the first label, so if + # The subsequent labels are not equal, there is no match + if other_domain_labels != other_valid_domain_labels: + return False + + if wildcard_label == '*': + return True + + wildcard_regex = re.compile('^' + wildcard_label.replace('*', '.*') + '$') + if wildcard_regex.match(first_domain_label): + return True + + return False + + +# The structures are taken from the OpenSSL source file x_x509a.c, and specify +# extra information that is added to X.509 certificates to store trust +# information about the certificate. + +class KeyPurposeIdentifiers(SequenceOf): + _child_spec = KeyPurposeId + + +class SequenceOfAlgorithmIdentifiers(SequenceOf): + _child_spec = AlgorithmIdentifier + + +class CertificateAux(Sequence): + _fields = [ + ('trust', KeyPurposeIdentifiers, {'optional': True}), + ('reject', KeyPurposeIdentifiers, {'implicit': 0, 'optional': True}), + ('alias', UTF8String, {'optional': True}), + ('keyid', OctetString, {'optional': True}), + ('other', SequenceOfAlgorithmIdentifiers, {'implicit': 1, 'optional': True}), + ] + + +class TrustedCertificate(Concat): + _child_specs = [Certificate, CertificateAux] diff --git a/venv/lib/python2.7/site-packages/babel/__init__.py b/venv/lib/python2.7/site-packages/babel/__init__.py new file mode 100644 index 0000000..de44ce6 --- /dev/null +++ b/venv/lib/python2.7/site-packages/babel/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +""" + babel + ~~~~~ + + Integrated collection of utilities that assist in internationalizing and + localizing applications. + + This package is basically composed of two major parts: + + * tools to build and work with ``gettext`` message catalogs + * a Python interface to the CLDR (Common Locale Data Repository), providing + access to various locale display names, localized number and date + formatting, etc. + + :copyright: (c) 2013-2018 by the Babel Team. + :license: BSD, see LICENSE for more details. +""" + +from babel.core import UnknownLocaleError, Locale, default_locale, \ + negotiate_locale, parse_locale, get_locale_identifier + + +__version__ = '2.6.0' diff --git a/venv/lib/python2.7/site-packages/babel/_compat.py b/venv/lib/python2.7/site-packages/babel/_compat.py new file mode 100644 index 0000000..1131f44 --- /dev/null +++ b/venv/lib/python2.7/site-packages/babel/_compat.py @@ -0,0 +1,80 @@ +import sys +import array + +PY2 = sys.version_info[0] == 2 + +_identity = lambda x: x + + +if not PY2: + text_type = str + binary_type = bytes + string_types = (str,) + integer_types = (int, ) + + text_to_native = lambda s, enc: s + unichr = chr + + iterkeys = lambda d: iter(d.keys()) + itervalues = lambda d: iter(d.values()) + iteritems = lambda d: iter(d.items()) + + from io import StringIO, BytesIO + import pickle + + izip = zip + imap = map + range_type = range + + cmp = lambda a, b: (a > b) - (a < b) + + array_tobytes = array.array.tobytes + +else: + text_type = unicode + binary_type = str + string_types = (str, unicode) + integer_types = (int, long) + + text_to_native = lambda s, enc: s.encode(enc) + unichr = unichr + + iterkeys = lambda d: d.iterkeys() + itervalues = lambda d: d.itervalues() + iteritems = lambda d: d.iteritems() + + from cStringIO import StringIO as BytesIO + from StringIO import StringIO + import cPickle as pickle + + from itertools import imap + from itertools import izip + range_type = xrange + + cmp = cmp + + array_tobytes = array.array.tostring + + +number_types = integer_types + (float,) + + +def force_text(s, encoding='utf-8', errors='strict'): + if isinstance(s, text_type): + return s + if isinstance(s, binary_type): + return s.decode(encoding, errors) + return text_type(s) + + +# +# Since Python 3.3, a fast decimal implementation is already included in the +# standard library. Otherwise use cdecimal when available +# +if sys.version_info[:2] >= (3, 3): + import decimal +else: + try: + import cdecimal as decimal + except ImportError: + import decimal diff --git a/venv/lib/python2.7/site-packages/babel/core.py b/venv/lib/python2.7/site-packages/babel/core.py new file mode 100644 index 0000000..d028c07 --- /dev/null +++ b/venv/lib/python2.7/site-packages/babel/core.py @@ -0,0 +1,1133 @@ +# -*- coding: utf-8 -*- +""" + babel.core + ~~~~~~~~~~ + + Core locale representation and locale data access. + + :copyright: (c) 2013-2018 by the Babel Team. + :license: BSD, see LICENSE for more details. +""" + +import os + +from babel import localedata +from babel._compat import pickle, string_types +from babel.plural import PluralRule + +__all__ = ['UnknownLocaleError', 'Locale', 'default_locale', 'negotiate_locale', + 'parse_locale'] + + +_global_data = None +_default_plural_rule = PluralRule({}) + + +def _raise_no_data_error(): + raise RuntimeError('The babel data files are not available. ' + 'This usually happens because you are using ' + 'a source checkout from Babel and you did ' + 'not build the data files. Just make sure ' + 'to run "python setup.py import_cldr" before ' + 'installing the library.') + + +def get_global(key): + """Return the dictionary for the given key in the global data. + + The global data is stored in the ``babel/global.dat`` file and contains + information independent of individual locales. + + >>> get_global('zone_aliases')['UTC'] + u'Etc/UTC' + >>> get_global('zone_territories')['Europe/Berlin'] + u'DE' + + The keys available are: + + - ``all_currencies`` + - ``currency_fractions`` + - ``language_aliases`` + - ``likely_subtags`` + - ``parent_exceptions`` + - ``script_aliases`` + - ``territory_aliases`` + - ``territory_currencies`` + - ``territory_languages`` + - ``territory_zones`` + - ``variant_aliases`` + - ``windows_zone_mapping`` + - ``zone_aliases`` + - ``zone_territories`` + + .. note:: The internal structure of the data may change between versions. + + .. versionadded:: 0.9 + + :param key: the data key + """ + global _global_data + if _global_data is None: + dirname = os.path.join(os.path.dirname(__file__)) + filename = os.path.join(dirname, 'global.dat') + if not os.path.isfile(filename): + _raise_no_data_error() + with open(filename, 'rb') as fileobj: + _global_data = pickle.load(fileobj) + return _global_data.get(key, {}) + + +LOCALE_ALIASES = { + 'ar': 'ar_SY', 'bg': 'bg_BG', 'bs': 'bs_BA', 'ca': 'ca_ES', 'cs': 'cs_CZ', + 'da': 'da_DK', 'de': 'de_DE', 'el': 'el_GR', 'en': 'en_US', 'es': 'es_ES', + 'et': 'et_EE', 'fa': 'fa_IR', 'fi': 'fi_FI', 'fr': 'fr_FR', 'gl': 'gl_ES', + 'he': 'he_IL', 'hu': 'hu_HU', 'id': 'id_ID', 'is': 'is_IS', 'it': 'it_IT', + 'ja': 'ja_JP', 'km': 'km_KH', 'ko': 'ko_KR', 'lt': 'lt_LT', 'lv': 'lv_LV', + 'mk': 'mk_MK', 'nl': 'nl_NL', 'nn': 'nn_NO', 'no': 'nb_NO', 'pl': 'pl_PL', + 'pt': 'pt_PT', 'ro': 'ro_RO', 'ru': 'ru_RU', 'sk': 'sk_SK', 'sl': 'sl_SI', + 'sv': 'sv_SE', 'th': 'th_TH', 'tr': 'tr_TR', 'uk': 'uk_UA' +} + + +class UnknownLocaleError(Exception): + """Exception thrown when a locale is requested for which no locale data + is available. + """ + + def __init__(self, identifier): + """Create the exception. + + :param identifier: the identifier string of the unsupported locale + """ + Exception.__init__(self, 'unknown locale %r' % identifier) + + #: The identifier of the locale that could not be found. + self.identifier = identifier + + +class Locale(object): + """Representation of a specific locale. + + >>> locale = Locale('en', 'US') + >>> repr(locale) + "Locale('en', territory='US')" + >>> locale.display_name + u'English (United States)' + + A `Locale` object can also be instantiated from a raw locale string: + + >>> locale = Locale.parse('en-US', sep='-') + >>> repr(locale) + "Locale('en', territory='US')" + + `Locale` objects provide access to a collection of locale data, such as + territory and language names, number and date format patterns, and more: + + >>> locale.number_symbols['decimal'] + u'.' + + If a locale is requested for which no locale data is available, an + `UnknownLocaleError` is raised: + + >>> Locale.parse('en_XX') + Traceback (most recent call last): + ... + UnknownLocaleError: unknown locale 'en_XX' + + For more information see :rfc:`3066`. + """ + + def __init__(self, language, territory=None, script=None, variant=None): + """Initialize the locale object from the given identifier components. + + >>> locale = Locale('en', 'US') + >>> locale.language + 'en' + >>> locale.territory + 'US' + + :param language: the language code + :param territory: the territory (country or region) code + :param script: the script code + :param variant: the variant code + :raise `UnknownLocaleError`: if no locale data is available for the + requested locale + """ + #: the language code + self.language = language + #: the territory (country or region) code + self.territory = territory + #: the script code + self.script = script + #: the variant code + self.variant = variant + self.__data = None + + identifier = str(self) + if not localedata.exists(identifier): + raise UnknownLocaleError(identifier) + + @classmethod + def default(cls, category=None, aliases=LOCALE_ALIASES): + """Return the system default locale for the specified category. + + >>> for name in ['LANGUAGE', 'LC_ALL', 'LC_CTYPE', 'LC_MESSAGES']: + ... os.environ[name] = '' + >>> os.environ['LANG'] = 'fr_FR.UTF-8' + >>> Locale.default('LC_MESSAGES') + Locale('fr', territory='FR') + + The following fallbacks to the variable are always considered: + + - ``LANGUAGE`` + - ``LC_ALL`` + - ``LC_CTYPE`` + - ``LANG`` + + :param category: one of the ``LC_XXX`` environment variable names + :param aliases: a dictionary of aliases for locale identifiers + """ + # XXX: use likely subtag expansion here instead of the + # aliases dictionary. + locale_string = default_locale(category, aliases=aliases) + return cls.parse(locale_string) + + @classmethod + def negotiate(cls, preferred, available, sep='_', aliases=LOCALE_ALIASES): + """Find the best match between available and requested locale strings. + + >>> Locale.negotiate(['de_DE', 'en_US'], ['de_DE', 'de_AT']) + Locale('de', territory='DE') + >>> Locale.negotiate(['de_DE', 'en_US'], ['en', 'de']) + Locale('de') + >>> Locale.negotiate(['de_DE', 'de'], ['en_US']) + + You can specify the character used in the locale identifiers to separate + the differnet components. This separator is applied to both lists. Also, + case is ignored in the comparison: + + >>> Locale.negotiate(['de-DE', 'de'], ['en-us', 'de-de'], sep='-') + Locale('de', territory='DE') + + :param preferred: the list of locale identifers preferred by the user + :param available: the list of locale identifiers available + :param aliases: a dictionary of aliases for locale identifiers + """ + identifier = negotiate_locale(preferred, available, sep=sep, + aliases=aliases) + if identifier: + return Locale.parse(identifier, sep=sep) + + @classmethod + def parse(cls, identifier, sep='_', resolve_likely_subtags=True): + """Create a `Locale` instance for the given locale identifier. + + >>> l = Locale.parse('de-DE', sep='-') + >>> l.display_name + u'Deutsch (Deutschland)' + + If the `identifier` parameter is not a string, but actually a `Locale` + object, that object is returned: + + >>> Locale.parse(l) + Locale('de', territory='DE') + + This also can perform resolving of likely subtags which it does + by default. This is for instance useful to figure out the most + likely locale for a territory you can use ``'und'`` as the + language tag: + + >>> Locale.parse('und_AT') + Locale('de', territory='AT') + + :param identifier: the locale identifier string + :param sep: optional component separator + :param resolve_likely_subtags: if this is specified then a locale will + have its likely subtag resolved if the + locale otherwise does not exist. For + instance ``zh_TW`` by itself is not a + locale that exists but Babel can + automatically expand it to the full + form of ``zh_hant_TW``. Note that this + expansion is only taking place if no + locale exists otherwise. For instance + there is a locale ``en`` that can exist + by itself. + :raise `ValueError`: if the string does not appear to be a valid locale + identifier + :raise `UnknownLocaleError`: if no locale data is available for the + requested locale + """ + if identifier is None: + return None + elif isinstance(identifier, Locale): + return identifier + elif not isinstance(identifier, string_types): + raise TypeError('Unexpected value for identifier: %r' % (identifier,)) + + parts = parse_locale(identifier, sep=sep) + input_id = get_locale_identifier(parts) + + def _try_load(parts): + try: + return cls(*parts) + except UnknownLocaleError: + return None + + def _try_load_reducing(parts): + # Success on first hit, return it. + locale = _try_load(parts) + if locale is not None: + return locale + + # Now try without script and variant + locale = _try_load(parts[:2]) + if locale is not None: + return locale + + locale = _try_load(parts) + if locale is not None: + return locale + if not resolve_likely_subtags: + raise UnknownLocaleError(input_id) + + # From here onwards is some very bad likely subtag resolving. This + # whole logic is not entirely correct but good enough (tm) for the + # time being. This has been added so that zh_TW does not cause + # errors for people when they upgrade. Later we should properly + # implement ICU like fuzzy locale objects and provide a way to + # maximize and minimize locale tags. + + language, territory, script, variant = parts + language = get_global('language_aliases').get(language, language) + territory = get_global('territory_aliases').get(territory, (territory,))[0] + script = get_global('script_aliases').get(script, script) + variant = get_global('variant_aliases').get(variant, variant) + + if territory == 'ZZ': + territory = None + if script == 'Zzzz': + script = None + + parts = language, territory, script, variant + + # First match: try the whole identifier + new_id = get_locale_identifier(parts) + likely_subtag = get_global('likely_subtags').get(new_id) + if likely_subtag is not None: + locale = _try_load_reducing(parse_locale(likely_subtag)) + if locale is not None: + return locale + + # If we did not find anything so far, try again with a + # simplified identifier that is just the language + likely_subtag = get_global('likely_subtags').get(language) + if likely_subtag is not None: + language2, _, script2, variant2 = parse_locale(likely_subtag) + locale = _try_load_reducing((language2, territory, script2, variant2)) + if locale is not None: + return locale + + raise UnknownLocaleError(input_id) + + def __eq__(self, other): + for key in ('language', 'territory', 'script', 'variant'): + if not hasattr(other, key): + return False + return (self.language == other.language) and \ + (self.territory == other.territory) and \ + (self.script == other.script) and \ + (self.variant == other.variant) + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return hash((self.language, self.territory, self.script, self.variant)) + + def __repr__(self): + parameters = [''] + for key in ('territory', 'script', 'variant'): + value = getattr(self, key) + if value is not None: + parameters.append('%s=%r' % (key, value)) + parameter_string = '%r' % self.language + ', '.join(parameters) + return 'Locale(%s)' % parameter_string + + def __str__(self): + return get_locale_identifier((self.language, self.territory, + self.script, self.variant)) + + @property + def _data(self): + if self.__data is None: + self.__data = localedata.LocaleDataDict(localedata.load(str(self))) + return self.__data + + def get_display_name(self, locale=None): + """Return the display name of the locale using the given locale. + + The display name will include the language, territory, script, and + variant, if those are specified. + + >>> Locale('zh', 'CN', script='Hans').get_display_name('en') + u'Chinese (Simplified, China)' + + :param locale: the locale to use + """ + if locale is None: + locale = self + locale = Locale.parse(locale) + retval = locale.languages.get(self.language) + if self.territory or self.script or self.variant: + details = [] + if self.script: + details.append(locale.scripts.get(self.script)) + if self.territory: + details.append(locale.territories.get(self.territory)) + if self.variant: + details.append(locale.variants.get(self.variant)) + details = filter(None, details) + if details: + retval += ' (%s)' % u', '.join(details) + return retval + + display_name = property(get_display_name, doc="""\ + The localized display name of the locale. + + >>> Locale('en').display_name + u'English' + >>> Locale('en', 'US').display_name + u'English (United States)' + >>> Locale('sv').display_name + u'svenska' + + :type: `unicode` + """) + + def get_language_name(self, locale=None): + """Return the language of this locale in the given locale. + + >>> Locale('zh', 'CN', script='Hans').get_language_name('de') + u'Chinesisch' + + .. versionadded:: 1.0 + + :param locale: the locale to use + """ + if locale is None: + locale = self + locale = Locale.parse(locale) + return locale.languages.get(self.language) + + language_name = property(get_language_name, doc="""\ + The localized language name of the locale. + + >>> Locale('en', 'US').language_name + u'English' + """) + + def get_territory_name(self, locale=None): + """Return the territory name in the given locale.""" + if locale is None: + locale = self + locale = Locale.parse(locale) + return locale.territories.get(self.territory) + + territory_name = property(get_territory_name, doc="""\ + The localized territory name of the locale if available. + + >>> Locale('de', 'DE').territory_name + u'Deutschland' + """) + + def get_script_name(self, locale=None): + """Return the script name in the given locale.""" + if locale is None: + locale = self + locale = Locale.parse(locale) + return locale.scripts.get(self.script) + + script_name = property(get_script_name, doc="""\ + The localized script name of the locale if available. + + >>> Locale('sr', 'ME', script='Latn').script_name + u'latinica' + """) + + @property + def english_name(self): + """The english display name of the locale. + + >>> Locale('de').english_name + u'German' + >>> Locale('de', 'DE').english_name + u'German (Germany)' + + :type: `unicode`""" + return self.get_display_name(Locale('en')) + + # { General Locale Display Names + + @property + def languages(self): + """Mapping of language codes to translated language names. + + >>> Locale('de', 'DE').languages['ja'] + u'Japanisch' + + See `ISO 639 `_ for + more information. + """ + return self._data['languages'] + + @property + def scripts(self): + """Mapping of script codes to translated script names. + + >>> Locale('en', 'US').scripts['Hira'] + u'Hiragana' + + See `ISO 15924 `_ + for more information. + """ + return self._data['scripts'] + + @property + def territories(self): + """Mapping of script codes to translated script names. + + >>> Locale('es', 'CO').territories['DE'] + u'Alemania' + + See `ISO 3166 `_ + for more information. + """ + return self._data['territories'] + + @property + def variants(self): + """Mapping of script codes to translated script names. + + >>> Locale('de', 'DE').variants['1901'] + u'Alte deutsche Rechtschreibung' + """ + return self._data['variants'] + + # { Number Formatting + + @property + def currencies(self): + """Mapping of currency codes to translated currency names. This + only returns the generic form of the currency name, not the count + specific one. If an actual number is requested use the + :func:`babel.numbers.get_currency_name` function. + + >>> Locale('en').currencies['COP'] + u'Colombian Peso' + >>> Locale('de', 'DE').currencies['COP'] + u'Kolumbianischer Peso' + """ + return self._data['currency_names'] + + @property + def currency_symbols(self): + """Mapping of currency codes to symbols. + + >>> Locale('en', 'US').currency_symbols['USD'] + u'$' + >>> Locale('es', 'CO').currency_symbols['USD'] + u'US$' + """ + return self._data['currency_symbols'] + + @property + def number_symbols(self): + """Symbols used in number formatting. + + .. note:: The format of the value returned may change between + Babel versions. + + >>> Locale('fr', 'FR').number_symbols['decimal'] + u',' + """ + return self._data['number_symbols'] + + @property + def decimal_formats(self): + """Locale patterns for decimal number formatting. + + .. note:: The format of the value returned may change between + Babel versions. + + >>> Locale('en', 'US').decimal_formats[None] + + """ + return self._data['decimal_formats'] + + @property + def currency_formats(self): + """Locale patterns for currency number formatting. + + .. note:: The format of the value returned may change between + Babel versions. + + >>> Locale('en', 'US').currency_formats['standard'] + + >>> Locale('en', 'US').currency_formats['accounting'] + + """ + return self._data['currency_formats'] + + @property + def percent_formats(self): + """Locale patterns for percent number formatting. + + .. note:: The format of the value returned may change between + Babel versions. + + >>> Locale('en', 'US').percent_formats[None] + + """ + return self._data['percent_formats'] + + @property + def scientific_formats(self): + """Locale patterns for scientific number formatting. + + .. note:: The format of the value returned may change between + Babel versions. + + >>> Locale('en', 'US').scientific_formats[None] + + """ + return self._data['scientific_formats'] + + # { Calendar Information and Date Formatting + + @property + def periods(self): + """Locale display names for day periods (AM/PM). + + >>> Locale('en', 'US').periods['am'] + u'AM' + """ + try: + return self._data['day_periods']['stand-alone']['wide'] + except KeyError: + return {} + + @property + def day_periods(self): + """Locale display names for various day periods (not necessarily only AM/PM). + + These are not meant to be used without the relevant `day_period_rules`. + """ + return self._data['day_periods'] + + @property + def day_period_rules(self): + """Day period rules for the locale. Used by `get_period_id`. + """ + return self._data.get('day_period_rules', {}) + + @property + def days(self): + """Locale display names for weekdays. + + >>> Locale('de', 'DE').days['format']['wide'][3] + u'Donnerstag' + """ + return self._data['days'] + + @property + def months(self): + """Locale display names for months. + + >>> Locale('de', 'DE').months['format']['wide'][10] + u'Oktober' + """ + return self._data['months'] + + @property + def quarters(self): + """Locale display names for quarters. + + >>> Locale('de', 'DE').quarters['format']['wide'][1] + u'1. Quartal' + """ + return self._data['quarters'] + + @property + def eras(self): + """Locale display names for eras. + + .. note:: The format of the value returned may change between + Babel versions. + + >>> Locale('en', 'US').eras['wide'][1] + u'Anno Domini' + >>> Locale('en', 'US').eras['abbreviated'][0] + u'BC' + """ + return self._data['eras'] + + @property + def time_zones(self): + """Locale display names for time zones. + + .. note:: The format of the value returned may change between + Babel versions. + + >>> Locale('en', 'US').time_zones['Europe/London']['long']['daylight'] + u'British Summer Time' + >>> Locale('en', 'US').time_zones['America/St_Johns']['city'] + u'St. John\u2019s' + """ + return self._data['time_zones'] + + @property + def meta_zones(self): + """Locale display names for meta time zones. + + Meta time zones are basically groups of different Olson time zones that + have the same GMT offset and daylight savings time. + + .. note:: The format of the value returned may change between + Babel versions. + + >>> Locale('en', 'US').meta_zones['Europe_Central']['long']['daylight'] + u'Central European Summer Time' + + .. versionadded:: 0.9 + """ + return self._data['meta_zones'] + + @property + def zone_formats(self): + """Patterns related to the formatting of time zones. + + .. note:: The format of the value returned may change between + Babel versions. + + >>> Locale('en', 'US').zone_formats['fallback'] + u'%(1)s (%(0)s)' + >>> Locale('pt', 'BR').zone_formats['region'] + u'Hor\\xe1rio %s' + + .. versionadded:: 0.9 + """ + return self._data['zone_formats'] + + @property + def first_week_day(self): + """The first day of a week, with 0 being Monday. + + >>> Locale('de', 'DE').first_week_day + 0 + >>> Locale('en', 'US').first_week_day + 6 + """ + return self._data['week_data']['first_day'] + + @property + def weekend_start(self): + """The day the weekend starts, with 0 being Monday. + + >>> Locale('de', 'DE').weekend_start + 5 + """ + return self._data['week_data']['weekend_start'] + + @property + def weekend_end(self): + """The day the weekend ends, with 0 being Monday. + + >>> Locale('de', 'DE').weekend_end + 6 + """ + return self._data['week_data']['weekend_end'] + + @property + def min_week_days(self): + """The minimum number of days in a week so that the week is counted as + the first week of a year or month. + + >>> Locale('de', 'DE').min_week_days + 4 + """ + return self._data['week_data']['min_days'] + + @property + def date_formats(self): + """Locale patterns for date formatting. + + .. note:: The format of the value returned may change between + Babel versions. + + >>> Locale('en', 'US').date_formats['short'] + + >>> Locale('fr', 'FR').date_formats['long'] + + """ + return self._data['date_formats'] + + @property + def time_formats(self): + """Locale patterns for time formatting. + + .. note:: The format of the value returned may change between + Babel versions. + + >>> Locale('en', 'US').time_formats['short'] + + >>> Locale('fr', 'FR').time_formats['long'] + + """ + return self._data['time_formats'] + + @property + def datetime_formats(self): + """Locale patterns for datetime formatting. + + .. note:: The format of the value returned may change between + Babel versions. + + >>> Locale('en').datetime_formats['full'] + u"{1} 'at' {0}" + >>> Locale('th').datetime_formats['medium'] + u'{1} {0}' + """ + return self._data['datetime_formats'] + + @property + def datetime_skeletons(self): + """Locale patterns for formatting parts of a datetime. + + >>> Locale('en').datetime_skeletons['MEd'] + + >>> Locale('fr').datetime_skeletons['MEd'] + + >>> Locale('fr').datetime_skeletons['H'] + + """ + return self._data['datetime_skeletons'] + + @property + def interval_formats(self): + """Locale patterns for interval formatting. + + .. note:: The format of the value returned may change between + Babel versions. + + How to format date intervals in Finnish when the day is the + smallest changing component: + + >>> Locale('fi_FI').interval_formats['MEd']['d'] + [u'E d. \u2013 ', u'E d.M.'] + + .. seealso:: + + The primary API to use this data is :py:func:`babel.dates.format_interval`. + + + :rtype: dict[str, dict[str, list[str]]] + """ + return self._data['interval_formats'] + + @property + def plural_form(self): + """Plural rules for the locale. + + >>> Locale('en').plural_form(1) + 'one' + >>> Locale('en').plural_form(0) + 'other' + >>> Locale('fr').plural_form(0) + 'one' + >>> Locale('ru').plural_form(100) + 'many' + """ + return self._data.get('plural_form', _default_plural_rule) + + @property + def list_patterns(self): + """Patterns for generating lists + + .. note:: The format of the value returned may change between + Babel versions. + + >>> Locale('en').list_patterns['standard']['start'] + u'{0}, {1}' + >>> Locale('en').list_patterns['standard']['end'] + u'{0}, and {1}' + >>> Locale('en_GB').list_patterns['standard']['end'] + u'{0} and {1}' + """ + return self._data['list_patterns'] + + @property + def ordinal_form(self): + """Plural rules for the locale. + + >>> Locale('en').ordinal_form(1) + 'one' + >>> Locale('en').ordinal_form(2) + 'two' + >>> Locale('en').ordinal_form(3) + 'few' + >>> Locale('fr').ordinal_form(2) + 'other' + >>> Locale('ru').ordinal_form(100) + 'other' + """ + return self._data.get('ordinal_form', _default_plural_rule) + + @property + def measurement_systems(self): + """Localized names for various measurement systems. + + >>> Locale('fr', 'FR').measurement_systems['US'] + u'am\\xe9ricain' + >>> Locale('en', 'US').measurement_systems['US'] + u'US' + + """ + return self._data['measurement_systems'] + + @property + def character_order(self): + """The text direction for the language. + + >>> Locale('de', 'DE').character_order + 'left-to-right' + >>> Locale('ar', 'SA').character_order + 'right-to-left' + """ + return self._data['character_order'] + + @property + def text_direction(self): + """The text direction for the language in CSS short-hand form. + + >>> Locale('de', 'DE').text_direction + 'ltr' + >>> Locale('ar', 'SA').text_direction + 'rtl' + """ + return ''.join(word[0] for word in self.character_order.split('-')) + + @property + def unit_display_names(self): + """Display names for units of measurement. + + .. seealso:: + + You may want to use :py:func:`babel.units.get_unit_name` instead. + + .. note:: The format of the value returned may change between + Babel versions. + + """ + return self._data['unit_display_names'] + + +def default_locale(category=None, aliases=LOCALE_ALIASES): + """Returns the system default locale for a given category, based on + environment variables. + + >>> for name in ['LANGUAGE', 'LC_ALL', 'LC_CTYPE']: + ... os.environ[name] = '' + >>> os.environ['LANG'] = 'fr_FR.UTF-8' + >>> default_locale('LC_MESSAGES') + 'fr_FR' + + The "C" or "POSIX" pseudo-locales are treated as aliases for the + "en_US_POSIX" locale: + + >>> os.environ['LC_MESSAGES'] = 'POSIX' + >>> default_locale('LC_MESSAGES') + 'en_US_POSIX' + + The following fallbacks to the variable are always considered: + + - ``LANGUAGE`` + - ``LC_ALL`` + - ``LC_CTYPE`` + - ``LANG`` + + :param category: one of the ``LC_XXX`` environment variable names + :param aliases: a dictionary of aliases for locale identifiers + """ + varnames = (category, 'LANGUAGE', 'LC_ALL', 'LC_CTYPE', 'LANG') + for name in filter(None, varnames): + locale = os.getenv(name) + if locale: + if name == 'LANGUAGE' and ':' in locale: + # the LANGUAGE variable may contain a colon-separated list of + # language codes; we just pick the language on the list + locale = locale.split(':')[0] + if locale.split('.')[0] in ('C', 'POSIX'): + locale = 'en_US_POSIX' + elif aliases and locale in aliases: + locale = aliases[locale] + try: + return get_locale_identifier(parse_locale(locale)) + except ValueError: + pass + + +def negotiate_locale(preferred, available, sep='_', aliases=LOCALE_ALIASES): + """Find the best match between available and requested locale strings. + + >>> negotiate_locale(['de_DE', 'en_US'], ['de_DE', 'de_AT']) + 'de_DE' + >>> negotiate_locale(['de_DE', 'en_US'], ['en', 'de']) + 'de' + + Case is ignored by the algorithm, the result uses the case of the preferred + locale identifier: + + >>> negotiate_locale(['de_DE', 'en_US'], ['de_de', 'de_at']) + 'de_DE' + + >>> negotiate_locale(['de_DE', 'en_US'], ['de_de', 'de_at']) + 'de_DE' + + By default, some web browsers unfortunately do not include the territory + in the locale identifier for many locales, and some don't even allow the + user to easily add the territory. So while you may prefer using qualified + locale identifiers in your web-application, they would not normally match + the language-only locale sent by such browsers. To workaround that, this + function uses a default mapping of commonly used langauge-only locale + identifiers to identifiers including the territory: + + >>> negotiate_locale(['ja', 'en_US'], ['ja_JP', 'en_US']) + 'ja_JP' + + Some browsers even use an incorrect or outdated language code, such as "no" + for Norwegian, where the correct locale identifier would actually be "nb_NO" + (Bokmål) or "nn_NO" (Nynorsk). The aliases are intended to take care of + such cases, too: + + >>> negotiate_locale(['no', 'sv'], ['nb_NO', 'sv_SE']) + 'nb_NO' + + You can override this default mapping by passing a different `aliases` + dictionary to this function, or you can bypass the behavior althogher by + setting the `aliases` parameter to `None`. + + :param preferred: the list of locale strings preferred by the user + :param available: the list of locale strings available + :param sep: character that separates the different parts of the locale + strings + :param aliases: a dictionary of aliases for locale identifiers + """ + available = [a.lower() for a in available if a] + for locale in preferred: + ll = locale.lower() + if ll in available: + return locale + if aliases: + alias = aliases.get(ll) + if alias: + alias = alias.replace('_', sep) + if alias.lower() in available: + return alias + parts = locale.split(sep) + if len(parts) > 1 and parts[0].lower() in available: + return parts[0] + return None + + +def parse_locale(identifier, sep='_'): + """Parse a locale identifier into a tuple of the form ``(language, + territory, script, variant)``. + + >>> parse_locale('zh_CN') + ('zh', 'CN', None, None) + >>> parse_locale('zh_Hans_CN') + ('zh', 'CN', 'Hans', None) + + The default component separator is "_", but a different separator can be + specified using the `sep` parameter: + + >>> parse_locale('zh-CN', sep='-') + ('zh', 'CN', None, None) + + If the identifier cannot be parsed into a locale, a `ValueError` exception + is raised: + + >>> parse_locale('not_a_LOCALE_String') + Traceback (most recent call last): + ... + ValueError: 'not_a_LOCALE_String' is not a valid locale identifier + + Encoding information and locale modifiers are removed from the identifier: + + >>> parse_locale('it_IT@euro') + ('it', 'IT', None, None) + >>> parse_locale('en_US.UTF-8') + ('en', 'US', None, None) + >>> parse_locale('de_DE.iso885915@euro') + ('de', 'DE', None, None) + + See :rfc:`4646` for more information. + + :param identifier: the locale identifier string + :param sep: character that separates the different components of the locale + identifier + :raise `ValueError`: if the string does not appear to be a valid locale + identifier + """ + if '.' in identifier: + # this is probably the charset/encoding, which we don't care about + identifier = identifier.split('.', 1)[0] + if '@' in identifier: + # this is a locale modifier such as @euro, which we don't care about + # either + identifier = identifier.split('@', 1)[0] + + parts = identifier.split(sep) + lang = parts.pop(0).lower() + if not lang.isalpha(): + raise ValueError('expected only letters, got %r' % lang) + + script = territory = variant = None + if parts: + if len(parts[0]) == 4 and parts[0].isalpha(): + script = parts.pop(0).title() + + if parts: + if len(parts[0]) == 2 and parts[0].isalpha(): + territory = parts.pop(0).upper() + elif len(parts[0]) == 3 and parts[0].isdigit(): + territory = parts.pop(0) + + if parts: + if len(parts[0]) == 4 and parts[0][0].isdigit() or \ + len(parts[0]) >= 5 and parts[0][0].isalpha(): + variant = parts.pop() + + if parts: + raise ValueError('%r is not a valid locale identifier' % identifier) + + return lang, territory, script, variant + + +def get_locale_identifier(tup, sep='_'): + """The reverse of :func:`parse_locale`. It creates a locale identifier out + of a ``(language, territory, script, variant)`` tuple. Items can be set to + ``None`` and trailing ``None``\\s can also be left out of the tuple. + + >>> get_locale_identifier(('de', 'DE', None, '1999')) + 'de_DE_1999' + + .. versionadded:: 1.0 + + :param tup: the tuple as returned by :func:`parse_locale`. + :param sep: the separator for the identifier. + """ + tup = tuple(tup[:4]) + lang, territory, script, variant = tup + (None,) * (4 - len(tup)) + return sep.join(filter(None, (lang, script, territory, variant))) diff --git a/venv/lib/python2.7/site-packages/babel/dates.py b/venv/lib/python2.7/site-packages/babel/dates.py new file mode 100644 index 0000000..cf58a48 --- /dev/null +++ b/venv/lib/python2.7/site-packages/babel/dates.py @@ -0,0 +1,1778 @@ +# -*- coding: utf-8 -*- +""" + babel.dates + ~~~~~~~~~~~ + + Locale dependent formatting and parsing of dates and times. + + The default locale for the functions in this module is determined by the + following environment variables, in that order: + + * ``LC_TIME``, + * ``LC_ALL``, and + * ``LANG`` + + :copyright: (c) 2013-2018 by the Babel Team. + :license: BSD, see LICENSE for more details. +""" + +from __future__ import division + +import re +import warnings +import pytz as _pytz + +from datetime import date, datetime, time, timedelta +from bisect import bisect_right + +from babel.core import default_locale, get_global, Locale +from babel.util import UTC, LOCALTZ +from babel._compat import string_types, integer_types, number_types, PY2 + +# "If a given short metazone form is known NOT to be understood in a given +# locale and the parent locale has this value such that it would normally +# be inherited, the inheritance of this value can be explicitly disabled by +# use of the 'no inheritance marker' as the value, which is 3 simultaneous [sic] +# empty set characters ( U+2205 )." +# - http://www.unicode.org/reports/tr35/tr35-dates.html#Metazone_Names + +NO_INHERITANCE_MARKER = u'\u2205\u2205\u2205' + + +LC_TIME = default_locale('LC_TIME') + +# Aliases for use in scopes where the modules are shadowed by local variables +date_ = date +datetime_ = datetime +time_ = time + + +def _get_dt_and_tzinfo(dt_or_tzinfo): + """ + Parse a `dt_or_tzinfo` value into a datetime and a tzinfo. + + See the docs for this function's callers for semantics. + + :rtype: tuple[datetime, tzinfo] + """ + if dt_or_tzinfo is None: + dt = datetime.now() + tzinfo = LOCALTZ + elif isinstance(dt_or_tzinfo, string_types): + dt = None + tzinfo = get_timezone(dt_or_tzinfo) + elif isinstance(dt_or_tzinfo, integer_types): + dt = None + tzinfo = UTC + elif isinstance(dt_or_tzinfo, (datetime, time)): + dt = _get_datetime(dt_or_tzinfo) + if dt.tzinfo is not None: + tzinfo = dt.tzinfo + else: + tzinfo = UTC + else: + dt = None + tzinfo = dt_or_tzinfo + return dt, tzinfo + + +def _get_datetime(instant): + """ + Get a datetime out of an "instant" (date, time, datetime, number). + + .. warning:: The return values of this function may depend on the system clock. + + If the instant is None, the current moment is used. + If the instant is a time, it's augmented with today's date. + + Dates are converted to naive datetimes with midnight as the time component. + + >>> _get_datetime(date(2015, 1, 1)) + datetime.datetime(2015, 1, 1, 0, 0) + + UNIX timestamps are converted to datetimes. + + >>> _get_datetime(1400000000) + datetime.datetime(2014, 5, 13, 16, 53, 20) + + Other values are passed through as-is. + + >>> x = datetime(2015, 1, 1) + >>> _get_datetime(x) is x + True + + :param instant: date, time, datetime, integer, float or None + :type instant: date|time|datetime|int|float|None + :return: a datetime + :rtype: datetime + """ + if instant is None: + return datetime_.utcnow() + elif isinstance(instant, integer_types) or isinstance(instant, float): + return datetime_.utcfromtimestamp(instant) + elif isinstance(instant, time): + return datetime_.combine(date.today(), instant) + elif isinstance(instant, date) and not isinstance(instant, datetime): + return datetime_.combine(instant, time()) + # TODO (3.x): Add an assertion/type check for this fallthrough branch: + return instant + + +def _ensure_datetime_tzinfo(datetime, tzinfo=None): + """ + Ensure the datetime passed has an attached tzinfo. + + If the datetime is tz-naive to begin with, UTC is attached. + + If a tzinfo is passed in, the datetime is normalized to that timezone. + + >>> _ensure_datetime_tzinfo(datetime(2015, 1, 1)).tzinfo.zone + 'UTC' + + >>> tz = get_timezone("Europe/Stockholm") + >>> _ensure_datetime_tzinfo(datetime(2015, 1, 1, 13, 15, tzinfo=UTC), tzinfo=tz).hour + 14 + + :param datetime: Datetime to augment. + :param tzinfo: Optional tznfo. + :return: datetime with tzinfo + :rtype: datetime + """ + if datetime.tzinfo is None: + datetime = datetime.replace(tzinfo=UTC) + if tzinfo is not None: + datetime = datetime.astimezone(get_timezone(tzinfo)) + if hasattr(tzinfo, 'normalize'): # pytz + datetime = tzinfo.normalize(datetime) + return datetime + + +def _get_time(time, tzinfo=None): + """ + Get a timezoned time from a given instant. + + .. warning:: The return values of this function may depend on the system clock. + + :param time: time, datetime or None + :rtype: time + """ + if time is None: + time = datetime.utcnow() + elif isinstance(time, number_types): + time = datetime.utcfromtimestamp(time) + if time.tzinfo is None: + time = time.replace(tzinfo=UTC) + if isinstance(time, datetime): + if tzinfo is not None: + time = time.astimezone(tzinfo) + if hasattr(tzinfo, 'normalize'): # pytz + time = tzinfo.normalize(time) + time = time.timetz() + elif tzinfo is not None: + time = time.replace(tzinfo=tzinfo) + return time + + +def get_timezone(zone=None): + """Looks up a timezone by name and returns it. The timezone object + returned comes from ``pytz`` and corresponds to the `tzinfo` interface and + can be used with all of the functions of Babel that operate with dates. + + If a timezone is not known a :exc:`LookupError` is raised. If `zone` + is ``None`` a local zone object is returned. + + :param zone: the name of the timezone to look up. If a timezone object + itself is passed in, mit's returned unchanged. + """ + if zone is None: + return LOCALTZ + if not isinstance(zone, string_types): + return zone + try: + return _pytz.timezone(zone) + except _pytz.UnknownTimeZoneError: + raise LookupError('Unknown timezone %s' % zone) + + +def get_next_timezone_transition(zone=None, dt=None): + """Given a timezone it will return a :class:`TimezoneTransition` object + that holds the information about the next timezone transition that's going + to happen. For instance this can be used to detect when the next DST + change is going to happen and how it looks like. + + The transition is calculated relative to the given datetime object. The + next transition that follows the date is used. If a transition cannot + be found the return value will be `None`. + + Transition information can only be provided for timezones returned by + the :func:`get_timezone` function. + + :param zone: the timezone for which the transition should be looked up. + If not provided the local timezone is used. + :param dt: the date after which the next transition should be found. + If not given the current time is assumed. + """ + zone = get_timezone(zone) + dt = _get_datetime(dt).replace(tzinfo=None) + + if not hasattr(zone, '_utc_transition_times'): + raise TypeError('Given timezone does not have UTC transition ' + 'times. This can happen because the operating ' + 'system fallback local timezone is used or a ' + 'custom timezone object') + + try: + idx = max(0, bisect_right(zone._utc_transition_times, dt)) + old_trans = zone._transition_info[idx - 1] + new_trans = zone._transition_info[idx] + old_tz = zone._tzinfos[old_trans] + new_tz = zone._tzinfos[new_trans] + except (LookupError, ValueError): + return None + + return TimezoneTransition( + activates=zone._utc_transition_times[idx], + from_tzinfo=old_tz, + to_tzinfo=new_tz, + reference_date=dt + ) + + +class TimezoneTransition(object): + """A helper object that represents the return value from + :func:`get_next_timezone_transition`. + """ + + def __init__(self, activates, from_tzinfo, to_tzinfo, reference_date=None): + #: the time of the activation of the timezone transition in UTC. + self.activates = activates + #: the timezone from where the transition starts. + self.from_tzinfo = from_tzinfo + #: the timezone for after the transition. + self.to_tzinfo = to_tzinfo + #: the reference date that was provided. This is the `dt` parameter + #: to the :func:`get_next_timezone_transition`. + self.reference_date = reference_date + + @property + def from_tz(self): + """The name of the timezone before the transition.""" + return self.from_tzinfo._tzname + + @property + def to_tz(self): + """The name of the timezone after the transition.""" + return self.to_tzinfo._tzname + + @property + def from_offset(self): + """The UTC offset in seconds before the transition.""" + return int(self.from_tzinfo._utcoffset.total_seconds()) + + @property + def to_offset(self): + """The UTC offset in seconds after the transition.""" + return int(self.to_tzinfo._utcoffset.total_seconds()) + + def __repr__(self): + return ' %s (%s)>' % ( + self.from_tz, + self.to_tz, + self.activates, + ) + + +def get_period_names(width='wide', context='stand-alone', locale=LC_TIME): + """Return the names for day periods (AM/PM) used by the locale. + + >>> get_period_names(locale='en_US')['am'] + u'AM' + + :param width: the width to use, one of "abbreviated", "narrow", or "wide" + :param context: the context, either "format" or "stand-alone" + :param locale: the `Locale` object, or a locale string + """ + return Locale.parse(locale).day_periods[context][width] + + +def get_day_names(width='wide', context='format', locale=LC_TIME): + """Return the day names used by the locale for the specified format. + + >>> get_day_names('wide', locale='en_US')[1] + u'Tuesday' + >>> get_day_names('short', locale='en_US')[1] + u'Tu' + >>> get_day_names('abbreviated', locale='es')[1] + u'mar.' + >>> get_day_names('narrow', context='stand-alone', locale='de_DE')[1] + u'D' + + :param width: the width to use, one of "wide", "abbreviated", "short" or "narrow" + :param context: the context, either "format" or "stand-alone" + :param locale: the `Locale` object, or a locale string + """ + return Locale.parse(locale).days[context][width] + + +def get_month_names(width='wide', context='format', locale=LC_TIME): + """Return the month names used by the locale for the specified format. + + >>> get_month_names('wide', locale='en_US')[1] + u'January' + >>> get_month_names('abbreviated', locale='es')[1] + u'ene.' + >>> get_month_names('narrow', context='stand-alone', locale='de_DE')[1] + u'J' + + :param width: the width to use, one of "wide", "abbreviated", or "narrow" + :param context: the context, either "format" or "stand-alone" + :param locale: the `Locale` object, or a locale string + """ + return Locale.parse(locale).months[context][width] + + +def get_quarter_names(width='wide', context='format', locale=LC_TIME): + """Return the quarter names used by the locale for the specified format. + + >>> get_quarter_names('wide', locale='en_US')[1] + u'1st quarter' + >>> get_quarter_names('abbreviated', locale='de_DE')[1] + u'Q1' + >>> get_quarter_names('narrow', locale='de_DE')[1] + u'1' + + :param width: the width to use, one of "wide", "abbreviated", or "narrow" + :param context: the context, either "format" or "stand-alone" + :param locale: the `Locale` object, or a locale string + """ + return Locale.parse(locale).quarters[context][width] + + +def get_era_names(width='wide', locale=LC_TIME): + """Return the era names used by the locale for the specified format. + + >>> get_era_names('wide', locale='en_US')[1] + u'Anno Domini' + >>> get_era_names('abbreviated', locale='de_DE')[1] + u'n. Chr.' + + :param width: the width to use, either "wide", "abbreviated", or "narrow" + :param locale: the `Locale` object, or a locale string + """ + return Locale.parse(locale).eras[width] + + +def get_date_format(format='medium', locale=LC_TIME): + """Return the date formatting patterns used by the locale for the specified + format. + + >>> get_date_format(locale='en_US') + + >>> get_date_format('full', locale='de_DE') + + + :param format: the format to use, one of "full", "long", "medium", or + "short" + :param locale: the `Locale` object, or a locale string + """ + return Locale.parse(locale).date_formats[format] + + +def get_datetime_format(format='medium', locale=LC_TIME): + """Return the datetime formatting patterns used by the locale for the + specified format. + + >>> get_datetime_format(locale='en_US') + u'{1}, {0}' + + :param format: the format to use, one of "full", "long", "medium", or + "short" + :param locale: the `Locale` object, or a locale string + """ + patterns = Locale.parse(locale).datetime_formats + if format not in patterns: + format = None + return patterns[format] + + +def get_time_format(format='medium', locale=LC_TIME): + """Return the time formatting patterns used by the locale for the specified + format. + + >>> get_time_format(locale='en_US') + + >>> get_time_format('full', locale='de_DE') + + + :param format: the format to use, one of "full", "long", "medium", or + "short" + :param locale: the `Locale` object, or a locale string + """ + return Locale.parse(locale).time_formats[format] + + +def get_timezone_gmt(datetime=None, width='long', locale=LC_TIME, return_z=False): + """Return the timezone associated with the given `datetime` object formatted + as string indicating the offset from GMT. + + >>> dt = datetime(2007, 4, 1, 15, 30) + >>> get_timezone_gmt(dt, locale='en') + u'GMT+00:00' + >>> get_timezone_gmt(dt, locale='en', return_z=True) + 'Z' + >>> get_timezone_gmt(dt, locale='en', width='iso8601_short') + u'+00' + >>> tz = get_timezone('America/Los_Angeles') + >>> dt = tz.localize(datetime(2007, 4, 1, 15, 30)) + >>> get_timezone_gmt(dt, locale='en') + u'GMT-07:00' + >>> get_timezone_gmt(dt, 'short', locale='en') + u'-0700' + >>> get_timezone_gmt(dt, locale='en', width='iso8601_short') + u'-07' + + The long format depends on the locale, for example in France the acronym + UTC string is used instead of GMT: + + >>> get_timezone_gmt(dt, 'long', locale='fr_FR') + u'UTC-07:00' + + .. versionadded:: 0.9 + + :param datetime: the ``datetime`` object; if `None`, the current date and + time in UTC is used + :param width: either "long" or "short" or "iso8601" or "iso8601_short" + :param locale: the `Locale` object, or a locale string + :param return_z: True or False; Function returns indicator "Z" + when local time offset is 0 + """ + datetime = _ensure_datetime_tzinfo(_get_datetime(datetime)) + locale = Locale.parse(locale) + + offset = datetime.tzinfo.utcoffset(datetime) + seconds = offset.days * 24 * 60 * 60 + offset.seconds + hours, seconds = divmod(seconds, 3600) + if return_z and hours == 0 and seconds == 0: + return 'Z' + elif seconds == 0 and width == 'iso8601_short': + return u'%+03d' % hours + elif width == 'short' or width == 'iso8601_short': + pattern = u'%+03d%02d' + elif width == 'iso8601': + pattern = u'%+03d:%02d' + else: + pattern = locale.zone_formats['gmt'] % '%+03d:%02d' + return pattern % (hours, seconds // 60) + + +def get_timezone_location(dt_or_tzinfo=None, locale=LC_TIME, return_city=False): + u"""Return a representation of the given timezone using "location format". + + The result depends on both the local display name of the country and the + city associated with the time zone: + + >>> tz = get_timezone('America/St_Johns') + >>> print(get_timezone_location(tz, locale='de_DE')) + Kanada (St. John’s) Zeit + >>> print(get_timezone_location(tz, locale='en')) + Canada (St. John’s) Time + >>> print(get_timezone_location(tz, locale='en', return_city=True)) + St. John’s + >>> tz = get_timezone('America/Mexico_City') + >>> get_timezone_location(tz, locale='de_DE') + u'Mexiko (Mexiko-Stadt) Zeit' + + If the timezone is associated with a country that uses only a single + timezone, just the localized country name is returned: + + >>> tz = get_timezone('Europe/Berlin') + >>> get_timezone_name(tz, locale='de_DE') + u'Mitteleurop\\xe4ische Zeit' + + .. versionadded:: 0.9 + + :param dt_or_tzinfo: the ``datetime`` or ``tzinfo`` object that determines + the timezone; if `None`, the current date and time in + UTC is assumed + :param locale: the `Locale` object, or a locale string + :param return_city: True or False, if True then return exemplar city (location) + for the time zone + :return: the localized timezone name using location format + + """ + dt, tzinfo = _get_dt_and_tzinfo(dt_or_tzinfo) + locale = Locale.parse(locale) + + if hasattr(tzinfo, 'zone'): + zone = tzinfo.zone + else: + zone = tzinfo.tzname(dt or datetime.utcnow()) + + # Get the canonical time-zone code + zone = get_global('zone_aliases').get(zone, zone) + + info = locale.time_zones.get(zone, {}) + + # Otherwise, if there is only one timezone for the country, return the + # localized country name + region_format = locale.zone_formats['region'] + territory = get_global('zone_territories').get(zone) + if territory not in locale.territories: + territory = 'ZZ' # invalid/unknown + territory_name = locale.territories[territory] + if not return_city and territory and len(get_global('territory_zones').get(territory, [])) == 1: + return region_format % territory_name + + # Otherwise, include the city in the output + fallback_format = locale.zone_formats['fallback'] + if 'city' in info: + city_name = info['city'] + else: + metazone = get_global('meta_zones').get(zone) + metazone_info = locale.meta_zones.get(metazone, {}) + if 'city' in metazone_info: + city_name = metazone_info['city'] + elif '/' in zone: + city_name = zone.split('/', 1)[1].replace('_', ' ') + else: + city_name = zone.replace('_', ' ') + + if return_city: + return city_name + return region_format % (fallback_format % { + '0': city_name, + '1': territory_name + }) + + +def get_timezone_name(dt_or_tzinfo=None, width='long', uncommon=False, + locale=LC_TIME, zone_variant=None, return_zone=False): + r"""Return the localized display name for the given timezone. The timezone + may be specified using a ``datetime`` or `tzinfo` object. + + >>> dt = time(15, 30, tzinfo=get_timezone('America/Los_Angeles')) + >>> get_timezone_name(dt, locale='en_US') + u'Pacific Standard Time' + >>> get_timezone_name(dt, locale='en_US', return_zone=True) + 'America/Los_Angeles' + >>> get_timezone_name(dt, width='short', locale='en_US') + u'PST' + + If this function gets passed only a `tzinfo` object and no concrete + `datetime`, the returned display name is indenpendent of daylight savings + time. This can be used for example for selecting timezones, or to set the + time of events that recur across DST changes: + + >>> tz = get_timezone('America/Los_Angeles') + >>> get_timezone_name(tz, locale='en_US') + u'Pacific Time' + >>> get_timezone_name(tz, 'short', locale='en_US') + u'PT' + + If no localized display name for the timezone is available, and the timezone + is associated with a country that uses only a single timezone, the name of + that country is returned, formatted according to the locale: + + >>> tz = get_timezone('Europe/Berlin') + >>> get_timezone_name(tz, locale='de_DE') + u'Mitteleurop\xe4ische Zeit' + >>> get_timezone_name(tz, locale='pt_BR') + u'Hor\xe1rio da Europa Central' + + On the other hand, if the country uses multiple timezones, the city is also + included in the representation: + + >>> tz = get_timezone('America/St_Johns') + >>> get_timezone_name(tz, locale='de_DE') + u'Neufundland-Zeit' + + Note that short format is currently not supported for all timezones and + all locales. This is partially because not every timezone has a short + code in every locale. In that case it currently falls back to the long + format. + + For more information see `LDML Appendix J: Time Zone Display Names + `_ + + .. versionadded:: 0.9 + + .. versionchanged:: 1.0 + Added `zone_variant` support. + + :param dt_or_tzinfo: the ``datetime`` or ``tzinfo`` object that determines + the timezone; if a ``tzinfo`` object is used, the + resulting display name will be generic, i.e. + independent of daylight savings time; if `None`, the + current date in UTC is assumed + :param width: either "long" or "short" + :param uncommon: deprecated and ignored + :param zone_variant: defines the zone variation to return. By default the + variation is defined from the datetime object + passed in. If no datetime object is passed in, the + ``'generic'`` variation is assumed. The following + values are valid: ``'generic'``, ``'daylight'`` and + ``'standard'``. + :param locale: the `Locale` object, or a locale string + :param return_zone: True or False. If true then function + returns long time zone ID + """ + dt, tzinfo = _get_dt_and_tzinfo(dt_or_tzinfo) + locale = Locale.parse(locale) + + if hasattr(tzinfo, 'zone'): + zone = tzinfo.zone + else: + zone = tzinfo.tzname(dt) + + if zone_variant is None: + if dt is None: + zone_variant = 'generic' + else: + dst = tzinfo.dst(dt) + if dst: + zone_variant = 'daylight' + else: + zone_variant = 'standard' + else: + if zone_variant not in ('generic', 'standard', 'daylight'): + raise ValueError('Invalid zone variation') + + # Get the canonical time-zone code + zone = get_global('zone_aliases').get(zone, zone) + if return_zone: + return zone + info = locale.time_zones.get(zone, {}) + # Try explicitly translated zone names first + if width in info: + if zone_variant in info[width]: + return info[width][zone_variant] + + metazone = get_global('meta_zones').get(zone) + if metazone: + metazone_info = locale.meta_zones.get(metazone, {}) + if width in metazone_info: + name = metazone_info[width].get(zone_variant) + if width == 'short' and name == NO_INHERITANCE_MARKER: + # If the short form is marked no-inheritance, + # try to fall back to the long name instead. + name = metazone_info.get('long', {}).get(zone_variant) + if name: + return name + + # If we have a concrete datetime, we assume that the result can't be + # independent of daylight savings time, so we return the GMT offset + if dt is not None: + return get_timezone_gmt(dt, width=width, locale=locale) + + return get_timezone_location(dt_or_tzinfo, locale=locale) + + +def format_date(date=None, format='medium', locale=LC_TIME): + """Return a date formatted according to the given pattern. + + >>> d = date(2007, 4, 1) + >>> format_date(d, locale='en_US') + u'Apr 1, 2007' + >>> format_date(d, format='full', locale='de_DE') + u'Sonntag, 1. April 2007' + + If you don't want to use the locale default formats, you can specify a + custom date pattern: + + >>> format_date(d, "EEE, MMM d, ''yy", locale='en') + u"Sun, Apr 1, '07" + + :param date: the ``date`` or ``datetime`` object; if `None`, the current + date is used + :param format: one of "full", "long", "medium", or "short", or a custom + date/time pattern + :param locale: a `Locale` object or a locale identifier + """ + if date is None: + date = date_.today() + elif isinstance(date, datetime): + date = date.date() + + locale = Locale.parse(locale) + if format in ('full', 'long', 'medium', 'short'): + format = get_date_format(format, locale=locale) + pattern = parse_pattern(format) + return pattern.apply(date, locale) + + +def format_datetime(datetime=None, format='medium', tzinfo=None, + locale=LC_TIME): + r"""Return a date formatted according to the given pattern. + + >>> dt = datetime(2007, 4, 1, 15, 30) + >>> format_datetime(dt, locale='en_US') + u'Apr 1, 2007, 3:30:00 PM' + + For any pattern requiring the display of the time-zone, the third-party + ``pytz`` package is needed to explicitly specify the time-zone: + + >>> format_datetime(dt, 'full', tzinfo=get_timezone('Europe/Paris'), + ... locale='fr_FR') + u'dimanche 1 avril 2007 \xe0 17:30:00 heure d\u2019\xe9t\xe9 d\u2019Europe centrale' + >>> format_datetime(dt, "yyyy.MM.dd G 'at' HH:mm:ss zzz", + ... tzinfo=get_timezone('US/Eastern'), locale='en') + u'2007.04.01 AD at 11:30:00 EDT' + + :param datetime: the `datetime` object; if `None`, the current date and + time is used + :param format: one of "full", "long", "medium", or "short", or a custom + date/time pattern + :param tzinfo: the timezone to apply to the time for display + :param locale: a `Locale` object or a locale identifier + """ + datetime = _ensure_datetime_tzinfo(_get_datetime(datetime), tzinfo) + + locale = Locale.parse(locale) + if format in ('full', 'long', 'medium', 'short'): + return get_datetime_format(format, locale=locale) \ + .replace("'", "") \ + .replace('{0}', format_time(datetime, format, tzinfo=None, + locale=locale)) \ + .replace('{1}', format_date(datetime, format, locale=locale)) + else: + return parse_pattern(format).apply(datetime, locale) + + +def format_time(time=None, format='medium', tzinfo=None, locale=LC_TIME): + r"""Return a time formatted according to the given pattern. + + >>> t = time(15, 30) + >>> format_time(t, locale='en_US') + u'3:30:00 PM' + >>> format_time(t, format='short', locale='de_DE') + u'15:30' + + If you don't want to use the locale default formats, you can specify a + custom time pattern: + + >>> format_time(t, "hh 'o''clock' a", locale='en') + u"03 o'clock PM" + + For any pattern requiring the display of the time-zone a + timezone has to be specified explicitly: + + >>> t = datetime(2007, 4, 1, 15, 30) + >>> tzinfo = get_timezone('Europe/Paris') + >>> t = tzinfo.localize(t) + >>> format_time(t, format='full', tzinfo=tzinfo, locale='fr_FR') + u'15:30:00 heure d\u2019\xe9t\xe9 d\u2019Europe centrale' + >>> format_time(t, "hh 'o''clock' a, zzzz", tzinfo=get_timezone('US/Eastern'), + ... locale='en') + u"09 o'clock AM, Eastern Daylight Time" + + As that example shows, when this function gets passed a + ``datetime.datetime`` value, the actual time in the formatted string is + adjusted to the timezone specified by the `tzinfo` parameter. If the + ``datetime`` is "naive" (i.e. it has no associated timezone information), + it is assumed to be in UTC. + + These timezone calculations are **not** performed if the value is of type + ``datetime.time``, as without date information there's no way to determine + what a given time would translate to in a different timezone without + information about whether daylight savings time is in effect or not. This + means that time values are left as-is, and the value of the `tzinfo` + parameter is only used to display the timezone name if needed: + + >>> t = time(15, 30) + >>> format_time(t, format='full', tzinfo=get_timezone('Europe/Paris'), + ... locale='fr_FR') + u'15:30:00 heure normale d\u2019Europe centrale' + >>> format_time(t, format='full', tzinfo=get_timezone('US/Eastern'), + ... locale='en_US') + u'3:30:00 PM Eastern Standard Time' + + :param time: the ``time`` or ``datetime`` object; if `None`, the current + time in UTC is used + :param format: one of "full", "long", "medium", or "short", or a custom + date/time pattern + :param tzinfo: the time-zone to apply to the time for display + :param locale: a `Locale` object or a locale identifier + """ + time = _get_time(time, tzinfo) + + locale = Locale.parse(locale) + if format in ('full', 'long', 'medium', 'short'): + format = get_time_format(format, locale=locale) + return parse_pattern(format).apply(time, locale) + + +def format_skeleton(skeleton, datetime=None, tzinfo=None, fuzzy=True, locale=LC_TIME): + r"""Return a time and/or date formatted according to the given pattern. + + The skeletons are defined in the CLDR data and provide more flexibility + than the simple short/long/medium formats, but are a bit harder to use. + The are defined using the date/time symbols without order or punctuation + and map to a suitable format for the given locale. + + >>> t = datetime(2007, 4, 1, 15, 30) + >>> format_skeleton('MMMEd', t, locale='fr') + u'dim. 1 avr.' + >>> format_skeleton('MMMEd', t, locale='en') + u'Sun, Apr 1' + >>> format_skeleton('yMMd', t, locale='fi') # yMMd is not in the Finnish locale; yMd gets used + u'1.4.2007' + >>> format_skeleton('yMMd', t, fuzzy=False, locale='fi') # yMMd is not in the Finnish locale, an error is thrown + Traceback (most recent call last): + ... + KeyError: yMMd + + After the skeleton is resolved to a pattern `format_datetime` is called so + all timezone processing etc is the same as for that. + + :param skeleton: A date time skeleton as defined in the cldr data. + :param datetime: the ``time`` or ``datetime`` object; if `None`, the current + time in UTC is used + :param tzinfo: the time-zone to apply to the time for display + :param fuzzy: If the skeleton is not found, allow choosing a skeleton that's + close enough to it. + :param locale: a `Locale` object or a locale identifier + """ + locale = Locale.parse(locale) + if fuzzy and skeleton not in locale.datetime_skeletons: + skeleton = match_skeleton(skeleton, locale.datetime_skeletons) + format = locale.datetime_skeletons[skeleton] + return format_datetime(datetime, format, tzinfo, locale) + + +TIMEDELTA_UNITS = ( + ('year', 3600 * 24 * 365), + ('month', 3600 * 24 * 30), + ('week', 3600 * 24 * 7), + ('day', 3600 * 24), + ('hour', 3600), + ('minute', 60), + ('second', 1) +) + + +def format_timedelta(delta, granularity='second', threshold=.85, + add_direction=False, format='long', + locale=LC_TIME): + """Return a time delta according to the rules of the given locale. + + >>> format_timedelta(timedelta(weeks=12), locale='en_US') + u'3 months' + >>> format_timedelta(timedelta(seconds=1), locale='es') + u'1 segundo' + + The granularity parameter can be provided to alter the lowest unit + presented, which defaults to a second. + + >>> format_timedelta(timedelta(hours=3), granularity='day', + ... locale='en_US') + u'1 day' + + The threshold parameter can be used to determine at which value the + presentation switches to the next higher unit. A higher threshold factor + means the presentation will switch later. For example: + + >>> format_timedelta(timedelta(hours=23), threshold=0.9, locale='en_US') + u'1 day' + >>> format_timedelta(timedelta(hours=23), threshold=1.1, locale='en_US') + u'23 hours' + + In addition directional information can be provided that informs + the user if the date is in the past or in the future: + + >>> format_timedelta(timedelta(hours=1), add_direction=True, locale='en') + u'in 1 hour' + >>> format_timedelta(timedelta(hours=-1), add_direction=True, locale='en') + u'1 hour ago' + + The format parameter controls how compact or wide the presentation is: + + >>> format_timedelta(timedelta(hours=3), format='short', locale='en') + u'3 hr' + >>> format_timedelta(timedelta(hours=3), format='narrow', locale='en') + u'3h' + + :param delta: a ``timedelta`` object representing the time difference to + format, or the delta in seconds as an `int` value + :param granularity: determines the smallest unit that should be displayed, + the value can be one of "year", "month", "week", "day", + "hour", "minute" or "second" + :param threshold: factor that determines at which point the presentation + switches to the next higher unit + :param add_direction: if this flag is set to `True` the return value will + include directional information. For instance a + positive timedelta will include the information about + it being in the future, a negative will be information + about the value being in the past. + :param format: the format, can be "narrow", "short" or "long". ( + "medium" is deprecated, currently converted to "long" to + maintain compatibility) + :param locale: a `Locale` object or a locale identifier + """ + if format not in ('narrow', 'short', 'medium', 'long'): + raise TypeError('Format must be one of "narrow", "short" or "long"') + if format == 'medium': + warnings.warn('"medium" value for format param of format_timedelta' + ' is deprecated. Use "long" instead', + category=DeprecationWarning) + format = 'long' + if isinstance(delta, timedelta): + seconds = int((delta.days * 86400) + delta.seconds) + else: + seconds = delta + locale = Locale.parse(locale) + + def _iter_patterns(a_unit): + if add_direction: + unit_rel_patterns = locale._data['date_fields'][a_unit] + if seconds >= 0: + yield unit_rel_patterns['future'] + else: + yield unit_rel_patterns['past'] + a_unit = 'duration-' + a_unit + yield locale._data['unit_patterns'].get(a_unit, {}).get(format) + + for unit, secs_per_unit in TIMEDELTA_UNITS: + value = abs(seconds) / secs_per_unit + if value >= threshold or unit == granularity: + if unit == granularity and value > 0: + value = max(1, value) + value = int(round(value)) + plural_form = locale.plural_form(value) + pattern = None + for patterns in _iter_patterns(unit): + if patterns is not None: + pattern = patterns[plural_form] + break + # This really should not happen + if pattern is None: + return u'' + return pattern.replace('{0}', str(value)) + + return u'' + + +def _format_fallback_interval(start, end, skeleton, tzinfo, locale): + if skeleton in locale.datetime_skeletons: # Use the given skeleton + format = lambda dt: format_skeleton(skeleton, dt, tzinfo, locale=locale) + elif all((isinstance(d, date) and not isinstance(d, datetime)) for d in (start, end)): # Both are just dates + format = lambda dt: format_date(dt, locale=locale) + elif all((isinstance(d, time) and not isinstance(d, date)) for d in (start, end)): # Both are times + format = lambda dt: format_time(dt, tzinfo=tzinfo, locale=locale) + else: + format = lambda dt: format_datetime(dt, tzinfo=tzinfo, locale=locale) + + formatted_start = format(start) + formatted_end = format(end) + + if formatted_start == formatted_end: + return format(start) + + return ( + locale.interval_formats.get(None, "{0}-{1}"). + replace("{0}", formatted_start). + replace("{1}", formatted_end) + ) + + +def format_interval(start, end, skeleton=None, tzinfo=None, fuzzy=True, locale=LC_TIME): + """ + Format an interval between two instants according to the locale's rules. + + >>> format_interval(date(2016, 1, 15), date(2016, 1, 17), "yMd", locale="fi") + u'15.\u201317.1.2016' + + >>> format_interval(time(12, 12), time(16, 16), "Hm", locale="en_GB") + '12:12\u201316:16' + + >>> format_interval(time(5, 12), time(16, 16), "hm", locale="en_US") + '5:12 AM \u2013 4:16 PM' + + >>> format_interval(time(16, 18), time(16, 24), "Hm", locale="it") + '16:18\u201316:24' + + If the start instant equals the end instant, the interval is formatted like the instant. + + >>> format_interval(time(16, 18), time(16, 18), "Hm", locale="it") + '16:18' + + Unknown skeletons fall back to "default" formatting. + + >>> format_interval(date(2015, 1, 1), date(2017, 1, 1), "wzq", locale="ja") + '2015/01/01\uff5e2017/01/01' + + >>> format_interval(time(16, 18), time(16, 24), "xxx", locale="ja") + '16:18:00\uff5e16:24:00' + + >>> format_interval(date(2016, 1, 15), date(2016, 1, 17), "xxx", locale="de") + '15.01.2016 \u2013 17.01.2016' + + :param start: First instant (datetime/date/time) + :param end: Second instant (datetime/date/time) + :param skeleton: The "skeleton format" to use for formatting. + :param tzinfo: tzinfo to use (if none is already attached) + :param fuzzy: If the skeleton is not found, allow choosing a skeleton that's + close enough to it. + :param locale: A locale object or identifier. + :return: Formatted interval + """ + locale = Locale.parse(locale) + + # NB: The quote comments below are from the algorithm description in + # http://www.unicode.org/reports/tr35/tr35-dates.html#intervalFormats + + # > Look for the intervalFormatItem element that matches the "skeleton", + # > starting in the current locale and then following the locale fallback + # > chain up to, but not including root. + + interval_formats = locale.interval_formats + + if skeleton not in interval_formats or not skeleton: + # > If no match was found from the previous step, check what the closest + # > match is in the fallback locale chain, as in availableFormats. That + # > is, this allows for adjusting the string value field's width, + # > including adjusting between "MMM" and "MMMM", and using different + # > variants of the same field, such as 'v' and 'z'. + if skeleton and fuzzy: + skeleton = match_skeleton(skeleton, interval_formats) + else: + skeleton = None + if not skeleton: # Still no match whatsoever? + # > Otherwise, format the start and end datetime using the fallback pattern. + return _format_fallback_interval(start, end, skeleton, tzinfo, locale) + + skel_formats = interval_formats[skeleton] + + if start == end: + return format_skeleton(skeleton, start, tzinfo, fuzzy=fuzzy, locale=locale) + + start = _ensure_datetime_tzinfo(_get_datetime(start), tzinfo=tzinfo) + end = _ensure_datetime_tzinfo(_get_datetime(end), tzinfo=tzinfo) + + start_fmt = DateTimeFormat(start, locale=locale) + end_fmt = DateTimeFormat(end, locale=locale) + + # > If a match is found from previous steps, compute the calendar field + # > with the greatest difference between start and end datetime. If there + # > is no difference among any of the fields in the pattern, format as a + # > single date using availableFormats, and return. + + for field in PATTERN_CHAR_ORDER: # These are in largest-to-smallest order + if field in skel_formats: + if start_fmt.extract(field) != end_fmt.extract(field): + # > If there is a match, use the pieces of the corresponding pattern to + # > format the start and end datetime, as above. + return "".join( + parse_pattern(pattern).apply(instant, locale) + for pattern, instant + in zip(skel_formats[field], (start, end)) + ) + + # > Otherwise, format the start and end datetime using the fallback pattern. + + return _format_fallback_interval(start, end, skeleton, tzinfo, locale) + + +def get_period_id(time, tzinfo=None, type=None, locale=LC_TIME): + """ + Get the day period ID for a given time. + + This ID can be used as a key for the period name dictionary. + + >>> get_period_names(locale="de")[get_period_id(time(7, 42), locale="de")] + u'Morgen' + + :param time: The time to inspect. + :param tzinfo: The timezone for the time. See ``format_time``. + :param type: The period type to use. Either "selection" or None. + The selection type is used for selecting among phrases such as + “Your email arrived yesterday evening” or “Your email arrived last night”. + :param locale: the `Locale` object, or a locale string + :return: period ID. Something is always returned -- even if it's just "am" or "pm". + """ + time = _get_time(time, tzinfo) + seconds_past_midnight = int(time.hour * 60 * 60 + time.minute * 60 + time.second) + locale = Locale.parse(locale) + + # The LDML rules state that the rules may not overlap, so iterating in arbitrary + # order should be alright, though `at` periods should be preferred. + rulesets = locale.day_period_rules.get(type, {}).items() + + for rule_id, rules in rulesets: + for rule in rules: + if "at" in rule and rule["at"] == seconds_past_midnight: + return rule_id + + for rule_id, rules in rulesets: + for rule in rules: + start_ok = end_ok = False + + if "from" in rule and seconds_past_midnight >= rule["from"]: + start_ok = True + if "to" in rule and seconds_past_midnight <= rule["to"]: + # This rule type does not exist in the present CLDR data; + # excuse the lack of test coverage. + end_ok = True + if "before" in rule and seconds_past_midnight < rule["before"]: + end_ok = True + if "after" in rule: + raise NotImplementedError("'after' is deprecated as of CLDR 29.") + + if start_ok and end_ok: + return rule_id + + if seconds_past_midnight < 43200: + return "am" + else: + return "pm" + + +def parse_date(string, locale=LC_TIME): + """Parse a date from a string. + + This function uses the date format for the locale as a hint to determine + the order in which the date fields appear in the string. + + >>> parse_date('4/1/04', locale='en_US') + datetime.date(2004, 4, 1) + >>> parse_date('01.04.2004', locale='de_DE') + datetime.date(2004, 4, 1) + + :param string: the string containing the date + :param locale: a `Locale` object or a locale identifier + """ + # TODO: try ISO format first? + format = get_date_format(locale=locale).pattern.lower() + year_idx = format.index('y') + month_idx = format.index('m') + if month_idx < 0: + month_idx = format.index('l') + day_idx = format.index('d') + + indexes = [(year_idx, 'Y'), (month_idx, 'M'), (day_idx, 'D')] + indexes.sort() + indexes = dict([(item[1], idx) for idx, item in enumerate(indexes)]) + + # FIXME: this currently only supports numbers, but should also support month + # names, both in the requested locale, and english + + numbers = re.findall(r'(\d+)', string) + year = numbers[indexes['Y']] + if len(year) == 2: + year = 2000 + int(year) + else: + year = int(year) + month = int(numbers[indexes['M']]) + day = int(numbers[indexes['D']]) + if month > 12: + month, day = day, month + return date(year, month, day) + + +def parse_time(string, locale=LC_TIME): + """Parse a time from a string. + + This function uses the time format for the locale as a hint to determine + the order in which the time fields appear in the string. + + >>> parse_time('15:30:00', locale='en_US') + datetime.time(15, 30) + + :param string: the string containing the time + :param locale: a `Locale` object or a locale identifier + :return: the parsed time + :rtype: `time` + """ + # TODO: try ISO format first? + format = get_time_format(locale=locale).pattern.lower() + hour_idx = format.index('h') + if hour_idx < 0: + hour_idx = format.index('k') + min_idx = format.index('m') + sec_idx = format.index('s') + + indexes = [(hour_idx, 'H'), (min_idx, 'M'), (sec_idx, 'S')] + indexes.sort() + indexes = dict([(item[1], idx) for idx, item in enumerate(indexes)]) + + # FIXME: support 12 hour clock, and 0-based hour specification + # and seconds should be optional, maybe minutes too + # oh, and time-zones, of course + + numbers = re.findall(r'(\d+)', string) + hour = int(numbers[indexes['H']]) + minute = int(numbers[indexes['M']]) + second = int(numbers[indexes['S']]) + return time(hour, minute, second) + + +class DateTimePattern(object): + + def __init__(self, pattern, format): + self.pattern = pattern + self.format = format + + def __repr__(self): + return '<%s %r>' % (type(self).__name__, self.pattern) + + def __unicode__(self): + return self.pattern + + def __str__(self): + pat = self.pattern + if PY2: + pat = pat.encode('utf-8') + return pat + + def __mod__(self, other): + if type(other) is not DateTimeFormat: + return NotImplemented + return self.format % other + + def apply(self, datetime, locale): + return self % DateTimeFormat(datetime, locale) + + +class DateTimeFormat(object): + + def __init__(self, value, locale): + assert isinstance(value, (date, datetime, time)) + if isinstance(value, (datetime, time)) and value.tzinfo is None: + value = value.replace(tzinfo=UTC) + self.value = value + self.locale = Locale.parse(locale) + + def __getitem__(self, name): + char = name[0] + num = len(name) + if char == 'G': + return self.format_era(char, num) + elif char in ('y', 'Y', 'u'): + return self.format_year(char, num) + elif char in ('Q', 'q'): + return self.format_quarter(char, num) + elif char in ('M', 'L'): + return self.format_month(char, num) + elif char in ('w', 'W'): + return self.format_week(char, num) + elif char == 'd': + return self.format(self.value.day, num) + elif char == 'D': + return self.format_day_of_year(num) + elif char == 'F': + return self.format_day_of_week_in_month() + elif char in ('E', 'e', 'c'): + return self.format_weekday(char, num) + elif char == 'a': + # TODO: Add support for the rest of the period formats (a*, b*, B*) + return self.format_period(char) + elif char == 'h': + if self.value.hour % 12 == 0: + return self.format(12, num) + else: + return self.format(self.value.hour % 12, num) + elif char == 'H': + return self.format(self.value.hour, num) + elif char == 'K': + return self.format(self.value.hour % 12, num) + elif char == 'k': + if self.value.hour == 0: + return self.format(24, num) + else: + return self.format(self.value.hour, num) + elif char == 'm': + return self.format(self.value.minute, num) + elif char == 's': + return self.format(self.value.second, num) + elif char == 'S': + return self.format_frac_seconds(num) + elif char == 'A': + return self.format_milliseconds_in_day(num) + elif char in ('z', 'Z', 'v', 'V', 'x', 'X', 'O'): + return self.format_timezone(char, num) + else: + raise KeyError('Unsupported date/time field %r' % char) + + def extract(self, char): + char = str(char)[0] + if char == 'y': + return self.value.year + elif char == 'M': + return self.value.month + elif char == 'd': + return self.value.day + elif char == 'H': + return self.value.hour + elif char == 'h': + return self.value.hour % 12 or 12 + elif char == 'm': + return self.value.minute + elif char == 'a': + return int(self.value.hour >= 12) # 0 for am, 1 for pm + else: + raise NotImplementedError("Not implemented: extracting %r from %r" % (char, self.value)) + + def format_era(self, char, num): + width = {3: 'abbreviated', 4: 'wide', 5: 'narrow'}[max(3, num)] + era = int(self.value.year >= 0) + return get_era_names(width, self.locale)[era] + + def format_year(self, char, num): + value = self.value.year + if char.isupper(): + week = self.get_week_number(self.get_day_of_year()) + if week == 0: + value -= 1 + year = self.format(value, num) + if num == 2: + year = year[-2:] + return year + + def format_quarter(self, char, num): + quarter = (self.value.month - 1) // 3 + 1 + if num <= 2: + return '%0*d' % (num, quarter) + width = {3: 'abbreviated', 4: 'wide', 5: 'narrow'}[num] + context = {'Q': 'format', 'q': 'stand-alone'}[char] + return get_quarter_names(width, context, self.locale)[quarter] + + def format_month(self, char, num): + if num <= 2: + return '%0*d' % (num, self.value.month) + width = {3: 'abbreviated', 4: 'wide', 5: 'narrow'}[num] + context = {'M': 'format', 'L': 'stand-alone'}[char] + return get_month_names(width, context, self.locale)[self.value.month] + + def format_week(self, char, num): + if char.islower(): # week of year + day_of_year = self.get_day_of_year() + week = self.get_week_number(day_of_year) + if week == 0: + date = self.value - timedelta(days=day_of_year) + week = self.get_week_number(self.get_day_of_year(date), + date.weekday()) + return self.format(week, num) + else: # week of month + week = self.get_week_number(self.value.day) + if week == 0: + date = self.value - timedelta(days=self.value.day) + week = self.get_week_number(date.day, date.weekday()) + return '%d' % week + + def format_weekday(self, char='E', num=4): + """ + Return weekday from parsed datetime according to format pattern. + + >>> format = DateTimeFormat(date(2016, 2, 28), Locale.parse('en_US')) + >>> format.format_weekday() + u'Sunday' + + 'E': Day of week - Use one through three letters for the abbreviated day name, four for the full (wide) name, + five for the narrow name, or six for the short name. + >>> format.format_weekday('E',2) + u'Sun' + + 'e': Local day of week. Same as E except adds a numeric value that will depend on the local starting day of the + week, using one or two letters. For this example, Monday is the first day of the week. + >>> format.format_weekday('e',2) + '01' + + 'c': Stand-Alone local day of week - Use one letter for the local numeric value (same as 'e'), three for the + abbreviated day name, four for the full (wide) name, five for the narrow name, or six for the short name. + >>> format.format_weekday('c',1) + '1' + + :param char: pattern format character ('e','E','c') + :param num: count of format character + + """ + if num < 3: + if char.islower(): + value = 7 - self.locale.first_week_day + self.value.weekday() + return self.format(value % 7 + 1, num) + num = 3 + weekday = self.value.weekday() + width = {3: 'abbreviated', 4: 'wide', 5: 'narrow', 6: 'short'}[num] + if char == 'c': + context = 'stand-alone' + else: + context = 'format' + return get_day_names(width, context, self.locale)[weekday] + + def format_day_of_year(self, num): + return self.format(self.get_day_of_year(), num) + + def format_day_of_week_in_month(self): + return '%d' % ((self.value.day - 1) // 7 + 1) + + def format_period(self, char): + period = {0: 'am', 1: 'pm'}[int(self.value.hour >= 12)] + for width in ('wide', 'narrow', 'abbreviated'): + period_names = get_period_names(context='format', width=width, locale=self.locale) + if period in period_names: + return period_names[period] + raise ValueError('Could not format period %s in %s' % (period, self.locale)) + + def format_frac_seconds(self, num): + """ Return fractional seconds. + + Rounds the time's microseconds to the precision given by the number \ + of digits passed in. + """ + value = self.value.microsecond / 1000000 + return self.format(round(value, num) * 10**num, num) + + def format_milliseconds_in_day(self, num): + msecs = self.value.microsecond // 1000 + self.value.second * 1000 + \ + self.value.minute * 60000 + self.value.hour * 3600000 + return self.format(msecs, num) + + def format_timezone(self, char, num): + width = {3: 'short', 4: 'long', 5: 'iso8601'}[max(3, num)] + if char == 'z': + return get_timezone_name(self.value, width, locale=self.locale) + elif char == 'Z': + if num == 5: + return get_timezone_gmt(self.value, width, locale=self.locale, return_z=True) + return get_timezone_gmt(self.value, width, locale=self.locale) + elif char == 'O': + if num == 4: + return get_timezone_gmt(self.value, width, locale=self.locale) + # TODO: To add support for O:1 + elif char == 'v': + return get_timezone_name(self.value.tzinfo, width, + locale=self.locale) + elif char == 'V': + if num == 1: + return get_timezone_name(self.value.tzinfo, width, + uncommon=True, locale=self.locale) + elif num == 2: + return get_timezone_name(self.value.tzinfo, locale=self.locale, return_zone=True) + elif num == 3: + return get_timezone_location(self.value.tzinfo, locale=self.locale, return_city=True) + return get_timezone_location(self.value.tzinfo, locale=self.locale) + # Included additional elif condition to add support for 'Xx' in timezone format + elif char == 'X': + if num == 1: + return get_timezone_gmt(self.value, width='iso8601_short', locale=self.locale, + return_z=True) + elif num in (2, 4): + return get_timezone_gmt(self.value, width='short', locale=self.locale, + return_z=True) + elif num in (3, 5): + return get_timezone_gmt(self.value, width='iso8601', locale=self.locale, + return_z=True) + elif char == 'x': + if num == 1: + return get_timezone_gmt(self.value, width='iso8601_short', locale=self.locale) + elif num in (2, 4): + return get_timezone_gmt(self.value, width='short', locale=self.locale) + elif num in (3, 5): + return get_timezone_gmt(self.value, width='iso8601', locale=self.locale) + + def format(self, value, length): + return '%0*d' % (length, value) + + def get_day_of_year(self, date=None): + if date is None: + date = self.value + return (date - date.replace(month=1, day=1)).days + 1 + + def get_week_number(self, day_of_period, day_of_week=None): + """Return the number of the week of a day within a period. This may be + the week number in a year or the week number in a month. + + Usually this will return a value equal to or greater than 1, but if the + first week of the period is so short that it actually counts as the last + week of the previous period, this function will return 0. + + >>> format = DateTimeFormat(date(2006, 1, 8), Locale.parse('de_DE')) + >>> format.get_week_number(6) + 1 + + >>> format = DateTimeFormat(date(2006, 1, 8), Locale.parse('en_US')) + >>> format.get_week_number(6) + 2 + + :param day_of_period: the number of the day in the period (usually + either the day of month or the day of year) + :param day_of_week: the week day; if ommitted, the week day of the + current date is assumed + """ + if day_of_week is None: + day_of_week = self.value.weekday() + first_day = (day_of_week - self.locale.first_week_day - + day_of_period + 1) % 7 + if first_day < 0: + first_day += 7 + week_number = (day_of_period + first_day - 1) // 7 + if 7 - first_day >= self.locale.min_week_days: + week_number += 1 + return week_number + + +PATTERN_CHARS = { + 'G': [1, 2, 3, 4, 5], # era + 'y': None, 'Y': None, 'u': None, # year + 'Q': [1, 2, 3, 4, 5], 'q': [1, 2, 3, 4, 5], # quarter + 'M': [1, 2, 3, 4, 5], 'L': [1, 2, 3, 4, 5], # month + 'w': [1, 2], 'W': [1], # week + 'd': [1, 2], 'D': [1, 2, 3], 'F': [1], 'g': None, # day + 'E': [1, 2, 3, 4, 5, 6], 'e': [1, 2, 3, 4, 5, 6], 'c': [1, 3, 4, 5, 6], # week day + 'a': [1], # period + 'h': [1, 2], 'H': [1, 2], 'K': [1, 2], 'k': [1, 2], # hour + 'm': [1, 2], # minute + 's': [1, 2], 'S': None, 'A': None, # second + 'z': [1, 2, 3, 4], 'Z': [1, 2, 3, 4, 5], 'O': [1, 4], 'v': [1, 4], # zone + 'V': [1, 2, 3, 4], 'x': [1, 2, 3, 4, 5], 'X': [1, 2, 3, 4, 5] # zone +} + +#: The pattern characters declared in the Date Field Symbol Table +#: (http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table) +#: in order of decreasing magnitude. +PATTERN_CHAR_ORDER = "GyYuUQqMLlwWdDFgEecabBChHKkjJmsSAzZOvVXx" + +_pattern_cache = {} + + +def parse_pattern(pattern): + """Parse date, time, and datetime format patterns. + + >>> parse_pattern("MMMMd").format + u'%(MMMM)s%(d)s' + >>> parse_pattern("MMM d, yyyy").format + u'%(MMM)s %(d)s, %(yyyy)s' + + Pattern can contain literal strings in single quotes: + + >>> parse_pattern("H:mm' Uhr 'z").format + u'%(H)s:%(mm)s Uhr %(z)s' + + An actual single quote can be used by using two adjacent single quote + characters: + + >>> parse_pattern("hh' o''clock'").format + u"%(hh)s o'clock" + + :param pattern: the formatting pattern to parse + """ + if type(pattern) is DateTimePattern: + return pattern + + if pattern in _pattern_cache: + return _pattern_cache[pattern] + + result = [] + + for tok_type, tok_value in tokenize_pattern(pattern): + if tok_type == "chars": + result.append(tok_value.replace('%', '%%')) + elif tok_type == "field": + fieldchar, fieldnum = tok_value + limit = PATTERN_CHARS[fieldchar] + if limit and fieldnum not in limit: + raise ValueError('Invalid length for field: %r' + % (fieldchar * fieldnum)) + result.append('%%(%s)s' % (fieldchar * fieldnum)) + else: + raise NotImplementedError("Unknown token type: %s" % tok_type) + + _pattern_cache[pattern] = pat = DateTimePattern(pattern, u''.join(result)) + return pat + + +def tokenize_pattern(pattern): + """ + Tokenize date format patterns. + + Returns a list of (token_type, token_value) tuples. + + ``token_type`` may be either "chars" or "field". + + For "chars" tokens, the value is the literal value. + + For "field" tokens, the value is a tuple of (field character, repetition count). + + :param pattern: Pattern string + :type pattern: str + :rtype: list[tuple] + """ + result = [] + quotebuf = None + charbuf = [] + fieldchar = [''] + fieldnum = [0] + + def append_chars(): + result.append(('chars', ''.join(charbuf).replace('\0', "'"))) + del charbuf[:] + + def append_field(): + result.append(('field', (fieldchar[0], fieldnum[0]))) + fieldchar[0] = '' + fieldnum[0] = 0 + + for idx, char in enumerate(pattern.replace("''", '\0')): + if quotebuf is None: + if char == "'": # quote started + if fieldchar[0]: + append_field() + elif charbuf: + append_chars() + quotebuf = [] + elif char in PATTERN_CHARS: + if charbuf: + append_chars() + if char == fieldchar[0]: + fieldnum[0] += 1 + else: + if fieldchar[0]: + append_field() + fieldchar[0] = char + fieldnum[0] = 1 + else: + if fieldchar[0]: + append_field() + charbuf.append(char) + + elif quotebuf is not None: + if char == "'": # end of quote + charbuf.extend(quotebuf) + quotebuf = None + else: # inside quote + quotebuf.append(char) + + if fieldchar[0]: + append_field() + elif charbuf: + append_chars() + + return result + + +def untokenize_pattern(tokens): + """ + Turn a date format pattern token stream back into a string. + + This is the reverse operation of ``tokenize_pattern``. + + :type tokens: Iterable[tuple] + :rtype: str + """ + output = [] + for tok_type, tok_value in tokens: + if tok_type == "field": + output.append(tok_value[0] * tok_value[1]) + elif tok_type == "chars": + if not any(ch in PATTERN_CHARS for ch in tok_value): # No need to quote + output.append(tok_value) + else: + output.append("'%s'" % tok_value.replace("'", "''")) + return "".join(output) + + +def split_interval_pattern(pattern): + """ + Split an interval-describing datetime pattern into multiple pieces. + + > The pattern is then designed to be broken up into two pieces by determining the first repeating field. + - http://www.unicode.org/reports/tr35/tr35-dates.html#intervalFormats + + >>> split_interval_pattern(u'E d.M. \u2013 E d.M.') + [u'E d.M. \u2013 ', 'E d.M.'] + >>> split_interval_pattern("Y 'text' Y 'more text'") + ["Y 'text '", "Y 'more text'"] + >>> split_interval_pattern(u"E, MMM d \u2013 E") + [u'E, MMM d \u2013 ', u'E'] + >>> split_interval_pattern("MMM d") + ['MMM d'] + >>> split_interval_pattern("y G") + ['y G'] + >>> split_interval_pattern(u"MMM d \u2013 d") + [u'MMM d \u2013 ', u'd'] + + :param pattern: Interval pattern string + :return: list of "subpatterns" + """ + + seen_fields = set() + parts = [[]] + + for tok_type, tok_value in tokenize_pattern(pattern): + if tok_type == "field": + if tok_value[0] in seen_fields: # Repeated field + parts.append([]) + seen_fields.clear() + seen_fields.add(tok_value[0]) + parts[-1].append((tok_type, tok_value)) + + return [untokenize_pattern(tokens) for tokens in parts] + + +def match_skeleton(skeleton, options, allow_different_fields=False): + """ + Find the closest match for the given datetime skeleton among the options given. + + This uses the rules outlined in the TR35 document. + + >>> match_skeleton('yMMd', ('yMd', 'yMMMd')) + 'yMd' + + >>> match_skeleton('yMMd', ('jyMMd',), allow_different_fields=True) + 'jyMMd' + + >>> match_skeleton('yMMd', ('qyMMd',), allow_different_fields=False) + + >>> match_skeleton('hmz', ('hmv',)) + 'hmv' + + :param skeleton: The skeleton to match + :type skeleton: str + :param options: An iterable of other skeletons to match against + :type options: Iterable[str] + :return: The closest skeleton match, or if no match was found, None. + :rtype: str|None + """ + + # TODO: maybe implement pattern expansion? + + # Based on the implementation in + # http://source.icu-project.org/repos/icu/icu4j/trunk/main/classes/core/src/com/ibm/icu/text/DateIntervalInfo.java + + # Filter out falsy values and sort for stability; when `interval_formats` is passed in, there may be a None key. + options = sorted(option for option in options if option) + + if 'z' in skeleton and not any('z' in option for option in options): + skeleton = skeleton.replace('z', 'v') + + get_input_field_width = dict(t[1] for t in tokenize_pattern(skeleton) if t[0] == "field").get + best_skeleton = None + best_distance = None + for option in options: + get_opt_field_width = dict(t[1] for t in tokenize_pattern(option) if t[0] == "field").get + distance = 0 + for field in PATTERN_CHARS: + input_width = get_input_field_width(field, 0) + opt_width = get_opt_field_width(field, 0) + if input_width == opt_width: + continue + if opt_width == 0 or input_width == 0: + if not allow_different_fields: # This one is not okay + option = None + break + distance += 0x1000 # Magic weight constant for "entirely different fields" + elif field == 'M' and ((input_width > 2 and opt_width <= 2) or (input_width <= 2 and opt_width > 2)): + distance += 0x100 # Magic weight for "text turns into a number" + else: + distance += abs(input_width - opt_width) + + if not option: # We lost the option along the way (probably due to "allow_different_fields") + continue + + if not best_skeleton or distance < best_distance: + best_skeleton = option + best_distance = distance + + if distance == 0: # Found a perfect match! + break + + return best_skeleton diff --git a/venv/lib/python2.7/site-packages/babel/global.dat b/venv/lib/python2.7/site-packages/babel/global.dat new file mode 100644 index 0000000..0083114 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/global.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/languages.py b/venv/lib/python2.7/site-packages/babel/languages.py new file mode 100644 index 0000000..0513d00 --- /dev/null +++ b/venv/lib/python2.7/site-packages/babel/languages.py @@ -0,0 +1,71 @@ +# -- encoding: UTF-8 -- +from babel.core import get_global + + +def get_official_languages(territory, regional=False, de_facto=False): + """ + Get the official language(s) for the given territory. + + The language codes, if any are known, are returned in order of descending popularity. + + If the `regional` flag is set, then languages which are regionally official are also returned. + + If the `de_facto` flag is set, then languages which are "de facto" official are also returned. + + .. warning:: Note that the data is as up to date as the current version of the CLDR used + by Babel. If you need scientifically accurate information, use another source! + + :param territory: Territory code + :type territory: str + :param regional: Whether to return regionally official languages too + :type regional: bool + :param de_facto: Whether to return de-facto official languages too + :type de_facto: bool + :return: Tuple of language codes + :rtype: tuple[str] + """ + + territory = str(territory).upper() + allowed_stati = {"official"} + if regional: + allowed_stati.add("official_regional") + if de_facto: + allowed_stati.add("de_facto_official") + + languages = get_global("territory_languages").get(territory, {}) + pairs = [ + (info['population_percent'], language) + for language, info in languages.items() + if info.get('official_status') in allowed_stati + ] + pairs.sort(reverse=True) + return tuple(lang for _, lang in pairs) + + +def get_territory_language_info(territory): + """ + Get a dictionary of language information for a territory. + + The dictionary is keyed by language code; the values are dicts with more information. + + The following keys are currently known for the values: + + * `population_percent`: The percentage of the territory's population speaking the + language. + * `official_status`: An optional string describing the officiality status of the language. + Known values are "official", "official_regional" and "de_facto_official". + + .. warning:: Note that the data is as up to date as the current version of the CLDR used + by Babel. If you need scientifically accurate information, use another source! + + .. note:: Note that the format of the dict returned may change between Babel versions. + + See http://www.unicode.org/cldr/charts/latest/supplemental/territory_language_information.html + + :param territory: Territory code + :type territory: str + :return: Language information dictionary + :rtype: dict[str, dict] + """ + territory = str(territory).upper() + return get_global("territory_languages").get(territory, {}).copy() diff --git a/venv/lib/python2.7/site-packages/babel/lists.py b/venv/lib/python2.7/site-packages/babel/lists.py new file mode 100644 index 0000000..3294379 --- /dev/null +++ b/venv/lib/python2.7/site-packages/babel/lists.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- +""" + babel.lists + ~~~~~~~~~~~ + + Locale dependent formatting of lists. + + The default locale for the functions in this module is determined by the + following environment variables, in that order: + + * ``LC_ALL``, and + * ``LANG`` + + :copyright: (c) 2015, 2018 by the Babel Team. + :license: BSD, see LICENSE for more details. +""" + +from babel.core import Locale, default_locale + +DEFAULT_LOCALE = default_locale() + + +def format_list(lst, style='standard', locale=DEFAULT_LOCALE): + """ + Format the items in `lst` as a list. + + >>> format_list(['apples', 'oranges', 'pears'], locale='en') + u'apples, oranges, and pears' + >>> format_list(['apples', 'oranges', 'pears'], locale='zh') + u'apples\u3001oranges\u548cpears' + >>> format_list(['omena', 'peruna', 'aplari'], style='or', locale='fi') + u'omena, peruna tai aplari' + + These styles are defined, but not all are necessarily available in all locales. + The following text is verbatim from the Unicode TR35-49 spec [1]. + + * standard: + A typical 'and' list for arbitrary placeholders. + eg. "January, February, and March" + * standard-short: + A short version of a 'and' list, suitable for use with short or abbreviated placeholder values. + eg. "Jan., Feb., and Mar." + * or: + A typical 'or' list for arbitrary placeholders. + eg. "January, February, or March" + * or-short: + A short version of an 'or' list. + eg. "Jan., Feb., or Mar." + * unit: + A list suitable for wide units. + eg. "3 feet, 7 inches" + * unit-short: + A list suitable for short units + eg. "3 ft, 7 in" + * unit-narrow: + A list suitable for narrow units, where space on the screen is very limited. + eg. "3′ 7″" + + [1]: https://www.unicode.org/reports/tr35/tr35-49/tr35-general.html#ListPatterns + + :param lst: a sequence of items to format in to a list + :param style: the style to format the list with. See above for description. + :param locale: the locale + """ + locale = Locale.parse(locale) + if not lst: + return '' + if len(lst) == 1: + return lst[0] + + if style not in locale.list_patterns: + raise ValueError('Locale %s does not support list formatting style %r (supported are %s)' % ( + locale, + style, + list(sorted(locale.list_patterns)), + )) + patterns = locale.list_patterns[style] + + if len(lst) == 2: + return patterns['2'].format(*lst) + + result = patterns['start'].format(lst[0], lst[1]) + for elem in lst[2:-1]: + result = patterns['middle'].format(result, elem) + result = patterns['end'].format(result, lst[-1]) + + return result diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/af.dat b/venv/lib/python2.7/site-packages/babel/locale-data/af.dat new file mode 100644 index 0000000..be29dea Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/af.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/af_NA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/af_NA.dat new file mode 100644 index 0000000..ee4bb8c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/af_NA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/af_ZA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/af_ZA.dat new file mode 100644 index 0000000..9a97396 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/af_ZA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/agq.dat b/venv/lib/python2.7/site-packages/babel/locale-data/agq.dat new file mode 100644 index 0000000..9ffc3e2 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/agq.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/agq_CM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/agq_CM.dat new file mode 100644 index 0000000..e7587c4 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/agq_CM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ak.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ak.dat new file mode 100644 index 0000000..15ffbd8 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ak.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ak_GH.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ak_GH.dat new file mode 100644 index 0000000..034698b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ak_GH.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/am.dat b/venv/lib/python2.7/site-packages/babel/locale-data/am.dat new file mode 100644 index 0000000..bab0a5c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/am.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/am_ET.dat b/venv/lib/python2.7/site-packages/babel/locale-data/am_ET.dat new file mode 100644 index 0000000..9b410bd Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/am_ET.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar.dat new file mode 100644 index 0000000..34fef40 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_001.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_001.dat new file mode 100644 index 0000000..9b7e492 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_001.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_AE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_AE.dat new file mode 100644 index 0000000..c9bda06 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_AE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_BH.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_BH.dat new file mode 100644 index 0000000..b0a4089 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_BH.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_DJ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_DJ.dat new file mode 100644 index 0000000..215c124 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_DJ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_DZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_DZ.dat new file mode 100644 index 0000000..38390d2 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_DZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_EG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_EG.dat new file mode 100644 index 0000000..2523255 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_EG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_EH.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_EH.dat new file mode 100644 index 0000000..aa949f4 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_EH.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_ER.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_ER.dat new file mode 100644 index 0000000..9ad4508 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_ER.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_IL.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_IL.dat new file mode 100644 index 0000000..0004f07 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_IL.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_IQ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_IQ.dat new file mode 100644 index 0000000..adf5947 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_IQ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_JO.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_JO.dat new file mode 100644 index 0000000..7a599de Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_JO.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_KM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_KM.dat new file mode 100644 index 0000000..b8ab3d5 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_KM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_KW.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_KW.dat new file mode 100644 index 0000000..e31e5fe Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_KW.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_LB.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_LB.dat new file mode 100644 index 0000000..88cb628 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_LB.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_LY.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_LY.dat new file mode 100644 index 0000000..2730168 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_LY.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_MA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_MA.dat new file mode 100644 index 0000000..3ee69ce Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_MA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_MR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_MR.dat new file mode 100644 index 0000000..6fbba6d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_MR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_OM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_OM.dat new file mode 100644 index 0000000..ac207bd Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_OM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_PS.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_PS.dat new file mode 100644 index 0000000..efb6141 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_PS.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_QA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_QA.dat new file mode 100644 index 0000000..17d4081 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_QA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_SA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_SA.dat new file mode 100644 index 0000000..844fbd5 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_SA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_SD.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_SD.dat new file mode 100644 index 0000000..e10dc22 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_SD.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_SO.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_SO.dat new file mode 100644 index 0000000..7afde36 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_SO.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_SS.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_SS.dat new file mode 100644 index 0000000..4829824 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_SS.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_SY.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_SY.dat new file mode 100644 index 0000000..dc488e5 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_SY.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_TD.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_TD.dat new file mode 100644 index 0000000..02e6cd7 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_TD.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_TN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_TN.dat new file mode 100644 index 0000000..a579e28 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_TN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ar_YE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ar_YE.dat new file mode 100644 index 0000000..d57841a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ar_YE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/as.dat b/venv/lib/python2.7/site-packages/babel/locale-data/as.dat new file mode 100644 index 0000000..72ef3c8 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/as.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/as_IN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/as_IN.dat new file mode 100644 index 0000000..0e40c2a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/as_IN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/asa.dat b/venv/lib/python2.7/site-packages/babel/locale-data/asa.dat new file mode 100644 index 0000000..2a17dec Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/asa.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/asa_TZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/asa_TZ.dat new file mode 100644 index 0000000..f9ef5e2 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/asa_TZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ast.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ast.dat new file mode 100644 index 0000000..296e872 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ast.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ast_ES.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ast_ES.dat new file mode 100644 index 0000000..bb956fb Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ast_ES.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/az.dat b/venv/lib/python2.7/site-packages/babel/locale-data/az.dat new file mode 100644 index 0000000..0c4bc22 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/az.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/az_Cyrl.dat b/venv/lib/python2.7/site-packages/babel/locale-data/az_Cyrl.dat new file mode 100644 index 0000000..0f5f568 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/az_Cyrl.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/az_Cyrl_AZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/az_Cyrl_AZ.dat new file mode 100644 index 0000000..b3abb18 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/az_Cyrl_AZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/az_Latn.dat b/venv/lib/python2.7/site-packages/babel/locale-data/az_Latn.dat new file mode 100644 index 0000000..9b9410b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/az_Latn.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/az_Latn_AZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/az_Latn_AZ.dat new file mode 100644 index 0000000..b3abb18 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/az_Latn_AZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/bas.dat b/venv/lib/python2.7/site-packages/babel/locale-data/bas.dat new file mode 100644 index 0000000..7ddd6f1 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/bas.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/bas_CM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/bas_CM.dat new file mode 100644 index 0000000..e4ec7ad Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/bas_CM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/be.dat b/venv/lib/python2.7/site-packages/babel/locale-data/be.dat new file mode 100644 index 0000000..31956df Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/be.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/be_BY.dat b/venv/lib/python2.7/site-packages/babel/locale-data/be_BY.dat new file mode 100644 index 0000000..cdf5d65 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/be_BY.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/bem.dat b/venv/lib/python2.7/site-packages/babel/locale-data/bem.dat new file mode 100644 index 0000000..1b0e1d3 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/bem.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/bem_ZM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/bem_ZM.dat new file mode 100644 index 0000000..db9d3be Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/bem_ZM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/bez.dat b/venv/lib/python2.7/site-packages/babel/locale-data/bez.dat new file mode 100644 index 0000000..916d84d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/bez.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/bez_TZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/bez_TZ.dat new file mode 100644 index 0000000..fea51a4 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/bez_TZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/bg.dat b/venv/lib/python2.7/site-packages/babel/locale-data/bg.dat new file mode 100644 index 0000000..954ff5d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/bg.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/bg_BG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/bg_BG.dat new file mode 100644 index 0000000..1387405 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/bg_BG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/bm.dat b/venv/lib/python2.7/site-packages/babel/locale-data/bm.dat new file mode 100644 index 0000000..9be9efe Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/bm.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/bm_ML.dat b/venv/lib/python2.7/site-packages/babel/locale-data/bm_ML.dat new file mode 100644 index 0000000..caa1725 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/bm_ML.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/bn.dat b/venv/lib/python2.7/site-packages/babel/locale-data/bn.dat new file mode 100644 index 0000000..9b406f0 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/bn.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/bn_BD.dat b/venv/lib/python2.7/site-packages/babel/locale-data/bn_BD.dat new file mode 100644 index 0000000..ca9a5f4 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/bn_BD.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/bn_IN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/bn_IN.dat new file mode 100644 index 0000000..516b11c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/bn_IN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/bo.dat b/venv/lib/python2.7/site-packages/babel/locale-data/bo.dat new file mode 100644 index 0000000..6c28be3 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/bo.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/bo_CN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/bo_CN.dat new file mode 100644 index 0000000..80ca9c3 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/bo_CN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/bo_IN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/bo_IN.dat new file mode 100644 index 0000000..646798c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/bo_IN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/br.dat b/venv/lib/python2.7/site-packages/babel/locale-data/br.dat new file mode 100644 index 0000000..5fa5d63 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/br.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/br_FR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/br_FR.dat new file mode 100644 index 0000000..d3e381e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/br_FR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/brx.dat b/venv/lib/python2.7/site-packages/babel/locale-data/brx.dat new file mode 100644 index 0000000..25bcb55 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/brx.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/brx_IN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/brx_IN.dat new file mode 100644 index 0000000..74bf327 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/brx_IN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/bs.dat b/venv/lib/python2.7/site-packages/babel/locale-data/bs.dat new file mode 100644 index 0000000..072971b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/bs.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/bs_Cyrl.dat b/venv/lib/python2.7/site-packages/babel/locale-data/bs_Cyrl.dat new file mode 100644 index 0000000..104e578 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/bs_Cyrl.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/bs_Cyrl_BA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/bs_Cyrl_BA.dat new file mode 100644 index 0000000..a763f67 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/bs_Cyrl_BA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/bs_Latn.dat b/venv/lib/python2.7/site-packages/babel/locale-data/bs_Latn.dat new file mode 100644 index 0000000..74ab833 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/bs_Latn.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/bs_Latn_BA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/bs_Latn_BA.dat new file mode 100644 index 0000000..e8ad4df Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/bs_Latn_BA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ca.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ca.dat new file mode 100644 index 0000000..40ce1ce Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ca.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ca_AD.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ca_AD.dat new file mode 100644 index 0000000..e85d380 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ca_AD.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ca_ES.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ca_ES.dat new file mode 100644 index 0000000..b400f78 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ca_ES.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ca_ES_VALENCIA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ca_ES_VALENCIA.dat new file mode 100644 index 0000000..8771db8 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ca_ES_VALENCIA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ca_FR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ca_FR.dat new file mode 100644 index 0000000..4b948b4 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ca_FR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ca_IT.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ca_IT.dat new file mode 100644 index 0000000..676fa32 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ca_IT.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ccp.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ccp.dat new file mode 100644 index 0000000..e8281fa Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ccp.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ccp_BD.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ccp_BD.dat new file mode 100644 index 0000000..64068a7 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ccp_BD.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ccp_IN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ccp_IN.dat new file mode 100644 index 0000000..20526f4 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ccp_IN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ce.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ce.dat new file mode 100644 index 0000000..4943057 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ce.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ce_RU.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ce_RU.dat new file mode 100644 index 0000000..4630895 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ce_RU.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/cgg.dat b/venv/lib/python2.7/site-packages/babel/locale-data/cgg.dat new file mode 100644 index 0000000..d090cb2 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/cgg.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/cgg_UG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/cgg_UG.dat new file mode 100644 index 0000000..6997922 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/cgg_UG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/chr.dat b/venv/lib/python2.7/site-packages/babel/locale-data/chr.dat new file mode 100644 index 0000000..db29372 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/chr.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/chr_US.dat b/venv/lib/python2.7/site-packages/babel/locale-data/chr_US.dat new file mode 100644 index 0000000..5ee5236 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/chr_US.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ckb.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ckb.dat new file mode 100644 index 0000000..36ce99f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ckb.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ckb_IQ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ckb_IQ.dat new file mode 100644 index 0000000..60b3e0d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ckb_IQ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ckb_IR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ckb_IR.dat new file mode 100644 index 0000000..eec38b1 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ckb_IR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/cs.dat b/venv/lib/python2.7/site-packages/babel/locale-data/cs.dat new file mode 100644 index 0000000..8394e19 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/cs.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/cs_CZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/cs_CZ.dat new file mode 100644 index 0000000..096d2ba Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/cs_CZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/cu.dat b/venv/lib/python2.7/site-packages/babel/locale-data/cu.dat new file mode 100644 index 0000000..2f7288d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/cu.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/cu_RU.dat b/venv/lib/python2.7/site-packages/babel/locale-data/cu_RU.dat new file mode 100644 index 0000000..28a0fcf Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/cu_RU.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/cy.dat b/venv/lib/python2.7/site-packages/babel/locale-data/cy.dat new file mode 100644 index 0000000..67a6dbd Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/cy.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/cy_GB.dat b/venv/lib/python2.7/site-packages/babel/locale-data/cy_GB.dat new file mode 100644 index 0000000..b17434b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/cy_GB.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/da.dat b/venv/lib/python2.7/site-packages/babel/locale-data/da.dat new file mode 100644 index 0000000..e135025 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/da.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/da_DK.dat b/venv/lib/python2.7/site-packages/babel/locale-data/da_DK.dat new file mode 100644 index 0000000..cf2ed22 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/da_DK.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/da_GL.dat b/venv/lib/python2.7/site-packages/babel/locale-data/da_GL.dat new file mode 100644 index 0000000..1f6fd3e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/da_GL.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/dav.dat b/venv/lib/python2.7/site-packages/babel/locale-data/dav.dat new file mode 100644 index 0000000..4d2b673 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/dav.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/dav_KE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/dav_KE.dat new file mode 100644 index 0000000..c525708 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/dav_KE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/de.dat b/venv/lib/python2.7/site-packages/babel/locale-data/de.dat new file mode 100644 index 0000000..bf48225 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/de.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/de_AT.dat b/venv/lib/python2.7/site-packages/babel/locale-data/de_AT.dat new file mode 100644 index 0000000..b1ef0a8 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/de_AT.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/de_BE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/de_BE.dat new file mode 100644 index 0000000..1951bbc Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/de_BE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/de_CH.dat b/venv/lib/python2.7/site-packages/babel/locale-data/de_CH.dat new file mode 100644 index 0000000..b38c9d1 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/de_CH.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/de_DE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/de_DE.dat new file mode 100644 index 0000000..961bca2 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/de_DE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/de_IT.dat b/venv/lib/python2.7/site-packages/babel/locale-data/de_IT.dat new file mode 100644 index 0000000..a16a207 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/de_IT.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/de_LI.dat b/venv/lib/python2.7/site-packages/babel/locale-data/de_LI.dat new file mode 100644 index 0000000..8a5efd3 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/de_LI.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/de_LU.dat b/venv/lib/python2.7/site-packages/babel/locale-data/de_LU.dat new file mode 100644 index 0000000..eb5eb6b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/de_LU.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/dje.dat b/venv/lib/python2.7/site-packages/babel/locale-data/dje.dat new file mode 100644 index 0000000..7fb2c98 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/dje.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/dje_NE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/dje_NE.dat new file mode 100644 index 0000000..5cc7603 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/dje_NE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/dsb.dat b/venv/lib/python2.7/site-packages/babel/locale-data/dsb.dat new file mode 100644 index 0000000..43afbac Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/dsb.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/dsb_DE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/dsb_DE.dat new file mode 100644 index 0000000..9ac45d9 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/dsb_DE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/dua.dat b/venv/lib/python2.7/site-packages/babel/locale-data/dua.dat new file mode 100644 index 0000000..df25ebc Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/dua.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/dua_CM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/dua_CM.dat new file mode 100644 index 0000000..b6c071c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/dua_CM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/dyo.dat b/venv/lib/python2.7/site-packages/babel/locale-data/dyo.dat new file mode 100644 index 0000000..99c7910 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/dyo.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/dyo_SN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/dyo_SN.dat new file mode 100644 index 0000000..34be5c1 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/dyo_SN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/dz.dat b/venv/lib/python2.7/site-packages/babel/locale-data/dz.dat new file mode 100644 index 0000000..a5c91f4 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/dz.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/dz_BT.dat b/venv/lib/python2.7/site-packages/babel/locale-data/dz_BT.dat new file mode 100644 index 0000000..c30b451 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/dz_BT.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ebu.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ebu.dat new file mode 100644 index 0000000..1da3094 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ebu.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ebu_KE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ebu_KE.dat new file mode 100644 index 0000000..2a3013d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ebu_KE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ee.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ee.dat new file mode 100644 index 0000000..d20e474 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ee.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ee_GH.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ee_GH.dat new file mode 100644 index 0000000..4ae3580 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ee_GH.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ee_TG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ee_TG.dat new file mode 100644 index 0000000..f8106a6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ee_TG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/el.dat b/venv/lib/python2.7/site-packages/babel/locale-data/el.dat new file mode 100644 index 0000000..01e3c72 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/el.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/el_CY.dat b/venv/lib/python2.7/site-packages/babel/locale-data/el_CY.dat new file mode 100644 index 0000000..894607e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/el_CY.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/el_GR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/el_GR.dat new file mode 100644 index 0000000..f986a88 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/el_GR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en.dat new file mode 100644 index 0000000..2ff4551 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_001.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_001.dat new file mode 100644 index 0000000..a6a9a6f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_001.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_150.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_150.dat new file mode 100644 index 0000000..d56ee64 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_150.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_AG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_AG.dat new file mode 100644 index 0000000..2549ec6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_AG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_AI.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_AI.dat new file mode 100644 index 0000000..67af14e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_AI.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_AS.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_AS.dat new file mode 100644 index 0000000..847883e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_AS.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_AT.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_AT.dat new file mode 100644 index 0000000..13340dd Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_AT.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_AU.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_AU.dat new file mode 100644 index 0000000..884edf3 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_AU.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_BB.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_BB.dat new file mode 100644 index 0000000..ba7ade6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_BB.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_BE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_BE.dat new file mode 100644 index 0000000..1461eb0 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_BE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_BI.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_BI.dat new file mode 100644 index 0000000..8bf4ae6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_BI.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_BM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_BM.dat new file mode 100644 index 0000000..a862a7c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_BM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_BS.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_BS.dat new file mode 100644 index 0000000..f36848e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_BS.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_BW.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_BW.dat new file mode 100644 index 0000000..a632784 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_BW.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_BZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_BZ.dat new file mode 100644 index 0000000..047ee8c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_BZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_CA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_CA.dat new file mode 100644 index 0000000..b9e9d62 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_CA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_CC.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_CC.dat new file mode 100644 index 0000000..394f849 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_CC.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_CH.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_CH.dat new file mode 100644 index 0000000..e25327c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_CH.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_CK.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_CK.dat new file mode 100644 index 0000000..a3a9740 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_CK.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_CM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_CM.dat new file mode 100644 index 0000000..035474a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_CM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_CX.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_CX.dat new file mode 100644 index 0000000..9978b5d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_CX.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_CY.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_CY.dat new file mode 100644 index 0000000..b9a76d8 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_CY.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_DE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_DE.dat new file mode 100644 index 0000000..2ec3527 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_DE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_DG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_DG.dat new file mode 100644 index 0000000..77ed14f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_DG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_DK.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_DK.dat new file mode 100644 index 0000000..585cc2f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_DK.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_DM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_DM.dat new file mode 100644 index 0000000..22751ae Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_DM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_ER.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_ER.dat new file mode 100644 index 0000000..8b5c0e6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_ER.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_FI.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_FI.dat new file mode 100644 index 0000000..41bc87c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_FI.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_FJ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_FJ.dat new file mode 100644 index 0000000..7e7268f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_FJ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_FK.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_FK.dat new file mode 100644 index 0000000..71a696e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_FK.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_FM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_FM.dat new file mode 100644 index 0000000..1a3bab3 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_FM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_GB.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_GB.dat new file mode 100644 index 0000000..0de437e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_GB.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_GD.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_GD.dat new file mode 100644 index 0000000..5ee403c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_GD.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_GG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_GG.dat new file mode 100644 index 0000000..f87642c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_GG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_GH.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_GH.dat new file mode 100644 index 0000000..d1ee03c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_GH.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_GI.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_GI.dat new file mode 100644 index 0000000..70ebe95 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_GI.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_GM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_GM.dat new file mode 100644 index 0000000..f6c5a93 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_GM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_GU.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_GU.dat new file mode 100644 index 0000000..927c442 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_GU.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_GY.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_GY.dat new file mode 100644 index 0000000..23f9dbd Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_GY.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_HK.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_HK.dat new file mode 100644 index 0000000..0882981 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_HK.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_IE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_IE.dat new file mode 100644 index 0000000..1a572c6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_IE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_IL.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_IL.dat new file mode 100644 index 0000000..4a55e90 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_IL.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_IM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_IM.dat new file mode 100644 index 0000000..180658a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_IM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_IN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_IN.dat new file mode 100644 index 0000000..5b8aaf3 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_IN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_IO.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_IO.dat new file mode 100644 index 0000000..bc8d1b9 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_IO.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_JE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_JE.dat new file mode 100644 index 0000000..55107d8 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_JE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_JM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_JM.dat new file mode 100644 index 0000000..736c9ad Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_JM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_KE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_KE.dat new file mode 100644 index 0000000..f5fd332 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_KE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_KI.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_KI.dat new file mode 100644 index 0000000..5b7151a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_KI.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_KN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_KN.dat new file mode 100644 index 0000000..b75e19a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_KN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_KY.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_KY.dat new file mode 100644 index 0000000..09a04fc Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_KY.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_LC.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_LC.dat new file mode 100644 index 0000000..1751264 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_LC.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_LR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_LR.dat new file mode 100644 index 0000000..0533bf0 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_LR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_LS.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_LS.dat new file mode 100644 index 0000000..a32ccda Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_LS.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_MG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_MG.dat new file mode 100644 index 0000000..9722670 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_MG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_MH.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_MH.dat new file mode 100644 index 0000000..208db8d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_MH.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_MO.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_MO.dat new file mode 100644 index 0000000..e66337f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_MO.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_MP.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_MP.dat new file mode 100644 index 0000000..cf7ed40 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_MP.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_MS.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_MS.dat new file mode 100644 index 0000000..dd1329f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_MS.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_MT.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_MT.dat new file mode 100644 index 0000000..8b3592f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_MT.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_MU.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_MU.dat new file mode 100644 index 0000000..c596e70 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_MU.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_MW.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_MW.dat new file mode 100644 index 0000000..16440ba Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_MW.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_MY.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_MY.dat new file mode 100644 index 0000000..abda6b6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_MY.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_NA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_NA.dat new file mode 100644 index 0000000..bb10428 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_NA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_NF.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_NF.dat new file mode 100644 index 0000000..a6e8ace Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_NF.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_NG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_NG.dat new file mode 100644 index 0000000..d4627c9 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_NG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_NL.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_NL.dat new file mode 100644 index 0000000..2d63932 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_NL.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_NR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_NR.dat new file mode 100644 index 0000000..7cf91ca Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_NR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_NU.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_NU.dat new file mode 100644 index 0000000..aab7154 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_NU.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_NZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_NZ.dat new file mode 100644 index 0000000..a3d3637 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_NZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_PG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_PG.dat new file mode 100644 index 0000000..1004687 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_PG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_PH.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_PH.dat new file mode 100644 index 0000000..d422108 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_PH.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_PK.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_PK.dat new file mode 100644 index 0000000..059b82d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_PK.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_PN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_PN.dat new file mode 100644 index 0000000..e3366d6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_PN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_PR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_PR.dat new file mode 100644 index 0000000..b185b98 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_PR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_PW.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_PW.dat new file mode 100644 index 0000000..b2d2cc7 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_PW.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_RW.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_RW.dat new file mode 100644 index 0000000..6f377b0 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_RW.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_SB.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_SB.dat new file mode 100644 index 0000000..47a55ce Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_SB.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_SC.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_SC.dat new file mode 100644 index 0000000..7ceb01c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_SC.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_SD.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_SD.dat new file mode 100644 index 0000000..88fa225 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_SD.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_SE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_SE.dat new file mode 100644 index 0000000..4b67cc9 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_SE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_SG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_SG.dat new file mode 100644 index 0000000..185ec90 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_SG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_SH.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_SH.dat new file mode 100644 index 0000000..da58d84 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_SH.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_SI.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_SI.dat new file mode 100644 index 0000000..ef58581 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_SI.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_SL.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_SL.dat new file mode 100644 index 0000000..69f3a4b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_SL.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_SS.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_SS.dat new file mode 100644 index 0000000..1249720 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_SS.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_SX.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_SX.dat new file mode 100644 index 0000000..f8ab369 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_SX.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_SZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_SZ.dat new file mode 100644 index 0000000..2c0e2bc Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_SZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_TC.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_TC.dat new file mode 100644 index 0000000..71032ac Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_TC.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_TK.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_TK.dat new file mode 100644 index 0000000..063ad91 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_TK.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_TO.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_TO.dat new file mode 100644 index 0000000..257617a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_TO.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_TT.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_TT.dat new file mode 100644 index 0000000..d8b029f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_TT.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_TV.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_TV.dat new file mode 100644 index 0000000..f1d297c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_TV.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_TZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_TZ.dat new file mode 100644 index 0000000..c28bd17 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_TZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_UG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_UG.dat new file mode 100644 index 0000000..ded681a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_UG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_UM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_UM.dat new file mode 100644 index 0000000..adb6a75 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_UM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_US.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_US.dat new file mode 100644 index 0000000..dac50a5 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_US.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_US_POSIX.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_US_POSIX.dat new file mode 100644 index 0000000..61b9a28 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_US_POSIX.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_VC.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_VC.dat new file mode 100644 index 0000000..688b3c3 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_VC.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_VG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_VG.dat new file mode 100644 index 0000000..3691240 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_VG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_VI.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_VI.dat new file mode 100644 index 0000000..f6bf6da Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_VI.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_VU.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_VU.dat new file mode 100644 index 0000000..c3b3726 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_VU.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_WS.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_WS.dat new file mode 100644 index 0000000..2996164 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_WS.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_ZA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_ZA.dat new file mode 100644 index 0000000..80eee20 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_ZA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_ZM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_ZM.dat new file mode 100644 index 0000000..02230df Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_ZM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/en_ZW.dat b/venv/lib/python2.7/site-packages/babel/locale-data/en_ZW.dat new file mode 100644 index 0000000..1b83536 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/en_ZW.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/eo.dat b/venv/lib/python2.7/site-packages/babel/locale-data/eo.dat new file mode 100644 index 0000000..5c9049e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/eo.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/eo_001.dat b/venv/lib/python2.7/site-packages/babel/locale-data/eo_001.dat new file mode 100644 index 0000000..b0ba7e4 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/eo_001.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es.dat new file mode 100644 index 0000000..a31d9bb Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_419.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_419.dat new file mode 100644 index 0000000..bfad1a4 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_419.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_AR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_AR.dat new file mode 100644 index 0000000..91521ec Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_AR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_BO.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_BO.dat new file mode 100644 index 0000000..772f95c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_BO.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_BR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_BR.dat new file mode 100644 index 0000000..1c447eb Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_BR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_BZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_BZ.dat new file mode 100644 index 0000000..66d38e9 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_BZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_CL.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_CL.dat new file mode 100644 index 0000000..bb34873 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_CL.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_CO.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_CO.dat new file mode 100644 index 0000000..81ebe2f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_CO.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_CR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_CR.dat new file mode 100644 index 0000000..dfd84d0 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_CR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_CU.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_CU.dat new file mode 100644 index 0000000..4c76d13 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_CU.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_DO.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_DO.dat new file mode 100644 index 0000000..fce5ead Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_DO.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_EA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_EA.dat new file mode 100644 index 0000000..0bfc094 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_EA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_EC.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_EC.dat new file mode 100644 index 0000000..5e3c82f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_EC.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_ES.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_ES.dat new file mode 100644 index 0000000..1f89158 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_ES.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_GQ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_GQ.dat new file mode 100644 index 0000000..55efec1 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_GQ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_GT.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_GT.dat new file mode 100644 index 0000000..1ef6af3 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_GT.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_HN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_HN.dat new file mode 100644 index 0000000..b3a7b54 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_HN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_IC.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_IC.dat new file mode 100644 index 0000000..68f992d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_IC.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_MX.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_MX.dat new file mode 100644 index 0000000..0815382 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_MX.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_NI.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_NI.dat new file mode 100644 index 0000000..ed2d539 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_NI.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_PA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_PA.dat new file mode 100644 index 0000000..4941600 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_PA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_PE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_PE.dat new file mode 100644 index 0000000..4979846 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_PE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_PH.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_PH.dat new file mode 100644 index 0000000..2a0607c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_PH.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_PR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_PR.dat new file mode 100644 index 0000000..f63660b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_PR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_PY.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_PY.dat new file mode 100644 index 0000000..a4fd6b2 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_PY.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_SV.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_SV.dat new file mode 100644 index 0000000..dfb13a4 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_SV.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_US.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_US.dat new file mode 100644 index 0000000..4321b57 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_US.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_UY.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_UY.dat new file mode 100644 index 0000000..bd9d0de Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_UY.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/es_VE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/es_VE.dat new file mode 100644 index 0000000..9a27aae Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/es_VE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/et.dat b/venv/lib/python2.7/site-packages/babel/locale-data/et.dat new file mode 100644 index 0000000..2c30cbd Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/et.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/et_EE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/et_EE.dat new file mode 100644 index 0000000..c735961 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/et_EE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/eu.dat b/venv/lib/python2.7/site-packages/babel/locale-data/eu.dat new file mode 100644 index 0000000..32294b4 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/eu.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/eu_ES.dat b/venv/lib/python2.7/site-packages/babel/locale-data/eu_ES.dat new file mode 100644 index 0000000..d397b2c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/eu_ES.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ewo.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ewo.dat new file mode 100644 index 0000000..5b28426 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ewo.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ewo_CM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ewo_CM.dat new file mode 100644 index 0000000..b2f3fea Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ewo_CM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fa.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fa.dat new file mode 100644 index 0000000..c989915 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fa.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fa_AF.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fa_AF.dat new file mode 100644 index 0000000..6be8da2 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fa_AF.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fa_IR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fa_IR.dat new file mode 100644 index 0000000..369ce29 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fa_IR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ff.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ff.dat new file mode 100644 index 0000000..35c073e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ff.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ff_CM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ff_CM.dat new file mode 100644 index 0000000..7c043b7 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ff_CM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ff_GN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ff_GN.dat new file mode 100644 index 0000000..d4846a4 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ff_GN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ff_MR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ff_MR.dat new file mode 100644 index 0000000..b04210a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ff_MR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ff_SN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ff_SN.dat new file mode 100644 index 0000000..900c704 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ff_SN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fi.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fi.dat new file mode 100644 index 0000000..d334952 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fi.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fi_FI.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fi_FI.dat new file mode 100644 index 0000000..ce56083 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fi_FI.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fil.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fil.dat new file mode 100644 index 0000000..187598b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fil.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fil_PH.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fil_PH.dat new file mode 100644 index 0000000..a62f828 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fil_PH.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fo.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fo.dat new file mode 100644 index 0000000..30c22d3 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fo.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fo_DK.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fo_DK.dat new file mode 100644 index 0000000..56df395 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fo_DK.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fo_FO.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fo_FO.dat new file mode 100644 index 0000000..bb79f49 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fo_FO.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr.dat new file mode 100644 index 0000000..11362c7 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_BE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_BE.dat new file mode 100644 index 0000000..560da3a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_BE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_BF.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_BF.dat new file mode 100644 index 0000000..9c96ac5 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_BF.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_BI.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_BI.dat new file mode 100644 index 0000000..036a299 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_BI.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_BJ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_BJ.dat new file mode 100644 index 0000000..4cf7a4b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_BJ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_BL.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_BL.dat new file mode 100644 index 0000000..f0e0799 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_BL.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_CA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_CA.dat new file mode 100644 index 0000000..dcddefa Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_CA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_CD.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_CD.dat new file mode 100644 index 0000000..3d9892c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_CD.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_CF.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_CF.dat new file mode 100644 index 0000000..7d6930f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_CF.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_CG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_CG.dat new file mode 100644 index 0000000..4f13922 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_CG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_CH.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_CH.dat new file mode 100644 index 0000000..d20b00f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_CH.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_CI.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_CI.dat new file mode 100644 index 0000000..99ebc12 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_CI.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_CM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_CM.dat new file mode 100644 index 0000000..cadffd0 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_CM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_DJ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_DJ.dat new file mode 100644 index 0000000..2fd3322 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_DJ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_DZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_DZ.dat new file mode 100644 index 0000000..3b1da1d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_DZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_FR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_FR.dat new file mode 100644 index 0000000..6aaa0db Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_FR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_GA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_GA.dat new file mode 100644 index 0000000..4c9e09c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_GA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_GF.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_GF.dat new file mode 100644 index 0000000..adec26c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_GF.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_GN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_GN.dat new file mode 100644 index 0000000..2362675 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_GN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_GP.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_GP.dat new file mode 100644 index 0000000..267c2c0 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_GP.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_GQ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_GQ.dat new file mode 100644 index 0000000..30f12cc Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_GQ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_HT.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_HT.dat new file mode 100644 index 0000000..a143cfa Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_HT.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_KM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_KM.dat new file mode 100644 index 0000000..9ecabe8 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_KM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_LU.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_LU.dat new file mode 100644 index 0000000..375645b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_LU.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_MA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_MA.dat new file mode 100644 index 0000000..11dd3c9 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_MA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_MC.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_MC.dat new file mode 100644 index 0000000..7098e60 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_MC.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_MF.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_MF.dat new file mode 100644 index 0000000..f6ca32f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_MF.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_MG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_MG.dat new file mode 100644 index 0000000..a8b24b9 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_MG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_ML.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_ML.dat new file mode 100644 index 0000000..296f161 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_ML.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_MQ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_MQ.dat new file mode 100644 index 0000000..415b071 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_MQ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_MR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_MR.dat new file mode 100644 index 0000000..89db4f2 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_MR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_MU.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_MU.dat new file mode 100644 index 0000000..43fe573 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_MU.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_NC.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_NC.dat new file mode 100644 index 0000000..241ccd4 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_NC.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_NE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_NE.dat new file mode 100644 index 0000000..f50a44b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_NE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_PF.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_PF.dat new file mode 100644 index 0000000..2870d46 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_PF.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_PM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_PM.dat new file mode 100644 index 0000000..e298001 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_PM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_RE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_RE.dat new file mode 100644 index 0000000..ac5f421 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_RE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_RW.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_RW.dat new file mode 100644 index 0000000..ae534e0 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_RW.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_SC.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_SC.dat new file mode 100644 index 0000000..05dcd22 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_SC.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_SN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_SN.dat new file mode 100644 index 0000000..91244de Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_SN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_SY.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_SY.dat new file mode 100644 index 0000000..707c23e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_SY.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_TD.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_TD.dat new file mode 100644 index 0000000..b51d9c6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_TD.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_TG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_TG.dat new file mode 100644 index 0000000..bfea4ed Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_TG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_TN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_TN.dat new file mode 100644 index 0000000..c07a1b7 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_TN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_VU.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_VU.dat new file mode 100644 index 0000000..c1a5e8c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_VU.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_WF.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_WF.dat new file mode 100644 index 0000000..4af674b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_WF.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fr_YT.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fr_YT.dat new file mode 100644 index 0000000..b29c6f4 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fr_YT.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fur.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fur.dat new file mode 100644 index 0000000..8483f8a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fur.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fur_IT.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fur_IT.dat new file mode 100644 index 0000000..43eb2bd Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fur_IT.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fy.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fy.dat new file mode 100644 index 0000000..4b48d9f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fy.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/fy_NL.dat b/venv/lib/python2.7/site-packages/babel/locale-data/fy_NL.dat new file mode 100644 index 0000000..759481d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/fy_NL.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ga.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ga.dat new file mode 100644 index 0000000..f46a702 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ga.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ga_IE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ga_IE.dat new file mode 100644 index 0000000..ad5fcf2 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ga_IE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/gd.dat b/venv/lib/python2.7/site-packages/babel/locale-data/gd.dat new file mode 100644 index 0000000..b7df00d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/gd.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/gd_GB.dat b/venv/lib/python2.7/site-packages/babel/locale-data/gd_GB.dat new file mode 100644 index 0000000..eb8d588 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/gd_GB.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/gl.dat b/venv/lib/python2.7/site-packages/babel/locale-data/gl.dat new file mode 100644 index 0000000..e84552d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/gl.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/gl_ES.dat b/venv/lib/python2.7/site-packages/babel/locale-data/gl_ES.dat new file mode 100644 index 0000000..19d182e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/gl_ES.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/gsw.dat b/venv/lib/python2.7/site-packages/babel/locale-data/gsw.dat new file mode 100644 index 0000000..a6dedbb Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/gsw.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/gsw_CH.dat b/venv/lib/python2.7/site-packages/babel/locale-data/gsw_CH.dat new file mode 100644 index 0000000..1f2f296 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/gsw_CH.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/gsw_FR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/gsw_FR.dat new file mode 100644 index 0000000..8a82b19 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/gsw_FR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/gsw_LI.dat b/venv/lib/python2.7/site-packages/babel/locale-data/gsw_LI.dat new file mode 100644 index 0000000..921d270 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/gsw_LI.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/gu.dat b/venv/lib/python2.7/site-packages/babel/locale-data/gu.dat new file mode 100644 index 0000000..1e9b869 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/gu.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/gu_IN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/gu_IN.dat new file mode 100644 index 0000000..b804342 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/gu_IN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/guz.dat b/venv/lib/python2.7/site-packages/babel/locale-data/guz.dat new file mode 100644 index 0000000..149f286 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/guz.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/guz_KE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/guz_KE.dat new file mode 100644 index 0000000..012f84f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/guz_KE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/gv.dat b/venv/lib/python2.7/site-packages/babel/locale-data/gv.dat new file mode 100644 index 0000000..0bf431e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/gv.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/gv_IM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/gv_IM.dat new file mode 100644 index 0000000..9ca87e5 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/gv_IM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ha.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ha.dat new file mode 100644 index 0000000..752fc1b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ha.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ha_GH.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ha_GH.dat new file mode 100644 index 0000000..8d376ed Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ha_GH.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ha_NE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ha_NE.dat new file mode 100644 index 0000000..a353f0f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ha_NE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ha_NG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ha_NG.dat new file mode 100644 index 0000000..0f9296c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ha_NG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/haw.dat b/venv/lib/python2.7/site-packages/babel/locale-data/haw.dat new file mode 100644 index 0000000..94a1b35 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/haw.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/haw_US.dat b/venv/lib/python2.7/site-packages/babel/locale-data/haw_US.dat new file mode 100644 index 0000000..3645536 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/haw_US.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/he.dat b/venv/lib/python2.7/site-packages/babel/locale-data/he.dat new file mode 100644 index 0000000..c0e87f9 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/he.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/he_IL.dat b/venv/lib/python2.7/site-packages/babel/locale-data/he_IL.dat new file mode 100644 index 0000000..b420e0c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/he_IL.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/hi.dat b/venv/lib/python2.7/site-packages/babel/locale-data/hi.dat new file mode 100644 index 0000000..8ae032b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/hi.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/hi_IN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/hi_IN.dat new file mode 100644 index 0000000..5e7f13a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/hi_IN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/hr.dat b/venv/lib/python2.7/site-packages/babel/locale-data/hr.dat new file mode 100644 index 0000000..85a8a4d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/hr.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/hr_BA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/hr_BA.dat new file mode 100644 index 0000000..1308dd0 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/hr_BA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/hr_HR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/hr_HR.dat new file mode 100644 index 0000000..a32e3e1 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/hr_HR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/hsb.dat b/venv/lib/python2.7/site-packages/babel/locale-data/hsb.dat new file mode 100644 index 0000000..2f086c6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/hsb.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/hsb_DE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/hsb_DE.dat new file mode 100644 index 0000000..2f55fb9 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/hsb_DE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/hu.dat b/venv/lib/python2.7/site-packages/babel/locale-data/hu.dat new file mode 100644 index 0000000..91bd763 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/hu.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/hu_HU.dat b/venv/lib/python2.7/site-packages/babel/locale-data/hu_HU.dat new file mode 100644 index 0000000..e095326 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/hu_HU.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/hy.dat b/venv/lib/python2.7/site-packages/babel/locale-data/hy.dat new file mode 100644 index 0000000..36e52b0 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/hy.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/hy_AM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/hy_AM.dat new file mode 100644 index 0000000..b418a26 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/hy_AM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/id.dat b/venv/lib/python2.7/site-packages/babel/locale-data/id.dat new file mode 100644 index 0000000..de93d00 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/id.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/id_ID.dat b/venv/lib/python2.7/site-packages/babel/locale-data/id_ID.dat new file mode 100644 index 0000000..de60c05 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/id_ID.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ig.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ig.dat new file mode 100644 index 0000000..7dc4d9d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ig.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ig_NG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ig_NG.dat new file mode 100644 index 0000000..b908c17 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ig_NG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ii.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ii.dat new file mode 100644 index 0000000..5a8dc66 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ii.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ii_CN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ii_CN.dat new file mode 100644 index 0000000..b7692fe Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ii_CN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/is.dat b/venv/lib/python2.7/site-packages/babel/locale-data/is.dat new file mode 100644 index 0000000..8768478 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/is.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/is_IS.dat b/venv/lib/python2.7/site-packages/babel/locale-data/is_IS.dat new file mode 100644 index 0000000..37ba4d7 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/is_IS.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/it.dat b/venv/lib/python2.7/site-packages/babel/locale-data/it.dat new file mode 100644 index 0000000..05e466e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/it.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/it_CH.dat b/venv/lib/python2.7/site-packages/babel/locale-data/it_CH.dat new file mode 100644 index 0000000..b20f389 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/it_CH.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/it_IT.dat b/venv/lib/python2.7/site-packages/babel/locale-data/it_IT.dat new file mode 100644 index 0000000..47d8d08 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/it_IT.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/it_SM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/it_SM.dat new file mode 100644 index 0000000..236d980 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/it_SM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/it_VA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/it_VA.dat new file mode 100644 index 0000000..414c730 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/it_VA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ja.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ja.dat new file mode 100644 index 0000000..2990d45 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ja.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ja_JP.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ja_JP.dat new file mode 100644 index 0000000..02db209 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ja_JP.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/jgo.dat b/venv/lib/python2.7/site-packages/babel/locale-data/jgo.dat new file mode 100644 index 0000000..047be2a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/jgo.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/jgo_CM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/jgo_CM.dat new file mode 100644 index 0000000..65ed07b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/jgo_CM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/jmc.dat b/venv/lib/python2.7/site-packages/babel/locale-data/jmc.dat new file mode 100644 index 0000000..a667eb6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/jmc.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/jmc_TZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/jmc_TZ.dat new file mode 100644 index 0000000..eb49678 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/jmc_TZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ka.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ka.dat new file mode 100644 index 0000000..0c2ad34 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ka.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ka_GE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ka_GE.dat new file mode 100644 index 0000000..b8ff0fc Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ka_GE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/kab.dat b/venv/lib/python2.7/site-packages/babel/locale-data/kab.dat new file mode 100644 index 0000000..9e1f5ee Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/kab.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/kab_DZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/kab_DZ.dat new file mode 100644 index 0000000..a5f8d5d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/kab_DZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/kam.dat b/venv/lib/python2.7/site-packages/babel/locale-data/kam.dat new file mode 100644 index 0000000..6f559f1 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/kam.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/kam_KE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/kam_KE.dat new file mode 100644 index 0000000..90c9bec Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/kam_KE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/kde.dat b/venv/lib/python2.7/site-packages/babel/locale-data/kde.dat new file mode 100644 index 0000000..2d054c3 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/kde.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/kde_TZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/kde_TZ.dat new file mode 100644 index 0000000..c0d7c8e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/kde_TZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/kea.dat b/venv/lib/python2.7/site-packages/babel/locale-data/kea.dat new file mode 100644 index 0000000..5114305 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/kea.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/kea_CV.dat b/venv/lib/python2.7/site-packages/babel/locale-data/kea_CV.dat new file mode 100644 index 0000000..a48f48a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/kea_CV.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/khq.dat b/venv/lib/python2.7/site-packages/babel/locale-data/khq.dat new file mode 100644 index 0000000..675b4b2 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/khq.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/khq_ML.dat b/venv/lib/python2.7/site-packages/babel/locale-data/khq_ML.dat new file mode 100644 index 0000000..6ed462f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/khq_ML.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ki.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ki.dat new file mode 100644 index 0000000..6ab2851 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ki.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ki_KE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ki_KE.dat new file mode 100644 index 0000000..922beae Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ki_KE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/kk.dat b/venv/lib/python2.7/site-packages/babel/locale-data/kk.dat new file mode 100644 index 0000000..f19d33f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/kk.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/kk_KZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/kk_KZ.dat new file mode 100644 index 0000000..7d71f55 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/kk_KZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/kkj.dat b/venv/lib/python2.7/site-packages/babel/locale-data/kkj.dat new file mode 100644 index 0000000..fa40294 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/kkj.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/kkj_CM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/kkj_CM.dat new file mode 100644 index 0000000..a714198 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/kkj_CM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/kl.dat b/venv/lib/python2.7/site-packages/babel/locale-data/kl.dat new file mode 100644 index 0000000..68da5d8 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/kl.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/kl_GL.dat b/venv/lib/python2.7/site-packages/babel/locale-data/kl_GL.dat new file mode 100644 index 0000000..cf6d06d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/kl_GL.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/kln.dat b/venv/lib/python2.7/site-packages/babel/locale-data/kln.dat new file mode 100644 index 0000000..32dbb0c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/kln.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/kln_KE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/kln_KE.dat new file mode 100644 index 0000000..a148607 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/kln_KE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/km.dat b/venv/lib/python2.7/site-packages/babel/locale-data/km.dat new file mode 100644 index 0000000..3717456 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/km.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/km_KH.dat b/venv/lib/python2.7/site-packages/babel/locale-data/km_KH.dat new file mode 100644 index 0000000..8f02ccc Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/km_KH.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/kn.dat b/venv/lib/python2.7/site-packages/babel/locale-data/kn.dat new file mode 100644 index 0000000..e7eb35d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/kn.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/kn_IN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/kn_IN.dat new file mode 100644 index 0000000..8741e0f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/kn_IN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ko.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ko.dat new file mode 100644 index 0000000..931d939 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ko.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ko_KP.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ko_KP.dat new file mode 100644 index 0000000..fc772b0 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ko_KP.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ko_KR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ko_KR.dat new file mode 100644 index 0000000..6f3f08a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ko_KR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/kok.dat b/venv/lib/python2.7/site-packages/babel/locale-data/kok.dat new file mode 100644 index 0000000..9450f7d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/kok.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/kok_IN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/kok_IN.dat new file mode 100644 index 0000000..64d18ce Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/kok_IN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ks.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ks.dat new file mode 100644 index 0000000..042ae7c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ks.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ks_IN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ks_IN.dat new file mode 100644 index 0000000..60c431b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ks_IN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ksb.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ksb.dat new file mode 100644 index 0000000..0cc79e8 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ksb.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ksb_TZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ksb_TZ.dat new file mode 100644 index 0000000..1223601 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ksb_TZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ksf.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ksf.dat new file mode 100644 index 0000000..b06fdda Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ksf.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ksf_CM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ksf_CM.dat new file mode 100644 index 0000000..f9da2a6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ksf_CM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ksh.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ksh.dat new file mode 100644 index 0000000..278b712 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ksh.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ksh_DE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ksh_DE.dat new file mode 100644 index 0000000..ea025f5 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ksh_DE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/kw.dat b/venv/lib/python2.7/site-packages/babel/locale-data/kw.dat new file mode 100644 index 0000000..9d336fd Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/kw.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/kw_GB.dat b/venv/lib/python2.7/site-packages/babel/locale-data/kw_GB.dat new file mode 100644 index 0000000..064c9ef Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/kw_GB.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ky.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ky.dat new file mode 100644 index 0000000..30ec42f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ky.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ky_KG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ky_KG.dat new file mode 100644 index 0000000..a3c7b75 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ky_KG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/lag.dat b/venv/lib/python2.7/site-packages/babel/locale-data/lag.dat new file mode 100644 index 0000000..5a18b23 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/lag.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/lag_TZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/lag_TZ.dat new file mode 100644 index 0000000..45309f5 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/lag_TZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/lb.dat b/venv/lib/python2.7/site-packages/babel/locale-data/lb.dat new file mode 100644 index 0000000..45e11c2 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/lb.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/lb_LU.dat b/venv/lib/python2.7/site-packages/babel/locale-data/lb_LU.dat new file mode 100644 index 0000000..386506b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/lb_LU.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/lg.dat b/venv/lib/python2.7/site-packages/babel/locale-data/lg.dat new file mode 100644 index 0000000..261cee1 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/lg.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/lg_UG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/lg_UG.dat new file mode 100644 index 0000000..2bb3fb4 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/lg_UG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/lkt.dat b/venv/lib/python2.7/site-packages/babel/locale-data/lkt.dat new file mode 100644 index 0000000..48c5e9a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/lkt.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/lkt_US.dat b/venv/lib/python2.7/site-packages/babel/locale-data/lkt_US.dat new file mode 100644 index 0000000..1609b0a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/lkt_US.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ln.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ln.dat new file mode 100644 index 0000000..4cef973 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ln.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ln_AO.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ln_AO.dat new file mode 100644 index 0000000..183950d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ln_AO.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ln_CD.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ln_CD.dat new file mode 100644 index 0000000..8ca5256 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ln_CD.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ln_CF.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ln_CF.dat new file mode 100644 index 0000000..5cafa01 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ln_CF.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ln_CG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ln_CG.dat new file mode 100644 index 0000000..a0b58d1 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ln_CG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/lo.dat b/venv/lib/python2.7/site-packages/babel/locale-data/lo.dat new file mode 100644 index 0000000..eed8c28 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/lo.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/lo_LA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/lo_LA.dat new file mode 100644 index 0000000..0b66c74 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/lo_LA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/lrc.dat b/venv/lib/python2.7/site-packages/babel/locale-data/lrc.dat new file mode 100644 index 0000000..95b4396 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/lrc.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/lrc_IQ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/lrc_IQ.dat new file mode 100644 index 0000000..87ae86d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/lrc_IQ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/lrc_IR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/lrc_IR.dat new file mode 100644 index 0000000..5200aeb Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/lrc_IR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/lt.dat b/venv/lib/python2.7/site-packages/babel/locale-data/lt.dat new file mode 100644 index 0000000..1b1b0dc Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/lt.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/lt_LT.dat b/venv/lib/python2.7/site-packages/babel/locale-data/lt_LT.dat new file mode 100644 index 0000000..5d19cee Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/lt_LT.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/lu.dat b/venv/lib/python2.7/site-packages/babel/locale-data/lu.dat new file mode 100644 index 0000000..3afc849 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/lu.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/lu_CD.dat b/venv/lib/python2.7/site-packages/babel/locale-data/lu_CD.dat new file mode 100644 index 0000000..76a4971 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/lu_CD.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/luo.dat b/venv/lib/python2.7/site-packages/babel/locale-data/luo.dat new file mode 100644 index 0000000..bf456e6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/luo.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/luo_KE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/luo_KE.dat new file mode 100644 index 0000000..8e16cf1 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/luo_KE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/luy.dat b/venv/lib/python2.7/site-packages/babel/locale-data/luy.dat new file mode 100644 index 0000000..6e56059 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/luy.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/luy_KE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/luy_KE.dat new file mode 100644 index 0000000..772fb1e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/luy_KE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/lv.dat b/venv/lib/python2.7/site-packages/babel/locale-data/lv.dat new file mode 100644 index 0000000..c4d12e6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/lv.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/lv_LV.dat b/venv/lib/python2.7/site-packages/babel/locale-data/lv_LV.dat new file mode 100644 index 0000000..3d44606 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/lv_LV.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mas.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mas.dat new file mode 100644 index 0000000..cea51f1 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mas.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mas_KE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mas_KE.dat new file mode 100644 index 0000000..18a9a09 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mas_KE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mas_TZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mas_TZ.dat new file mode 100644 index 0000000..728bd0c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mas_TZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mer.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mer.dat new file mode 100644 index 0000000..6e18305 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mer.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mer_KE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mer_KE.dat new file mode 100644 index 0000000..5a7a4a6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mer_KE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mfe.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mfe.dat new file mode 100644 index 0000000..e264b29 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mfe.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mfe_MU.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mfe_MU.dat new file mode 100644 index 0000000..5eeb2ca Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mfe_MU.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mg.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mg.dat new file mode 100644 index 0000000..744515b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mg.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mg_MG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mg_MG.dat new file mode 100644 index 0000000..0739db3 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mg_MG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mgh.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mgh.dat new file mode 100644 index 0000000..49ca844 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mgh.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mgh_MZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mgh_MZ.dat new file mode 100644 index 0000000..75423fd Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mgh_MZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mgo.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mgo.dat new file mode 100644 index 0000000..2d314b8 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mgo.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mgo_CM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mgo_CM.dat new file mode 100644 index 0000000..a5ea52d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mgo_CM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mk.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mk.dat new file mode 100644 index 0000000..6358cd9 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mk.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mk_MK.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mk_MK.dat new file mode 100644 index 0000000..05c216c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mk_MK.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ml.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ml.dat new file mode 100644 index 0000000..3cf66c6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ml.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ml_IN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ml_IN.dat new file mode 100644 index 0000000..b53075e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ml_IN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mn.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mn.dat new file mode 100644 index 0000000..23f1002 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mn.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mn_MN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mn_MN.dat new file mode 100644 index 0000000..a4f4af7 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mn_MN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mr.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mr.dat new file mode 100644 index 0000000..f2c1b23 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mr.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mr_IN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mr_IN.dat new file mode 100644 index 0000000..06ad81b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mr_IN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ms.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ms.dat new file mode 100644 index 0000000..1438b33 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ms.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ms_BN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ms_BN.dat new file mode 100644 index 0000000..76c68ee Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ms_BN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ms_MY.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ms_MY.dat new file mode 100644 index 0000000..ff3e6d9 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ms_MY.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ms_SG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ms_SG.dat new file mode 100644 index 0000000..d7ee6e2 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ms_SG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mt.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mt.dat new file mode 100644 index 0000000..8d1400e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mt.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mt_MT.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mt_MT.dat new file mode 100644 index 0000000..9fc5a36 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mt_MT.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mua.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mua.dat new file mode 100644 index 0000000..be136bb Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mua.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mua_CM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mua_CM.dat new file mode 100644 index 0000000..cdc2c34 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mua_CM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/my.dat b/venv/lib/python2.7/site-packages/babel/locale-data/my.dat new file mode 100644 index 0000000..45513cd Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/my.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/my_MM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/my_MM.dat new file mode 100644 index 0000000..ae746a7 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/my_MM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mzn.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mzn.dat new file mode 100644 index 0000000..fd56911 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mzn.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/mzn_IR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/mzn_IR.dat new file mode 100644 index 0000000..0ddac3b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/mzn_IR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/naq.dat b/venv/lib/python2.7/site-packages/babel/locale-data/naq.dat new file mode 100644 index 0000000..52a04c6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/naq.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/naq_NA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/naq_NA.dat new file mode 100644 index 0000000..9d96216 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/naq_NA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nb.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nb.dat new file mode 100644 index 0000000..ff6f2e1 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nb.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nb_NO.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nb_NO.dat new file mode 100644 index 0000000..064f195 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nb_NO.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nb_SJ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nb_SJ.dat new file mode 100644 index 0000000..8792142 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nb_SJ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nd.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nd.dat new file mode 100644 index 0000000..c4fba32 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nd.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nd_ZW.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nd_ZW.dat new file mode 100644 index 0000000..992c7f7 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nd_ZW.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nds.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nds.dat new file mode 100644 index 0000000..fcc7659 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nds.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nds_DE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nds_DE.dat new file mode 100644 index 0000000..8dfa891 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nds_DE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nds_NL.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nds_NL.dat new file mode 100644 index 0000000..1f1a1d4 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nds_NL.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ne.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ne.dat new file mode 100644 index 0000000..82373d2 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ne.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ne_IN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ne_IN.dat new file mode 100644 index 0000000..41c7fd5 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ne_IN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ne_NP.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ne_NP.dat new file mode 100644 index 0000000..af81bc8 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ne_NP.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nl.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nl.dat new file mode 100644 index 0000000..ffde39e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nl.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nl_AW.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nl_AW.dat new file mode 100644 index 0000000..f898f13 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nl_AW.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nl_BE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nl_BE.dat new file mode 100644 index 0000000..7c40de7 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nl_BE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nl_BQ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nl_BQ.dat new file mode 100644 index 0000000..1398810 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nl_BQ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nl_CW.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nl_CW.dat new file mode 100644 index 0000000..0f81a33 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nl_CW.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nl_NL.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nl_NL.dat new file mode 100644 index 0000000..3dd943d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nl_NL.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nl_SR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nl_SR.dat new file mode 100644 index 0000000..1d70525 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nl_SR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nl_SX.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nl_SX.dat new file mode 100644 index 0000000..946040d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nl_SX.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nmg.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nmg.dat new file mode 100644 index 0000000..082e069 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nmg.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nmg_CM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nmg_CM.dat new file mode 100644 index 0000000..9adcf3a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nmg_CM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nn.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nn.dat new file mode 100644 index 0000000..41ff15b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nn.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nn_NO.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nn_NO.dat new file mode 100644 index 0000000..06f2e44 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nn_NO.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nnh.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nnh.dat new file mode 100644 index 0000000..0594f76 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nnh.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nnh_CM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nnh_CM.dat new file mode 100644 index 0000000..914cda2 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nnh_CM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nus.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nus.dat new file mode 100644 index 0000000..6a69691 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nus.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nus_SS.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nus_SS.dat new file mode 100644 index 0000000..2d7fd09 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nus_SS.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nyn.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nyn.dat new file mode 100644 index 0000000..def53ef Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nyn.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/nyn_UG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/nyn_UG.dat new file mode 100644 index 0000000..c8ebab6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/nyn_UG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/om.dat b/venv/lib/python2.7/site-packages/babel/locale-data/om.dat new file mode 100644 index 0000000..519d14f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/om.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/om_ET.dat b/venv/lib/python2.7/site-packages/babel/locale-data/om_ET.dat new file mode 100644 index 0000000..24647e1 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/om_ET.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/om_KE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/om_KE.dat new file mode 100644 index 0000000..7a6458a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/om_KE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/or.dat b/venv/lib/python2.7/site-packages/babel/locale-data/or.dat new file mode 100644 index 0000000..dc28b4d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/or.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/or_IN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/or_IN.dat new file mode 100644 index 0000000..225aa81 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/or_IN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/os.dat b/venv/lib/python2.7/site-packages/babel/locale-data/os.dat new file mode 100644 index 0000000..950449d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/os.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/os_GE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/os_GE.dat new file mode 100644 index 0000000..c75b219 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/os_GE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/os_RU.dat b/venv/lib/python2.7/site-packages/babel/locale-data/os_RU.dat new file mode 100644 index 0000000..66c37a7 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/os_RU.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/pa.dat b/venv/lib/python2.7/site-packages/babel/locale-data/pa.dat new file mode 100644 index 0000000..4b0324f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/pa.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/pa_Arab.dat b/venv/lib/python2.7/site-packages/babel/locale-data/pa_Arab.dat new file mode 100644 index 0000000..35c0b05 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/pa_Arab.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/pa_Arab_PK.dat b/venv/lib/python2.7/site-packages/babel/locale-data/pa_Arab_PK.dat new file mode 100644 index 0000000..c929d1e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/pa_Arab_PK.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/pa_Guru.dat b/venv/lib/python2.7/site-packages/babel/locale-data/pa_Guru.dat new file mode 100644 index 0000000..dbaa9e6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/pa_Guru.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/pa_Guru_IN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/pa_Guru_IN.dat new file mode 100644 index 0000000..3033953 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/pa_Guru_IN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/pl.dat b/venv/lib/python2.7/site-packages/babel/locale-data/pl.dat new file mode 100644 index 0000000..ddbf79a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/pl.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/pl_PL.dat b/venv/lib/python2.7/site-packages/babel/locale-data/pl_PL.dat new file mode 100644 index 0000000..48f4089 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/pl_PL.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/prg.dat b/venv/lib/python2.7/site-packages/babel/locale-data/prg.dat new file mode 100644 index 0000000..3b22973 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/prg.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/prg_001.dat b/venv/lib/python2.7/site-packages/babel/locale-data/prg_001.dat new file mode 100644 index 0000000..6beaf17 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/prg_001.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ps.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ps.dat new file mode 100644 index 0000000..c5c61a6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ps.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ps_AF.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ps_AF.dat new file mode 100644 index 0000000..8a929ff Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ps_AF.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/pt.dat b/venv/lib/python2.7/site-packages/babel/locale-data/pt.dat new file mode 100644 index 0000000..2f816f2 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/pt.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/pt_AO.dat b/venv/lib/python2.7/site-packages/babel/locale-data/pt_AO.dat new file mode 100644 index 0000000..03f8c98 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/pt_AO.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/pt_BR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/pt_BR.dat new file mode 100644 index 0000000..8ccd0ac Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/pt_BR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/pt_CH.dat b/venv/lib/python2.7/site-packages/babel/locale-data/pt_CH.dat new file mode 100644 index 0000000..c9188f4 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/pt_CH.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/pt_CV.dat b/venv/lib/python2.7/site-packages/babel/locale-data/pt_CV.dat new file mode 100644 index 0000000..e5791d9 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/pt_CV.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/pt_GQ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/pt_GQ.dat new file mode 100644 index 0000000..9a4526e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/pt_GQ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/pt_GW.dat b/venv/lib/python2.7/site-packages/babel/locale-data/pt_GW.dat new file mode 100644 index 0000000..53e156a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/pt_GW.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/pt_LU.dat b/venv/lib/python2.7/site-packages/babel/locale-data/pt_LU.dat new file mode 100644 index 0000000..0377835 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/pt_LU.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/pt_MO.dat b/venv/lib/python2.7/site-packages/babel/locale-data/pt_MO.dat new file mode 100644 index 0000000..d82176e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/pt_MO.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/pt_MZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/pt_MZ.dat new file mode 100644 index 0000000..8cf10f5 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/pt_MZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/pt_PT.dat b/venv/lib/python2.7/site-packages/babel/locale-data/pt_PT.dat new file mode 100644 index 0000000..ad0679d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/pt_PT.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/pt_ST.dat b/venv/lib/python2.7/site-packages/babel/locale-data/pt_ST.dat new file mode 100644 index 0000000..ef11fff Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/pt_ST.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/pt_TL.dat b/venv/lib/python2.7/site-packages/babel/locale-data/pt_TL.dat new file mode 100644 index 0000000..eaef918 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/pt_TL.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/qu.dat b/venv/lib/python2.7/site-packages/babel/locale-data/qu.dat new file mode 100644 index 0000000..05826a6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/qu.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/qu_BO.dat b/venv/lib/python2.7/site-packages/babel/locale-data/qu_BO.dat new file mode 100644 index 0000000..f03cce3 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/qu_BO.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/qu_EC.dat b/venv/lib/python2.7/site-packages/babel/locale-data/qu_EC.dat new file mode 100644 index 0000000..f0d0010 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/qu_EC.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/qu_PE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/qu_PE.dat new file mode 100644 index 0000000..e49bbc0 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/qu_PE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/rm.dat b/venv/lib/python2.7/site-packages/babel/locale-data/rm.dat new file mode 100644 index 0000000..c3a5094 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/rm.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/rm_CH.dat b/venv/lib/python2.7/site-packages/babel/locale-data/rm_CH.dat new file mode 100644 index 0000000..7f40817 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/rm_CH.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/rn.dat b/venv/lib/python2.7/site-packages/babel/locale-data/rn.dat new file mode 100644 index 0000000..0b7190b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/rn.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/rn_BI.dat b/venv/lib/python2.7/site-packages/babel/locale-data/rn_BI.dat new file mode 100644 index 0000000..8c7c159 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/rn_BI.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ro.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ro.dat new file mode 100644 index 0000000..8106c7f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ro.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ro_MD.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ro_MD.dat new file mode 100644 index 0000000..c9b02d3 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ro_MD.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ro_RO.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ro_RO.dat new file mode 100644 index 0000000..0095bba Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ro_RO.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/rof.dat b/venv/lib/python2.7/site-packages/babel/locale-data/rof.dat new file mode 100644 index 0000000..b4ba958 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/rof.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/rof_TZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/rof_TZ.dat new file mode 100644 index 0000000..f6d694a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/rof_TZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/root.dat b/venv/lib/python2.7/site-packages/babel/locale-data/root.dat new file mode 100644 index 0000000..c469c80 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/root.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ru.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ru.dat new file mode 100644 index 0000000..fd85575 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ru.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ru_BY.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ru_BY.dat new file mode 100644 index 0000000..b1f3aee Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ru_BY.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ru_KG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ru_KG.dat new file mode 100644 index 0000000..7f683e7 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ru_KG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ru_KZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ru_KZ.dat new file mode 100644 index 0000000..cafa799 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ru_KZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ru_MD.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ru_MD.dat new file mode 100644 index 0000000..3c05fe6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ru_MD.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ru_RU.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ru_RU.dat new file mode 100644 index 0000000..4c2eed0 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ru_RU.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ru_UA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ru_UA.dat new file mode 100644 index 0000000..d1de031 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ru_UA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/rw.dat b/venv/lib/python2.7/site-packages/babel/locale-data/rw.dat new file mode 100644 index 0000000..237aeb9 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/rw.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/rw_RW.dat b/venv/lib/python2.7/site-packages/babel/locale-data/rw_RW.dat new file mode 100644 index 0000000..d2e99cf Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/rw_RW.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/rwk.dat b/venv/lib/python2.7/site-packages/babel/locale-data/rwk.dat new file mode 100644 index 0000000..479049e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/rwk.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/rwk_TZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/rwk_TZ.dat new file mode 100644 index 0000000..e683208 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/rwk_TZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sah.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sah.dat new file mode 100644 index 0000000..f47a47a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sah.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sah_RU.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sah_RU.dat new file mode 100644 index 0000000..7050309 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sah_RU.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/saq.dat b/venv/lib/python2.7/site-packages/babel/locale-data/saq.dat new file mode 100644 index 0000000..9ff373a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/saq.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/saq_KE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/saq_KE.dat new file mode 100644 index 0000000..4eb0d18 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/saq_KE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sbp.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sbp.dat new file mode 100644 index 0000000..606eebf Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sbp.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sbp_TZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sbp_TZ.dat new file mode 100644 index 0000000..93a079e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sbp_TZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sd.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sd.dat new file mode 100644 index 0000000..7820c98 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sd.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sd_PK.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sd_PK.dat new file mode 100644 index 0000000..fa3ed74 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sd_PK.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/se.dat b/venv/lib/python2.7/site-packages/babel/locale-data/se.dat new file mode 100644 index 0000000..91dccd8 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/se.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/se_FI.dat b/venv/lib/python2.7/site-packages/babel/locale-data/se_FI.dat new file mode 100644 index 0000000..e4f77c6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/se_FI.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/se_NO.dat b/venv/lib/python2.7/site-packages/babel/locale-data/se_NO.dat new file mode 100644 index 0000000..a6bdcc7 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/se_NO.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/se_SE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/se_SE.dat new file mode 100644 index 0000000..b3b0f79 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/se_SE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/seh.dat b/venv/lib/python2.7/site-packages/babel/locale-data/seh.dat new file mode 100644 index 0000000..7c8e6f4 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/seh.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/seh_MZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/seh_MZ.dat new file mode 100644 index 0000000..dc54990 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/seh_MZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ses.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ses.dat new file mode 100644 index 0000000..86cef94 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ses.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ses_ML.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ses_ML.dat new file mode 100644 index 0000000..bd53231 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ses_ML.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sg.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sg.dat new file mode 100644 index 0000000..bff585d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sg.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sg_CF.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sg_CF.dat new file mode 100644 index 0000000..cb0e93f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sg_CF.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/shi.dat b/venv/lib/python2.7/site-packages/babel/locale-data/shi.dat new file mode 100644 index 0000000..9d0654c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/shi.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/shi_Latn.dat b/venv/lib/python2.7/site-packages/babel/locale-data/shi_Latn.dat new file mode 100644 index 0000000..389e5fe Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/shi_Latn.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/shi_Latn_MA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/shi_Latn_MA.dat new file mode 100644 index 0000000..d0d6626 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/shi_Latn_MA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/shi_Tfng.dat b/venv/lib/python2.7/site-packages/babel/locale-data/shi_Tfng.dat new file mode 100644 index 0000000..5e2bd8a Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/shi_Tfng.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/shi_Tfng_MA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/shi_Tfng_MA.dat new file mode 100644 index 0000000..d0d6626 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/shi_Tfng_MA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/si.dat b/venv/lib/python2.7/site-packages/babel/locale-data/si.dat new file mode 100644 index 0000000..9cd13ad Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/si.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/si_LK.dat b/venv/lib/python2.7/site-packages/babel/locale-data/si_LK.dat new file mode 100644 index 0000000..b081fd2 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/si_LK.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sk.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sk.dat new file mode 100644 index 0000000..2fd90f7 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sk.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sk_SK.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sk_SK.dat new file mode 100644 index 0000000..d04b5a1 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sk_SK.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sl.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sl.dat new file mode 100644 index 0000000..ad4de03 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sl.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sl_SI.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sl_SI.dat new file mode 100644 index 0000000..9cd99cc Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sl_SI.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/smn.dat b/venv/lib/python2.7/site-packages/babel/locale-data/smn.dat new file mode 100644 index 0000000..00068fd Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/smn.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/smn_FI.dat b/venv/lib/python2.7/site-packages/babel/locale-data/smn_FI.dat new file mode 100644 index 0000000..3085e87 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/smn_FI.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sn.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sn.dat new file mode 100644 index 0000000..bed43a6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sn.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sn_ZW.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sn_ZW.dat new file mode 100644 index 0000000..177570c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sn_ZW.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/so.dat b/venv/lib/python2.7/site-packages/babel/locale-data/so.dat new file mode 100644 index 0000000..73d1873 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/so.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/so_DJ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/so_DJ.dat new file mode 100644 index 0000000..7fb31d7 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/so_DJ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/so_ET.dat b/venv/lib/python2.7/site-packages/babel/locale-data/so_ET.dat new file mode 100644 index 0000000..5a66b21 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/so_ET.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/so_KE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/so_KE.dat new file mode 100644 index 0000000..538a627 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/so_KE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/so_SO.dat b/venv/lib/python2.7/site-packages/babel/locale-data/so_SO.dat new file mode 100644 index 0000000..0798b41 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/so_SO.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sq.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sq.dat new file mode 100644 index 0000000..e16183b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sq.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sq_AL.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sq_AL.dat new file mode 100644 index 0000000..57f214e Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sq_AL.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sq_MK.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sq_MK.dat new file mode 100644 index 0000000..78bb733 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sq_MK.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sq_XK.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sq_XK.dat new file mode 100644 index 0000000..c76b473 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sq_XK.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sr.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sr.dat new file mode 100644 index 0000000..17e58c7 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sr.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sr_Cyrl.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sr_Cyrl.dat new file mode 100644 index 0000000..66e7c53 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sr_Cyrl.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sr_Cyrl_BA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sr_Cyrl_BA.dat new file mode 100644 index 0000000..0a649ba Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sr_Cyrl_BA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sr_Cyrl_ME.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sr_Cyrl_ME.dat new file mode 100644 index 0000000..8b91237 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sr_Cyrl_ME.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sr_Cyrl_RS.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sr_Cyrl_RS.dat new file mode 100644 index 0000000..ee97c2d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sr_Cyrl_RS.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sr_Cyrl_XK.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sr_Cyrl_XK.dat new file mode 100644 index 0000000..5861aef Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sr_Cyrl_XK.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sr_Latn.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sr_Latn.dat new file mode 100644 index 0000000..ef591d5 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sr_Latn.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sr_Latn_BA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sr_Latn_BA.dat new file mode 100644 index 0000000..9e7afed Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sr_Latn_BA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sr_Latn_ME.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sr_Latn_ME.dat new file mode 100644 index 0000000..05f52a3 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sr_Latn_ME.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sr_Latn_RS.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sr_Latn_RS.dat new file mode 100644 index 0000000..ee97c2d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sr_Latn_RS.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sr_Latn_XK.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sr_Latn_XK.dat new file mode 100644 index 0000000..d91bdf8 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sr_Latn_XK.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sv.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sv.dat new file mode 100644 index 0000000..2a4b832 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sv.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sv_AX.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sv_AX.dat new file mode 100644 index 0000000..bf0c5c0 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sv_AX.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sv_FI.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sv_FI.dat new file mode 100644 index 0000000..887b57c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sv_FI.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sv_SE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sv_SE.dat new file mode 100644 index 0000000..0eac3e4 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sv_SE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sw.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sw.dat new file mode 100644 index 0000000..ab6f980 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sw.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sw_CD.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sw_CD.dat new file mode 100644 index 0000000..01e10fc Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sw_CD.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sw_KE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sw_KE.dat new file mode 100644 index 0000000..ddc20e7 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sw_KE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sw_TZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sw_TZ.dat new file mode 100644 index 0000000..bd76e78 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sw_TZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/sw_UG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/sw_UG.dat new file mode 100644 index 0000000..2ceabc7 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/sw_UG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ta.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ta.dat new file mode 100644 index 0000000..0ffbe73 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ta.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ta_IN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ta_IN.dat new file mode 100644 index 0000000..ec278f8 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ta_IN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ta_LK.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ta_LK.dat new file mode 100644 index 0000000..8420c4f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ta_LK.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ta_MY.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ta_MY.dat new file mode 100644 index 0000000..0eb6925 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ta_MY.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ta_SG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ta_SG.dat new file mode 100644 index 0000000..bf50ad3 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ta_SG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/te.dat b/venv/lib/python2.7/site-packages/babel/locale-data/te.dat new file mode 100644 index 0000000..b2ffe34 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/te.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/te_IN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/te_IN.dat new file mode 100644 index 0000000..a13ca16 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/te_IN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/teo.dat b/venv/lib/python2.7/site-packages/babel/locale-data/teo.dat new file mode 100644 index 0000000..cade2d3 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/teo.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/teo_KE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/teo_KE.dat new file mode 100644 index 0000000..eaf7b4f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/teo_KE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/teo_UG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/teo_UG.dat new file mode 100644 index 0000000..51f213b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/teo_UG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/tg.dat b/venv/lib/python2.7/site-packages/babel/locale-data/tg.dat new file mode 100644 index 0000000..947e576 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/tg.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/tg_TJ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/tg_TJ.dat new file mode 100644 index 0000000..7c21a6d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/tg_TJ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/th.dat b/venv/lib/python2.7/site-packages/babel/locale-data/th.dat new file mode 100644 index 0000000..135e295 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/th.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/th_TH.dat b/venv/lib/python2.7/site-packages/babel/locale-data/th_TH.dat new file mode 100644 index 0000000..dee51ea Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/th_TH.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ti.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ti.dat new file mode 100644 index 0000000..0048f21 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ti.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ti_ER.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ti_ER.dat new file mode 100644 index 0000000..d8ddab2 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ti_ER.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ti_ET.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ti_ET.dat new file mode 100644 index 0000000..a41754d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ti_ET.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/tk.dat b/venv/lib/python2.7/site-packages/babel/locale-data/tk.dat new file mode 100644 index 0000000..153e5af Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/tk.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/tk_TM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/tk_TM.dat new file mode 100644 index 0000000..6654113 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/tk_TM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/to.dat b/venv/lib/python2.7/site-packages/babel/locale-data/to.dat new file mode 100644 index 0000000..66a7804 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/to.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/to_TO.dat b/venv/lib/python2.7/site-packages/babel/locale-data/to_TO.dat new file mode 100644 index 0000000..1b5e8e3 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/to_TO.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/tr.dat b/venv/lib/python2.7/site-packages/babel/locale-data/tr.dat new file mode 100644 index 0000000..802d53f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/tr.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/tr_CY.dat b/venv/lib/python2.7/site-packages/babel/locale-data/tr_CY.dat new file mode 100644 index 0000000..ea500f1 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/tr_CY.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/tr_TR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/tr_TR.dat new file mode 100644 index 0000000..4f60eb0 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/tr_TR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/tt.dat b/venv/lib/python2.7/site-packages/babel/locale-data/tt.dat new file mode 100644 index 0000000..392389d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/tt.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/tt_RU.dat b/venv/lib/python2.7/site-packages/babel/locale-data/tt_RU.dat new file mode 100644 index 0000000..14764b2 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/tt_RU.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/twq.dat b/venv/lib/python2.7/site-packages/babel/locale-data/twq.dat new file mode 100644 index 0000000..2c3eade Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/twq.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/twq_NE.dat b/venv/lib/python2.7/site-packages/babel/locale-data/twq_NE.dat new file mode 100644 index 0000000..56de984 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/twq_NE.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/tzm.dat b/venv/lib/python2.7/site-packages/babel/locale-data/tzm.dat new file mode 100644 index 0000000..704abb5 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/tzm.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/tzm_MA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/tzm_MA.dat new file mode 100644 index 0000000..04741ab Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/tzm_MA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ug.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ug.dat new file mode 100644 index 0000000..3a3a361 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ug.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ug_CN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ug_CN.dat new file mode 100644 index 0000000..25b4986 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ug_CN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/uk.dat b/venv/lib/python2.7/site-packages/babel/locale-data/uk.dat new file mode 100644 index 0000000..83a6513 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/uk.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/uk_UA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/uk_UA.dat new file mode 100644 index 0000000..534dab2 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/uk_UA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ur.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ur.dat new file mode 100644 index 0000000..c0843d7 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ur.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ur_IN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ur_IN.dat new file mode 100644 index 0000000..b828d6c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ur_IN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/ur_PK.dat b/venv/lib/python2.7/site-packages/babel/locale-data/ur_PK.dat new file mode 100644 index 0000000..54a51bb Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/ur_PK.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/uz.dat b/venv/lib/python2.7/site-packages/babel/locale-data/uz.dat new file mode 100644 index 0000000..13b4263 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/uz.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/uz_Arab.dat b/venv/lib/python2.7/site-packages/babel/locale-data/uz_Arab.dat new file mode 100644 index 0000000..1dae044 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/uz_Arab.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/uz_Arab_AF.dat b/venv/lib/python2.7/site-packages/babel/locale-data/uz_Arab_AF.dat new file mode 100644 index 0000000..d222b3b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/uz_Arab_AF.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/uz_Cyrl.dat b/venv/lib/python2.7/site-packages/babel/locale-data/uz_Cyrl.dat new file mode 100644 index 0000000..fe96fbe Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/uz_Cyrl.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/uz_Cyrl_UZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/uz_Cyrl_UZ.dat new file mode 100644 index 0000000..d16b8a0 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/uz_Cyrl_UZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/uz_Latn.dat b/venv/lib/python2.7/site-packages/babel/locale-data/uz_Latn.dat new file mode 100644 index 0000000..2931ac5 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/uz_Latn.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/uz_Latn_UZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/uz_Latn_UZ.dat new file mode 100644 index 0000000..79b751c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/uz_Latn_UZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/vai.dat b/venv/lib/python2.7/site-packages/babel/locale-data/vai.dat new file mode 100644 index 0000000..58fbe80 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/vai.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/vai_Latn.dat b/venv/lib/python2.7/site-packages/babel/locale-data/vai_Latn.dat new file mode 100644 index 0000000..5110acd Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/vai_Latn.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/vai_Latn_LR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/vai_Latn_LR.dat new file mode 100644 index 0000000..3e8b1e5 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/vai_Latn_LR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/vai_Vaii.dat b/venv/lib/python2.7/site-packages/babel/locale-data/vai_Vaii.dat new file mode 100644 index 0000000..815c41d Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/vai_Vaii.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/vai_Vaii_LR.dat b/venv/lib/python2.7/site-packages/babel/locale-data/vai_Vaii_LR.dat new file mode 100644 index 0000000..3e8b1e5 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/vai_Vaii_LR.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/vi.dat b/venv/lib/python2.7/site-packages/babel/locale-data/vi.dat new file mode 100644 index 0000000..33933e4 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/vi.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/vi_VN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/vi_VN.dat new file mode 100644 index 0000000..96c0f38 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/vi_VN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/vo.dat b/venv/lib/python2.7/site-packages/babel/locale-data/vo.dat new file mode 100644 index 0000000..14ce2bc Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/vo.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/vo_001.dat b/venv/lib/python2.7/site-packages/babel/locale-data/vo_001.dat new file mode 100644 index 0000000..2a2be20 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/vo_001.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/vun.dat b/venv/lib/python2.7/site-packages/babel/locale-data/vun.dat new file mode 100644 index 0000000..32ef57c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/vun.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/vun_TZ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/vun_TZ.dat new file mode 100644 index 0000000..8001f1b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/vun_TZ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/wae.dat b/venv/lib/python2.7/site-packages/babel/locale-data/wae.dat new file mode 100644 index 0000000..7a6a629 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/wae.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/wae_CH.dat b/venv/lib/python2.7/site-packages/babel/locale-data/wae_CH.dat new file mode 100644 index 0000000..1b22e48 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/wae_CH.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/wo.dat b/venv/lib/python2.7/site-packages/babel/locale-data/wo.dat new file mode 100644 index 0000000..d74f0aa Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/wo.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/wo_SN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/wo_SN.dat new file mode 100644 index 0000000..eddbf70 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/wo_SN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/xog.dat b/venv/lib/python2.7/site-packages/babel/locale-data/xog.dat new file mode 100644 index 0000000..1b06fcb Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/xog.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/xog_UG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/xog_UG.dat new file mode 100644 index 0000000..b0c6d9c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/xog_UG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/yav.dat b/venv/lib/python2.7/site-packages/babel/locale-data/yav.dat new file mode 100644 index 0000000..5264774 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/yav.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/yav_CM.dat b/venv/lib/python2.7/site-packages/babel/locale-data/yav_CM.dat new file mode 100644 index 0000000..a8d4ee0 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/yav_CM.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/yi.dat b/venv/lib/python2.7/site-packages/babel/locale-data/yi.dat new file mode 100644 index 0000000..a5c63b3 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/yi.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/yi_001.dat b/venv/lib/python2.7/site-packages/babel/locale-data/yi_001.dat new file mode 100644 index 0000000..c5aa401 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/yi_001.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/yo.dat b/venv/lib/python2.7/site-packages/babel/locale-data/yo.dat new file mode 100644 index 0000000..89d03b4 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/yo.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/yo_BJ.dat b/venv/lib/python2.7/site-packages/babel/locale-data/yo_BJ.dat new file mode 100644 index 0000000..e6d678c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/yo_BJ.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/yo_NG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/yo_NG.dat new file mode 100644 index 0000000..aa6e297 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/yo_NG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/yue.dat b/venv/lib/python2.7/site-packages/babel/locale-data/yue.dat new file mode 100644 index 0000000..6de5b4f Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/yue.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/yue_Hans.dat b/venv/lib/python2.7/site-packages/babel/locale-data/yue_Hans.dat new file mode 100644 index 0000000..98a6603 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/yue_Hans.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/yue_Hans_CN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/yue_Hans_CN.dat new file mode 100644 index 0000000..aaa9917 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/yue_Hans_CN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/yue_Hant.dat b/venv/lib/python2.7/site-packages/babel/locale-data/yue_Hant.dat new file mode 100644 index 0000000..a42b221 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/yue_Hant.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/yue_Hant_HK.dat b/venv/lib/python2.7/site-packages/babel/locale-data/yue_Hant_HK.dat new file mode 100644 index 0000000..d62f965 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/yue_Hant_HK.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/zgh.dat b/venv/lib/python2.7/site-packages/babel/locale-data/zgh.dat new file mode 100644 index 0000000..6d02608 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/zgh.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/zgh_MA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/zgh_MA.dat new file mode 100644 index 0000000..481eb25 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/zgh_MA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/zh.dat b/venv/lib/python2.7/site-packages/babel/locale-data/zh.dat new file mode 100644 index 0000000..97fec96 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/zh.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hans.dat b/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hans.dat new file mode 100644 index 0000000..cd96937 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hans.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hans_CN.dat b/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hans_CN.dat new file mode 100644 index 0000000..6cc7662 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hans_CN.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hans_HK.dat b/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hans_HK.dat new file mode 100644 index 0000000..3602ffb Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hans_HK.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hans_MO.dat b/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hans_MO.dat new file mode 100644 index 0000000..e6ad5a9 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hans_MO.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hans_SG.dat b/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hans_SG.dat new file mode 100644 index 0000000..e8fcb98 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hans_SG.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hant.dat b/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hant.dat new file mode 100644 index 0000000..9c2967b Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hant.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hant_HK.dat b/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hant_HK.dat new file mode 100644 index 0000000..3933cab Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hant_HK.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hant_MO.dat b/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hant_MO.dat new file mode 100644 index 0000000..bd45a5c Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hant_MO.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hant_TW.dat b/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hant_TW.dat new file mode 100644 index 0000000..4595ba2 Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/zh_Hant_TW.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/zu.dat b/venv/lib/python2.7/site-packages/babel/locale-data/zu.dat new file mode 100644 index 0000000..fa671cb Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/zu.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/locale-data/zu_ZA.dat b/venv/lib/python2.7/site-packages/babel/locale-data/zu_ZA.dat new file mode 100644 index 0000000..cceceba Binary files /dev/null and b/venv/lib/python2.7/site-packages/babel/locale-data/zu_ZA.dat differ diff --git a/venv/lib/python2.7/site-packages/babel/localedata.py b/venv/lib/python2.7/site-packages/babel/localedata.py new file mode 100644 index 0000000..a638e58 --- /dev/null +++ b/venv/lib/python2.7/site-packages/babel/localedata.py @@ -0,0 +1,228 @@ +# -*- coding: utf-8 -*- +""" + babel.localedata + ~~~~~~~~~~~~~~~~ + + Low-level locale data access. + + :note: The `Locale` class, which uses this module under the hood, provides a + more convenient interface for accessing the locale data. + + :copyright: (c) 2013-2018 by the Babel Team. + :license: BSD, see LICENSE for more details. +""" + +import os +import threading +from collections import MutableMapping +from itertools import chain + +from babel._compat import pickle, string_types + + +_cache = {} +_cache_lock = threading.RLock() +_dirname = os.path.join(os.path.dirname(__file__), 'locale-data') + + +def normalize_locale(name): + """Normalize a locale ID by stripping spaces and apply proper casing. + + Returns the normalized locale ID string or `None` if the ID is not + recognized. + """ + if not name or not isinstance(name, string_types): + return None + name = name.strip().lower() + for locale_id in chain.from_iterable([_cache, locale_identifiers()]): + if name == locale_id.lower(): + return locale_id + + +def exists(name): + """Check whether locale data is available for the given locale. + + Returns `True` if it exists, `False` otherwise. + + :param name: the locale identifier string + """ + if not name or not isinstance(name, string_types): + return False + if name in _cache: + return True + file_found = os.path.exists(os.path.join(_dirname, '%s.dat' % name)) + return True if file_found else bool(normalize_locale(name)) + + +def locale_identifiers(): + """Return a list of all locale identifiers for which locale data is + available. + + .. versionadded:: 0.8.1 + + :return: a list of locale identifiers (strings) + """ + return [stem for stem, extension in [ + os.path.splitext(filename) for filename in os.listdir(_dirname) + ] if extension == '.dat' and stem != 'root'] + + +def load(name, merge_inherited=True): + """Load the locale data for the given locale. + + The locale data is a dictionary that contains much of the data defined by + the Common Locale Data Repository (CLDR). This data is stored as a + collection of pickle files inside the ``babel`` package. + + >>> d = load('en_US') + >>> d['languages']['sv'] + u'Swedish' + + Note that the results are cached, and subsequent requests for the same + locale return the same dictionary: + + >>> d1 = load('en_US') + >>> d2 = load('en_US') + >>> d1 is d2 + True + + :param name: the locale identifier string (or "root") + :param merge_inherited: whether the inherited data should be merged into + the data of the requested locale + :raise `IOError`: if no locale data file is found for the given locale + identifer, or one of the locales it inherits from + """ + _cache_lock.acquire() + try: + data = _cache.get(name) + if not data: + # Load inherited data + if name == 'root' or not merge_inherited: + data = {} + else: + from babel.core import get_global + parent = get_global('parent_exceptions').get(name) + if not parent: + parts = name.split('_') + if len(parts) == 1: + parent = 'root' + else: + parent = '_'.join(parts[:-1]) + data = load(parent).copy() + filename = os.path.join(_dirname, '%s.dat' % name) + with open(filename, 'rb') as fileobj: + if name != 'root' and merge_inherited: + merge(data, pickle.load(fileobj)) + else: + data = pickle.load(fileobj) + _cache[name] = data + return data + finally: + _cache_lock.release() + + +def merge(dict1, dict2): + """Merge the data from `dict2` into the `dict1` dictionary, making copies + of nested dictionaries. + + >>> d = {1: 'foo', 3: 'baz'} + >>> merge(d, {1: 'Foo', 2: 'Bar'}) + >>> sorted(d.items()) + [(1, 'Foo'), (2, 'Bar'), (3, 'baz')] + + :param dict1: the dictionary to merge into + :param dict2: the dictionary containing the data that should be merged + """ + for key, val2 in dict2.items(): + if val2 is not None: + val1 = dict1.get(key) + if isinstance(val2, dict): + if val1 is None: + val1 = {} + if isinstance(val1, Alias): + val1 = (val1, val2) + elif isinstance(val1, tuple): + alias, others = val1 + others = others.copy() + merge(others, val2) + val1 = (alias, others) + else: + val1 = val1.copy() + merge(val1, val2) + else: + val1 = val2 + dict1[key] = val1 + + +class Alias(object): + """Representation of an alias in the locale data. + + An alias is a value that refers to some other part of the locale data, + as specified by the `keys`. + """ + + def __init__(self, keys): + self.keys = tuple(keys) + + def __repr__(self): + return '<%s %r>' % (type(self).__name__, self.keys) + + def resolve(self, data): + """Resolve the alias based on the given data. + + This is done recursively, so if one alias resolves to a second alias, + that second alias will also be resolved. + + :param data: the locale data + :type data: `dict` + """ + base = data + for key in self.keys: + data = data[key] + if isinstance(data, Alias): + data = data.resolve(base) + elif isinstance(data, tuple): + alias, others = data + data = alias.resolve(base) + return data + + +class LocaleDataDict(MutableMapping): + """Dictionary wrapper that automatically resolves aliases to the actual + values. + """ + + def __init__(self, data, base=None): + self._data = data + if base is None: + base = data + self.base = base + + def __len__(self): + return len(self._data) + + def __iter__(self): + return iter(self._data) + + def __getitem__(self, key): + orig = val = self._data[key] + if isinstance(val, Alias): # resolve an alias + val = val.resolve(self.base) + if isinstance(val, tuple): # Merge a partial dict with an alias + alias, others = val + val = alias.resolve(self.base).copy() + merge(val, others) + if type(val) is dict: # Return a nested alias-resolving dict + val = LocaleDataDict(val, base=self.base) + if val is not orig: + self._data[key] = val + return val + + def __setitem__(self, key, value): + self._data[key] = value + + def __delitem__(self, key): + del self._data[key] + + def copy(self): + return LocaleDataDict(self._data.copy(), base=self.base) diff --git a/venv/lib/python2.7/site-packages/babel/localtime/__init__.py b/venv/lib/python2.7/site-packages/babel/localtime/__init__.py new file mode 100644 index 0000000..bb4341d --- /dev/null +++ b/venv/lib/python2.7/site-packages/babel/localtime/__init__.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +""" + babel.localtime + ~~~~~~~~~~~~~~~ + + Babel specific fork of tzlocal to determine the local timezone + of the system. + + :copyright: (c) 2013-2018 by the Babel Team. + :license: BSD, see LICENSE for more details. +""" + +import sys +import pytz +import time +from datetime import timedelta +from datetime import tzinfo +from threading import RLock + +if sys.platform == 'win32': + from babel.localtime._win32 import _get_localzone +else: + from babel.localtime._unix import _get_localzone + + +_cached_tz = None +_cache_lock = RLock() + +STDOFFSET = timedelta(seconds=-time.timezone) +if time.daylight: + DSTOFFSET = timedelta(seconds=-time.altzone) +else: + DSTOFFSET = STDOFFSET + +DSTDIFF = DSTOFFSET - STDOFFSET +ZERO = timedelta(0) + + +class _FallbackLocalTimezone(tzinfo): + + def utcoffset(self, dt): + if self._isdst(dt): + return DSTOFFSET + else: + return STDOFFSET + + def dst(self, dt): + if self._isdst(dt): + return DSTDIFF + else: + return ZERO + + def tzname(self, dt): + return time.tzname[self._isdst(dt)] + + def _isdst(self, dt): + tt = (dt.year, dt.month, dt.day, + dt.hour, dt.minute, dt.second, + dt.weekday(), 0, -1) + stamp = time.mktime(tt) + tt = time.localtime(stamp) + return tt.tm_isdst > 0 + + +def get_localzone(): + """Returns the current underlying local timezone object. + Generally this function does not need to be used, it's a + better idea to use the :data:`LOCALTZ` singleton instead. + """ + return _get_localzone() + + +try: + LOCALTZ = get_localzone() +except pytz.UnknownTimeZoneError: + LOCALTZ = _FallbackLocalTimezone() diff --git a/venv/lib/python2.7/site-packages/babel/localtime/_unix.py b/venv/lib/python2.7/site-packages/babel/localtime/_unix.py new file mode 100644 index 0000000..c219469 --- /dev/null +++ b/venv/lib/python2.7/site-packages/babel/localtime/_unix.py @@ -0,0 +1,128 @@ +# -*- coding: utf-8 -*- +from __future__ import with_statement +import os +import re +import sys +import pytz +import subprocess + +_systemconfig_tz = re.compile(r'^Time Zone: (.*)$', re.MULTILINE) + + +def _tz_from_env(tzenv): + if tzenv[0] == ':': + tzenv = tzenv[1:] + + # TZ specifies a file + if os.path.exists(tzenv): + with open(tzenv, 'rb') as tzfile: + return pytz.tzfile.build_tzinfo('local', tzfile) + + # TZ specifies a zoneinfo zone. + try: + tz = pytz.timezone(tzenv) + # That worked, so we return this: + return tz + except pytz.UnknownTimeZoneError: + raise pytz.UnknownTimeZoneError( + "tzlocal() does not support non-zoneinfo timezones like %s. \n" + "Please use a timezone in the form of Continent/City") + + +def _get_localzone(_root='/'): + """Tries to find the local timezone configuration. + This method prefers finding the timezone name and passing that to pytz, + over passing in the localtime file, as in the later case the zoneinfo + name is unknown. + The parameter _root makes the function look for files like /etc/localtime + beneath the _root directory. This is primarily used by the tests. + In normal usage you call the function without parameters. + """ + + tzenv = os.environ.get('TZ') + if tzenv: + return _tz_from_env(tzenv) + + # This is actually a pretty reliable way to test for the local time + # zone on operating systems like OS X. On OS X especially this is the + # only one that actually works. + try: + link_dst = os.readlink('/etc/localtime') + except OSError: + pass + else: + pos = link_dst.find('/zoneinfo/') + if pos >= 0: + zone_name = link_dst[pos + 10:] + try: + return pytz.timezone(zone_name) + except pytz.UnknownTimeZoneError: + pass + + # If we are on OS X now we are pretty sure that the rest of the + # code will fail and just fall through until it hits the reading + # of /etc/localtime and using it without name. At this point we + # can invoke systemconfig which internally invokes ICU. ICU itself + # does the same thing we do (readlink + compare file contents) but + # since it knows where the zone files are that should be a bit + # better than reimplementing the logic here. + if sys.platform == 'darwin': + c = subprocess.Popen(['systemsetup', '-gettimezone'], + stdout=subprocess.PIPE) + sys_result = c.communicate()[0] + c.wait() + tz_match = _systemconfig_tz.search(sys_result) + if tz_match is not None: + zone_name = tz_match.group(1) + try: + return pytz.timezone(zone_name) + except pytz.UnknownTimeZoneError: + pass + + # Now look for distribution specific configuration files + # that contain the timezone name. + tzpath = os.path.join(_root, 'etc/timezone') + if os.path.exists(tzpath): + with open(tzpath, 'rb') as tzfile: + data = tzfile.read() + + # Issue #3 in tzlocal was that /etc/timezone was a zoneinfo file. + # That's a misconfiguration, but we need to handle it gracefully: + if data[:5] != b'TZif2': + etctz = data.strip().decode() + # Get rid of host definitions and comments: + if ' ' in etctz: + etctz, dummy = etctz.split(' ', 1) + if '#' in etctz: + etctz, dummy = etctz.split('#', 1) + return pytz.timezone(etctz.replace(' ', '_')) + + # CentOS has a ZONE setting in /etc/sysconfig/clock, + # OpenSUSE has a TIMEZONE setting in /etc/sysconfig/clock and + # Gentoo has a TIMEZONE setting in /etc/conf.d/clock + # We look through these files for a timezone: + timezone_re = re.compile(r'\s*(TIME)?ZONE\s*=\s*"(?P.+)"') + + for filename in ('etc/sysconfig/clock', 'etc/conf.d/clock'): + tzpath = os.path.join(_root, filename) + if not os.path.exists(tzpath): + continue + with open(tzpath, 'rt') as tzfile: + for line in tzfile: + match = timezone_re.match(line) + if match is not None: + # We found a timezone + etctz = match.group("etctz") + return pytz.timezone(etctz.replace(' ', '_')) + + # No explicit setting existed. Use localtime + for filename in ('etc/localtime', 'usr/local/etc/localtime'): + tzpath = os.path.join(_root, filename) + + if not os.path.exists(tzpath): + continue + + with open(tzpath, 'rb') as tzfile: + return pytz.tzfile.build_tzinfo('local', tzfile) + + raise pytz.UnknownTimeZoneError('Can not find any timezone configuration') diff --git a/venv/lib/python2.7/site-packages/babel/localtime/_win32.py b/venv/lib/python2.7/site-packages/babel/localtime/_win32.py new file mode 100644 index 0000000..3752dff --- /dev/null +++ b/venv/lib/python2.7/site-packages/babel/localtime/_win32.py @@ -0,0 +1,96 @@ +try: + import _winreg as winreg +except ImportError: + try: + import winreg + except ImportError: + winreg = None + +from babel.core import get_global +import pytz + + +# When building the cldr data on windows this module gets imported. +# Because at that point there is no global.dat yet this call will +# fail. We want to catch it down in that case then and just assume +# the mapping was empty. +try: + tz_names = get_global('windows_zone_mapping') +except RuntimeError: + tz_names = {} + + +def valuestodict(key): + """Convert a registry key's values to a dictionary.""" + dict = {} + size = winreg.QueryInfoKey(key)[1] + for i in range(size): + data = winreg.EnumValue(key, i) + dict[data[0]] = data[1] + return dict + + +def get_localzone_name(): + # Windows is special. It has unique time zone names (in several + # meanings of the word) available, but unfortunately, they can be + # translated to the language of the operating system, so we need to + # do a backwards lookup, by going through all time zones and see which + # one matches. + handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) + + TZLOCALKEYNAME = r'SYSTEM\CurrentControlSet\Control\TimeZoneInformation' + localtz = winreg.OpenKey(handle, TZLOCALKEYNAME) + keyvalues = valuestodict(localtz) + localtz.Close() + if 'TimeZoneKeyName' in keyvalues: + # Windows 7 (and Vista?) + + # For some reason this returns a string with loads of NUL bytes at + # least on some systems. I don't know if this is a bug somewhere, I + # just work around it. + tzkeyname = keyvalues['TimeZoneKeyName'].split('\x00', 1)[0] + else: + # Windows 2000 or XP + + # This is the localized name: + tzwin = keyvalues['StandardName'] + + # Open the list of timezones to look up the real name: + TZKEYNAME = r'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones' + tzkey = winreg.OpenKey(handle, TZKEYNAME) + + # Now, match this value to Time Zone information + tzkeyname = None + for i in range(winreg.QueryInfoKey(tzkey)[0]): + subkey = winreg.EnumKey(tzkey, i) + sub = winreg.OpenKey(tzkey, subkey) + data = valuestodict(sub) + sub.Close() + if data['Std'] == tzwin: + tzkeyname = subkey + break + + tzkey.Close() + handle.Close() + + if tzkeyname is None: + raise LookupError('Can not find Windows timezone configuration') + + timezone = tz_names.get(tzkeyname) + if timezone is None: + # Nope, that didn't work. Try adding 'Standard Time', + # it seems to work a lot of times: + timezone = tz_names.get(tzkeyname + ' Standard Time') + + # Return what we have. + if timezone is None: + raise pytz.UnknownTimeZoneError('Can not find timezone ' + tzkeyname) + + return timezone + + +def _get_localzone(): + if winreg is None: + raise pytz.UnknownTimeZoneError( + 'Runtime support not available') + return pytz.timezone(get_localzone_name()) diff --git a/venv/lib/python2.7/site-packages/babel/messages/__init__.py b/venv/lib/python2.7/site-packages/babel/messages/__init__.py new file mode 100644 index 0000000..7dd6f8b --- /dev/null +++ b/venv/lib/python2.7/site-packages/babel/messages/__init__.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- +""" + babel.messages + ~~~~~~~~~~~~~~ + + Support for ``gettext`` message catalogs. + + :copyright: (c) 2013-2018 by the Babel Team. + :license: BSD, see LICENSE for more details. +""" + +from babel.messages.catalog import * diff --git a/venv/lib/python2.7/site-packages/babel/messages/catalog.py b/venv/lib/python2.7/site-packages/babel/messages/catalog.py new file mode 100644 index 0000000..6d61a38 --- /dev/null +++ b/venv/lib/python2.7/site-packages/babel/messages/catalog.py @@ -0,0 +1,846 @@ +# -*- coding: utf-8 -*- +""" + babel.messages.catalog + ~~~~~~~~~~~~~~~~~~~~~~ + + Data structures for message catalogs. + + :copyright: (c) 2013-2018 by the Babel Team. + :license: BSD, see LICENSE for more details. +""" + +import re +import time + +from cgi import parse_header +from datetime import datetime, time as time_ +from difflib import get_close_matches +from email import message_from_string +from copy import copy + +from babel import __version__ as VERSION +from babel.core import Locale, UnknownLocaleError +from babel.dates import format_datetime +from babel.messages.plurals import get_plural +from babel.util import odict, distinct, LOCALTZ, FixedOffsetTimezone +from babel._compat import string_types, number_types, PY2, cmp, text_type, force_text + +__all__ = ['Message', 'Catalog', 'TranslationError'] + + +PYTHON_FORMAT = re.compile(r''' + \% + (?:\(([\w]*)\))? + ( + [-#0\ +]?(?:\*|[\d]+)? + (?:\.(?:\*|[\d]+))? + [hlL]? + ) + ([diouxXeEfFgGcrs%]) +''', re.VERBOSE) + + +def _parse_datetime_header(value): + match = re.match(r'^(?P.*?)(?P[+-]\d{4})?$', value) + + tt = time.strptime(match.group('datetime'), '%Y-%m-%d %H:%M') + ts = time.mktime(tt) + dt = datetime.fromtimestamp(ts) + + # Separate the offset into a sign component, hours, and # minutes + tzoffset = match.group('tzoffset') + if tzoffset is not None: + plus_minus_s, rest = tzoffset[0], tzoffset[1:] + hours_offset_s, mins_offset_s = rest[:2], rest[2:] + + # Make them all integers + plus_minus = int(plus_minus_s + '1') + hours_offset = int(hours_offset_s) + mins_offset = int(mins_offset_s) + + # Calculate net offset + net_mins_offset = hours_offset * 60 + net_mins_offset += mins_offset + net_mins_offset *= plus_minus + + # Create an offset object + tzoffset = FixedOffsetTimezone(net_mins_offset) + + # Store the offset in a datetime object + dt = dt.replace(tzinfo=tzoffset) + + return dt + + +class Message(object): + """Representation of a single message in a catalog.""" + + def __init__(self, id, string=u'', locations=(), flags=(), auto_comments=(), + user_comments=(), previous_id=(), lineno=None, context=None): + """Create the message object. + + :param id: the message ID, or a ``(singular, plural)`` tuple for + pluralizable messages + :param string: the translated message string, or a + ``(singular, plural)`` tuple for pluralizable messages + :param locations: a sequence of ``(filename, lineno)`` tuples + :param flags: a set or sequence of flags + :param auto_comments: a sequence of automatic comments for the message + :param user_comments: a sequence of user comments for the message + :param previous_id: the previous message ID, or a ``(singular, plural)`` + tuple for pluralizable messages + :param lineno: the line number on which the msgid line was found in the + PO file, if any + :param context: the message context + """ + self.id = id + if not string and self.pluralizable: + string = (u'', u'') + self.string = string + self.locations = list(distinct(locations)) + self.flags = set(flags) + if id and self.python_format: + self.flags.add('python-format') + else: + self.flags.discard('python-format') + self.auto_comments = list(distinct(auto_comments)) + self.user_comments = list(distinct(user_comments)) + if isinstance(previous_id, string_types): + self.previous_id = [previous_id] + else: + self.previous_id = list(previous_id) + self.lineno = lineno + self.context = context + + def __repr__(self): + return '<%s %r (flags: %r)>' % (type(self).__name__, self.id, + list(self.flags)) + + def __cmp__(self, other): + """Compare Messages, taking into account plural ids""" + def values_to_compare(obj): + if isinstance(obj, Message) and obj.pluralizable: + return obj.id[0], obj.context or '' + return obj.id, obj.context or '' + return cmp(values_to_compare(self), values_to_compare(other)) + + def __gt__(self, other): + return self.__cmp__(other) > 0 + + def __lt__(self, other): + return self.__cmp__(other) < 0 + + def __ge__(self, other): + return self.__cmp__(other) >= 0 + + def __le__(self, other): + return self.__cmp__(other) <= 0 + + def __eq__(self, other): + return self.__cmp__(other) == 0 + + def __ne__(self, other): + return self.__cmp__(other) != 0 + + def clone(self): + return Message(*map(copy, (self.id, self.string, self.locations, + self.flags, self.auto_comments, + self.user_comments, self.previous_id, + self.lineno, self.context))) + + def check(self, catalog=None): + """Run various validation checks on the message. Some validations + are only performed if the catalog is provided. This method returns + a sequence of `TranslationError` objects. + + :rtype: ``iterator`` + :param catalog: A catalog instance that is passed to the checkers + :see: `Catalog.check` for a way to perform checks for all messages + in a catalog. + """ + from babel.messages.checkers import checkers + errors = [] + for checker in checkers: + try: + checker(catalog, self) + except TranslationError as e: + errors.append(e) + return errors + + @property + def fuzzy(self): + """Whether the translation is fuzzy. + + >>> Message('foo').fuzzy + False + >>> msg = Message('foo', 'foo', flags=['fuzzy']) + >>> msg.fuzzy + True + >>> msg + + + :type: `bool`""" + return 'fuzzy' in self.flags + + @property + def pluralizable(self): + """Whether the message is plurizable. + + >>> Message('foo').pluralizable + False + >>> Message(('foo', 'bar')).pluralizable + True + + :type: `bool`""" + return isinstance(self.id, (list, tuple)) + + @property + def python_format(self): + """Whether the message contains Python-style parameters. + + >>> Message('foo %(name)s bar').python_format + True + >>> Message(('foo %(name)s', 'foo %(name)s')).python_format + True + + :type: `bool`""" + ids = self.id + if not isinstance(ids, (list, tuple)): + ids = [ids] + return any(PYTHON_FORMAT.search(id) for id in ids) + + +class TranslationError(Exception): + """Exception thrown by translation checkers when invalid message + translations are encountered.""" + + +DEFAULT_HEADER = u"""\ +# Translations template for PROJECT. +# Copyright (C) YEAR ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , YEAR. +#""" + + +if PY2: + def _parse_header(header_string): + # message_from_string only works for str, not for unicode + headers = message_from_string(header_string.encode('utf8')) + decoded_headers = {} + for name, value in headers.items(): + name = name.decode('utf8') + value = value.decode('utf8') + decoded_headers[name] = value + return decoded_headers + +else: + _parse_header = message_from_string + + +class Catalog(object): + """Representation of a message catalog.""" + + def __init__(self, locale=None, domain=None, header_comment=DEFAULT_HEADER, + project=None, version=None, copyright_holder=None, + msgid_bugs_address=None, creation_date=None, + revision_date=None, last_translator=None, language_team=None, + charset=None, fuzzy=True): + """Initialize the catalog object. + + :param locale: the locale identifier or `Locale` object, or `None` + if the catalog is not bound to a locale (which basically + means it's a template) + :param domain: the message domain + :param header_comment: the header comment as string, or `None` for the + default header + :param project: the project's name + :param version: the project's version + :param copyright_holder: the copyright holder of the catalog + :param msgid_bugs_address: the email address or URL to submit bug + reports to + :param creation_date: the date the catalog was created + :param revision_date: the date the catalog was revised + :param last_translator: the name and email of the last translator + :param language_team: the name and email of the language team + :param charset: the encoding to use in the output (defaults to utf-8) + :param fuzzy: the fuzzy bit on the catalog header + """ + self.domain = domain + self.locale = locale + self._header_comment = header_comment + self._messages = odict() + + self.project = project or 'PROJECT' + self.version = version or 'VERSION' + self.copyright_holder = copyright_holder or 'ORGANIZATION' + self.msgid_bugs_address = msgid_bugs_address or 'EMAIL@ADDRESS' + + self.last_translator = last_translator or 'FULL NAME ' + """Name and email address of the last translator.""" + self.language_team = language_team or 'LANGUAGE ' + """Name and email address of the language team.""" + + self.charset = charset or 'utf-8' + + if creation_date is None: + creation_date = datetime.now(LOCALTZ) + elif isinstance(creation_date, datetime) and not creation_date.tzinfo: + creation_date = creation_date.replace(tzinfo=LOCALTZ) + self.creation_date = creation_date + if revision_date is None: + revision_date = 'YEAR-MO-DA HO:MI+ZONE' + elif isinstance(revision_date, datetime) and not revision_date.tzinfo: + revision_date = revision_date.replace(tzinfo=LOCALTZ) + self.revision_date = revision_date + self.fuzzy = fuzzy + + self.obsolete = odict() # Dictionary of obsolete messages + self._num_plurals = None + self._plural_expr = None + + def _set_locale(self, locale): + if locale is None: + self._locale_identifier = None + self._locale = None + return + + if isinstance(locale, Locale): + self._locale_identifier = text_type(locale) + self._locale = locale + return + + if isinstance(locale, string_types): + self._locale_identifier = text_type(locale) + try: + self._locale = Locale.parse(locale) + except UnknownLocaleError: + self._locale = None + return + + raise TypeError('`locale` must be a Locale, a locale identifier string, or None; got %r' % locale) + + def _get_locale(self): + return self._locale + + def _get_locale_identifier(self): + return self._locale_identifier + + locale = property(_get_locale, _set_locale) + locale_identifier = property(_get_locale_identifier) + + def _get_header_comment(self): + comment = self._header_comment + year = datetime.now(LOCALTZ).strftime('%Y') + if hasattr(self.revision_date, 'strftime'): + year = self.revision_date.strftime('%Y') + comment = comment.replace('PROJECT', self.project) \ + .replace('VERSION', self.version) \ + .replace('YEAR', year) \ + .replace('ORGANIZATION', self.copyright_holder) + locale_name = (self.locale.english_name if self.locale else self.locale_identifier) + if locale_name: + comment = comment.replace('Translations template', '%s translations' % locale_name) + return comment + + def _set_header_comment(self, string): + self._header_comment = string + + header_comment = property(_get_header_comment, _set_header_comment, doc="""\ + The header comment for the catalog. + + >>> catalog = Catalog(project='Foobar', version='1.0', + ... copyright_holder='Foo Company') + >>> print(catalog.header_comment) #doctest: +ELLIPSIS + # Translations template for Foobar. + # Copyright (C) ... Foo Company + # This file is distributed under the same license as the Foobar project. + # FIRST AUTHOR , .... + # + + The header can also be set from a string. Any known upper-case variables + will be replaced when the header is retrieved again: + + >>> catalog = Catalog(project='Foobar', version='1.0', + ... copyright_holder='Foo Company') + >>> catalog.header_comment = '''\\ + ... # The POT for my really cool PROJECT project. + ... # Copyright (C) 1990-2003 ORGANIZATION + ... # This file is distributed under the same license as the PROJECT + ... # project. + ... #''' + >>> print(catalog.header_comment) + # The POT for my really cool Foobar project. + # Copyright (C) 1990-2003 Foo Company + # This file is distributed under the same license as the Foobar + # project. + # + + :type: `unicode` + """) + + def _get_mime_headers(self): + headers = [] + headers.append(('Project-Id-Version', + '%s %s' % (self.project, self.version))) + headers.append(('Report-Msgid-Bugs-To', self.msgid_bugs_address)) + headers.append(('POT-Creation-Date', + format_datetime(self.creation_date, 'yyyy-MM-dd HH:mmZ', + locale='en'))) + if isinstance(self.revision_date, (datetime, time_) + number_types): + headers.append(('PO-Revision-Date', + format_datetime(self.revision_date, + 'yyyy-MM-dd HH:mmZ', locale='en'))) + else: + headers.append(('PO-Revision-Date', self.revision_date)) + headers.append(('Last-Translator', self.last_translator)) + if self.locale_identifier: + headers.append(('Language', str(self.locale_identifier))) + if self.locale_identifier and ('LANGUAGE' in self.language_team): + headers.append(('Language-Team', + self.language_team.replace('LANGUAGE', + str(self.locale_identifier)))) + else: + headers.append(('Language-Team', self.language_team)) + if self.locale is not None: + headers.append(('Plural-Forms', self.plural_forms)) + headers.append(('MIME-Version', '1.0')) + headers.append(('Content-Type', + 'text/plain; charset=%s' % self.charset)) + headers.append(('Content-Transfer-Encoding', '8bit')) + headers.append(('Generated-By', 'Babel %s\n' % VERSION)) + return headers + + def _set_mime_headers(self, headers): + for name, value in headers: + name = force_text(name.lower(), encoding=self.charset) + value = force_text(value, encoding=self.charset) + if name == 'project-id-version': + parts = value.split(' ') + self.project = u' '.join(parts[:-1]) + self.version = parts[-1] + elif name == 'report-msgid-bugs-to': + self.msgid_bugs_address = value + elif name == 'last-translator': + self.last_translator = value + elif name == 'language': + value = value.replace('-', '_') + self._set_locale(value) + elif name == 'language-team': + self.language_team = value + elif name == 'content-type': + mimetype, params = parse_header(value) + if 'charset' in params: + self.charset = params['charset'].lower() + elif name == 'plural-forms': + _, params = parse_header(' ;' + value) + self._num_plurals = int(params.get('nplurals', 2)) + self._plural_expr = params.get('plural', '(n != 1)') + elif name == 'pot-creation-date': + self.creation_date = _parse_datetime_header(value) + elif name == 'po-revision-date': + # Keep the value if it's not the default one + if 'YEAR' not in value: + self.revision_date = _parse_datetime_header(value) + + mime_headers = property(_get_mime_headers, _set_mime_headers, doc="""\ + The MIME headers of the catalog, used for the special ``msgid ""`` entry. + + The behavior of this property changes slightly depending on whether a locale + is set or not, the latter indicating that the catalog is actually a template + for actual translations. + + Here's an example of the output for such a catalog template: + + >>> from babel.dates import UTC + >>> created = datetime(1990, 4, 1, 15, 30, tzinfo=UTC) + >>> catalog = Catalog(project='Foobar', version='1.0', + ... creation_date=created) + >>> for name, value in catalog.mime_headers: + ... print('%s: %s' % (name, value)) + Project-Id-Version: Foobar 1.0 + Report-Msgid-Bugs-To: EMAIL@ADDRESS + POT-Creation-Date: 1990-04-01 15:30+0000 + PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE + Last-Translator: FULL NAME + Language-Team: LANGUAGE + MIME-Version: 1.0 + Content-Type: text/plain; charset=utf-8 + Content-Transfer-Encoding: 8bit + Generated-By: Babel ... + + And here's an example of the output when the locale is set: + + >>> revised = datetime(1990, 8, 3, 12, 0, tzinfo=UTC) + >>> catalog = Catalog(locale='de_DE', project='Foobar', version='1.0', + ... creation_date=created, revision_date=revised, + ... last_translator='John Doe ', + ... language_team='de_DE ') + >>> for name, value in catalog.mime_headers: + ... print('%s: %s' % (name, value)) + Project-Id-Version: Foobar 1.0 + Report-Msgid-Bugs-To: EMAIL@ADDRESS + POT-Creation-Date: 1990-04-01 15:30+0000 + PO-Revision-Date: 1990-08-03 12:00+0000 + Last-Translator: John Doe + Language: de_DE + Language-Team: de_DE + Plural-Forms: nplurals=2; plural=(n != 1) + MIME-Version: 1.0 + Content-Type: text/plain; charset=utf-8 + Content-Transfer-Encoding: 8bit + Generated-By: Babel ... + + :type: `list` + """) + + @property + def num_plurals(self): + """The number of plurals used by the catalog or locale. + + >>> Catalog(locale='en').num_plurals + 2 + >>> Catalog(locale='ga').num_plurals + 5 + + :type: `int`""" + if self._num_plurals is None: + num = 2 + if self.locale: + num = get_plural(self.locale)[0] + self._num_plurals = num + return self._num_plurals + + @property + def plural_expr(self): + """The plural expression used by the catalog or locale. + + >>> Catalog(locale='en').plural_expr + '(n != 1)' + >>> Catalog(locale='ga').plural_expr + '(n==1 ? 0 : n==2 ? 1 : n>=3 && n<=6 ? 2 : n>=7 && n<=10 ? 3 : 4)' + >>> Catalog(locale='ding').plural_expr # unknown locale + '(n != 1)' + + :type: `string_types`""" + if self._plural_expr is None: + expr = '(n != 1)' + if self.locale: + expr = get_plural(self.locale)[1] + self._plural_expr = expr + return self._plural_expr + + @property + def plural_forms(self): + """Return the plural forms declaration for the locale. + + >>> Catalog(locale='en').plural_forms + 'nplurals=2; plural=(n != 1)' + >>> Catalog(locale='pt_BR').plural_forms + 'nplurals=2; plural=(n > 1)' + + :type: `str`""" + return 'nplurals=%s; plural=%s' % (self.num_plurals, self.plural_expr) + + def __contains__(self, id): + """Return whether the catalog has a message with the specified ID.""" + return self._key_for(id) in self._messages + + def __len__(self): + """The number of messages in the catalog. + + This does not include the special ``msgid ""`` entry.""" + return len(self._messages) + + def __iter__(self): + """Iterates through all the entries in the catalog, in the order they + were added, yielding a `Message` object for every entry. + + :rtype: ``iterator``""" + buf = [] + for name, value in self.mime_headers: + buf.append('%s: %s' % (name, value)) + flags = set() + if self.fuzzy: + flags |= {'fuzzy'} + yield Message(u'', '\n'.join(buf), flags=flags) + for key in self._messages: + yield self._messages[key] + + def __repr__(self): + locale = '' + if self.locale: + locale = ' %s' % self.locale + return '<%s %r%s>' % (type(self).__name__, self.domain, locale) + + def __delitem__(self, id): + """Delete the message with the specified ID.""" + self.delete(id) + + def __getitem__(self, id): + """Return the message with the specified ID. + + :param id: the message ID + """ + return self.get(id) + + def __setitem__(self, id, message): + """Add or update the message with the specified ID. + + >>> catalog = Catalog() + >>> catalog[u'foo'] = Message(u'foo') + >>> catalog[u'foo'] + + + If a message with that ID is already in the catalog, it is updated + to include the locations and flags of the new message. + + >>> catalog = Catalog() + >>> catalog[u'foo'] = Message(u'foo', locations=[('main.py', 1)]) + >>> catalog[u'foo'].locations + [('main.py', 1)] + >>> catalog[u'foo'] = Message(u'foo', locations=[('utils.py', 5)]) + >>> catalog[u'foo'].locations + [('main.py', 1), ('utils.py', 5)] + + :param id: the message ID + :param message: the `Message` object + """ + assert isinstance(message, Message), 'expected a Message object' + key = self._key_for(id, message.context) + current = self._messages.get(key) + if current: + if message.pluralizable and not current.pluralizable: + # The new message adds pluralization + current.id = message.id + current.string = message.string + current.locations = list(distinct(current.locations + + message.locations)) + current.auto_comments = list(distinct(current.auto_comments + + message.auto_comments)) + current.user_comments = list(distinct(current.user_comments + + message.user_comments)) + current.flags |= message.flags + message = current + elif id == '': + # special treatment for the header message + self.mime_headers = _parse_header(message.string).items() + self.header_comment = '\n'.join([('# %s' % c).rstrip() for c + in message.user_comments]) + self.fuzzy = message.fuzzy + else: + if isinstance(id, (list, tuple)): + assert isinstance(message.string, (list, tuple)), \ + 'Expected sequence but got %s' % type(message.string) + self._messages[key] = message + + def add(self, id, string=None, locations=(), flags=(), auto_comments=(), + user_comments=(), previous_id=(), lineno=None, context=None): + """Add or update the message with the specified ID. + + >>> catalog = Catalog() + >>> catalog.add(u'foo') + + >>> catalog[u'foo'] + + + This method simply constructs a `Message` object with the given + arguments and invokes `__setitem__` with that object. + + :param id: the message ID, or a ``(singular, plural)`` tuple for + pluralizable messages + :param string: the translated message string, or a + ``(singular, plural)`` tuple for pluralizable messages + :param locations: a sequence of ``(filename, lineno)`` tuples + :param flags: a set or sequence of flags + :param auto_comments: a sequence of automatic comments + :param user_comments: a sequence of user comments + :param previous_id: the previous message ID, or a ``(singular, plural)`` + tuple for pluralizable messages + :param lineno: the line number on which the msgid line was found in the + PO file, if any + :param context: the message context + """ + message = Message(id, string, list(locations), flags, auto_comments, + user_comments, previous_id, lineno=lineno, + context=context) + self[id] = message + return message + + def check(self): + """Run various validation checks on the translations in the catalog. + + For every message which fails validation, this method yield a + ``(message, errors)`` tuple, where ``message`` is the `Message` object + and ``errors`` is a sequence of `TranslationError` objects. + + :rtype: ``iterator`` + """ + for message in self._messages.values(): + errors = message.check(catalog=self) + if errors: + yield message, errors + + def get(self, id, context=None): + """Return the message with the specified ID and context. + + :param id: the message ID + :param context: the message context, or ``None`` for no context + """ + return self._messages.get(self._key_for(id, context)) + + def delete(self, id, context=None): + """Delete the message with the specified ID and context. + + :param id: the message ID + :param context: the message context, or ``None`` for no context + """ + key = self._key_for(id, context) + if key in self._messages: + del self._messages[key] + + def update(self, template, no_fuzzy_matching=False, update_header_comment=False): + """Update the catalog based on the given template catalog. + + >>> from babel.messages import Catalog + >>> template = Catalog() + >>> template.add('green', locations=[('main.py', 99)]) + + >>> template.add('blue', locations=[('main.py', 100)]) + + >>> template.add(('salad', 'salads'), locations=[('util.py', 42)]) + + >>> catalog = Catalog(locale='de_DE') + >>> catalog.add('blue', u'blau', locations=[('main.py', 98)]) + + >>> catalog.add('head', u'Kopf', locations=[('util.py', 33)]) + + >>> catalog.add(('salad', 'salads'), (u'Salat', u'Salate'), + ... locations=[('util.py', 38)]) + + + >>> catalog.update(template) + >>> len(catalog) + 3 + + >>> msg1 = catalog['green'] + >>> msg1.string + >>> msg1.locations + [('main.py', 99)] + + >>> msg2 = catalog['blue'] + >>> msg2.string + u'blau' + >>> msg2.locations + [('main.py', 100)] + + >>> msg3 = catalog['salad'] + >>> msg3.string + (u'Salat', u'Salate') + >>> msg3.locations + [('util.py', 42)] + + Messages that are in the catalog but not in the template are removed + from the main collection, but can still be accessed via the `obsolete` + member: + + >>> 'head' in catalog + False + >>> list(catalog.obsolete.values()) + [] + + :param template: the reference catalog, usually read from a POT file + :param no_fuzzy_matching: whether to use fuzzy matching of message IDs + """ + messages = self._messages + remaining = messages.copy() + self._messages = odict() + + # Prepare for fuzzy matching + fuzzy_candidates = [] + if not no_fuzzy_matching: + fuzzy_candidates = dict([ + (self._key_for(msgid), messages[msgid].context) + for msgid in messages if msgid and messages[msgid].string + ]) + fuzzy_matches = set() + + def _merge(message, oldkey, newkey): + message = message.clone() + fuzzy = False + if oldkey != newkey: + fuzzy = True + fuzzy_matches.add(oldkey) + oldmsg = messages.get(oldkey) + if isinstance(oldmsg.id, string_types): + message.previous_id = [oldmsg.id] + else: + message.previous_id = list(oldmsg.id) + else: + oldmsg = remaining.pop(oldkey, None) + message.string = oldmsg.string + if isinstance(message.id, (list, tuple)): + if not isinstance(message.string, (list, tuple)): + fuzzy = True + message.string = tuple( + [message.string] + ([u''] * (len(message.id) - 1)) + ) + elif len(message.string) != self.num_plurals: + fuzzy = True + message.string = tuple(message.string[:len(oldmsg.string)]) + elif isinstance(message.string, (list, tuple)): + fuzzy = True + message.string = message.string[0] + message.flags |= oldmsg.flags + if fuzzy: + message.flags |= {u'fuzzy'} + self[message.id] = message + + for message in template: + if message.id: + key = self._key_for(message.id, message.context) + if key in messages: + _merge(message, key, key) + else: + if no_fuzzy_matching is False: + # do some fuzzy matching with difflib + if isinstance(key, tuple): + matchkey = key[0] # just the msgid, no context + else: + matchkey = key + matches = get_close_matches(matchkey.lower().strip(), + fuzzy_candidates.keys(), 1) + if matches: + newkey = matches[0] + newctxt = fuzzy_candidates[newkey] + if newctxt is not None: + newkey = newkey, newctxt + _merge(message, newkey, key) + continue + + self[message.id] = message + + for msgid in remaining: + if no_fuzzy_matching or msgid not in fuzzy_matches: + self.obsolete[msgid] = remaining[msgid] + + if update_header_comment: + # Allow the updated catalog's header to be rewritten based on the + # template's header + self.header_comment = template.header_comment + + # Make updated catalog's POT-Creation-Date equal to the template + # used to update the catalog + self.creation_date = template.creation_date + + def _key_for(self, id, context=None): + """The key for a message is just the singular ID even for pluralizable + messages, but is a ``(msgid, msgctxt)`` tuple for context-specific + messages. + """ + key = id + if isinstance(key, (list, tuple)): + key = id[0] + if context is not None: + key = (key, context) + return key diff --git a/venv/lib/python2.7/site-packages/babel/messages/checkers.py b/venv/lib/python2.7/site-packages/babel/messages/checkers.py new file mode 100644 index 0000000..d04ad70 --- /dev/null +++ b/venv/lib/python2.7/site-packages/babel/messages/checkers.py @@ -0,0 +1,173 @@ +# -*- coding: utf-8 -*- +""" + babel.messages.checkers + ~~~~~~~~~~~~~~~~~~~~~~~ + + Various routines that help with validation of translations. + + :since: version 0.9 + + :copyright: (c) 2013-2018 by the Babel Team. + :license: BSD, see LICENSE for more details. +""" + +from babel.messages.catalog import TranslationError, PYTHON_FORMAT +from babel._compat import string_types, izip + + +#: list of format chars that are compatible to each other +_string_format_compatibilities = [ + {'i', 'd', 'u'}, + {'x', 'X'}, + {'f', 'F', 'g', 'G'} +] + + +def num_plurals(catalog, message): + """Verify the number of plurals in the translation.""" + if not message.pluralizable: + if not isinstance(message.string, string_types): + raise TranslationError("Found plural forms for non-pluralizable " + "message") + return + + # skip further tests if no catalog is provided. + elif catalog is None: + return + + msgstrs = message.string + if not isinstance(msgstrs, (list, tuple)): + msgstrs = (msgstrs,) + if len(msgstrs) != catalog.num_plurals: + raise TranslationError("Wrong number of plural forms (expected %d)" % + catalog.num_plurals) + + +def python_format(catalog, message): + """Verify the format string placeholders in the translation.""" + if 'python-format' not in message.flags: + return + msgids = message.id + if not isinstance(msgids, (list, tuple)): + msgids = (msgids,) + msgstrs = message.string + if not isinstance(msgstrs, (list, tuple)): + msgstrs = (msgstrs,) + + for msgid, msgstr in izip(msgids, msgstrs): + if msgstr: + _validate_format(msgid, msgstr) + + +def _validate_format(format, alternative): + """Test format string `alternative` against `format`. `format` can be the + msgid of a message and `alternative` one of the `msgstr`\\s. The two + arguments are not interchangeable as `alternative` may contain less + placeholders if `format` uses named placeholders. + + The behavior of this function is undefined if the string does not use + string formattings. + + If the string formatting of `alternative` is compatible to `format` the + function returns `None`, otherwise a `TranslationError` is raised. + + Examples for compatible format strings: + + >>> _validate_format('Hello %s!', 'Hallo %s!') + >>> _validate_format('Hello %i!', 'Hallo %d!') + + Example for an incompatible format strings: + + >>> _validate_format('Hello %(name)s!', 'Hallo %s!') + Traceback (most recent call last): + ... + TranslationError: the format strings are of different kinds + + This function is used by the `python_format` checker. + + :param format: The original format string + :param alternative: The alternative format string that should be checked + against format + :raises TranslationError: on formatting errors + """ + + def _parse(string): + result = [] + for match in PYTHON_FORMAT.finditer(string): + name, format, typechar = match.groups() + if typechar == '%' and name is None: + continue + result.append((name, str(typechar))) + return result + + def _compatible(a, b): + if a == b: + return True + for set in _string_format_compatibilities: + if a in set and b in set: + return True + return False + + def _check_positional(results): + positional = None + for name, char in results: + if positional is None: + positional = name is None + else: + if (name is None) != positional: + raise TranslationError('format string mixes positional ' + 'and named placeholders') + return bool(positional) + + a, b = map(_parse, (format, alternative)) + + # now check if both strings are positional or named + a_positional, b_positional = map(_check_positional, (a, b)) + if a_positional and not b_positional and not b: + raise TranslationError('placeholders are incompatible') + elif a_positional != b_positional: + raise TranslationError('the format strings are of different kinds') + + # if we are operating on positional strings both must have the + # same number of format chars and those must be compatible + if a_positional: + if len(a) != len(b): + raise TranslationError('positional format placeholders are ' + 'unbalanced') + for idx, ((_, first), (_, second)) in enumerate(izip(a, b)): + if not _compatible(first, second): + raise TranslationError('incompatible format for placeholder ' + '%d: %r and %r are not compatible' % + (idx + 1, first, second)) + + # otherwise the second string must not have names the first one + # doesn't have and the types of those included must be compatible + else: + type_map = dict(a) + for name, typechar in b: + if name not in type_map: + raise TranslationError('unknown named placeholder %r' % name) + elif not _compatible(typechar, type_map[name]): + raise TranslationError('incompatible format for ' + 'placeholder %r: ' + '%r and %r are not compatible' % + (name, typechar, type_map[name])) + + +def _find_checkers(): + checkers = [] + try: + from pkg_resources import working_set + except ImportError: + pass + else: + for entry_point in working_set.iter_entry_points('babel.checkers'): + checkers.append(entry_point.load()) + if len(checkers) == 0: + # if pkg_resources is not available or no usable egg-info was found + # (see #230), just resort to hard-coded checkers + return [num_plurals, python_format] + return checkers + + +checkers = _find_checkers() diff --git a/venv/lib/python2.7/site-packages/babel/messages/extract.py b/venv/lib/python2.7/site-packages/babel/messages/extract.py new file mode 100644 index 0000000..009bea2 --- /dev/null +++ b/venv/lib/python2.7/site-packages/babel/messages/extract.py @@ -0,0 +1,642 @@ +# -*- coding: utf-8 -*- +""" + babel.messages.extract + ~~~~~~~~~~~~~~~~~~~~~~ + + Basic infrastructure for extracting localizable messages from source files. + + This module defines an extensible system for collecting localizable message + strings from a variety of sources. A native extractor for Python source + files is builtin, extractors for other sources can be added using very + simple plugins. + + The main entry points into the extraction functionality are the functions + `extract_from_dir` and `extract_from_file`. + + :copyright: (c) 2013-2018 by the Babel Team. + :license: BSD, see LICENSE for more details. +""" + +import os +from os.path import relpath +import sys +from tokenize import generate_tokens, COMMENT, NAME, OP, STRING + +from babel.util import parse_encoding, parse_future_flags, pathmatch +from babel._compat import PY2, text_type +from textwrap import dedent + + +GROUP_NAME = 'babel.extractors' + +DEFAULT_KEYWORDS = { + '_': None, + 'gettext': None, + 'ngettext': (1, 2), + 'ugettext': None, + 'ungettext': (1, 2), + 'dgettext': (2,), + 'dngettext': (2, 3), + 'N_': None, + 'pgettext': ((1, 'c'), 2), + 'npgettext': ((1, 'c'), 2, 3) +} + +DEFAULT_MAPPING = [('**.py', 'python')] + +empty_msgid_warning = ( + '%s: warning: Empty msgid. It is reserved by GNU gettext: gettext("") ' + 'returns the header entry with meta information, not the empty string.') + + +def _strip_comment_tags(comments, tags): + """Helper function for `extract` that strips comment tags from strings + in a list of comment lines. This functions operates in-place. + """ + def _strip(line): + for tag in tags: + if line.startswith(tag): + return line[len(tag):].strip() + return line + comments[:] = map(_strip, comments) + + +def extract_from_dir(dirname=None, method_map=DEFAULT_MAPPING, + options_map=None, keywords=DEFAULT_KEYWORDS, + comment_tags=(), callback=None, strip_comment_tags=False): + """Extract messages from any source files found in the given directory. + + This function generates tuples of the form ``(filename, lineno, message, + comments, context)``. + + Which extraction method is used per file is determined by the `method_map` + parameter, which maps extended glob patterns to extraction method names. + For example, the following is the default mapping: + + >>> method_map = [ + ... ('**.py', 'python') + ... ] + + This basically says that files with the filename extension ".py" at any + level inside the directory should be processed by the "python" extraction + method. Files that don't match any of the mapping patterns are ignored. See + the documentation of the `pathmatch` function for details on the pattern + syntax. + + The following extended mapping would also use the "genshi" extraction + method on any file in "templates" subdirectory: + + >>> method_map = [ + ... ('**/templates/**.*', 'genshi'), + ... ('**.py', 'python') + ... ] + + The dictionary provided by the optional `options_map` parameter augments + these mappings. It uses extended glob patterns as keys, and the values are + dictionaries mapping options names to option values (both strings). + + The glob patterns of the `options_map` do not necessarily need to be the + same as those used in the method mapping. For example, while all files in + the ``templates`` folders in an application may be Genshi applications, the + options for those files may differ based on extension: + + >>> options_map = { + ... '**/templates/**.txt': { + ... 'template_class': 'genshi.template:TextTemplate', + ... 'encoding': 'latin-1' + ... }, + ... '**/templates/**.html': { + ... 'include_attrs': '' + ... } + ... } + + :param dirname: the path to the directory to extract messages from. If + not given the current working directory is used. + :param method_map: a list of ``(pattern, method)`` tuples that maps of + extraction method names to extended glob patterns + :param options_map: a dictionary of additional options (optional) + :param keywords: a dictionary mapping keywords (i.e. names of functions + that should be recognized as translation functions) to + tuples that specify which of their arguments contain + localizable strings + :param comment_tags: a list of tags of translator comments to search for + and include in the results + :param callback: a function that is called for every file that message are + extracted from, just before the extraction itself is + performed; the function is passed the filename, the name + of the extraction method and and the options dictionary as + positional arguments, in that order + :param strip_comment_tags: a flag that if set to `True` causes all comment + tags to be removed from the collected comments. + :see: `pathmatch` + """ + if dirname is None: + dirname = os.getcwd() + if options_map is None: + options_map = {} + + absname = os.path.abspath(dirname) + for root, dirnames, filenames in os.walk(absname): + dirnames[:] = [ + subdir for subdir in dirnames + if not (subdir.startswith('.') or subdir.startswith('_')) + ] + dirnames.sort() + filenames.sort() + for filename in filenames: + filepath = os.path.join(root, filename).replace(os.sep, '/') + + for message_tuple in check_and_call_extract_file( + filepath, + method_map, + options_map, + callback, + keywords, + comment_tags, + strip_comment_tags, + dirpath=absname, + ): + yield message_tuple + + +def check_and_call_extract_file(filepath, method_map, options_map, + callback, keywords, comment_tags, + strip_comment_tags, dirpath=None): + """Checks if the given file matches an extraction method mapping, and if so, calls extract_from_file. + + Note that the extraction method mappings are based relative to dirpath. + So, given an absolute path to a file `filepath`, we want to check using + just the relative path from `dirpath` to `filepath`. + + Yields 5-tuples (filename, lineno, messages, comments, context). + + :param filepath: An absolute path to a file that exists. + :param method_map: a list of ``(pattern, method)`` tuples that maps of + extraction method names to extended glob patterns + :param options_map: a dictionary of additional options (optional) + :param callback: a function that is called for every file that message are + extracted from, just before the extraction itself is + performed; the function is passed the filename, the name + of the extraction method and and the options dictionary as + positional arguments, in that order + :param keywords: a dictionary mapping keywords (i.e. names of functions + that should be recognized as translation functions) to + tuples that specify which of their arguments contain + localizable strings + :param comment_tags: a list of tags of translator comments to search for + and include in the results + :param strip_comment_tags: a flag that if set to `True` causes all comment + tags to be removed from the collected comments. + :param dirpath: the path to the directory to extract messages from. + :return: iterable of 5-tuples (filename, lineno, messages, comments, context) + :rtype: Iterable[tuple[str, int, str|tuple[str], list[str], str|None] + """ + # filename is the relative path from dirpath to the actual file + filename = relpath(filepath, dirpath) + + for pattern, method in method_map: + if not pathmatch(pattern, filename): + continue + + options = {} + for opattern, odict in options_map.items(): + if pathmatch(opattern, filename): + options = odict + if callback: + callback(filename, method, options) + for message_tuple in extract_from_file( + method, filepath, + keywords=keywords, + comment_tags=comment_tags, + options=options, + strip_comment_tags=strip_comment_tags + ): + yield (filename, ) + message_tuple + + break + + +def extract_from_file(method, filename, keywords=DEFAULT_KEYWORDS, + comment_tags=(), options=None, strip_comment_tags=False): + """Extract messages from a specific file. + + This function returns a list of tuples of the form ``(lineno, message, comments, context)``. + + :param filename: the path to the file to extract messages from + :param method: a string specifying the extraction method (.e.g. "python") + :param keywords: a dictionary mapping keywords (i.e. names of functions + that should be recognized as translation functions) to + tuples that specify which of their arguments contain + localizable strings + :param comment_tags: a list of translator tags to search for and include + in the results + :param strip_comment_tags: a flag that if set to `True` causes all comment + tags to be removed from the collected comments. + :param options: a dictionary of additional options (optional) + :returns: list of tuples of the form ``(lineno, message, comments, context)`` + :rtype: list[tuple[int, str|tuple[str], list[str], str|None] + """ + with open(filename, 'rb') as fileobj: + return list(extract(method, fileobj, keywords, comment_tags, options, + strip_comment_tags)) + + +def extract(method, fileobj, keywords=DEFAULT_KEYWORDS, comment_tags=(), + options=None, strip_comment_tags=False): + """Extract messages from the given file-like object using the specified + extraction method. + + This function returns tuples of the form ``(lineno, message, comments, context)``. + + The implementation dispatches the actual extraction to plugins, based on the + value of the ``method`` parameter. + + >>> source = b'''# foo module + ... def run(argv): + ... print(_('Hello, world!')) + ... ''' + + >>> from babel._compat import BytesIO + >>> for message in extract('python', BytesIO(source)): + ... print(message) + (3, u'Hello, world!', [], None) + + :param method: an extraction method (a callable), or + a string specifying the extraction method (.e.g. "python"); + if this is a simple name, the extraction function will be + looked up by entry point; if it is an explicit reference + to a function (of the form ``package.module:funcname`` or + ``package.module.funcname``), the corresponding function + will be imported and used + :param fileobj: the file-like object the messages should be extracted from + :param keywords: a dictionary mapping keywords (i.e. names of functions + that should be recognized as translation functions) to + tuples that specify which of their arguments contain + localizable strings + :param comment_tags: a list of translator tags to search for and include + in the results + :param options: a dictionary of additional options (optional) + :param strip_comment_tags: a flag that if set to `True` causes all comment + tags to be removed from the collected comments. + :raise ValueError: if the extraction method is not registered + :returns: iterable of tuples of the form ``(lineno, message, comments, context)`` + :rtype: Iterable[tuple[int, str|tuple[str], list[str], str|None] + """ + func = None + if callable(method): + func = method + elif ':' in method or '.' in method: + if ':' not in method: + lastdot = method.rfind('.') + module, attrname = method[:lastdot], method[lastdot + 1:] + else: + module, attrname = method.split(':', 1) + func = getattr(__import__(module, {}, {}, [attrname]), attrname) + else: + try: + from pkg_resources import working_set + except ImportError: + pass + else: + for entry_point in working_set.iter_entry_points(GROUP_NAME, + method): + func = entry_point.load(require=True) + break + if func is None: + # if pkg_resources is not available or no usable egg-info was found + # (see #230), we resort to looking up the builtin extractors + # directly + builtin = { + 'ignore': extract_nothing, + 'python': extract_python, + 'javascript': extract_javascript + } + func = builtin.get(method) + + if func is None: + raise ValueError('Unknown extraction method %r' % method) + + results = func(fileobj, keywords.keys(), comment_tags, + options=options or {}) + + for lineno, funcname, messages, comments in results: + if funcname: + spec = keywords[funcname] or (1,) + else: + spec = (1,) + if not isinstance(messages, (list, tuple)): + messages = [messages] + if not messages: + continue + + # Validate the messages against the keyword's specification + context = None + msgs = [] + invalid = False + # last_index is 1 based like the keyword spec + last_index = len(messages) + for index in spec: + if isinstance(index, tuple): + context = messages[index[0] - 1] + continue + if last_index < index: + # Not enough arguments + invalid = True + break + message = messages[index - 1] + if message is None: + invalid = True + break + msgs.append(message) + if invalid: + continue + + # keyword spec indexes are 1 based, therefore '-1' + if isinstance(spec[0], tuple): + # context-aware *gettext method + first_msg_index = spec[1] - 1 + else: + first_msg_index = spec[0] - 1 + if not messages[first_msg_index]: + # An empty string msgid isn't valid, emit a warning + where = '%s:%i' % (hasattr(fileobj, 'name') and + fileobj.name or '(unknown)', lineno) + sys.stderr.write((empty_msgid_warning % where) + '\n') + continue + + messages = tuple(msgs) + if len(messages) == 1: + messages = messages[0] + + if strip_comment_tags: + _strip_comment_tags(comments, comment_tags) + yield lineno, messages, comments, context + + +def extract_nothing(fileobj, keywords, comment_tags, options): + """Pseudo extractor that does not actually extract anything, but simply + returns an empty list. + """ + return [] + + +def extract_python(fileobj, keywords, comment_tags, options): + """Extract messages from Python source code. + + It returns an iterator yielding tuples in the following form ``(lineno, + funcname, message, comments)``. + + :param fileobj: the seekable, file-like object the messages should be + extracted from + :param keywords: a list of keywords (i.e. function names) that should be + recognized as translation functions + :param comment_tags: a list of translator tags to search for and include + in the results + :param options: a dictionary of additional options (optional) + :rtype: ``iterator`` + """ + funcname = lineno = message_lineno = None + call_stack = -1 + buf = [] + messages = [] + translator_comments = [] + in_def = in_translator_comments = False + comment_tag = None + + encoding = parse_encoding(fileobj) or options.get('encoding', 'UTF-8') + future_flags = parse_future_flags(fileobj, encoding) + + if PY2: + next_line = fileobj.readline + else: + next_line = lambda: fileobj.readline().decode(encoding) + + tokens = generate_tokens(next_line) + for tok, value, (lineno, _), _, _ in tokens: + if call_stack == -1 and tok == NAME and value in ('def', 'class'): + in_def = True + elif tok == OP and value == '(': + if in_def: + # Avoid false positives for declarations such as: + # def gettext(arg='message'): + in_def = False + continue + if funcname: + message_lineno = lineno + call_stack += 1 + elif in_def and tok == OP and value == ':': + # End of a class definition without parens + in_def = False + continue + elif call_stack == -1 and tok == COMMENT: + # Strip the comment token from the line + if PY2: + value = value.decode(encoding) + value = value[1:].strip() + if in_translator_comments and \ + translator_comments[-1][0] == lineno - 1: + # We're already inside a translator comment, continue appending + translator_comments.append((lineno, value)) + continue + # If execution reaches this point, let's see if comment line + # starts with one of the comment tags + for comment_tag in comment_tags: + if value.startswith(comment_tag): + in_translator_comments = True + translator_comments.append((lineno, value)) + break + elif funcname and call_stack == 0: + nested = (tok == NAME and value in keywords) + if (tok == OP and value == ')') or nested: + if buf: + messages.append(''.join(buf)) + del buf[:] + else: + messages.append(None) + + if len(messages) > 1: + messages = tuple(messages) + else: + messages = messages[0] + # Comments don't apply unless they immediately preceed the + # message + if translator_comments and \ + translator_comments[-1][0] < message_lineno - 1: + translator_comments = [] + + yield (message_lineno, funcname, messages, + [comment[1] for comment in translator_comments]) + + funcname = lineno = message_lineno = None + call_stack = -1 + messages = [] + translator_comments = [] + in_translator_comments = False + if nested: + funcname = value + elif tok == STRING: + # Unwrap quotes in a safe manner, maintaining the string's + # encoding + # https://sourceforge.net/tracker/?func=detail&atid=355470& + # aid=617979&group_id=5470 + code = compile('# coding=%s\n%s' % (str(encoding), value), + '', 'eval', future_flags) + value = eval(code, {'__builtins__': {}}, {}) + if PY2 and not isinstance(value, text_type): + value = value.decode(encoding) + buf.append(value) + elif tok == OP and value == ',': + if buf: + messages.append(''.join(buf)) + del buf[:] + else: + messages.append(None) + if translator_comments: + # We have translator comments, and since we're on a + # comma(,) user is allowed to break into a new line + # Let's increase the last comment's lineno in order + # for the comment to still be a valid one + old_lineno, old_comment = translator_comments.pop() + translator_comments.append((old_lineno + 1, old_comment)) + elif call_stack > 0 and tok == OP and value == ')': + call_stack -= 1 + elif funcname and call_stack == -1: + funcname = None + elif tok == NAME and value in keywords: + funcname = value + + +def extract_javascript(fileobj, keywords, comment_tags, options): + """Extract messages from JavaScript source code. + + :param fileobj: the seekable, file-like object the messages should be + extracted from + :param keywords: a list of keywords (i.e. function names) that should be + recognized as translation functions + :param comment_tags: a list of translator tags to search for and include + in the results + :param options: a dictionary of additional options (optional) + Supported options are: + * `jsx` -- set to false to disable JSX/E4X support. + * `template_string` -- set to false to disable ES6 + template string support. + """ + from babel.messages.jslexer import Token, tokenize, unquote_string + funcname = message_lineno = None + messages = [] + last_argument = None + translator_comments = [] + concatenate_next = False + encoding = options.get('encoding', 'utf-8') + last_token = None + call_stack = -1 + dotted = any('.' in kw for kw in keywords) + + for token in tokenize( + fileobj.read().decode(encoding), + jsx=options.get("jsx", True), + template_string=options.get("template_string", True), + dotted=dotted + ): + if ( # Turn keyword`foo` expressions into keyword("foo") calls: + funcname and # have a keyword... + (last_token and last_token.type == 'name') and # we've seen nothing after the keyword... + token.type == 'template_string' # this is a template string + ): + message_lineno = token.lineno + messages = [unquote_string(token.value)] + call_stack = 0 + token = Token('operator', ')', token.lineno) + + if token.type == 'operator' and token.value == '(': + if funcname: + message_lineno = token.lineno + call_stack += 1 + + elif call_stack == -1 and token.type == 'linecomment': + value = token.value[2:].strip() + if translator_comments and \ + translator_comments[-1][0] == token.lineno - 1: + translator_comments.append((token.lineno, value)) + continue + + for comment_tag in comment_tags: + if value.startswith(comment_tag): + translator_comments.append((token.lineno, value.strip())) + break + + elif token.type == 'multilinecomment': + # only one multi-line comment may preceed a translation + translator_comments = [] + value = token.value[2:-2].strip() + for comment_tag in comment_tags: + if value.startswith(comment_tag): + lines = value.splitlines() + if lines: + lines[0] = lines[0].strip() + lines[1:] = dedent('\n'.join(lines[1:])).splitlines() + for offset, line in enumerate(lines): + translator_comments.append((token.lineno + offset, + line)) + break + + elif funcname and call_stack == 0: + if token.type == 'operator' and token.value == ')': + if last_argument is not None: + messages.append(last_argument) + if len(messages) > 1: + messages = tuple(messages) + elif messages: + messages = messages[0] + else: + messages = None + + # Comments don't apply unless they immediately precede the + # message + if translator_comments and \ + translator_comments[-1][0] < message_lineno - 1: + translator_comments = [] + + if messages is not None: + yield (message_lineno, funcname, messages, + [comment[1] for comment in translator_comments]) + + funcname = message_lineno = last_argument = None + concatenate_next = False + translator_comments = [] + messages = [] + call_stack = -1 + + elif token.type in ('string', 'template_string'): + new_value = unquote_string(token.value) + if concatenate_next: + last_argument = (last_argument or '') + new_value + concatenate_next = False + else: + last_argument = new_value + + elif token.type == 'operator': + if token.value == ',': + if last_argument is not None: + messages.append(last_argument) + last_argument = None + else: + messages.append(None) + concatenate_next = False + elif token.value == '+': + concatenate_next = True + + elif call_stack > 0 and token.type == 'operator' \ + and token.value == ')': + call_stack -= 1 + + elif funcname and call_stack == -1: + funcname = None + + elif call_stack == -1 and token.type == 'name' and \ + token.value in keywords and \ + (last_token is None or last_token.type != 'name' or + last_token.value != 'function'): + funcname = token.value + + last_token = token diff --git a/venv/lib/python2.7/site-packages/babel/messages/frontend.py b/venv/lib/python2.7/site-packages/babel/messages/frontend.py new file mode 100644 index 0000000..16cb900 --- /dev/null +++ b/venv/lib/python2.7/site-packages/babel/messages/frontend.py @@ -0,0 +1,1023 @@ +# -*- coding: utf-8 -*- +""" + babel.messages.frontend + ~~~~~~~~~~~~~~~~~~~~~~~ + + Frontends for the message extraction functionality. + + :copyright: (c) 2013-2018 by the Babel Team. + :license: BSD, see LICENSE for more details. +""" +from __future__ import print_function + +import logging +import optparse +import os +import re +import shutil +import sys +import tempfile +from datetime import datetime +from locale import getpreferredencoding + +from babel import __version__ as VERSION +from babel import Locale, localedata +from babel._compat import StringIO, string_types, text_type, PY2 +from babel.core import UnknownLocaleError +from babel.messages.catalog import Catalog +from babel.messages.extract import DEFAULT_KEYWORDS, DEFAULT_MAPPING, check_and_call_extract_file, extract_from_dir +from babel.messages.mofile import write_mo +from babel.messages.pofile import read_po, write_po +from babel.util import LOCALTZ, odict +from distutils import log as distutils_log +from distutils.cmd import Command as _Command +from distutils.errors import DistutilsOptionError, DistutilsSetupError + +try: + from ConfigParser import RawConfigParser +except ImportError: + from configparser import RawConfigParser + + +po_file_read_mode = ('rU' if PY2 else 'r') + + +def listify_value(arg, split=None): + """ + Make a list out of an argument. + + Values from `distutils` argument parsing are always single strings; + values from `optparse` parsing may be lists of strings that may need + to be further split. + + No matter the input, this function returns a flat list of whitespace-trimmed + strings, with `None` values filtered out. + + >>> listify_value("foo bar") + ['foo', 'bar'] + >>> listify_value(["foo bar"]) + ['foo', 'bar'] + >>> listify_value([["foo"], "bar"]) + ['foo', 'bar'] + >>> listify_value([["foo"], ["bar", None, "foo"]]) + ['foo', 'bar', 'foo'] + >>> listify_value("foo, bar, quux", ",") + ['foo', 'bar', 'quux'] + + :param arg: A string or a list of strings + :param split: The argument to pass to `str.split()`. + :return: + """ + out = [] + + if not isinstance(arg, (list, tuple)): + arg = [arg] + + for val in arg: + if val is None: + continue + if isinstance(val, (list, tuple)): + out.extend(listify_value(val, split=split)) + continue + out.extend(s.strip() for s in text_type(val).split(split)) + assert all(isinstance(val, string_types) for val in out) + return out + + +class Command(_Command): + # This class is a small shim between Distutils commands and + # optparse option parsing in the frontend command line. + + #: Option name to be input as `args` on the script command line. + as_args = None + + #: Options which allow multiple values. + #: This is used by the `optparse` transmogrification code. + multiple_value_options = () + + #: Options which are booleans. + #: This is used by the `optparse` transmogrification code. + # (This is actually used by distutils code too, but is never + # declared in the base class.) + boolean_options = () + + #: Option aliases, to retain standalone command compatibility. + #: Distutils does not support option aliases, but optparse does. + #: This maps the distutils argument name to an iterable of aliases + #: that are usable with optparse. + option_aliases = {} + + #: Choices for options that needed to be restricted to specific + #: list of choices. + option_choices = {} + + #: Log object. To allow replacement in the script command line runner. + log = distutils_log + + def __init__(self, dist=None): + # A less strict version of distutils' `__init__`. + self.distribution = dist + self.initialize_options() + self._dry_run = None + self.verbose = False + self.force = None + self.help = 0 + self.finalized = 0 + + +class compile_catalog(Command): + """Catalog compilation command for use in ``setup.py`` scripts. + + If correctly installed, this command is available to Setuptools-using + setup scripts automatically. For projects using plain old ``distutils``, + the command needs to be registered explicitly in ``setup.py``:: + + from babel.messages.frontend import compile_catalog + + setup( + ... + cmdclass = {'compile_catalog': compile_catalog} + ) + + .. versionadded:: 0.9 + """ + + description = 'compile message catalogs to binary MO files' + user_options = [ + ('domain=', 'D', + "domains of PO files (space separated list, default 'messages')"), + ('directory=', 'd', + 'path to base directory containing the catalogs'), + ('input-file=', 'i', + 'name of the input file'), + ('output-file=', 'o', + "name of the output file (default " + "'//LC_MESSAGES/.mo')"), + ('locale=', 'l', + 'locale of the catalog to compile'), + ('use-fuzzy', 'f', + 'also include fuzzy translations'), + ('statistics', None, + 'print statistics about translations') + ] + boolean_options = ['use-fuzzy', 'statistics'] + + def initialize_options(self): + self.domain = 'messages' + self.directory = None + self.input_file = None + self.output_file = None + self.locale = None + self.use_fuzzy = False + self.statistics = False + + def finalize_options(self): + self.domain = listify_value(self.domain) + if not self.input_file and not self.directory: + raise DistutilsOptionError('you must specify either the input file ' + 'or the base directory') + if not self.output_file and not self.directory: + raise DistutilsOptionError('you must specify either the output file ' + 'or the base directory') + + def run(self): + for domain in self.domain: + self._run_domain(domain) + + def _run_domain(self, domain): + po_files = [] + mo_files = [] + + if not self.input_file: + if self.locale: + po_files.append((self.locale, + os.path.join(self.directory, self.locale, + 'LC_MESSAGES', + domain + '.po'))) + mo_files.append(os.path.join(self.directory, self.locale, + 'LC_MESSAGES', + domain + '.mo')) + else: + for locale in os.listdir(self.directory): + po_file = os.path.join(self.directory, locale, + 'LC_MESSAGES', domain + '.po') + if os.path.exists(po_file): + po_files.append((locale, po_file)) + mo_files.append(os.path.join(self.directory, locale, + 'LC_MESSAGES', + domain + '.mo')) + else: + po_files.append((self.locale, self.input_file)) + if self.output_file: + mo_files.append(self.output_file) + else: + mo_files.append(os.path.join(self.directory, self.locale, + 'LC_MESSAGES', + domain + '.mo')) + + if not po_files: + raise DistutilsOptionError('no message catalogs found') + + for idx, (locale, po_file) in enumerate(po_files): + mo_file = mo_files[idx] + with open(po_file, 'rb') as infile: + catalog = read_po(infile, locale) + + if self.statistics: + translated = 0 + for message in list(catalog)[1:]: + if message.string: + translated += 1 + percentage = 0 + if len(catalog): + percentage = translated * 100 // len(catalog) + self.log.info( + '%d of %d messages (%d%%) translated in %s', + translated, len(catalog), percentage, po_file + ) + + if catalog.fuzzy and not self.use_fuzzy: + self.log.info('catalog %s is marked as fuzzy, skipping', po_file) + continue + + for message, errors in catalog.check(): + for error in errors: + self.log.error( + 'error: %s:%d: %s', po_file, message.lineno, error + ) + + self.log.info('compiling catalog %s to %s', po_file, mo_file) + + with open(mo_file, 'wb') as outfile: + write_mo(outfile, catalog, use_fuzzy=self.use_fuzzy) + + +class extract_messages(Command): + """Message extraction command for use in ``setup.py`` scripts. + + If correctly installed, this command is available to Setuptools-using + setup scripts automatically. For projects using plain old ``distutils``, + the command needs to be registered explicitly in ``setup.py``:: + + from babel.messages.frontend import extract_messages + + setup( + ... + cmdclass = {'extract_messages': extract_messages} + ) + """ + + description = 'extract localizable strings from the project code' + user_options = [ + ('charset=', None, + 'charset to use in the output file (default "utf-8")'), + ('keywords=', 'k', + 'space-separated list of keywords to look for in addition to the ' + 'defaults (may be repeated multiple times)'), + ('no-default-keywords', None, + 'do not include the default keywords'), + ('mapping-file=', 'F', + 'path to the mapping configuration file'), + ('no-location', None, + 'do not include location comments with filename and line number'), + ('add-location=', None, + 'location lines format. If it is not given or "full", it generates ' + 'the lines with both file name and line number. If it is "file", ' + 'the line number part is omitted. If it is "never", it completely ' + 'suppresses the lines (same as --no-location).'), + ('omit-header', None, + 'do not include msgid "" entry in header'), + ('output-file=', 'o', + 'name of the output file'), + ('width=', 'w', + 'set output line width (default 76)'), + ('no-wrap', None, + 'do not break long message lines, longer than the output line width, ' + 'into several lines'), + ('sort-output', None, + 'generate sorted output (default False)'), + ('sort-by-file', None, + 'sort output by file location (default False)'), + ('msgid-bugs-address=', None, + 'set report address for msgid'), + ('copyright-holder=', None, + 'set copyright holder in output'), + ('project=', None, + 'set project name in output'), + ('version=', None, + 'set project version in output'), + ('add-comments=', 'c', + 'place comment block with TAG (or those preceding keyword lines) in ' + 'output file. Separate multiple TAGs with commas(,)'), # TODO: Support repetition of this argument + ('strip-comments', 's', + 'strip the comment TAGs from the comments.'), + ('input-paths=', None, + 'files or directories that should be scanned for messages. Separate multiple ' + 'files or directories with commas(,)'), # TODO: Support repetition of this argument + ('input-dirs=', None, # TODO (3.x): Remove me. + 'alias for input-paths (does allow files as well as directories).'), + ] + boolean_options = [ + 'no-default-keywords', 'no-location', 'omit-header', 'no-wrap', + 'sort-output', 'sort-by-file', 'strip-comments' + ] + as_args = 'input-paths' + multiple_value_options = ('add-comments', 'keywords') + option_aliases = { + 'keywords': ('--keyword',), + 'mapping-file': ('--mapping',), + 'output-file': ('--output',), + 'strip-comments': ('--strip-comment-tags',), + } + option_choices = { + 'add-location': ('full', 'file', 'never',), + } + + def initialize_options(self): + self.charset = 'utf-8' + self.keywords = None + self.no_default_keywords = False + self.mapping_file = None + self.no_location = False + self.add_location = None + self.omit_header = False + self.output_file = None + self.input_dirs = None + self.input_paths = None + self.width = None + self.no_wrap = False + self.sort_output = False + self.sort_by_file = False + self.msgid_bugs_address = None + self.copyright_holder = None + self.project = None + self.version = None + self.add_comments = None + self.strip_comments = False + self.include_lineno = True + + def finalize_options(self): + if self.input_dirs: + if not self.input_paths: + self.input_paths = self.input_dirs + else: + raise DistutilsOptionError( + 'input-dirs and input-paths are mutually exclusive' + ) + + if self.no_default_keywords: + keywords = {} + else: + keywords = DEFAULT_KEYWORDS.copy() + + keywords.update(parse_keywords(listify_value(self.keywords))) + + self.keywords = keywords + + if not self.keywords: + raise DistutilsOptionError('you must specify new keywords if you ' + 'disable the default ones') + + if not self.output_file: + raise DistutilsOptionError('no output file specified') + if self.no_wrap and self.width: + raise DistutilsOptionError("'--no-wrap' and '--width' are mutually " + "exclusive") + if not self.no_wrap and not self.width: + self.width = 76 + elif self.width is not None: + self.width = int(self.width) + + if self.sort_output and self.sort_by_file: + raise DistutilsOptionError("'--sort-output' and '--sort-by-file' " + "are mutually exclusive") + + if self.input_paths: + if isinstance(self.input_paths, string_types): + self.input_paths = re.split(r',\s*', self.input_paths) + elif self.distribution is not None: + self.input_paths = dict.fromkeys([ + k.split('.', 1)[0] + for k in (self.distribution.packages or ()) + ]).keys() + else: + self.input_paths = [] + + if not self.input_paths: + raise DistutilsOptionError("no input files or directories specified") + + for path in self.input_paths: + if not os.path.exists(path): + raise DistutilsOptionError("Input path: %s does not exist" % path) + + self.add_comments = listify_value(self.add_comments or (), ",") + + if self.distribution: + if not self.project: + self.project = self.distribution.get_name() + if not self.version: + self.version = self.distribution.get_version() + + if self.add_location == 'never': + self.no_location = True + elif self.add_location == 'file': + self.include_lineno = False + + def run(self): + mappings = self._get_mappings() + with open(self.output_file, 'wb') as outfile: + catalog = Catalog(project=self.project, + version=self.version, + msgid_bugs_address=self.msgid_bugs_address, + copyright_holder=self.copyright_holder, + charset=self.charset) + + for path, method_map, options_map in mappings: + def callback(filename, method, options): + if method == 'ignore': + return + + # If we explicitly provide a full filepath, just use that. + # Otherwise, path will be the directory path and filename + # is the relative path from that dir to the file. + # So we can join those to get the full filepath. + if os.path.isfile(path): + filepath = path + else: + filepath = os.path.normpath(os.path.join(path, filename)) + + optstr = '' + if options: + optstr = ' (%s)' % ', '.join(['%s="%s"' % (k, v) for + k, v in options.items()]) + self.log.info('extracting messages from %s%s', filepath, optstr) + + if os.path.isfile(path): + current_dir = os.getcwd() + extracted = check_and_call_extract_file( + path, method_map, options_map, + callback, self.keywords, self.add_comments, + self.strip_comments, current_dir + ) + else: + extracted = extract_from_dir( + path, method_map, options_map, + keywords=self.keywords, + comment_tags=self.add_comments, + callback=callback, + strip_comment_tags=self.strip_comments + ) + for filename, lineno, message, comments, context in extracted: + if os.path.isfile(path): + filepath = filename # already normalized + else: + filepath = os.path.normpath(os.path.join(path, filename)) + + catalog.add(message, None, [(filepath, lineno)], + auto_comments=comments, context=context) + + self.log.info('writing PO template file to %s', self.output_file) + write_po(outfile, catalog, width=self.width, + no_location=self.no_location, + omit_header=self.omit_header, + sort_output=self.sort_output, + sort_by_file=self.sort_by_file, + include_lineno=self.include_lineno) + + def _get_mappings(self): + mappings = [] + + if self.mapping_file: + with open(self.mapping_file, po_file_read_mode) as fileobj: + method_map, options_map = parse_mapping(fileobj) + for path in self.input_paths: + mappings.append((path, method_map, options_map)) + + elif getattr(self.distribution, 'message_extractors', None): + message_extractors = self.distribution.message_extractors + for path, mapping in message_extractors.items(): + if isinstance(mapping, string_types): + method_map, options_map = parse_mapping(StringIO(mapping)) + else: + method_map, options_map = [], {} + for pattern, method, options in mapping: + method_map.append((pattern, method)) + options_map[pattern] = options or {} + mappings.append((path, method_map, options_map)) + + else: + for path in self.input_paths: + mappings.append((path, DEFAULT_MAPPING, {})) + + return mappings + + +def check_message_extractors(dist, name, value): + """Validate the ``message_extractors`` keyword argument to ``setup()``. + + :param dist: the distutils/setuptools ``Distribution`` object + :param name: the name of the keyword argument (should always be + "message_extractors") + :param value: the value of the keyword argument + :raise `DistutilsSetupError`: if the value is not valid + """ + assert name == 'message_extractors' + if not isinstance(value, dict): + raise DistutilsSetupError('the value of the "message_extractors" ' + 'parameter must be a dictionary') + + +class init_catalog(Command): + """New catalog initialization command for use in ``setup.py`` scripts. + + If correctly installed, this command is available to Setuptools-using + setup scripts automatically. For projects using plain old ``distutils``, + the command needs to be registered explicitly in ``setup.py``:: + + from babel.messages.frontend import init_catalog + + setup( + ... + cmdclass = {'init_catalog': init_catalog} + ) + """ + + description = 'create a new catalog based on a POT file' + user_options = [ + ('domain=', 'D', + "domain of PO file (default 'messages')"), + ('input-file=', 'i', + 'name of the input file'), + ('output-dir=', 'd', + 'path to output directory'), + ('output-file=', 'o', + "name of the output file (default " + "'//LC_MESSAGES/.po')"), + ('locale=', 'l', + 'locale for the new localized catalog'), + ('width=', 'w', + 'set output line width (default 76)'), + ('no-wrap', None, + 'do not break long message lines, longer than the output line width, ' + 'into several lines'), + ] + boolean_options = ['no-wrap'] + + def initialize_options(self): + self.output_dir = None + self.output_file = None + self.input_file = None + self.locale = None + self.domain = 'messages' + self.no_wrap = False + self.width = None + + def finalize_options(self): + if not self.input_file: + raise DistutilsOptionError('you must specify the input file') + + if not self.locale: + raise DistutilsOptionError('you must provide a locale for the ' + 'new catalog') + try: + self._locale = Locale.parse(self.locale) + except UnknownLocaleError as e: + raise DistutilsOptionError(e) + + if not self.output_file and not self.output_dir: + raise DistutilsOptionError('you must specify the output directory') + if not self.output_file: + self.output_file = os.path.join(self.output_dir, self.locale, + 'LC_MESSAGES', self.domain + '.po') + + if not os.path.exists(os.path.dirname(self.output_file)): + os.makedirs(os.path.dirname(self.output_file)) + if self.no_wrap and self.width: + raise DistutilsOptionError("'--no-wrap' and '--width' are mutually " + "exclusive") + if not self.no_wrap and not self.width: + self.width = 76 + elif self.width is not None: + self.width = int(self.width) + + def run(self): + self.log.info( + 'creating catalog %s based on %s', self.output_file, self.input_file + ) + + with open(self.input_file, 'rb') as infile: + # Although reading from the catalog template, read_po must be fed + # the locale in order to correctly calculate plurals + catalog = read_po(infile, locale=self.locale) + + catalog.locale = self._locale + catalog.revision_date = datetime.now(LOCALTZ) + catalog.fuzzy = False + + with open(self.output_file, 'wb') as outfile: + write_po(outfile, catalog, width=self.width) + + +class update_catalog(Command): + """Catalog merging command for use in ``setup.py`` scripts. + + If correctly installed, this command is available to Setuptools-using + setup scripts automatically. For projects using plain old ``distutils``, + the command needs to be registered explicitly in ``setup.py``:: + + from babel.messages.frontend import update_catalog + + setup( + ... + cmdclass = {'update_catalog': update_catalog} + ) + + .. versionadded:: 0.9 + """ + + description = 'update message catalogs from a POT file' + user_options = [ + ('domain=', 'D', + "domain of PO file (default 'messages')"), + ('input-file=', 'i', + 'name of the input file'), + ('output-dir=', 'd', + 'path to base directory containing the catalogs'), + ('output-file=', 'o', + "name of the output file (default " + "'//LC_MESSAGES/.po')"), + ('locale=', 'l', + 'locale of the catalog to compile'), + ('width=', 'w', + 'set output line width (default 76)'), + ('no-wrap', None, + 'do not break long message lines, longer than the output line width, ' + 'into several lines'), + ('ignore-obsolete=', None, + 'whether to omit obsolete messages from the output'), + ('no-fuzzy-matching', 'N', + 'do not use fuzzy matching'), + ('update-header-comment', None, + 'update target header comment'), + ('previous', None, + 'keep previous msgids of translated messages') + ] + boolean_options = ['no-wrap', 'ignore-obsolete', 'no-fuzzy-matching', 'previous', 'update-header-comment'] + + def initialize_options(self): + self.domain = 'messages' + self.input_file = None + self.output_dir = None + self.output_file = None + self.locale = None + self.width = None + self.no_wrap = False + self.ignore_obsolete = False + self.no_fuzzy_matching = False + self.update_header_comment = False + self.previous = False + + def finalize_options(self): + if not self.input_file: + raise DistutilsOptionError('you must specify the input file') + if not self.output_file and not self.output_dir: + raise DistutilsOptionError('you must specify the output file or ' + 'directory') + if self.output_file and not self.locale: + raise DistutilsOptionError('you must specify the locale') + if self.no_wrap and self.width: + raise DistutilsOptionError("'--no-wrap' and '--width' are mutually " + "exclusive") + if not self.no_wrap and not self.width: + self.width = 76 + elif self.width is not None: + self.width = int(self.width) + if self.no_fuzzy_matching and self.previous: + self.previous = False + + def run(self): + po_files = [] + if not self.output_file: + if self.locale: + po_files.append((self.locale, + os.path.join(self.output_dir, self.locale, + 'LC_MESSAGES', + self.domain + '.po'))) + else: + for locale in os.listdir(self.output_dir): + po_file = os.path.join(self.output_dir, locale, + 'LC_MESSAGES', + self.domain + '.po') + if os.path.exists(po_file): + po_files.append((locale, po_file)) + else: + po_files.append((self.locale, self.output_file)) + + if not po_files: + raise DistutilsOptionError('no message catalogs found') + + domain = self.domain + if not domain: + domain = os.path.splitext(os.path.basename(self.input_file))[0] + + with open(self.input_file, 'rb') as infile: + template = read_po(infile) + + for locale, filename in po_files: + self.log.info('updating catalog %s based on %s', filename, self.input_file) + with open(filename, 'rb') as infile: + catalog = read_po(infile, locale=locale, domain=domain) + + catalog.update( + template, self.no_fuzzy_matching, + update_header_comment=self.update_header_comment + ) + + tmpname = os.path.join(os.path.dirname(filename), + tempfile.gettempprefix() + + os.path.basename(filename)) + try: + with open(tmpname, 'wb') as tmpfile: + write_po(tmpfile, catalog, + ignore_obsolete=self.ignore_obsolete, + include_previous=self.previous, width=self.width) + except: + os.remove(tmpname) + raise + + try: + os.rename(tmpname, filename) + except OSError: + # We're probably on Windows, which doesn't support atomic + # renames, at least not through Python + # If the error is in fact due to a permissions problem, that + # same error is going to be raised from one of the following + # operations + os.remove(filename) + shutil.copy(tmpname, filename) + os.remove(tmpname) + + +class CommandLineInterface(object): + """Command-line interface. + + This class provides a simple command-line interface to the message + extraction and PO file generation functionality. + """ + + usage = '%%prog %s [options] %s' + version = '%%prog %s' % VERSION + commands = { + 'compile': 'compile message catalogs to MO files', + 'extract': 'extract messages from source files and generate a POT file', + 'init': 'create new message catalogs from a POT file', + 'update': 'update existing message catalogs from a POT file' + } + + command_classes = { + 'compile': compile_catalog, + 'extract': extract_messages, + 'init': init_catalog, + 'update': update_catalog, + } + + log = None # Replaced on instance level + + def run(self, argv=None): + """Main entry point of the command-line interface. + + :param argv: list of arguments passed on the command-line + """ + + if argv is None: + argv = sys.argv + + self.parser = optparse.OptionParser(usage=self.usage % ('command', '[args]'), + version=self.version) + self.parser.disable_interspersed_args() + self.parser.print_help = self._help + self.parser.add_option('--list-locales', dest='list_locales', + action='store_true', + help="print all known locales and exit") + self.parser.add_option('-v', '--verbose', action='store_const', + dest='loglevel', const=logging.DEBUG, + help='print as much as possible') + self.parser.add_option('-q', '--quiet', action='store_const', + dest='loglevel', const=logging.ERROR, + help='print as little as possible') + self.parser.set_defaults(list_locales=False, loglevel=logging.INFO) + + options, args = self.parser.parse_args(argv[1:]) + + self._configure_logging(options.loglevel) + if options.list_locales: + identifiers = localedata.locale_identifiers() + longest = max([len(identifier) for identifier in identifiers]) + identifiers.sort() + format = u'%%-%ds %%s' % (longest + 1) + for identifier in identifiers: + locale = Locale.parse(identifier) + output = format % (identifier, locale.english_name) + print(output.encode(sys.stdout.encoding or + getpreferredencoding() or + 'ascii', 'replace')) + return 0 + + if not args: + self.parser.error('no valid command or option passed. ' + 'Try the -h/--help option for more information.') + + cmdname = args[0] + if cmdname not in self.commands: + self.parser.error('unknown command "%s"' % cmdname) + + cmdinst = self._configure_command(cmdname, args[1:]) + return cmdinst.run() + + def _configure_logging(self, loglevel): + self.log = logging.getLogger('babel') + self.log.setLevel(loglevel) + # Don't add a new handler for every instance initialization (#227), this + # would cause duplicated output when the CommandLineInterface as an + # normal Python class. + if self.log.handlers: + handler = self.log.handlers[0] + else: + handler = logging.StreamHandler() + self.log.addHandler(handler) + handler.setLevel(loglevel) + formatter = logging.Formatter('%(message)s') + handler.setFormatter(formatter) + + def _help(self): + print(self.parser.format_help()) + print("commands:") + longest = max([len(command) for command in self.commands]) + format = " %%-%ds %%s" % max(8, longest + 1) + commands = sorted(self.commands.items()) + for name, description in commands: + print(format % (name, description)) + + def _configure_command(self, cmdname, argv): + """ + :type cmdname: str + :type argv: list[str] + """ + cmdclass = self.command_classes[cmdname] + cmdinst = cmdclass() + if self.log: + cmdinst.log = self.log # Use our logger, not distutils'. + assert isinstance(cmdinst, Command) + cmdinst.initialize_options() + + parser = optparse.OptionParser( + usage=self.usage % (cmdname, ''), + description=self.commands[cmdname] + ) + as_args = getattr(cmdclass, "as_args", ()) + for long, short, help in cmdclass.user_options: + name = long.strip("=") + default = getattr(cmdinst, name.replace('-', '_')) + strs = ["--%s" % name] + if short: + strs.append("-%s" % short) + strs.extend(cmdclass.option_aliases.get(name, ())) + choices = cmdclass.option_choices.get(name, None) + if name == as_args: + parser.usage += "<%s>" % name + elif name in cmdclass.boolean_options: + parser.add_option(*strs, action="store_true", help=help) + elif name in cmdclass.multiple_value_options: + parser.add_option(*strs, action="append", help=help, choices=choices) + else: + parser.add_option(*strs, help=help, default=default, choices=choices) + options, args = parser.parse_args(argv) + + if as_args: + setattr(options, as_args.replace('-', '_'), args) + + for key, value in vars(options).items(): + setattr(cmdinst, key, value) + + try: + cmdinst.ensure_finalized() + except DistutilsOptionError as err: + parser.error(str(err)) + + return cmdinst + + +def main(): + return CommandLineInterface().run(sys.argv) + + +def parse_mapping(fileobj, filename=None): + """Parse an extraction method mapping from a file-like object. + + >>> buf = StringIO(''' + ... [extractors] + ... custom = mypackage.module:myfunc + ... + ... # Python source files + ... [python: **.py] + ... + ... # Genshi templates + ... [genshi: **/templates/**.html] + ... include_attrs = + ... [genshi: **/templates/**.txt] + ... template_class = genshi.template:TextTemplate + ... encoding = latin-1 + ... + ... # Some custom extractor + ... [custom: **/custom/*.*] + ... ''') + + >>> method_map, options_map = parse_mapping(buf) + >>> len(method_map) + 4 + + >>> method_map[0] + ('**.py', 'python') + >>> options_map['**.py'] + {} + >>> method_map[1] + ('**/templates/**.html', 'genshi') + >>> options_map['**/templates/**.html']['include_attrs'] + '' + >>> method_map[2] + ('**/templates/**.txt', 'genshi') + >>> options_map['**/templates/**.txt']['template_class'] + 'genshi.template:TextTemplate' + >>> options_map['**/templates/**.txt']['encoding'] + 'latin-1' + + >>> method_map[3] + ('**/custom/*.*', 'mypackage.module:myfunc') + >>> options_map['**/custom/*.*'] + {} + + :param fileobj: a readable file-like object containing the configuration + text to parse + :see: `extract_from_directory` + """ + extractors = {} + method_map = [] + options_map = {} + + parser = RawConfigParser() + parser._sections = odict(parser._sections) # We need ordered sections + + if PY2: + parser.readfp(fileobj, filename) + else: + parser.read_file(fileobj, filename) + + for section in parser.sections(): + if section == 'extractors': + extractors = dict(parser.items(section)) + else: + method, pattern = [part.strip() for part in section.split(':', 1)] + method_map.append((pattern, method)) + options_map[pattern] = dict(parser.items(section)) + + if extractors: + for idx, (pattern, method) in enumerate(method_map): + if method in extractors: + method = extractors[method] + method_map[idx] = (pattern, method) + + return method_map, options_map + + +def parse_keywords(strings=[]): + """Parse keywords specifications from the given list of strings. + + >>> kw = sorted(parse_keywords(['_', 'dgettext:2', 'dngettext:2,3', 'pgettext:1c,2']).items()) + >>> for keyword, indices in kw: + ... print((keyword, indices)) + ('_', None) + ('dgettext', (2,)) + ('dngettext', (2, 3)) + ('pgettext', ((1, 'c'), 2)) + """ + keywords = {} + for string in strings: + if ':' in string: + funcname, indices = string.split(':') + else: + funcname, indices = string, None + if funcname not in keywords: + if indices: + inds = [] + for x in indices.split(','): + if x[-1] == 'c': + inds.append((int(x[:-1]), 'c')) + else: + inds.append(int(x)) + indices = tuple(inds) + keywords[funcname] = indices + return keywords + + +if __name__ == '__main__': + main() diff --git a/venv/lib/python2.7/site-packages/babel/messages/jslexer.py b/venv/lib/python2.7/site-packages/babel/messages/jslexer.py new file mode 100644 index 0000000..04d0276 --- /dev/null +++ b/venv/lib/python2.7/site-packages/babel/messages/jslexer.py @@ -0,0 +1,185 @@ +# -*- coding: utf-8 -*- +""" + babel.messages.jslexer + ~~~~~~~~~~~~~~~~~~~~~~ + + A simple JavaScript 1.5 lexer which is used for the JavaScript + extractor. + + :copyright: (c) 2013-2018 by the Babel Team. + :license: BSD, see LICENSE for more details. +""" +from collections import namedtuple +import re +from babel._compat import unichr + +operators = sorted([ + '+', '-', '*', '%', '!=', '==', '<', '>', '<=', '>=', '=', + '+=', '-=', '*=', '%=', '<<', '>>', '>>>', '<<=', '>>=', + '>>>=', '&', '&=', '|', '|=', '&&', '||', '^', '^=', '(', ')', + '[', ']', '{', '}', '!', '--', '++', '~', ',', ';', '.', ':' +], key=len, reverse=True) + +escapes = {'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r', 't': '\t'} + +name_re = re.compile(r'[\w$_][\w\d$_]*', re.UNICODE) +dotted_name_re = re.compile(r'[\w$_][\w\d$_.]*[\w\d$_.]', re.UNICODE) +division_re = re.compile(r'/=?') +regex_re = re.compile(r'/(?:[^/\\]*(?:\\.[^/\\]*)*)/[a-zA-Z]*', re.DOTALL) +line_re = re.compile(r'(\r\n|\n|\r)') +line_join_re = re.compile(r'\\' + line_re.pattern) +uni_escape_re = re.compile(r'[a-fA-F0-9]{1,4}') + +Token = namedtuple('Token', 'type value lineno') + +_rules = [ + (None, re.compile(r'\s+', re.UNICODE)), + (None, re.compile(r' 0.42261 +# 256 --> 0.57851 +# 512 --> 0.74851 +# 1024 --> 0.89384 +# 2048 --> 0.97583 +# +# Ideal Distribution Ratio = 0.74851/(1-0.74851) =2.98 +# Random Distribution Ration = 512/(5401-512)=0.105 +# +# Typical Distribution Ratio about 25% of Ideal one, still much higher than RDR + +BIG5_TYPICAL_DISTRIBUTION_RATIO = 0.75 + +#Char to FreqOrder table +BIG5_TABLE_SIZE = 5376 + +BIG5_CHAR_TO_FREQ_ORDER = ( + 1,1801,1506, 255,1431, 198, 9, 82, 6,5008, 177, 202,3681,1256,2821, 110, # 16 +3814, 33,3274, 261, 76, 44,2114, 16,2946,2187,1176, 659,3971, 26,3451,2653, # 32 +1198,3972,3350,4202, 410,2215, 302, 590, 361,1964, 8, 204, 58,4510,5009,1932, # 48 + 63,5010,5011, 317,1614, 75, 222, 159,4203,2417,1480,5012,3555,3091, 224,2822, # 64 +3682, 3, 10,3973,1471, 29,2787,1135,2866,1940, 873, 130,3275,1123, 312,5013, # 80 +4511,2052, 507, 252, 682,5014, 142,1915, 124, 206,2947, 34,3556,3204, 64, 604, # 96 +5015,2501,1977,1978, 155,1991, 645, 641,1606,5016,3452, 337, 72, 406,5017, 80, # 112 + 630, 238,3205,1509, 263, 939,1092,2654, 756,1440,1094,3453, 449, 69,2987, 591, # 128 + 179,2096, 471, 115,2035,1844, 60, 50,2988, 134, 806,1869, 734,2036,3454, 180, # 144 + 995,1607, 156, 537,2907, 688,5018, 319,1305, 779,2145, 514,2379, 298,4512, 359, # 160 +2502, 90,2716,1338, 663, 11, 906,1099,2553, 20,2441, 182, 532,1716,5019, 732, # 176 +1376,4204,1311,1420,3206, 25,2317,1056, 113, 399, 382,1950, 242,3455,2474, 529, # 192 +3276, 475,1447,3683,5020, 117, 21, 656, 810,1297,2300,2334,3557,5021, 126,4205, # 208 + 706, 456, 150, 613,4513, 71,1118,2037,4206, 145,3092, 85, 835, 486,2115,1246, # 224 +1426, 428, 727,1285,1015, 800, 106, 623, 303,1281,5022,2128,2359, 347,3815, 221, # 240 +3558,3135,5023,1956,1153,4207, 83, 296,1199,3093, 192, 624, 93,5024, 822,1898, # 256 +2823,3136, 795,2065, 991,1554,1542,1592, 27, 43,2867, 859, 139,1456, 860,4514, # 272 + 437, 712,3974, 164,2397,3137, 695, 211,3037,2097, 195,3975,1608,3559,3560,3684, # 288 +3976, 234, 811,2989,2098,3977,2233,1441,3561,1615,2380, 668,2077,1638, 305, 228, # 304 +1664,4515, 467, 415,5025, 262,2099,1593, 239, 108, 300, 200,1033, 512,1247,2078, # 320 +5026,5027,2176,3207,3685,2682, 593, 845,1062,3277, 88,1723,2038,3978,1951, 212, # 336 + 266, 152, 149, 468,1899,4208,4516, 77, 187,5028,3038, 37, 5,2990,5029,3979, # 352 +5030,5031, 39,2524,4517,2908,3208,2079, 55, 148, 74,4518, 545, 483,1474,1029, # 368 +1665, 217,1870,1531,3138,1104,2655,4209, 24, 172,3562, 900,3980,3563,3564,4519, # 384 + 32,1408,2824,1312, 329, 487,2360,2251,2717, 784,2683, 4,3039,3351,1427,1789, # 400 + 188, 109, 499,5032,3686,1717,1790, 888,1217,3040,4520,5033,3565,5034,3352,1520, # 416 +3687,3981, 196,1034, 775,5035,5036, 929,1816, 249, 439, 38,5037,1063,5038, 794, # 432 +3982,1435,2301, 46, 178,3278,2066,5039,2381,5040, 214,1709,4521, 804, 35, 707, # 448 + 324,3688,1601,2554, 140, 459,4210,5041,5042,1365, 839, 272, 978,2262,2580,3456, # 464 +2129,1363,3689,1423, 697, 100,3094, 48, 70,1231, 495,3139,2196,5043,1294,5044, # 480 +2080, 462, 586,1042,3279, 853, 256, 988, 185,2382,3457,1698, 434,1084,5045,3458, # 496 + 314,2625,2788,4522,2335,2336, 569,2285, 637,1817,2525, 757,1162,1879,1616,3459, # 512 + 287,1577,2116, 768,4523,1671,2868,3566,2526,1321,3816, 909,2418,5046,4211, 933, # 528 +3817,4212,2053,2361,1222,4524, 765,2419,1322, 786,4525,5047,1920,1462,1677,2909, # 544 +1699,5048,4526,1424,2442,3140,3690,2600,3353,1775,1941,3460,3983,4213, 309,1369, # 560 +1130,2825, 364,2234,1653,1299,3984,3567,3985,3986,2656, 525,1085,3041, 902,2001, # 576 +1475, 964,4527, 421,1845,1415,1057,2286, 940,1364,3141, 376,4528,4529,1381, 7, # 592 +2527, 983,2383, 336,1710,2684,1846, 321,3461, 559,1131,3042,2752,1809,1132,1313, # 608 + 265,1481,1858,5049, 352,1203,2826,3280, 167,1089, 420,2827, 776, 792,1724,3568, # 624 +4214,2443,3281,5050,4215,5051, 446, 229, 333,2753, 901,3818,1200,1557,4530,2657, # 640 +1921, 395,2754,2685,3819,4216,1836, 125, 916,3209,2626,4531,5052,5053,3820,5054, # 656 +5055,5056,4532,3142,3691,1133,2555,1757,3462,1510,2318,1409,3569,5057,2146, 438, # 672 +2601,2910,2384,3354,1068, 958,3043, 461, 311,2869,2686,4217,1916,3210,4218,1979, # 688 + 383, 750,2755,2627,4219, 274, 539, 385,1278,1442,5058,1154,1965, 384, 561, 210, # 704 + 98,1295,2556,3570,5059,1711,2420,1482,3463,3987,2911,1257, 129,5060,3821, 642, # 720 + 523,2789,2790,2658,5061, 141,2235,1333, 68, 176, 441, 876, 907,4220, 603,2602, # 736 + 710, 171,3464, 404, 549, 18,3143,2398,1410,3692,1666,5062,3571,4533,2912,4534, # 752 +5063,2991, 368,5064, 146, 366, 99, 871,3693,1543, 748, 807,1586,1185, 22,2263, # 768 + 379,3822,3211,5065,3212, 505,1942,2628,1992,1382,2319,5066, 380,2362, 218, 702, # 784 +1818,1248,3465,3044,3572,3355,3282,5067,2992,3694, 930,3283,3823,5068, 59,5069, # 800 + 585, 601,4221, 497,3466,1112,1314,4535,1802,5070,1223,1472,2177,5071, 749,1837, # 816 + 690,1900,3824,1773,3988,1476, 429,1043,1791,2236,2117, 917,4222, 447,1086,1629, # 832 +5072, 556,5073,5074,2021,1654, 844,1090, 105, 550, 966,1758,2828,1008,1783, 686, # 848 +1095,5075,2287, 793,1602,5076,3573,2603,4536,4223,2948,2302,4537,3825, 980,2503, # 864 + 544, 353, 527,4538, 908,2687,2913,5077, 381,2629,1943,1348,5078,1341,1252, 560, # 880 +3095,5079,3467,2870,5080,2054, 973, 886,2081, 143,4539,5081,5082, 157,3989, 496, # 896 +4224, 57, 840, 540,2039,4540,4541,3468,2118,1445, 970,2264,1748,1966,2082,4225, # 912 +3144,1234,1776,3284,2829,3695, 773,1206,2130,1066,2040,1326,3990,1738,1725,4226, # 928 + 279,3145, 51,1544,2604, 423,1578,2131,2067, 173,4542,1880,5083,5084,1583, 264, # 944 + 610,3696,4543,2444, 280, 154,5085,5086,5087,1739, 338,1282,3096, 693,2871,1411, # 960 +1074,3826,2445,5088,4544,5089,5090,1240, 952,2399,5091,2914,1538,2688, 685,1483, # 976 +4227,2475,1436, 953,4228,2055,4545, 671,2400, 79,4229,2446,3285, 608, 567,2689, # 992 +3469,4230,4231,1691, 393,1261,1792,2401,5092,4546,5093,5094,5095,5096,1383,1672, # 1008 +3827,3213,1464, 522,1119, 661,1150, 216, 675,4547,3991,1432,3574, 609,4548,2690, # 1024 +2402,5097,5098,5099,4232,3045, 0,5100,2476, 315, 231,2447, 301,3356,4549,2385, # 1040 +5101, 233,4233,3697,1819,4550,4551,5102, 96,1777,1315,2083,5103, 257,5104,1810, # 1056 +3698,2718,1139,1820,4234,2022,1124,2164,2791,1778,2659,5105,3097, 363,1655,3214, # 1072 +5106,2993,5107,5108,5109,3992,1567,3993, 718, 103,3215, 849,1443, 341,3357,2949, # 1088 +1484,5110,1712, 127, 67, 339,4235,2403, 679,1412, 821,5111,5112, 834, 738, 351, # 1104 +2994,2147, 846, 235,1497,1881, 418,1993,3828,2719, 186,1100,2148,2756,3575,1545, # 1120 +1355,2950,2872,1377, 583,3994,4236,2581,2995,5113,1298,3699,1078,2557,3700,2363, # 1136 + 78,3829,3830, 267,1289,2100,2002,1594,4237, 348, 369,1274,2197,2178,1838,4552, # 1152 +1821,2830,3701,2757,2288,2003,4553,2951,2758, 144,3358, 882,4554,3995,2759,3470, # 1168 +4555,2915,5114,4238,1726, 320,5115,3996,3046, 788,2996,5116,2831,1774,1327,2873, # 1184 +3997,2832,5117,1306,4556,2004,1700,3831,3576,2364,2660, 787,2023, 506, 824,3702, # 1200 + 534, 323,4557,1044,3359,2024,1901, 946,3471,5118,1779,1500,1678,5119,1882,4558, # 1216 + 165, 243,4559,3703,2528, 123, 683,4239, 764,4560, 36,3998,1793, 589,2916, 816, # 1232 + 626,1667,3047,2237,1639,1555,1622,3832,3999,5120,4000,2874,1370,1228,1933, 891, # 1248 +2084,2917, 304,4240,5121, 292,2997,2720,3577, 691,2101,4241,1115,4561, 118, 662, # 1264 +5122, 611,1156, 854,2386,1316,2875, 2, 386, 515,2918,5123,5124,3286, 868,2238, # 1280 +1486, 855,2661, 785,2216,3048,5125,1040,3216,3578,5126,3146, 448,5127,1525,5128, # 1296 +2165,4562,5129,3833,5130,4242,2833,3579,3147, 503, 818,4001,3148,1568, 814, 676, # 1312 +1444, 306,1749,5131,3834,1416,1030, 197,1428, 805,2834,1501,4563,5132,5133,5134, # 1328 +1994,5135,4564,5136,5137,2198, 13,2792,3704,2998,3149,1229,1917,5138,3835,2132, # 1344 +5139,4243,4565,2404,3580,5140,2217,1511,1727,1120,5141,5142, 646,3836,2448, 307, # 1360 +5143,5144,1595,3217,5145,5146,5147,3705,1113,1356,4002,1465,2529,2530,5148, 519, # 1376 +5149, 128,2133, 92,2289,1980,5150,4003,1512, 342,3150,2199,5151,2793,2218,1981, # 1392 +3360,4244, 290,1656,1317, 789, 827,2365,5152,3837,4566, 562, 581,4004,5153, 401, # 1408 +4567,2252, 94,4568,5154,1399,2794,5155,1463,2025,4569,3218,1944,5156, 828,1105, # 1424 +4245,1262,1394,5157,4246, 605,4570,5158,1784,2876,5159,2835, 819,2102, 578,2200, # 1440 +2952,5160,1502, 436,3287,4247,3288,2836,4005,2919,3472,3473,5161,2721,2320,5162, # 1456 +5163,2337,2068, 23,4571, 193, 826,3838,2103, 699,1630,4248,3098, 390,1794,1064, # 1472 +3581,5164,1579,3099,3100,1400,5165,4249,1839,1640,2877,5166,4572,4573, 137,4250, # 1488 + 598,3101,1967, 780, 104, 974,2953,5167, 278, 899, 253, 402, 572, 504, 493,1339, # 1504 +5168,4006,1275,4574,2582,2558,5169,3706,3049,3102,2253, 565,1334,2722, 863, 41, # 1520 +5170,5171,4575,5172,1657,2338, 19, 463,2760,4251, 606,5173,2999,3289,1087,2085, # 1536 +1323,2662,3000,5174,1631,1623,1750,4252,2691,5175,2878, 791,2723,2663,2339, 232, # 1552 +2421,5176,3001,1498,5177,2664,2630, 755,1366,3707,3290,3151,2026,1609, 119,1918, # 1568 +3474, 862,1026,4253,5178,4007,3839,4576,4008,4577,2265,1952,2477,5179,1125, 817, # 1584 +4254,4255,4009,1513,1766,2041,1487,4256,3050,3291,2837,3840,3152,5180,5181,1507, # 1600 +5182,2692, 733, 40,1632,1106,2879, 345,4257, 841,2531, 230,4578,3002,1847,3292, # 1616 +3475,5183,1263, 986,3476,5184, 735, 879, 254,1137, 857, 622,1300,1180,1388,1562, # 1632 +4010,4011,2954, 967,2761,2665,1349, 592,2134,1692,3361,3003,1995,4258,1679,4012, # 1648 +1902,2188,5185, 739,3708,2724,1296,1290,5186,4259,2201,2202,1922,1563,2605,2559, # 1664 +1871,2762,3004,5187, 435,5188, 343,1108, 596, 17,1751,4579,2239,3477,3709,5189, # 1680 +4580, 294,3582,2955,1693, 477, 979, 281,2042,3583, 643,2043,3710,2631,2795,2266, # 1696 +1031,2340,2135,2303,3584,4581, 367,1249,2560,5190,3585,5191,4582,1283,3362,2005, # 1712 + 240,1762,3363,4583,4584, 836,1069,3153, 474,5192,2149,2532, 268,3586,5193,3219, # 1728 +1521,1284,5194,1658,1546,4260,5195,3587,3588,5196,4261,3364,2693,1685,4262, 961, # 1744 +1673,2632, 190,2006,2203,3841,4585,4586,5197, 570,2504,3711,1490,5198,4587,2633, # 1760 +3293,1957,4588, 584,1514, 396,1045,1945,5199,4589,1968,2449,5200,5201,4590,4013, # 1776 + 619,5202,3154,3294, 215,2007,2796,2561,3220,4591,3221,4592, 763,4263,3842,4593, # 1792 +5203,5204,1958,1767,2956,3365,3712,1174, 452,1477,4594,3366,3155,5205,2838,1253, # 1808 +2387,2189,1091,2290,4264, 492,5206, 638,1169,1825,2136,1752,4014, 648, 926,1021, # 1824 +1324,4595, 520,4596, 997, 847,1007, 892,4597,3843,2267,1872,3713,2405,1785,4598, # 1840 +1953,2957,3103,3222,1728,4265,2044,3714,4599,2008,1701,3156,1551, 30,2268,4266, # 1856 +5207,2027,4600,3589,5208, 501,5209,4267, 594,3478,2166,1822,3590,3479,3591,3223, # 1872 + 829,2839,4268,5210,1680,3157,1225,4269,5211,3295,4601,4270,3158,2341,5212,4602, # 1888 +4271,5213,4015,4016,5214,1848,2388,2606,3367,5215,4603, 374,4017, 652,4272,4273, # 1904 + 375,1140, 798,5216,5217,5218,2366,4604,2269, 546,1659, 138,3051,2450,4605,5219, # 1920 +2254, 612,1849, 910, 796,3844,1740,1371, 825,3845,3846,5220,2920,2562,5221, 692, # 1936 + 444,3052,2634, 801,4606,4274,5222,1491, 244,1053,3053,4275,4276, 340,5223,4018, # 1952 +1041,3005, 293,1168, 87,1357,5224,1539, 959,5225,2240, 721, 694,4277,3847, 219, # 1968 +1478, 644,1417,3368,2666,1413,1401,1335,1389,4019,5226,5227,3006,2367,3159,1826, # 1984 + 730,1515, 184,2840, 66,4607,5228,1660,2958, 246,3369, 378,1457, 226,3480, 975, # 2000 +4020,2959,1264,3592, 674, 696,5229, 163,5230,1141,2422,2167, 713,3593,3370,4608, # 2016 +4021,5231,5232,1186, 15,5233,1079,1070,5234,1522,3224,3594, 276,1050,2725, 758, # 2032 +1126, 653,2960,3296,5235,2342, 889,3595,4022,3104,3007, 903,1250,4609,4023,3481, # 2048 +3596,1342,1681,1718, 766,3297, 286, 89,2961,3715,5236,1713,5237,2607,3371,3008, # 2064 +5238,2962,2219,3225,2880,5239,4610,2505,2533, 181, 387,1075,4024, 731,2190,3372, # 2080 +5240,3298, 310, 313,3482,2304, 770,4278, 54,3054, 189,4611,3105,3848,4025,5241, # 2096 +1230,1617,1850, 355,3597,4279,4612,3373, 111,4280,3716,1350,3160,3483,3055,4281, # 2112 +2150,3299,3598,5242,2797,4026,4027,3009, 722,2009,5243,1071, 247,1207,2343,2478, # 2128 +1378,4613,2010, 864,1437,1214,4614, 373,3849,1142,2220, 667,4615, 442,2763,2563, # 2144 +3850,4028,1969,4282,3300,1840, 837, 170,1107, 934,1336,1883,5244,5245,2119,4283, # 2160 +2841, 743,1569,5246,4616,4284, 582,2389,1418,3484,5247,1803,5248, 357,1395,1729, # 2176 +3717,3301,2423,1564,2241,5249,3106,3851,1633,4617,1114,2086,4285,1532,5250, 482, # 2192 +2451,4618,5251,5252,1492, 833,1466,5253,2726,3599,1641,2842,5254,1526,1272,3718, # 2208 +4286,1686,1795, 416,2564,1903,1954,1804,5255,3852,2798,3853,1159,2321,5256,2881, # 2224 +4619,1610,1584,3056,2424,2764, 443,3302,1163,3161,5257,5258,4029,5259,4287,2506, # 2240 +3057,4620,4030,3162,2104,1647,3600,2011,1873,4288,5260,4289, 431,3485,5261, 250, # 2256 + 97, 81,4290,5262,1648,1851,1558, 160, 848,5263, 866, 740,1694,5264,2204,2843, # 2272 +3226,4291,4621,3719,1687, 950,2479, 426, 469,3227,3720,3721,4031,5265,5266,1188, # 2288 + 424,1996, 861,3601,4292,3854,2205,2694, 168,1235,3602,4293,5267,2087,1674,4622, # 2304 +3374,3303, 220,2565,1009,5268,3855, 670,3010, 332,1208, 717,5269,5270,3603,2452, # 2320 +4032,3375,5271, 513,5272,1209,2882,3376,3163,4623,1080,5273,5274,5275,5276,2534, # 2336 +3722,3604, 815,1587,4033,4034,5277,3605,3486,3856,1254,4624,1328,3058,1390,4035, # 2352 +1741,4036,3857,4037,5278, 236,3858,2453,3304,5279,5280,3723,3859,1273,3860,4625, # 2368 +5281, 308,5282,4626, 245,4627,1852,2480,1307,2583, 430, 715,2137,2454,5283, 270, # 2384 + 199,2883,4038,5284,3606,2727,1753, 761,1754, 725,1661,1841,4628,3487,3724,5285, # 2400 +5286, 587, 14,3305, 227,2608, 326, 480,2270, 943,2765,3607, 291, 650,1884,5287, # 2416 +1702,1226, 102,1547, 62,3488, 904,4629,3489,1164,4294,5288,5289,1224,1548,2766, # 2432 + 391, 498,1493,5290,1386,1419,5291,2056,1177,4630, 813, 880,1081,2368, 566,1145, # 2448 +4631,2291,1001,1035,2566,2609,2242, 394,1286,5292,5293,2069,5294, 86,1494,1730, # 2464 +4039, 491,1588, 745, 897,2963, 843,3377,4040,2767,2884,3306,1768, 998,2221,2070, # 2480 + 397,1827,1195,1970,3725,3011,3378, 284,5295,3861,2507,2138,2120,1904,5296,4041, # 2496 +2151,4042,4295,1036,3490,1905, 114,2567,4296, 209,1527,5297,5298,2964,2844,2635, # 2512 +2390,2728,3164, 812,2568,5299,3307,5300,1559, 737,1885,3726,1210, 885, 28,2695, # 2528 +3608,3862,5301,4297,1004,1780,4632,5302, 346,1982,2222,2696,4633,3863,1742, 797, # 2544 +1642,4043,1934,1072,1384,2152, 896,4044,3308,3727,3228,2885,3609,5303,2569,1959, # 2560 +4634,2455,1786,5304,5305,5306,4045,4298,1005,1308,3728,4299,2729,4635,4636,1528, # 2576 +2610, 161,1178,4300,1983, 987,4637,1101,4301, 631,4046,1157,3229,2425,1343,1241, # 2592 +1016,2243,2570, 372, 877,2344,2508,1160, 555,1935, 911,4047,5307, 466,1170, 169, # 2608 +1051,2921,2697,3729,2481,3012,1182,2012,2571,1251,2636,5308, 992,2345,3491,1540, # 2624 +2730,1201,2071,2406,1997,2482,5309,4638, 528,1923,2191,1503,1874,1570,2369,3379, # 2640 +3309,5310, 557,1073,5311,1828,3492,2088,2271,3165,3059,3107, 767,3108,2799,4639, # 2656 +1006,4302,4640,2346,1267,2179,3730,3230, 778,4048,3231,2731,1597,2667,5312,4641, # 2672 +5313,3493,5314,5315,5316,3310,2698,1433,3311, 131, 95,1504,4049, 723,4303,3166, # 2688 +1842,3610,2768,2192,4050,2028,2105,3731,5317,3013,4051,1218,5318,3380,3232,4052, # 2704 +4304,2584, 248,1634,3864, 912,5319,2845,3732,3060,3865, 654, 53,5320,3014,5321, # 2720 +1688,4642, 777,3494,1032,4053,1425,5322, 191, 820,2121,2846, 971,4643, 931,3233, # 2736 + 135, 664, 783,3866,1998, 772,2922,1936,4054,3867,4644,2923,3234, 282,2732, 640, # 2752 +1372,3495,1127, 922, 325,3381,5323,5324, 711,2045,5325,5326,4055,2223,2800,1937, # 2768 +4056,3382,2224,2255,3868,2305,5327,4645,3869,1258,3312,4057,3235,2139,2965,4058, # 2784 +4059,5328,2225, 258,3236,4646, 101,1227,5329,3313,1755,5330,1391,3314,5331,2924, # 2800 +2057, 893,5332,5333,5334,1402,4305,2347,5335,5336,3237,3611,5337,5338, 878,1325, # 2816 +1781,2801,4647, 259,1385,2585, 744,1183,2272,4648,5339,4060,2509,5340, 684,1024, # 2832 +4306,5341, 472,3612,3496,1165,3315,4061,4062, 322,2153, 881, 455,1695,1152,1340, # 2848 + 660, 554,2154,4649,1058,4650,4307, 830,1065,3383,4063,4651,1924,5342,1703,1919, # 2864 +5343, 932,2273, 122,5344,4652, 947, 677,5345,3870,2637, 297,1906,1925,2274,4653, # 2880 +2322,3316,5346,5347,4308,5348,4309, 84,4310, 112, 989,5349, 547,1059,4064, 701, # 2896 +3613,1019,5350,4311,5351,3497, 942, 639, 457,2306,2456, 993,2966, 407, 851, 494, # 2912 +4654,3384, 927,5352,1237,5353,2426,3385, 573,4312, 680, 921,2925,1279,1875, 285, # 2928 + 790,1448,1984, 719,2168,5354,5355,4655,4065,4066,1649,5356,1541, 563,5357,1077, # 2944 +5358,3386,3061,3498, 511,3015,4067,4068,3733,4069,1268,2572,3387,3238,4656,4657, # 2960 +5359, 535,1048,1276,1189,2926,2029,3167,1438,1373,2847,2967,1134,2013,5360,4313, # 2976 +1238,2586,3109,1259,5361, 700,5362,2968,3168,3734,4314,5363,4315,1146,1876,1907, # 2992 +4658,2611,4070, 781,2427, 132,1589, 203, 147, 273,2802,2407, 898,1787,2155,4071, # 3008 +4072,5364,3871,2803,5365,5366,4659,4660,5367,3239,5368,1635,3872, 965,5369,1805, # 3024 +2699,1516,3614,1121,1082,1329,3317,4073,1449,3873, 65,1128,2848,2927,2769,1590, # 3040 +3874,5370,5371, 12,2668, 45, 976,2587,3169,4661, 517,2535,1013,1037,3240,5372, # 3056 +3875,2849,5373,3876,5374,3499,5375,2612, 614,1999,2323,3877,3110,2733,2638,5376, # 3072 +2588,4316, 599,1269,5377,1811,3735,5378,2700,3111, 759,1060, 489,1806,3388,3318, # 3088 +1358,5379,5380,2391,1387,1215,2639,2256, 490,5381,5382,4317,1759,2392,2348,5383, # 3104 +4662,3878,1908,4074,2640,1807,3241,4663,3500,3319,2770,2349, 874,5384,5385,3501, # 3120 +3736,1859, 91,2928,3737,3062,3879,4664,5386,3170,4075,2669,5387,3502,1202,1403, # 3136 +3880,2969,2536,1517,2510,4665,3503,2511,5388,4666,5389,2701,1886,1495,1731,4076, # 3152 +2370,4667,5390,2030,5391,5392,4077,2702,1216, 237,2589,4318,2324,4078,3881,4668, # 3168 +4669,2703,3615,3504, 445,4670,5393,5394,5395,5396,2771, 61,4079,3738,1823,4080, # 3184 +5397, 687,2046, 935, 925, 405,2670, 703,1096,1860,2734,4671,4081,1877,1367,2704, # 3200 +3389, 918,2106,1782,2483, 334,3320,1611,1093,4672, 564,3171,3505,3739,3390, 945, # 3216 +2641,2058,4673,5398,1926, 872,4319,5399,3506,2705,3112, 349,4320,3740,4082,4674, # 3232 +3882,4321,3741,2156,4083,4675,4676,4322,4677,2408,2047, 782,4084, 400, 251,4323, # 3248 +1624,5400,5401, 277,3742, 299,1265, 476,1191,3883,2122,4324,4325,1109, 205,5402, # 3264 +2590,1000,2157,3616,1861,5403,5404,5405,4678,5406,4679,2573, 107,2484,2158,4085, # 3280 +3507,3172,5407,1533, 541,1301, 158, 753,4326,2886,3617,5408,1696, 370,1088,4327, # 3296 +4680,3618, 579, 327, 440, 162,2244, 269,1938,1374,3508, 968,3063, 56,1396,3113, # 3312 +2107,3321,3391,5409,1927,2159,4681,3016,5410,3619,5411,5412,3743,4682,2485,5413, # 3328 +2804,5414,1650,4683,5415,2613,5416,5417,4086,2671,3392,1149,3393,4087,3884,4088, # 3344 +5418,1076, 49,5419, 951,3242,3322,3323, 450,2850, 920,5420,1812,2805,2371,4328, # 3360 +1909,1138,2372,3885,3509,5421,3243,4684,1910,1147,1518,2428,4685,3886,5422,4686, # 3376 +2393,2614, 260,1796,3244,5423,5424,3887,3324, 708,5425,3620,1704,5426,3621,1351, # 3392 +1618,3394,3017,1887, 944,4329,3395,4330,3064,3396,4331,5427,3744, 422, 413,1714, # 3408 +3325, 500,2059,2350,4332,2486,5428,1344,1911, 954,5429,1668,5430,5431,4089,2409, # 3424 +4333,3622,3888,4334,5432,2307,1318,2512,3114, 133,3115,2887,4687, 629, 31,2851, # 3440 +2706,3889,4688, 850, 949,4689,4090,2970,1732,2089,4335,1496,1853,5433,4091, 620, # 3456 +3245, 981,1242,3745,3397,1619,3746,1643,3326,2140,2457,1971,1719,3510,2169,5434, # 3472 +3246,5435,5436,3398,1829,5437,1277,4690,1565,2048,5438,1636,3623,3116,5439, 869, # 3488 +2852, 655,3890,3891,3117,4092,3018,3892,1310,3624,4691,5440,5441,5442,1733, 558, # 3504 +4692,3747, 335,1549,3065,1756,4336,3748,1946,3511,1830,1291,1192, 470,2735,2108, # 3520 +2806, 913,1054,4093,5443,1027,5444,3066,4094,4693, 982,2672,3399,3173,3512,3247, # 3536 +3248,1947,2807,5445, 571,4694,5446,1831,5447,3625,2591,1523,2429,5448,2090, 984, # 3552 +4695,3749,1960,5449,3750, 852, 923,2808,3513,3751, 969,1519, 999,2049,2325,1705, # 3568 +5450,3118, 615,1662, 151, 597,4095,2410,2326,1049, 275,4696,3752,4337, 568,3753, # 3584 +3626,2487,4338,3754,5451,2430,2275, 409,3249,5452,1566,2888,3514,1002, 769,2853, # 3600 + 194,2091,3174,3755,2226,3327,4339, 628,1505,5453,5454,1763,2180,3019,4096, 521, # 3616 +1161,2592,1788,2206,2411,4697,4097,1625,4340,4341, 412, 42,3119, 464,5455,2642, # 3632 +4698,3400,1760,1571,2889,3515,2537,1219,2207,3893,2643,2141,2373,4699,4700,3328, # 3648 +1651,3401,3627,5456,5457,3628,2488,3516,5458,3756,5459,5460,2276,2092, 460,5461, # 3664 +4701,5462,3020, 962, 588,3629, 289,3250,2644,1116, 52,5463,3067,1797,5464,5465, # 3680 +5466,1467,5467,1598,1143,3757,4342,1985,1734,1067,4702,1280,3402, 465,4703,1572, # 3696 + 510,5468,1928,2245,1813,1644,3630,5469,4704,3758,5470,5471,2673,1573,1534,5472, # 3712 +5473, 536,1808,1761,3517,3894,3175,2645,5474,5475,5476,4705,3518,2929,1912,2809, # 3728 +5477,3329,1122, 377,3251,5478, 360,5479,5480,4343,1529, 551,5481,2060,3759,1769, # 3744 +2431,5482,2930,4344,3330,3120,2327,2109,2031,4706,1404, 136,1468,1479, 672,1171, # 3760 +3252,2308, 271,3176,5483,2772,5484,2050, 678,2736, 865,1948,4707,5485,2014,4098, # 3776 +2971,5486,2737,2227,1397,3068,3760,4708,4709,1735,2931,3403,3631,5487,3895, 509, # 3792 +2854,2458,2890,3896,5488,5489,3177,3178,4710,4345,2538,4711,2309,1166,1010, 552, # 3808 + 681,1888,5490,5491,2972,2973,4099,1287,1596,1862,3179, 358, 453, 736, 175, 478, # 3824 +1117, 905,1167,1097,5492,1854,1530,5493,1706,5494,2181,3519,2292,3761,3520,3632, # 3840 +4346,2093,4347,5495,3404,1193,2489,4348,1458,2193,2208,1863,1889,1421,3331,2932, # 3856 +3069,2182,3521, 595,2123,5496,4100,5497,5498,4349,1707,2646, 223,3762,1359, 751, # 3872 +3121, 183,3522,5499,2810,3021, 419,2374, 633, 704,3897,2394, 241,5500,5501,5502, # 3888 + 838,3022,3763,2277,2773,2459,3898,1939,2051,4101,1309,3122,2246,1181,5503,1136, # 3904 +2209,3899,2375,1446,4350,2310,4712,5504,5505,4351,1055,2615, 484,3764,5506,4102, # 3920 + 625,4352,2278,3405,1499,4353,4103,5507,4104,4354,3253,2279,2280,3523,5508,5509, # 3936 +2774, 808,2616,3765,3406,4105,4355,3123,2539, 526,3407,3900,4356, 955,5510,1620, # 3952 +4357,2647,2432,5511,1429,3766,1669,1832, 994, 928,5512,3633,1260,5513,5514,5515, # 3968 +1949,2293, 741,2933,1626,4358,2738,2460, 867,1184, 362,3408,1392,5516,5517,4106, # 3984 +4359,1770,1736,3254,2934,4713,4714,1929,2707,1459,1158,5518,3070,3409,2891,1292, # 4000 +1930,2513,2855,3767,1986,1187,2072,2015,2617,4360,5519,2574,2514,2170,3768,2490, # 4016 +3332,5520,3769,4715,5521,5522, 666,1003,3023,1022,3634,4361,5523,4716,1814,2257, # 4032 + 574,3901,1603, 295,1535, 705,3902,4362, 283, 858, 417,5524,5525,3255,4717,4718, # 4048 +3071,1220,1890,1046,2281,2461,4107,1393,1599, 689,2575, 388,4363,5526,2491, 802, # 4064 +5527,2811,3903,2061,1405,2258,5528,4719,3904,2110,1052,1345,3256,1585,5529, 809, # 4080 +5530,5531,5532, 575,2739,3524, 956,1552,1469,1144,2328,5533,2329,1560,2462,3635, # 4096 +3257,4108, 616,2210,4364,3180,2183,2294,5534,1833,5535,3525,4720,5536,1319,3770, # 4112 +3771,1211,3636,1023,3258,1293,2812,5537,5538,5539,3905, 607,2311,3906, 762,2892, # 4128 +1439,4365,1360,4721,1485,3072,5540,4722,1038,4366,1450,2062,2648,4367,1379,4723, # 4144 +2593,5541,5542,4368,1352,1414,2330,2935,1172,5543,5544,3907,3908,4724,1798,1451, # 4160 +5545,5546,5547,5548,2936,4109,4110,2492,2351, 411,4111,4112,3637,3333,3124,4725, # 4176 +1561,2674,1452,4113,1375,5549,5550, 47,2974, 316,5551,1406,1591,2937,3181,5552, # 4192 +1025,2142,3125,3182, 354,2740, 884,2228,4369,2412, 508,3772, 726,3638, 996,2433, # 4208 +3639, 729,5553, 392,2194,1453,4114,4726,3773,5554,5555,2463,3640,2618,1675,2813, # 4224 + 919,2352,2975,2353,1270,4727,4115, 73,5556,5557, 647,5558,3259,2856,2259,1550, # 4240 +1346,3024,5559,1332, 883,3526,5560,5561,5562,5563,3334,2775,5564,1212, 831,1347, # 4256 +4370,4728,2331,3909,1864,3073, 720,3910,4729,4730,3911,5565,4371,5566,5567,4731, # 4272 +5568,5569,1799,4732,3774,2619,4733,3641,1645,2376,4734,5570,2938, 669,2211,2675, # 4288 +2434,5571,2893,5572,5573,1028,3260,5574,4372,2413,5575,2260,1353,5576,5577,4735, # 4304 +3183, 518,5578,4116,5579,4373,1961,5580,2143,4374,5581,5582,3025,2354,2355,3912, # 4320 + 516,1834,1454,4117,2708,4375,4736,2229,2620,1972,1129,3642,5583,2776,5584,2976, # 4336 +1422, 577,1470,3026,1524,3410,5585,5586, 432,4376,3074,3527,5587,2594,1455,2515, # 4352 +2230,1973,1175,5588,1020,2741,4118,3528,4737,5589,2742,5590,1743,1361,3075,3529, # 4368 +2649,4119,4377,4738,2295, 895, 924,4378,2171, 331,2247,3076, 166,1627,3077,1098, # 4384 +5591,1232,2894,2231,3411,4739, 657, 403,1196,2377, 542,3775,3412,1600,4379,3530, # 4400 +5592,4740,2777,3261, 576, 530,1362,4741,4742,2540,2676,3776,4120,5593, 842,3913, # 4416 +5594,2814,2032,1014,4121, 213,2709,3413, 665, 621,4380,5595,3777,2939,2435,5596, # 4432 +2436,3335,3643,3414,4743,4381,2541,4382,4744,3644,1682,4383,3531,1380,5597, 724, # 4448 +2282, 600,1670,5598,1337,1233,4745,3126,2248,5599,1621,4746,5600, 651,4384,5601, # 4464 +1612,4385,2621,5602,2857,5603,2743,2312,3078,5604, 716,2464,3079, 174,1255,2710, # 4480 +4122,3645, 548,1320,1398, 728,4123,1574,5605,1891,1197,3080,4124,5606,3081,3082, # 4496 +3778,3646,3779, 747,5607, 635,4386,4747,5608,5609,5610,4387,5611,5612,4748,5613, # 4512 +3415,4749,2437, 451,5614,3780,2542,2073,4388,2744,4389,4125,5615,1764,4750,5616, # 4528 +4390, 350,4751,2283,2395,2493,5617,4391,4126,2249,1434,4127, 488,4752, 458,4392, # 4544 +4128,3781, 771,1330,2396,3914,2576,3184,2160,2414,1553,2677,3185,4393,5618,2494, # 4560 +2895,2622,1720,2711,4394,3416,4753,5619,2543,4395,5620,3262,4396,2778,5621,2016, # 4576 +2745,5622,1155,1017,3782,3915,5623,3336,2313, 201,1865,4397,1430,5624,4129,5625, # 4592 +5626,5627,5628,5629,4398,1604,5630, 414,1866, 371,2595,4754,4755,3532,2017,3127, # 4608 +4756,1708, 960,4399, 887, 389,2172,1536,1663,1721,5631,2232,4130,2356,2940,1580, # 4624 +5632,5633,1744,4757,2544,4758,4759,5634,4760,5635,2074,5636,4761,3647,3417,2896, # 4640 +4400,5637,4401,2650,3418,2815, 673,2712,2465, 709,3533,4131,3648,4402,5638,1148, # 4656 + 502, 634,5639,5640,1204,4762,3649,1575,4763,2623,3783,5641,3784,3128, 948,3263, # 4672 + 121,1745,3916,1110,5642,4403,3083,2516,3027,4132,3785,1151,1771,3917,1488,4133, # 4688 +1987,5643,2438,3534,5644,5645,2094,5646,4404,3918,1213,1407,2816, 531,2746,2545, # 4704 +3264,1011,1537,4764,2779,4405,3129,1061,5647,3786,3787,1867,2897,5648,2018, 120, # 4720 +4406,4407,2063,3650,3265,2314,3919,2678,3419,1955,4765,4134,5649,3535,1047,2713, # 4736 +1266,5650,1368,4766,2858, 649,3420,3920,2546,2747,1102,2859,2679,5651,5652,2000, # 4752 +5653,1111,3651,2977,5654,2495,3921,3652,2817,1855,3421,3788,5655,5656,3422,2415, # 4768 +2898,3337,3266,3653,5657,2577,5658,3654,2818,4135,1460, 856,5659,3655,5660,2899, # 4784 +2978,5661,2900,3922,5662,4408, 632,2517, 875,3923,1697,3924,2296,5663,5664,4767, # 4800 +3028,1239, 580,4768,4409,5665, 914, 936,2075,1190,4136,1039,2124,5666,5667,5668, # 4816 +5669,3423,1473,5670,1354,4410,3925,4769,2173,3084,4137, 915,3338,4411,4412,3339, # 4832 +1605,1835,5671,2748, 398,3656,4413,3926,4138, 328,1913,2860,4139,3927,1331,4414, # 4848 +3029, 937,4415,5672,3657,4140,4141,3424,2161,4770,3425, 524, 742, 538,3085,1012, # 4864 +5673,5674,3928,2466,5675, 658,1103, 225,3929,5676,5677,4771,5678,4772,5679,3267, # 4880 +1243,5680,4142, 963,2250,4773,5681,2714,3658,3186,5682,5683,2596,2332,5684,4774, # 4896 +5685,5686,5687,3536, 957,3426,2547,2033,1931,2941,2467, 870,2019,3659,1746,2780, # 4912 +2781,2439,2468,5688,3930,5689,3789,3130,3790,3537,3427,3791,5690,1179,3086,5691, # 4928 +3187,2378,4416,3792,2548,3188,3131,2749,4143,5692,3428,1556,2549,2297, 977,2901, # 4944 +2034,4144,1205,3429,5693,1765,3430,3189,2125,1271, 714,1689,4775,3538,5694,2333, # 4960 +3931, 533,4417,3660,2184, 617,5695,2469,3340,3539,2315,5696,5697,3190,5698,5699, # 4976 +3932,1988, 618, 427,2651,3540,3431,5700,5701,1244,1690,5702,2819,4418,4776,5703, # 4992 +3541,4777,5704,2284,1576, 473,3661,4419,3432, 972,5705,3662,5706,3087,5707,5708, # 5008 +4778,4779,5709,3793,4145,4146,5710, 153,4780, 356,5711,1892,2902,4420,2144, 408, # 5024 + 803,2357,5712,3933,5713,4421,1646,2578,2518,4781,4782,3934,5714,3935,4422,5715, # 5040 +2416,3433, 752,5716,5717,1962,3341,2979,5718, 746,3030,2470,4783,4423,3794, 698, # 5056 +4784,1893,4424,3663,2550,4785,3664,3936,5719,3191,3434,5720,1824,1302,4147,2715, # 5072 +3937,1974,4425,5721,4426,3192, 823,1303,1288,1236,2861,3542,4148,3435, 774,3938, # 5088 +5722,1581,4786,1304,2862,3939,4787,5723,2440,2162,1083,3268,4427,4149,4428, 344, # 5104 +1173, 288,2316, 454,1683,5724,5725,1461,4788,4150,2597,5726,5727,4789, 985, 894, # 5120 +5728,3436,3193,5729,1914,2942,3795,1989,5730,2111,1975,5731,4151,5732,2579,1194, # 5136 + 425,5733,4790,3194,1245,3796,4429,5734,5735,2863,5736, 636,4791,1856,3940, 760, # 5152 +1800,5737,4430,2212,1508,4792,4152,1894,1684,2298,5738,5739,4793,4431,4432,2213, # 5168 + 479,5740,5741, 832,5742,4153,2496,5743,2980,2497,3797, 990,3132, 627,1815,2652, # 5184 +4433,1582,4434,2126,2112,3543,4794,5744, 799,4435,3195,5745,4795,2113,1737,3031, # 5200 +1018, 543, 754,4436,3342,1676,4796,4797,4154,4798,1489,5746,3544,5747,2624,2903, # 5216 +4155,5748,5749,2981,5750,5751,5752,5753,3196,4799,4800,2185,1722,5754,3269,3270, # 5232 +1843,3665,1715, 481, 365,1976,1857,5755,5756,1963,2498,4801,5757,2127,3666,3271, # 5248 + 433,1895,2064,2076,5758, 602,2750,5759,5760,5761,5762,5763,3032,1628,3437,5764, # 5264 +3197,4802,4156,2904,4803,2519,5765,2551,2782,5766,5767,5768,3343,4804,2905,5769, # 5280 +4805,5770,2864,4806,4807,1221,2982,4157,2520,5771,5772,5773,1868,1990,5774,5775, # 5296 +5776,1896,5777,5778,4808,1897,4158, 318,5779,2095,4159,4437,5780,5781, 485,5782, # 5312 + 938,3941, 553,2680, 116,5783,3942,3667,5784,3545,2681,2783,3438,3344,2820,5785, # 5328 +3668,2943,4160,1747,2944,2983,5786,5787, 207,5788,4809,5789,4810,2521,5790,3033, # 5344 + 890,3669,3943,5791,1878,3798,3439,5792,2186,2358,3440,1652,5793,5794,5795, 941, # 5360 +2299, 208,3546,4161,2020, 330,4438,3944,2906,2499,3799,4439,4811,5796,5797,5798, # 5376 +) + diff --git a/venv/lib/python2.7/site-packages/chardet/big5prober.py b/venv/lib/python2.7/site-packages/chardet/big5prober.py new file mode 100644 index 0000000..98f9970 --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/big5prober.py @@ -0,0 +1,47 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import Big5DistributionAnalysis +from .mbcssm import BIG5_SM_MODEL + + +class Big5Prober(MultiByteCharSetProber): + def __init__(self): + super(Big5Prober, self).__init__() + self.coding_sm = CodingStateMachine(BIG5_SM_MODEL) + self.distribution_analyzer = Big5DistributionAnalysis() + self.reset() + + @property + def charset_name(self): + return "Big5" + + @property + def language(self): + return "Chinese" diff --git a/venv/lib/python2.7/site-packages/chardet/chardistribution.py b/venv/lib/python2.7/site-packages/chardet/chardistribution.py new file mode 100644 index 0000000..c0395f4 --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/chardistribution.py @@ -0,0 +1,233 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .euctwfreq import (EUCTW_CHAR_TO_FREQ_ORDER, EUCTW_TABLE_SIZE, + EUCTW_TYPICAL_DISTRIBUTION_RATIO) +from .euckrfreq import (EUCKR_CHAR_TO_FREQ_ORDER, EUCKR_TABLE_SIZE, + EUCKR_TYPICAL_DISTRIBUTION_RATIO) +from .gb2312freq import (GB2312_CHAR_TO_FREQ_ORDER, GB2312_TABLE_SIZE, + GB2312_TYPICAL_DISTRIBUTION_RATIO) +from .big5freq import (BIG5_CHAR_TO_FREQ_ORDER, BIG5_TABLE_SIZE, + BIG5_TYPICAL_DISTRIBUTION_RATIO) +from .jisfreq import (JIS_CHAR_TO_FREQ_ORDER, JIS_TABLE_SIZE, + JIS_TYPICAL_DISTRIBUTION_RATIO) + + +class CharDistributionAnalysis(object): + ENOUGH_DATA_THRESHOLD = 1024 + SURE_YES = 0.99 + SURE_NO = 0.01 + MINIMUM_DATA_THRESHOLD = 3 + + def __init__(self): + # Mapping table to get frequency order from char order (get from + # GetOrder()) + self._char_to_freq_order = None + self._table_size = None # Size of above table + # This is a constant value which varies from language to language, + # used in calculating confidence. See + # http://www.mozilla.org/projects/intl/UniversalCharsetDetection.html + # for further detail. + self.typical_distribution_ratio = None + self._done = None + self._total_chars = None + self._freq_chars = None + self.reset() + + def reset(self): + """reset analyser, clear any state""" + # If this flag is set to True, detection is done and conclusion has + # been made + self._done = False + self._total_chars = 0 # Total characters encountered + # The number of characters whose frequency order is less than 512 + self._freq_chars = 0 + + def feed(self, char, char_len): + """feed a character with known length""" + if char_len == 2: + # we only care about 2-bytes character in our distribution analysis + order = self.get_order(char) + else: + order = -1 + if order >= 0: + self._total_chars += 1 + # order is valid + if order < self._table_size: + if 512 > self._char_to_freq_order[order]: + self._freq_chars += 1 + + def get_confidence(self): + """return confidence based on existing data""" + # if we didn't receive any character in our consideration range, + # return negative answer + if self._total_chars <= 0 or self._freq_chars <= self.MINIMUM_DATA_THRESHOLD: + return self.SURE_NO + + if self._total_chars != self._freq_chars: + r = (self._freq_chars / ((self._total_chars - self._freq_chars) + * self.typical_distribution_ratio)) + if r < self.SURE_YES: + return r + + # normalize confidence (we don't want to be 100% sure) + return self.SURE_YES + + def got_enough_data(self): + # It is not necessary to receive all data to draw conclusion. + # For charset detection, certain amount of data is enough + return self._total_chars > self.ENOUGH_DATA_THRESHOLD + + def get_order(self, byte_str): + # We do not handle characters based on the original encoding string, + # but convert this encoding string to a number, here called order. + # This allows multiple encodings of a language to share one frequency + # table. + return -1 + + +class EUCTWDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + super(EUCTWDistributionAnalysis, self).__init__() + self._char_to_freq_order = EUCTW_CHAR_TO_FREQ_ORDER + self._table_size = EUCTW_TABLE_SIZE + self.typical_distribution_ratio = EUCTW_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str): + # for euc-TW encoding, we are interested + # first byte range: 0xc4 -- 0xfe + # second byte range: 0xa1 -- 0xfe + # no validation needed here. State machine has done that + first_char = byte_str[0] + if first_char >= 0xC4: + return 94 * (first_char - 0xC4) + byte_str[1] - 0xA1 + else: + return -1 + + +class EUCKRDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + super(EUCKRDistributionAnalysis, self).__init__() + self._char_to_freq_order = EUCKR_CHAR_TO_FREQ_ORDER + self._table_size = EUCKR_TABLE_SIZE + self.typical_distribution_ratio = EUCKR_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str): + # for euc-KR encoding, we are interested + # first byte range: 0xb0 -- 0xfe + # second byte range: 0xa1 -- 0xfe + # no validation needed here. State machine has done that + first_char = byte_str[0] + if first_char >= 0xB0: + return 94 * (first_char - 0xB0) + byte_str[1] - 0xA1 + else: + return -1 + + +class GB2312DistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + super(GB2312DistributionAnalysis, self).__init__() + self._char_to_freq_order = GB2312_CHAR_TO_FREQ_ORDER + self._table_size = GB2312_TABLE_SIZE + self.typical_distribution_ratio = GB2312_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str): + # for GB2312 encoding, we are interested + # first byte range: 0xb0 -- 0xfe + # second byte range: 0xa1 -- 0xfe + # no validation needed here. State machine has done that + first_char, second_char = byte_str[0], byte_str[1] + if (first_char >= 0xB0) and (second_char >= 0xA1): + return 94 * (first_char - 0xB0) + second_char - 0xA1 + else: + return -1 + + +class Big5DistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + super(Big5DistributionAnalysis, self).__init__() + self._char_to_freq_order = BIG5_CHAR_TO_FREQ_ORDER + self._table_size = BIG5_TABLE_SIZE + self.typical_distribution_ratio = BIG5_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str): + # for big5 encoding, we are interested + # first byte range: 0xa4 -- 0xfe + # second byte range: 0x40 -- 0x7e , 0xa1 -- 0xfe + # no validation needed here. State machine has done that + first_char, second_char = byte_str[0], byte_str[1] + if first_char >= 0xA4: + if second_char >= 0xA1: + return 157 * (first_char - 0xA4) + second_char - 0xA1 + 63 + else: + return 157 * (first_char - 0xA4) + second_char - 0x40 + else: + return -1 + + +class SJISDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + super(SJISDistributionAnalysis, self).__init__() + self._char_to_freq_order = JIS_CHAR_TO_FREQ_ORDER + self._table_size = JIS_TABLE_SIZE + self.typical_distribution_ratio = JIS_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str): + # for sjis encoding, we are interested + # first byte range: 0x81 -- 0x9f , 0xe0 -- 0xfe + # second byte range: 0x40 -- 0x7e, 0x81 -- oxfe + # no validation needed here. State machine has done that + first_char, second_char = byte_str[0], byte_str[1] + if (first_char >= 0x81) and (first_char <= 0x9F): + order = 188 * (first_char - 0x81) + elif (first_char >= 0xE0) and (first_char <= 0xEF): + order = 188 * (first_char - 0xE0 + 31) + else: + return -1 + order = order + second_char - 0x40 + if second_char > 0x7F: + order = -1 + return order + + +class EUCJPDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + super(EUCJPDistributionAnalysis, self).__init__() + self._char_to_freq_order = JIS_CHAR_TO_FREQ_ORDER + self._table_size = JIS_TABLE_SIZE + self.typical_distribution_ratio = JIS_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str): + # for euc-JP encoding, we are interested + # first byte range: 0xa0 -- 0xfe + # second byte range: 0xa1 -- 0xfe + # no validation needed here. State machine has done that + char = byte_str[0] + if char >= 0xA0: + return 94 * (char - 0xA1) + byte_str[1] - 0xa1 + else: + return -1 diff --git a/venv/lib/python2.7/site-packages/chardet/charsetgroupprober.py b/venv/lib/python2.7/site-packages/chardet/charsetgroupprober.py new file mode 100644 index 0000000..8b3738e --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/charsetgroupprober.py @@ -0,0 +1,106 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .enums import ProbingState +from .charsetprober import CharSetProber + + +class CharSetGroupProber(CharSetProber): + def __init__(self, lang_filter=None): + super(CharSetGroupProber, self).__init__(lang_filter=lang_filter) + self._active_num = 0 + self.probers = [] + self._best_guess_prober = None + + def reset(self): + super(CharSetGroupProber, self).reset() + self._active_num = 0 + for prober in self.probers: + if prober: + prober.reset() + prober.active = True + self._active_num += 1 + self._best_guess_prober = None + + @property + def charset_name(self): + if not self._best_guess_prober: + self.get_confidence() + if not self._best_guess_prober: + return None + return self._best_guess_prober.charset_name + + @property + def language(self): + if not self._best_guess_prober: + self.get_confidence() + if not self._best_guess_prober: + return None + return self._best_guess_prober.language + + def feed(self, byte_str): + for prober in self.probers: + if not prober: + continue + if not prober.active: + continue + state = prober.feed(byte_str) + if not state: + continue + if state == ProbingState.FOUND_IT: + self._best_guess_prober = prober + return self.state + elif state == ProbingState.NOT_ME: + prober.active = False + self._active_num -= 1 + if self._active_num <= 0: + self._state = ProbingState.NOT_ME + return self.state + return self.state + + def get_confidence(self): + state = self.state + if state == ProbingState.FOUND_IT: + return 0.99 + elif state == ProbingState.NOT_ME: + return 0.01 + best_conf = 0.0 + self._best_guess_prober = None + for prober in self.probers: + if not prober: + continue + if not prober.active: + self.logger.debug('%s not active', prober.charset_name) + continue + conf = prober.get_confidence() + self.logger.debug('%s %s confidence = %s', prober.charset_name, prober.language, conf) + if best_conf < conf: + best_conf = conf + self._best_guess_prober = prober + if not self._best_guess_prober: + return 0.0 + return best_conf diff --git a/venv/lib/python2.7/site-packages/chardet/charsetprober.py b/venv/lib/python2.7/site-packages/chardet/charsetprober.py new file mode 100644 index 0000000..eac4e59 --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/charsetprober.py @@ -0,0 +1,145 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import logging +import re + +from .enums import ProbingState + + +class CharSetProber(object): + + SHORTCUT_THRESHOLD = 0.95 + + def __init__(self, lang_filter=None): + self._state = None + self.lang_filter = lang_filter + self.logger = logging.getLogger(__name__) + + def reset(self): + self._state = ProbingState.DETECTING + + @property + def charset_name(self): + return None + + def feed(self, buf): + pass + + @property + def state(self): + return self._state + + def get_confidence(self): + return 0.0 + + @staticmethod + def filter_high_byte_only(buf): + buf = re.sub(b'([\x00-\x7F])+', b' ', buf) + return buf + + @staticmethod + def filter_international_words(buf): + """ + We define three types of bytes: + alphabet: english alphabets [a-zA-Z] + international: international characters [\x80-\xFF] + marker: everything else [^a-zA-Z\x80-\xFF] + + The input buffer can be thought to contain a series of words delimited + by markers. This function works to filter all words that contain at + least one international character. All contiguous sequences of markers + are replaced by a single space ascii character. + + This filter applies to all scripts which do not use English characters. + """ + filtered = bytearray() + + # This regex expression filters out only words that have at-least one + # international character. The word may include one marker character at + # the end. + words = re.findall(b'[a-zA-Z]*[\x80-\xFF]+[a-zA-Z]*[^a-zA-Z\x80-\xFF]?', + buf) + + for word in words: + filtered.extend(word[:-1]) + + # If the last character in the word is a marker, replace it with a + # space as markers shouldn't affect our analysis (they are used + # similarly across all languages and may thus have similar + # frequencies). + last_char = word[-1:] + if not last_char.isalpha() and last_char < b'\x80': + last_char = b' ' + filtered.extend(last_char) + + return filtered + + @staticmethod + def filter_with_english_letters(buf): + """ + Returns a copy of ``buf`` that retains only the sequences of English + alphabet and high byte characters that are not between <> characters. + Also retains English alphabet and high byte characters immediately + before occurrences of >. + + This filter can be applied to all scripts which contain both English + characters and extended ASCII characters, but is currently only used by + ``Latin1Prober``. + """ + filtered = bytearray() + in_tag = False + prev = 0 + + for curr in range(len(buf)): + # Slice here to get bytes instead of an int with Python 3 + buf_char = buf[curr:curr + 1] + # Check if we're coming out of or entering an HTML tag + if buf_char == b'>': + in_tag = False + elif buf_char == b'<': + in_tag = True + + # If current character is not extended-ASCII and not alphabetic... + if buf_char < b'\x80' and not buf_char.isalpha(): + # ...and we're not in a tag + if curr > prev and not in_tag: + # Keep everything after last non-extended-ASCII, + # non-alphabetic character + filtered.extend(buf[prev:curr]) + # Output a space to delimit stretch we kept + filtered.extend(b' ') + prev = curr + 1 + + # If we're not in a tag... + if not in_tag: + # Keep everything after last non-extended-ASCII, non-alphabetic + # character + filtered.extend(buf[prev:]) + + return filtered diff --git a/venv/lib/python2.7/site-packages/chardet/cli/__init__.py b/venv/lib/python2.7/site-packages/chardet/cli/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/cli/__init__.py @@ -0,0 +1 @@ + diff --git a/venv/lib/python2.7/site-packages/chardet/cli/chardetect.py b/venv/lib/python2.7/site-packages/chardet/cli/chardetect.py new file mode 100644 index 0000000..f0a4cc5 --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/cli/chardetect.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python +""" +Script which takes one or more file paths and reports on their detected +encodings + +Example:: + + % chardetect somefile someotherfile + somefile: windows-1252 with confidence 0.5 + someotherfile: ascii with confidence 1.0 + +If no paths are provided, it takes its input from stdin. + +""" + +from __future__ import absolute_import, print_function, unicode_literals + +import argparse +import sys + +from chardet import __version__ +from chardet.compat import PY2 +from chardet.universaldetector import UniversalDetector + + +def description_of(lines, name='stdin'): + """ + Return a string describing the probable encoding of a file or + list of strings. + + :param lines: The lines to get the encoding of. + :type lines: Iterable of bytes + :param name: Name of file or collection of lines + :type name: str + """ + u = UniversalDetector() + for line in lines: + line = bytearray(line) + u.feed(line) + # shortcut out of the loop to save reading further - particularly useful if we read a BOM. + if u.done: + break + u.close() + result = u.result + if PY2: + name = name.decode(sys.getfilesystemencoding(), 'ignore') + if result['encoding']: + return '{0}: {1} with confidence {2}'.format(name, result['encoding'], + result['confidence']) + else: + return '{0}: no result'.format(name) + + +def main(argv=None): + """ + Handles command line arguments and gets things started. + + :param argv: List of arguments, as if specified on the command-line. + If None, ``sys.argv[1:]`` is used instead. + :type argv: list of str + """ + # Get command line arguments + parser = argparse.ArgumentParser( + description="Takes one or more file paths and reports their detected \ + encodings") + parser.add_argument('input', + help='File whose encoding we would like to determine. \ + (default: stdin)', + type=argparse.FileType('rb'), nargs='*', + default=[sys.stdin if PY2 else sys.stdin.buffer]) + parser.add_argument('--version', action='version', + version='%(prog)s {0}'.format(__version__)) + args = parser.parse_args(argv) + + for f in args.input: + if f.isatty(): + print("You are running chardetect interactively. Press " + + "CTRL-D twice at the start of a blank line to signal the " + + "end of your input. If you want help, run chardetect " + + "--help\n", file=sys.stderr) + print(description_of(f, f.name)) + + +if __name__ == '__main__': + main() diff --git a/venv/lib/python2.7/site-packages/chardet/codingstatemachine.py b/venv/lib/python2.7/site-packages/chardet/codingstatemachine.py new file mode 100644 index 0000000..68fba44 --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/codingstatemachine.py @@ -0,0 +1,88 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import logging + +from .enums import MachineState + + +class CodingStateMachine(object): + """ + A state machine to verify a byte sequence for a particular encoding. For + each byte the detector receives, it will feed that byte to every active + state machine available, one byte at a time. The state machine changes its + state based on its previous state and the byte it receives. There are 3 + states in a state machine that are of interest to an auto-detector: + + START state: This is the state to start with, or a legal byte sequence + (i.e. a valid code point) for character has been identified. + + ME state: This indicates that the state machine identified a byte sequence + that is specific to the charset it is designed for and that + there is no other possible encoding which can contain this byte + sequence. This will to lead to an immediate positive answer for + the detector. + + ERROR state: This indicates the state machine identified an illegal byte + sequence for that encoding. This will lead to an immediate + negative answer for this encoding. Detector will exclude this + encoding from consideration from here on. + """ + def __init__(self, sm): + self._model = sm + self._curr_byte_pos = 0 + self._curr_char_len = 0 + self._curr_state = None + self.logger = logging.getLogger(__name__) + self.reset() + + def reset(self): + self._curr_state = MachineState.START + + def next_state(self, c): + # for each byte we get its class + # if it is first byte, we also get byte length + byte_class = self._model['class_table'][c] + if self._curr_state == MachineState.START: + self._curr_byte_pos = 0 + self._curr_char_len = self._model['char_len_table'][byte_class] + # from byte's class and state_table, we get its next state + curr_state = (self._curr_state * self._model['class_factor'] + + byte_class) + self._curr_state = self._model['state_table'][curr_state] + self._curr_byte_pos += 1 + return self._curr_state + + def get_current_charlen(self): + return self._curr_char_len + + def get_coding_state_machine(self): + return self._model['name'] + + @property + def language(self): + return self._model['language'] diff --git a/venv/lib/python2.7/site-packages/chardet/compat.py b/venv/lib/python2.7/site-packages/chardet/compat.py new file mode 100644 index 0000000..ddd7468 --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/compat.py @@ -0,0 +1,34 @@ +######################## BEGIN LICENSE BLOCK ######################## +# Contributor(s): +# Dan Blanchard +# Ian Cordasco +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import sys + + +if sys.version_info < (3, 0): + PY2 = True + PY3 = False + base_str = (str, unicode) + text_type = unicode +else: + PY2 = False + PY3 = True + base_str = (bytes, str) + text_type = str diff --git a/venv/lib/python2.7/site-packages/chardet/cp949prober.py b/venv/lib/python2.7/site-packages/chardet/cp949prober.py new file mode 100644 index 0000000..efd793a --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/cp949prober.py @@ -0,0 +1,49 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .chardistribution import EUCKRDistributionAnalysis +from .codingstatemachine import CodingStateMachine +from .mbcharsetprober import MultiByteCharSetProber +from .mbcssm import CP949_SM_MODEL + + +class CP949Prober(MultiByteCharSetProber): + def __init__(self): + super(CP949Prober, self).__init__() + self.coding_sm = CodingStateMachine(CP949_SM_MODEL) + # NOTE: CP949 is a superset of EUC-KR, so the distribution should be + # not different. + self.distribution_analyzer = EUCKRDistributionAnalysis() + self.reset() + + @property + def charset_name(self): + return "CP949" + + @property + def language(self): + return "Korean" diff --git a/venv/lib/python2.7/site-packages/chardet/enums.py b/venv/lib/python2.7/site-packages/chardet/enums.py new file mode 100644 index 0000000..0451207 --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/enums.py @@ -0,0 +1,76 @@ +""" +All of the Enums that are used throughout the chardet package. + +:author: Dan Blanchard (dan.blanchard@gmail.com) +""" + + +class InputState(object): + """ + This enum represents the different states a universal detector can be in. + """ + PURE_ASCII = 0 + ESC_ASCII = 1 + HIGH_BYTE = 2 + + +class LanguageFilter(object): + """ + This enum represents the different language filters we can apply to a + ``UniversalDetector``. + """ + CHINESE_SIMPLIFIED = 0x01 + CHINESE_TRADITIONAL = 0x02 + JAPANESE = 0x04 + KOREAN = 0x08 + NON_CJK = 0x10 + ALL = 0x1F + CHINESE = CHINESE_SIMPLIFIED | CHINESE_TRADITIONAL + CJK = CHINESE | JAPANESE | KOREAN + + +class ProbingState(object): + """ + This enum represents the different states a prober can be in. + """ + DETECTING = 0 + FOUND_IT = 1 + NOT_ME = 2 + + +class MachineState(object): + """ + This enum represents the different states a state machine can be in. + """ + START = 0 + ERROR = 1 + ITS_ME = 2 + + +class SequenceLikelihood(object): + """ + This enum represents the likelihood of a character following the previous one. + """ + NEGATIVE = 0 + UNLIKELY = 1 + LIKELY = 2 + POSITIVE = 3 + + @classmethod + def get_num_categories(cls): + """:returns: The number of likelihood categories in the enum.""" + return 4 + + +class CharacterCategory(object): + """ + This enum represents the different categories language models for + ``SingleByteCharsetProber`` put characters into. + + Anything less than CONTROL is considered a letter. + """ + UNDEFINED = 255 + LINE_BREAK = 254 + SYMBOL = 253 + DIGIT = 252 + CONTROL = 251 diff --git a/venv/lib/python2.7/site-packages/chardet/escprober.py b/venv/lib/python2.7/site-packages/chardet/escprober.py new file mode 100644 index 0000000..c70493f --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/escprober.py @@ -0,0 +1,101 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetprober import CharSetProber +from .codingstatemachine import CodingStateMachine +from .enums import LanguageFilter, ProbingState, MachineState +from .escsm import (HZ_SM_MODEL, ISO2022CN_SM_MODEL, ISO2022JP_SM_MODEL, + ISO2022KR_SM_MODEL) + + +class EscCharSetProber(CharSetProber): + """ + This CharSetProber uses a "code scheme" approach for detecting encodings, + whereby easily recognizable escape or shift sequences are relied on to + identify these encodings. + """ + + def __init__(self, lang_filter=None): + super(EscCharSetProber, self).__init__(lang_filter=lang_filter) + self.coding_sm = [] + if self.lang_filter & LanguageFilter.CHINESE_SIMPLIFIED: + self.coding_sm.append(CodingStateMachine(HZ_SM_MODEL)) + self.coding_sm.append(CodingStateMachine(ISO2022CN_SM_MODEL)) + if self.lang_filter & LanguageFilter.JAPANESE: + self.coding_sm.append(CodingStateMachine(ISO2022JP_SM_MODEL)) + if self.lang_filter & LanguageFilter.KOREAN: + self.coding_sm.append(CodingStateMachine(ISO2022KR_SM_MODEL)) + self.active_sm_count = None + self._detected_charset = None + self._detected_language = None + self._state = None + self.reset() + + def reset(self): + super(EscCharSetProber, self).reset() + for coding_sm in self.coding_sm: + if not coding_sm: + continue + coding_sm.active = True + coding_sm.reset() + self.active_sm_count = len(self.coding_sm) + self._detected_charset = None + self._detected_language = None + + @property + def charset_name(self): + return self._detected_charset + + @property + def language(self): + return self._detected_language + + def get_confidence(self): + if self._detected_charset: + return 0.99 + else: + return 0.00 + + def feed(self, byte_str): + for c in byte_str: + for coding_sm in self.coding_sm: + if not coding_sm or not coding_sm.active: + continue + coding_state = coding_sm.next_state(c) + if coding_state == MachineState.ERROR: + coding_sm.active = False + self.active_sm_count -= 1 + if self.active_sm_count <= 0: + self._state = ProbingState.NOT_ME + return self.state + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + self._detected_charset = coding_sm.get_coding_state_machine() + self._detected_language = coding_sm.language + return self.state + + return self.state diff --git a/venv/lib/python2.7/site-packages/chardet/escsm.py b/venv/lib/python2.7/site-packages/chardet/escsm.py new file mode 100644 index 0000000..0069523 --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/escsm.py @@ -0,0 +1,246 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .enums import MachineState + +HZ_CLS = ( +1,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,0,0, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,0,0,0,0, # 20 - 27 +0,0,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +0,0,0,0,0,0,0,0, # 40 - 47 +0,0,0,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,4,0,5,2,0, # 78 - 7f +1,1,1,1,1,1,1,1, # 80 - 87 +1,1,1,1,1,1,1,1, # 88 - 8f +1,1,1,1,1,1,1,1, # 90 - 97 +1,1,1,1,1,1,1,1, # 98 - 9f +1,1,1,1,1,1,1,1, # a0 - a7 +1,1,1,1,1,1,1,1, # a8 - af +1,1,1,1,1,1,1,1, # b0 - b7 +1,1,1,1,1,1,1,1, # b8 - bf +1,1,1,1,1,1,1,1, # c0 - c7 +1,1,1,1,1,1,1,1, # c8 - cf +1,1,1,1,1,1,1,1, # d0 - d7 +1,1,1,1,1,1,1,1, # d8 - df +1,1,1,1,1,1,1,1, # e0 - e7 +1,1,1,1,1,1,1,1, # e8 - ef +1,1,1,1,1,1,1,1, # f0 - f7 +1,1,1,1,1,1,1,1, # f8 - ff +) + +HZ_ST = ( +MachineState.START,MachineState.ERROR, 3,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,# 00-07 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 08-0f +MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START, 4,MachineState.ERROR,# 10-17 + 5,MachineState.ERROR, 6,MachineState.ERROR, 5, 5, 4,MachineState.ERROR,# 18-1f + 4,MachineState.ERROR, 4, 4, 4,MachineState.ERROR, 4,MachineState.ERROR,# 20-27 + 4,MachineState.ITS_ME,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 28-2f +) + +HZ_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0) + +HZ_SM_MODEL = {'class_table': HZ_CLS, + 'class_factor': 6, + 'state_table': HZ_ST, + 'char_len_table': HZ_CHAR_LEN_TABLE, + 'name': "HZ-GB-2312", + 'language': 'Chinese'} + +ISO2022CN_CLS = ( +2,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,0,0, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,0,0,0,0, # 20 - 27 +0,3,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +0,0,0,4,0,0,0,0, # 40 - 47 +0,0,0,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,0,0,0,0,0, # 78 - 7f +2,2,2,2,2,2,2,2, # 80 - 87 +2,2,2,2,2,2,2,2, # 88 - 8f +2,2,2,2,2,2,2,2, # 90 - 97 +2,2,2,2,2,2,2,2, # 98 - 9f +2,2,2,2,2,2,2,2, # a0 - a7 +2,2,2,2,2,2,2,2, # a8 - af +2,2,2,2,2,2,2,2, # b0 - b7 +2,2,2,2,2,2,2,2, # b8 - bf +2,2,2,2,2,2,2,2, # c0 - c7 +2,2,2,2,2,2,2,2, # c8 - cf +2,2,2,2,2,2,2,2, # d0 - d7 +2,2,2,2,2,2,2,2, # d8 - df +2,2,2,2,2,2,2,2, # e0 - e7 +2,2,2,2,2,2,2,2, # e8 - ef +2,2,2,2,2,2,2,2, # f0 - f7 +2,2,2,2,2,2,2,2, # f8 - ff +) + +ISO2022CN_ST = ( +MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 00-07 +MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 08-0f +MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 10-17 +MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,# 18-1f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 20-27 + 5, 6,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 28-2f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 30-37 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,# 38-3f +) + +ISO2022CN_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0, 0, 0, 0) + +ISO2022CN_SM_MODEL = {'class_table': ISO2022CN_CLS, + 'class_factor': 9, + 'state_table': ISO2022CN_ST, + 'char_len_table': ISO2022CN_CHAR_LEN_TABLE, + 'name': "ISO-2022-CN", + 'language': 'Chinese'} + +ISO2022JP_CLS = ( +2,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,2,2, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,7,0,0,0, # 20 - 27 +3,0,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +6,0,4,0,8,0,0,0, # 40 - 47 +0,9,5,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,0,0,0,0,0, # 78 - 7f +2,2,2,2,2,2,2,2, # 80 - 87 +2,2,2,2,2,2,2,2, # 88 - 8f +2,2,2,2,2,2,2,2, # 90 - 97 +2,2,2,2,2,2,2,2, # 98 - 9f +2,2,2,2,2,2,2,2, # a0 - a7 +2,2,2,2,2,2,2,2, # a8 - af +2,2,2,2,2,2,2,2, # b0 - b7 +2,2,2,2,2,2,2,2, # b8 - bf +2,2,2,2,2,2,2,2, # c0 - c7 +2,2,2,2,2,2,2,2, # c8 - cf +2,2,2,2,2,2,2,2, # d0 - d7 +2,2,2,2,2,2,2,2, # d8 - df +2,2,2,2,2,2,2,2, # e0 - e7 +2,2,2,2,2,2,2,2, # e8 - ef +2,2,2,2,2,2,2,2, # f0 - f7 +2,2,2,2,2,2,2,2, # f8 - ff +) + +ISO2022JP_ST = ( +MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 00-07 +MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 08-0f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 10-17 +MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,# 18-1f +MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,MachineState.ERROR,# 20-27 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 6,MachineState.ITS_ME,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,# 28-2f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,# 30-37 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 38-3f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,MachineState.START,# 40-47 +) + +ISO2022JP_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + +ISO2022JP_SM_MODEL = {'class_table': ISO2022JP_CLS, + 'class_factor': 10, + 'state_table': ISO2022JP_ST, + 'char_len_table': ISO2022JP_CHAR_LEN_TABLE, + 'name': "ISO-2022-JP", + 'language': 'Japanese'} + +ISO2022KR_CLS = ( +2,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,0,0, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,3,0,0,0, # 20 - 27 +0,4,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +0,0,0,5,0,0,0,0, # 40 - 47 +0,0,0,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,0,0,0,0,0, # 78 - 7f +2,2,2,2,2,2,2,2, # 80 - 87 +2,2,2,2,2,2,2,2, # 88 - 8f +2,2,2,2,2,2,2,2, # 90 - 97 +2,2,2,2,2,2,2,2, # 98 - 9f +2,2,2,2,2,2,2,2, # a0 - a7 +2,2,2,2,2,2,2,2, # a8 - af +2,2,2,2,2,2,2,2, # b0 - b7 +2,2,2,2,2,2,2,2, # b8 - bf +2,2,2,2,2,2,2,2, # c0 - c7 +2,2,2,2,2,2,2,2, # c8 - cf +2,2,2,2,2,2,2,2, # d0 - d7 +2,2,2,2,2,2,2,2, # d8 - df +2,2,2,2,2,2,2,2, # e0 - e7 +2,2,2,2,2,2,2,2, # e8 - ef +2,2,2,2,2,2,2,2, # f0 - f7 +2,2,2,2,2,2,2,2, # f8 - ff +) + +ISO2022KR_ST = ( +MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,# 00-07 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 08-0f +MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,MachineState.ERROR,# 10-17 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 18-1f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 20-27 +) + +ISO2022KR_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0) + +ISO2022KR_SM_MODEL = {'class_table': ISO2022KR_CLS, + 'class_factor': 6, + 'state_table': ISO2022KR_ST, + 'char_len_table': ISO2022KR_CHAR_LEN_TABLE, + 'name': "ISO-2022-KR", + 'language': 'Korean'} + + diff --git a/venv/lib/python2.7/site-packages/chardet/eucjpprober.py b/venv/lib/python2.7/site-packages/chardet/eucjpprober.py new file mode 100644 index 0000000..20ce8f7 --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/eucjpprober.py @@ -0,0 +1,92 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .enums import ProbingState, MachineState +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import EUCJPDistributionAnalysis +from .jpcntx import EUCJPContextAnalysis +from .mbcssm import EUCJP_SM_MODEL + + +class EUCJPProber(MultiByteCharSetProber): + def __init__(self): + super(EUCJPProber, self).__init__() + self.coding_sm = CodingStateMachine(EUCJP_SM_MODEL) + self.distribution_analyzer = EUCJPDistributionAnalysis() + self.context_analyzer = EUCJPContextAnalysis() + self.reset() + + def reset(self): + super(EUCJPProber, self).reset() + self.context_analyzer.reset() + + @property + def charset_name(self): + return "EUC-JP" + + @property + def language(self): + return "Japanese" + + def feed(self, byte_str): + for i in range(len(byte_str)): + # PY3K: byte_str is a byte array, so byte_str[i] is an int, not a byte + coding_state = self.coding_sm.next_state(byte_str[i]) + if coding_state == MachineState.ERROR: + self.logger.debug('%s %s prober hit error at byte %s', + self.charset_name, self.language, i) + self._state = ProbingState.NOT_ME + break + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + break + elif coding_state == MachineState.START: + char_len = self.coding_sm.get_current_charlen() + if i == 0: + self._last_char[1] = byte_str[0] + self.context_analyzer.feed(self._last_char, char_len) + self.distribution_analyzer.feed(self._last_char, char_len) + else: + self.context_analyzer.feed(byte_str[i - 1:i + 1], + char_len) + self.distribution_analyzer.feed(byte_str[i - 1:i + 1], + char_len) + + self._last_char[0] = byte_str[-1] + + if self.state == ProbingState.DETECTING: + if (self.context_analyzer.got_enough_data() and + (self.get_confidence() > self.SHORTCUT_THRESHOLD)): + self._state = ProbingState.FOUND_IT + + return self.state + + def get_confidence(self): + context_conf = self.context_analyzer.get_confidence() + distrib_conf = self.distribution_analyzer.get_confidence() + return max(context_conf, distrib_conf) diff --git a/venv/lib/python2.7/site-packages/chardet/euckrfreq.py b/venv/lib/python2.7/site-packages/chardet/euckrfreq.py new file mode 100644 index 0000000..b68078c --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/euckrfreq.py @@ -0,0 +1,195 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# Sampling from about 20M text materials include literature and computer technology + +# 128 --> 0.79 +# 256 --> 0.92 +# 512 --> 0.986 +# 1024 --> 0.99944 +# 2048 --> 0.99999 +# +# Idea Distribution Ratio = 0.98653 / (1-0.98653) = 73.24 +# Random Distribution Ration = 512 / (2350-512) = 0.279. +# +# Typical Distribution Ratio + +EUCKR_TYPICAL_DISTRIBUTION_RATIO = 6.0 + +EUCKR_TABLE_SIZE = 2352 + +# Char to FreqOrder table , +EUCKR_CHAR_TO_FREQ_ORDER = ( + 13, 130, 120,1396, 481,1719,1720, 328, 609, 212,1721, 707, 400, 299,1722, 87, +1397,1723, 104, 536,1117,1203,1724,1267, 685,1268, 508,1725,1726,1727,1728,1398, +1399,1729,1730,1731, 141, 621, 326,1057, 368,1732, 267, 488, 20,1733,1269,1734, + 945,1400,1735, 47, 904,1270,1736,1737, 773, 248,1738, 409, 313, 786, 429,1739, + 116, 987, 813,1401, 683, 75,1204, 145,1740,1741,1742,1743, 16, 847, 667, 622, + 708,1744,1745,1746, 966, 787, 304, 129,1747, 60, 820, 123, 676,1748,1749,1750, +1751, 617,1752, 626,1753,1754,1755,1756, 653,1757,1758,1759,1760,1761,1762, 856, + 344,1763,1764,1765,1766, 89, 401, 418, 806, 905, 848,1767,1768,1769, 946,1205, + 709,1770,1118,1771, 241,1772,1773,1774,1271,1775, 569,1776, 999,1777,1778,1779, +1780, 337, 751,1058, 28, 628, 254,1781, 177, 906, 270, 349, 891,1079,1782, 19, +1783, 379,1784, 315,1785, 629, 754,1402, 559,1786, 636, 203,1206,1787, 710, 567, +1788, 935, 814,1789,1790,1207, 766, 528,1791,1792,1208,1793,1794,1795,1796,1797, +1403,1798,1799, 533,1059,1404,1405,1156,1406, 936, 884,1080,1800, 351,1801,1802, +1803,1804,1805, 801,1806,1807,1808,1119,1809,1157, 714, 474,1407,1810, 298, 899, + 885,1811,1120, 802,1158,1812, 892,1813,1814,1408, 659,1815,1816,1121,1817,1818, +1819,1820,1821,1822, 319,1823, 594, 545,1824, 815, 937,1209,1825,1826, 573,1409, +1022,1827,1210,1828,1829,1830,1831,1832,1833, 556, 722, 807,1122,1060,1834, 697, +1835, 900, 557, 715,1836,1410, 540,1411, 752,1159, 294, 597,1211, 976, 803, 770, +1412,1837,1838, 39, 794,1413, 358,1839, 371, 925,1840, 453, 661, 788, 531, 723, + 544,1023,1081, 869, 91,1841, 392, 430, 790, 602,1414, 677,1082, 457,1415,1416, +1842,1843, 475, 327,1024,1417, 795, 121,1844, 733, 403,1418,1845,1846,1847, 300, + 119, 711,1212, 627,1848,1272, 207,1849,1850, 796,1213, 382,1851, 519,1852,1083, + 893,1853,1854,1855, 367, 809, 487, 671,1856, 663,1857,1858, 956, 471, 306, 857, +1859,1860,1160,1084,1861,1862,1863,1864,1865,1061,1866,1867,1868,1869,1870,1871, + 282, 96, 574,1872, 502,1085,1873,1214,1874, 907,1875,1876, 827, 977,1419,1420, +1421, 268,1877,1422,1878,1879,1880, 308,1881, 2, 537,1882,1883,1215,1884,1885, + 127, 791,1886,1273,1423,1887, 34, 336, 404, 643,1888, 571, 654, 894, 840,1889, + 0, 886,1274, 122, 575, 260, 908, 938,1890,1275, 410, 316,1891,1892, 100,1893, +1894,1123, 48,1161,1124,1025,1895, 633, 901,1276,1896,1897, 115, 816,1898, 317, +1899, 694,1900, 909, 734,1424, 572, 866,1425, 691, 85, 524,1010, 543, 394, 841, +1901,1902,1903,1026,1904,1905,1906,1907,1908,1909, 30, 451, 651, 988, 310,1910, +1911,1426, 810,1216, 93,1912,1913,1277,1217,1914, 858, 759, 45, 58, 181, 610, + 269,1915,1916, 131,1062, 551, 443,1000, 821,1427, 957, 895,1086,1917,1918, 375, +1919, 359,1920, 687,1921, 822,1922, 293,1923,1924, 40, 662, 118, 692, 29, 939, + 887, 640, 482, 174,1925, 69,1162, 728,1428, 910,1926,1278,1218,1279, 386, 870, + 217, 854,1163, 823,1927,1928,1929,1930, 834,1931, 78,1932, 859,1933,1063,1934, +1935,1936,1937, 438,1164, 208, 595,1938,1939,1940,1941,1219,1125,1942, 280, 888, +1429,1430,1220,1431,1943,1944,1945,1946,1947,1280, 150, 510,1432,1948,1949,1950, +1951,1952,1953,1954,1011,1087,1955,1433,1043,1956, 881,1957, 614, 958,1064,1065, +1221,1958, 638,1001, 860, 967, 896,1434, 989, 492, 553,1281,1165,1959,1282,1002, +1283,1222,1960,1961,1962,1963, 36, 383, 228, 753, 247, 454,1964, 876, 678,1965, +1966,1284, 126, 464, 490, 835, 136, 672, 529, 940,1088,1435, 473,1967,1968, 467, + 50, 390, 227, 587, 279, 378, 598, 792, 968, 240, 151, 160, 849, 882,1126,1285, + 639,1044, 133, 140, 288, 360, 811, 563,1027, 561, 142, 523,1969,1970,1971, 7, + 103, 296, 439, 407, 506, 634, 990,1972,1973,1974,1975, 645,1976,1977,1978,1979, +1980,1981, 236,1982,1436,1983,1984,1089, 192, 828, 618, 518,1166, 333,1127,1985, + 818,1223,1986,1987,1988,1989,1990,1991,1992,1993, 342,1128,1286, 746, 842,1994, +1995, 560, 223,1287, 98, 8, 189, 650, 978,1288,1996,1437,1997, 17, 345, 250, + 423, 277, 234, 512, 226, 97, 289, 42, 167,1998, 201,1999,2000, 843, 836, 824, + 532, 338, 783,1090, 182, 576, 436,1438,1439, 527, 500,2001, 947, 889,2002,2003, +2004,2005, 262, 600, 314, 447,2006, 547,2007, 693, 738,1129,2008, 71,1440, 745, + 619, 688,2009, 829,2010,2011, 147,2012, 33, 948,2013,2014, 74, 224,2015, 61, + 191, 918, 399, 637,2016,1028,1130, 257, 902,2017,2018,2019,2020,2021,2022,2023, +2024,2025,2026, 837,2027,2028,2029,2030, 179, 874, 591, 52, 724, 246,2031,2032, +2033,2034,1167, 969,2035,1289, 630, 605, 911,1091,1168,2036,2037,2038,1441, 912, +2039, 623,2040,2041, 253,1169,1290,2042,1442, 146, 620, 611, 577, 433,2043,1224, + 719,1170, 959, 440, 437, 534, 84, 388, 480,1131, 159, 220, 198, 679,2044,1012, + 819,1066,1443, 113,1225, 194, 318,1003,1029,2045,2046,2047,2048,1067,2049,2050, +2051,2052,2053, 59, 913, 112,2054, 632,2055, 455, 144, 739,1291,2056, 273, 681, + 499,2057, 448,2058,2059, 760,2060,2061, 970, 384, 169, 245,1132,2062,2063, 414, +1444,2064,2065, 41, 235,2066, 157, 252, 877, 568, 919, 789, 580,2067, 725,2068, +2069,1292,2070,2071,1445,2072,1446,2073,2074, 55, 588, 66,1447, 271,1092,2075, +1226,2076, 960,1013, 372,2077,2078,2079,2080,2081,1293,2082,2083,2084,2085, 850, +2086,2087,2088,2089,2090, 186,2091,1068, 180,2092,2093,2094, 109,1227, 522, 606, +2095, 867,1448,1093, 991,1171, 926, 353,1133,2096, 581,2097,2098,2099,1294,1449, +1450,2100, 596,1172,1014,1228,2101,1451,1295,1173,1229,2102,2103,1296,1134,1452, + 949,1135,2104,2105,1094,1453,1454,1455,2106,1095,2107,2108,2109,2110,2111,2112, +2113,2114,2115,2116,2117, 804,2118,2119,1230,1231, 805,1456, 405,1136,2120,2121, +2122,2123,2124, 720, 701,1297, 992,1457, 927,1004,2125,2126,2127,2128,2129,2130, + 22, 417,2131, 303,2132, 385,2133, 971, 520, 513,2134,1174, 73,1096, 231, 274, + 962,1458, 673,2135,1459,2136, 152,1137,2137,2138,2139,2140,1005,1138,1460,1139, +2141,2142,2143,2144, 11, 374, 844,2145, 154,1232, 46,1461,2146, 838, 830, 721, +1233, 106,2147, 90, 428, 462, 578, 566,1175, 352,2148,2149, 538,1234, 124,1298, +2150,1462, 761, 565,2151, 686,2152, 649,2153, 72, 173,2154, 460, 415,2155,1463, +2156,1235, 305,2157,2158,2159,2160,2161,2162, 579,2163,2164,2165,2166,2167, 747, +2168,2169,2170,2171,1464, 669,2172,2173,2174,2175,2176,1465,2177, 23, 530, 285, +2178, 335, 729,2179, 397,2180,2181,2182,1030,2183,2184, 698,2185,2186, 325,2187, +2188, 369,2189, 799,1097,1015, 348,2190,1069, 680,2191, 851,1466,2192,2193, 10, +2194, 613, 424,2195, 979, 108, 449, 589, 27, 172, 81,1031, 80, 774, 281, 350, +1032, 525, 301, 582,1176,2196, 674,1045,2197,2198,1467, 730, 762,2199,2200,2201, +2202,1468,2203, 993,2204,2205, 266,1070, 963,1140,2206,2207,2208, 664,1098, 972, +2209,2210,2211,1177,1469,1470, 871,2212,2213,2214,2215,2216,1471,2217,2218,2219, +2220,2221,2222,2223,2224,2225,2226,2227,1472,1236,2228,2229,2230,2231,2232,2233, +2234,2235,1299,2236,2237, 200,2238, 477, 373,2239,2240, 731, 825, 777,2241,2242, +2243, 521, 486, 548,2244,2245,2246,1473,1300, 53, 549, 137, 875, 76, 158,2247, +1301,1474, 469, 396,1016, 278, 712,2248, 321, 442, 503, 767, 744, 941,1237,1178, +1475,2249, 82, 178,1141,1179, 973,2250,1302,2251, 297,2252,2253, 570,2254,2255, +2256, 18, 450, 206,2257, 290, 292,1142,2258, 511, 162, 99, 346, 164, 735,2259, +1476,1477, 4, 554, 343, 798,1099,2260,1100,2261, 43, 171,1303, 139, 215,2262, +2263, 717, 775,2264,1033, 322, 216,2265, 831,2266, 149,2267,1304,2268,2269, 702, +1238, 135, 845, 347, 309,2270, 484,2271, 878, 655, 238,1006,1478,2272, 67,2273, + 295,2274,2275, 461,2276, 478, 942, 412,2277,1034,2278,2279,2280, 265,2281, 541, +2282,2283,2284,2285,2286, 70, 852,1071,2287,2288,2289,2290, 21, 56, 509, 117, + 432,2291,2292, 331, 980, 552,1101, 148, 284, 105, 393,1180,1239, 755,2293, 187, +2294,1046,1479,2295, 340,2296, 63,1047, 230,2297,2298,1305, 763,1306, 101, 800, + 808, 494,2299,2300,2301, 903,2302, 37,1072, 14, 5,2303, 79, 675,2304, 312, +2305,2306,2307,2308,2309,1480, 6,1307,2310,2311,2312, 1, 470, 35, 24, 229, +2313, 695, 210, 86, 778, 15, 784, 592, 779, 32, 77, 855, 964,2314, 259,2315, + 501, 380,2316,2317, 83, 981, 153, 689,1308,1481,1482,1483,2318,2319, 716,1484, +2320,2321,2322,2323,2324,2325,1485,2326,2327, 128, 57, 68, 261,1048, 211, 170, +1240, 31,2328, 51, 435, 742,2329,2330,2331, 635,2332, 264, 456,2333,2334,2335, + 425,2336,1486, 143, 507, 263, 943,2337, 363, 920,1487, 256,1488,1102, 243, 601, +1489,2338,2339,2340,2341,2342,2343,2344, 861,2345,2346,2347,2348,2349,2350, 395, +2351,1490,1491, 62, 535, 166, 225,2352,2353, 668, 419,1241, 138, 604, 928,2354, +1181,2355,1492,1493,2356,2357,2358,1143,2359, 696,2360, 387, 307,1309, 682, 476, +2361,2362, 332, 12, 222, 156,2363, 232,2364, 641, 276, 656, 517,1494,1495,1035, + 416, 736,1496,2365,1017, 586,2366,2367,2368,1497,2369, 242,2370,2371,2372,1498, +2373, 965, 713,2374,2375,2376,2377, 740, 982,1499, 944,1500,1007,2378,2379,1310, +1501,2380,2381,2382, 785, 329,2383,2384,1502,2385,2386,2387, 932,2388,1503,2389, +2390,2391,2392,1242,2393,2394,2395,2396,2397, 994, 950,2398,2399,2400,2401,1504, +1311,2402,2403,2404,2405,1049, 749,2406,2407, 853, 718,1144,1312,2408,1182,1505, +2409,2410, 255, 516, 479, 564, 550, 214,1506,1507,1313, 413, 239, 444, 339,1145, +1036,1508,1509,1314,1037,1510,1315,2411,1511,2412,2413,2414, 176, 703, 497, 624, + 593, 921, 302,2415, 341, 165,1103,1512,2416,1513,2417,2418,2419, 376,2420, 700, +2421,2422,2423, 258, 768,1316,2424,1183,2425, 995, 608,2426,2427,2428,2429, 221, +2430,2431,2432,2433,2434,2435,2436,2437, 195, 323, 726, 188, 897, 983,1317, 377, + 644,1050, 879,2438, 452,2439,2440,2441,2442,2443,2444, 914,2445,2446,2447,2448, + 915, 489,2449,1514,1184,2450,2451, 515, 64, 427, 495,2452, 583,2453, 483, 485, +1038, 562, 213,1515, 748, 666,2454,2455,2456,2457, 334,2458, 780, 996,1008, 705, +1243,2459,2460,2461,2462,2463, 114,2464, 493,1146, 366, 163,1516, 961,1104,2465, + 291,2466,1318,1105,2467,1517, 365,2468, 355, 951,1244,2469,1319,2470, 631,2471, +2472, 218,1320, 364, 320, 756,1518,1519,1321,1520,1322,2473,2474,2475,2476, 997, +2477,2478,2479,2480, 665,1185,2481, 916,1521,2482,2483,2484, 584, 684,2485,2486, + 797,2487,1051,1186,2488,2489,2490,1522,2491,2492, 370,2493,1039,1187, 65,2494, + 434, 205, 463,1188,2495, 125, 812, 391, 402, 826, 699, 286, 398, 155, 781, 771, + 585,2496, 590, 505,1073,2497, 599, 244, 219, 917,1018, 952, 646,1523,2498,1323, +2499,2500, 49, 984, 354, 741,2501, 625,2502,1324,2503,1019, 190, 357, 757, 491, + 95, 782, 868,2504,2505,2506,2507,2508,2509, 134,1524,1074, 422,1525, 898,2510, + 161,2511,2512,2513,2514, 769,2515,1526,2516,2517, 411,1325,2518, 472,1527,2519, +2520,2521,2522,2523,2524, 985,2525,2526,2527,2528,2529,2530, 764,2531,1245,2532, +2533, 25, 204, 311,2534, 496,2535,1052,2536,2537,2538,2539,2540,2541,2542, 199, + 704, 504, 468, 758, 657,1528, 196, 44, 839,1246, 272, 750,2543, 765, 862,2544, +2545,1326,2546, 132, 615, 933,2547, 732,2548,2549,2550,1189,1529,2551, 283,1247, +1053, 607, 929,2552,2553,2554, 930, 183, 872, 616,1040,1147,2555,1148,1020, 441, + 249,1075,2556,2557,2558, 466, 743,2559,2560,2561, 92, 514, 426, 420, 526,2562, +2563,2564,2565,2566,2567,2568, 185,2569,2570,2571,2572, 776,1530, 658,2573, 362, +2574, 361, 922,1076, 793,2575,2576,2577,2578,2579,2580,1531, 251,2581,2582,2583, +2584,1532, 54, 612, 237,1327,2585,2586, 275, 408, 647, 111,2587,1533,1106, 465, + 3, 458, 9, 38,2588, 107, 110, 890, 209, 26, 737, 498,2589,1534,2590, 431, + 202, 88,1535, 356, 287,1107, 660,1149,2591, 381,1536, 986,1150, 445,1248,1151, + 974,2592,2593, 846,2594, 446, 953, 184,1249,1250, 727,2595, 923, 193, 883,2596, +2597,2598, 102, 324, 539, 817,2599, 421,1041,2600, 832,2601, 94, 175, 197, 406, +2602, 459,2603,2604,2605,2606,2607, 330, 555,2608,2609,2610, 706,1108, 389,2611, +2612,2613,2614, 233,2615, 833, 558, 931, 954,1251,2616,2617,1537, 546,2618,2619, +1009,2620,2621,2622,1538, 690,1328,2623, 955,2624,1539,2625,2626, 772,2627,2628, +2629,2630,2631, 924, 648, 863, 603,2632,2633, 934,1540, 864, 865,2634, 642,1042, + 670,1190,2635,2636,2637,2638, 168,2639, 652, 873, 542,1054,1541,2640,2641,2642, # 512, 256 +) + diff --git a/venv/lib/python2.7/site-packages/chardet/euckrprober.py b/venv/lib/python2.7/site-packages/chardet/euckrprober.py new file mode 100644 index 0000000..345a060 --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/euckrprober.py @@ -0,0 +1,47 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import EUCKRDistributionAnalysis +from .mbcssm import EUCKR_SM_MODEL + + +class EUCKRProber(MultiByteCharSetProber): + def __init__(self): + super(EUCKRProber, self).__init__() + self.coding_sm = CodingStateMachine(EUCKR_SM_MODEL) + self.distribution_analyzer = EUCKRDistributionAnalysis() + self.reset() + + @property + def charset_name(self): + return "EUC-KR" + + @property + def language(self): + return "Korean" diff --git a/venv/lib/python2.7/site-packages/chardet/euctwfreq.py b/venv/lib/python2.7/site-packages/chardet/euctwfreq.py new file mode 100644 index 0000000..ed7a995 --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/euctwfreq.py @@ -0,0 +1,387 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# EUCTW frequency table +# Converted from big5 work +# by Taiwan's Mandarin Promotion Council +# + +# 128 --> 0.42261 +# 256 --> 0.57851 +# 512 --> 0.74851 +# 1024 --> 0.89384 +# 2048 --> 0.97583 +# +# Idea Distribution Ratio = 0.74851/(1-0.74851) =2.98 +# Random Distribution Ration = 512/(5401-512)=0.105 +# +# Typical Distribution Ratio about 25% of Ideal one, still much higher than RDR + +EUCTW_TYPICAL_DISTRIBUTION_RATIO = 0.75 + +# Char to FreqOrder table , +EUCTW_TABLE_SIZE = 5376 + +EUCTW_CHAR_TO_FREQ_ORDER = ( + 1,1800,1506, 255,1431, 198, 9, 82, 6,7310, 177, 202,3615,1256,2808, 110, # 2742 +3735, 33,3241, 261, 76, 44,2113, 16,2931,2184,1176, 659,3868, 26,3404,2643, # 2758 +1198,3869,3313,4060, 410,2211, 302, 590, 361,1963, 8, 204, 58,4296,7311,1931, # 2774 + 63,7312,7313, 317,1614, 75, 222, 159,4061,2412,1480,7314,3500,3068, 224,2809, # 2790 +3616, 3, 10,3870,1471, 29,2774,1135,2852,1939, 873, 130,3242,1123, 312,7315, # 2806 +4297,2051, 507, 252, 682,7316, 142,1914, 124, 206,2932, 34,3501,3173, 64, 604, # 2822 +7317,2494,1976,1977, 155,1990, 645, 641,1606,7318,3405, 337, 72, 406,7319, 80, # 2838 + 630, 238,3174,1509, 263, 939,1092,2644, 756,1440,1094,3406, 449, 69,2969, 591, # 2854 + 179,2095, 471, 115,2034,1843, 60, 50,2970, 134, 806,1868, 734,2035,3407, 180, # 2870 + 995,1607, 156, 537,2893, 688,7320, 319,1305, 779,2144, 514,2374, 298,4298, 359, # 2886 +2495, 90,2707,1338, 663, 11, 906,1099,2545, 20,2436, 182, 532,1716,7321, 732, # 2902 +1376,4062,1311,1420,3175, 25,2312,1056, 113, 399, 382,1949, 242,3408,2467, 529, # 2918 +3243, 475,1447,3617,7322, 117, 21, 656, 810,1297,2295,2329,3502,7323, 126,4063, # 2934 + 706, 456, 150, 613,4299, 71,1118,2036,4064, 145,3069, 85, 835, 486,2114,1246, # 2950 +1426, 428, 727,1285,1015, 800, 106, 623, 303,1281,7324,2127,2354, 347,3736, 221, # 2966 +3503,3110,7325,1955,1153,4065, 83, 296,1199,3070, 192, 624, 93,7326, 822,1897, # 2982 +2810,3111, 795,2064, 991,1554,1542,1592, 27, 43,2853, 859, 139,1456, 860,4300, # 2998 + 437, 712,3871, 164,2392,3112, 695, 211,3017,2096, 195,3872,1608,3504,3505,3618, # 3014 +3873, 234, 811,2971,2097,3874,2229,1441,3506,1615,2375, 668,2076,1638, 305, 228, # 3030 +1664,4301, 467, 415,7327, 262,2098,1593, 239, 108, 300, 200,1033, 512,1247,2077, # 3046 +7328,7329,2173,3176,3619,2673, 593, 845,1062,3244, 88,1723,2037,3875,1950, 212, # 3062 + 266, 152, 149, 468,1898,4066,4302, 77, 187,7330,3018, 37, 5,2972,7331,3876, # 3078 +7332,7333, 39,2517,4303,2894,3177,2078, 55, 148, 74,4304, 545, 483,1474,1029, # 3094 +1665, 217,1869,1531,3113,1104,2645,4067, 24, 172,3507, 900,3877,3508,3509,4305, # 3110 + 32,1408,2811,1312, 329, 487,2355,2247,2708, 784,2674, 4,3019,3314,1427,1788, # 3126 + 188, 109, 499,7334,3620,1717,1789, 888,1217,3020,4306,7335,3510,7336,3315,1520, # 3142 +3621,3878, 196,1034, 775,7337,7338, 929,1815, 249, 439, 38,7339,1063,7340, 794, # 3158 +3879,1435,2296, 46, 178,3245,2065,7341,2376,7342, 214,1709,4307, 804, 35, 707, # 3174 + 324,3622,1601,2546, 140, 459,4068,7343,7344,1365, 839, 272, 978,2257,2572,3409, # 3190 +2128,1363,3623,1423, 697, 100,3071, 48, 70,1231, 495,3114,2193,7345,1294,7346, # 3206 +2079, 462, 586,1042,3246, 853, 256, 988, 185,2377,3410,1698, 434,1084,7347,3411, # 3222 + 314,2615,2775,4308,2330,2331, 569,2280, 637,1816,2518, 757,1162,1878,1616,3412, # 3238 + 287,1577,2115, 768,4309,1671,2854,3511,2519,1321,3737, 909,2413,7348,4069, 933, # 3254 +3738,7349,2052,2356,1222,4310, 765,2414,1322, 786,4311,7350,1919,1462,1677,2895, # 3270 +1699,7351,4312,1424,2437,3115,3624,2590,3316,1774,1940,3413,3880,4070, 309,1369, # 3286 +1130,2812, 364,2230,1653,1299,3881,3512,3882,3883,2646, 525,1085,3021, 902,2000, # 3302 +1475, 964,4313, 421,1844,1415,1057,2281, 940,1364,3116, 376,4314,4315,1381, 7, # 3318 +2520, 983,2378, 336,1710,2675,1845, 321,3414, 559,1131,3022,2742,1808,1132,1313, # 3334 + 265,1481,1857,7352, 352,1203,2813,3247, 167,1089, 420,2814, 776, 792,1724,3513, # 3350 +4071,2438,3248,7353,4072,7354, 446, 229, 333,2743, 901,3739,1200,1557,4316,2647, # 3366 +1920, 395,2744,2676,3740,4073,1835, 125, 916,3178,2616,4317,7355,7356,3741,7357, # 3382 +7358,7359,4318,3117,3625,1133,2547,1757,3415,1510,2313,1409,3514,7360,2145, 438, # 3398 +2591,2896,2379,3317,1068, 958,3023, 461, 311,2855,2677,4074,1915,3179,4075,1978, # 3414 + 383, 750,2745,2617,4076, 274, 539, 385,1278,1442,7361,1154,1964, 384, 561, 210, # 3430 + 98,1295,2548,3515,7362,1711,2415,1482,3416,3884,2897,1257, 129,7363,3742, 642, # 3446 + 523,2776,2777,2648,7364, 141,2231,1333, 68, 176, 441, 876, 907,4077, 603,2592, # 3462 + 710, 171,3417, 404, 549, 18,3118,2393,1410,3626,1666,7365,3516,4319,2898,4320, # 3478 +7366,2973, 368,7367, 146, 366, 99, 871,3627,1543, 748, 807,1586,1185, 22,2258, # 3494 + 379,3743,3180,7368,3181, 505,1941,2618,1991,1382,2314,7369, 380,2357, 218, 702, # 3510 +1817,1248,3418,3024,3517,3318,3249,7370,2974,3628, 930,3250,3744,7371, 59,7372, # 3526 + 585, 601,4078, 497,3419,1112,1314,4321,1801,7373,1223,1472,2174,7374, 749,1836, # 3542 + 690,1899,3745,1772,3885,1476, 429,1043,1790,2232,2116, 917,4079, 447,1086,1629, # 3558 +7375, 556,7376,7377,2020,1654, 844,1090, 105, 550, 966,1758,2815,1008,1782, 686, # 3574 +1095,7378,2282, 793,1602,7379,3518,2593,4322,4080,2933,2297,4323,3746, 980,2496, # 3590 + 544, 353, 527,4324, 908,2678,2899,7380, 381,2619,1942,1348,7381,1341,1252, 560, # 3606 +3072,7382,3420,2856,7383,2053, 973, 886,2080, 143,4325,7384,7385, 157,3886, 496, # 3622 +4081, 57, 840, 540,2038,4326,4327,3421,2117,1445, 970,2259,1748,1965,2081,4082, # 3638 +3119,1234,1775,3251,2816,3629, 773,1206,2129,1066,2039,1326,3887,1738,1725,4083, # 3654 + 279,3120, 51,1544,2594, 423,1578,2130,2066, 173,4328,1879,7386,7387,1583, 264, # 3670 + 610,3630,4329,2439, 280, 154,7388,7389,7390,1739, 338,1282,3073, 693,2857,1411, # 3686 +1074,3747,2440,7391,4330,7392,7393,1240, 952,2394,7394,2900,1538,2679, 685,1483, # 3702 +4084,2468,1436, 953,4085,2054,4331, 671,2395, 79,4086,2441,3252, 608, 567,2680, # 3718 +3422,4087,4088,1691, 393,1261,1791,2396,7395,4332,7396,7397,7398,7399,1383,1672, # 3734 +3748,3182,1464, 522,1119, 661,1150, 216, 675,4333,3888,1432,3519, 609,4334,2681, # 3750 +2397,7400,7401,7402,4089,3025, 0,7403,2469, 315, 231,2442, 301,3319,4335,2380, # 3766 +7404, 233,4090,3631,1818,4336,4337,7405, 96,1776,1315,2082,7406, 257,7407,1809, # 3782 +3632,2709,1139,1819,4091,2021,1124,2163,2778,1777,2649,7408,3074, 363,1655,3183, # 3798 +7409,2975,7410,7411,7412,3889,1567,3890, 718, 103,3184, 849,1443, 341,3320,2934, # 3814 +1484,7413,1712, 127, 67, 339,4092,2398, 679,1412, 821,7414,7415, 834, 738, 351, # 3830 +2976,2146, 846, 235,1497,1880, 418,1992,3749,2710, 186,1100,2147,2746,3520,1545, # 3846 +1355,2935,2858,1377, 583,3891,4093,2573,2977,7416,1298,3633,1078,2549,3634,2358, # 3862 + 78,3750,3751, 267,1289,2099,2001,1594,4094, 348, 369,1274,2194,2175,1837,4338, # 3878 +1820,2817,3635,2747,2283,2002,4339,2936,2748, 144,3321, 882,4340,3892,2749,3423, # 3894 +4341,2901,7417,4095,1726, 320,7418,3893,3026, 788,2978,7419,2818,1773,1327,2859, # 3910 +3894,2819,7420,1306,4342,2003,1700,3752,3521,2359,2650, 787,2022, 506, 824,3636, # 3926 + 534, 323,4343,1044,3322,2023,1900, 946,3424,7421,1778,1500,1678,7422,1881,4344, # 3942 + 165, 243,4345,3637,2521, 123, 683,4096, 764,4346, 36,3895,1792, 589,2902, 816, # 3958 + 626,1667,3027,2233,1639,1555,1622,3753,3896,7423,3897,2860,1370,1228,1932, 891, # 3974 +2083,2903, 304,4097,7424, 292,2979,2711,3522, 691,2100,4098,1115,4347, 118, 662, # 3990 +7425, 611,1156, 854,2381,1316,2861, 2, 386, 515,2904,7426,7427,3253, 868,2234, # 4006 +1486, 855,2651, 785,2212,3028,7428,1040,3185,3523,7429,3121, 448,7430,1525,7431, # 4022 +2164,4348,7432,3754,7433,4099,2820,3524,3122, 503, 818,3898,3123,1568, 814, 676, # 4038 +1444, 306,1749,7434,3755,1416,1030, 197,1428, 805,2821,1501,4349,7435,7436,7437, # 4054 +1993,7438,4350,7439,7440,2195, 13,2779,3638,2980,3124,1229,1916,7441,3756,2131, # 4070 +7442,4100,4351,2399,3525,7443,2213,1511,1727,1120,7444,7445, 646,3757,2443, 307, # 4086 +7446,7447,1595,3186,7448,7449,7450,3639,1113,1356,3899,1465,2522,2523,7451, 519, # 4102 +7452, 128,2132, 92,2284,1979,7453,3900,1512, 342,3125,2196,7454,2780,2214,1980, # 4118 +3323,7455, 290,1656,1317, 789, 827,2360,7456,3758,4352, 562, 581,3901,7457, 401, # 4134 +4353,2248, 94,4354,1399,2781,7458,1463,2024,4355,3187,1943,7459, 828,1105,4101, # 4150 +1262,1394,7460,4102, 605,4356,7461,1783,2862,7462,2822, 819,2101, 578,2197,2937, # 4166 +7463,1502, 436,3254,4103,3255,2823,3902,2905,3425,3426,7464,2712,2315,7465,7466, # 4182 +2332,2067, 23,4357, 193, 826,3759,2102, 699,1630,4104,3075, 390,1793,1064,3526, # 4198 +7467,1579,3076,3077,1400,7468,4105,1838,1640,2863,7469,4358,4359, 137,4106, 598, # 4214 +3078,1966, 780, 104, 974,2938,7470, 278, 899, 253, 402, 572, 504, 493,1339,7471, # 4230 +3903,1275,4360,2574,2550,7472,3640,3029,3079,2249, 565,1334,2713, 863, 41,7473, # 4246 +7474,4361,7475,1657,2333, 19, 463,2750,4107, 606,7476,2981,3256,1087,2084,1323, # 4262 +2652,2982,7477,1631,1623,1750,4108,2682,7478,2864, 791,2714,2653,2334, 232,2416, # 4278 +7479,2983,1498,7480,2654,2620, 755,1366,3641,3257,3126,2025,1609, 119,1917,3427, # 4294 + 862,1026,4109,7481,3904,3760,4362,3905,4363,2260,1951,2470,7482,1125, 817,4110, # 4310 +4111,3906,1513,1766,2040,1487,4112,3030,3258,2824,3761,3127,7483,7484,1507,7485, # 4326 +2683, 733, 40,1632,1106,2865, 345,4113, 841,2524, 230,4364,2984,1846,3259,3428, # 4342 +7486,1263, 986,3429,7487, 735, 879, 254,1137, 857, 622,1300,1180,1388,1562,3907, # 4358 +3908,2939, 967,2751,2655,1349, 592,2133,1692,3324,2985,1994,4114,1679,3909,1901, # 4374 +2185,7488, 739,3642,2715,1296,1290,7489,4115,2198,2199,1921,1563,2595,2551,1870, # 4390 +2752,2986,7490, 435,7491, 343,1108, 596, 17,1751,4365,2235,3430,3643,7492,4366, # 4406 + 294,3527,2940,1693, 477, 979, 281,2041,3528, 643,2042,3644,2621,2782,2261,1031, # 4422 +2335,2134,2298,3529,4367, 367,1249,2552,7493,3530,7494,4368,1283,3325,2004, 240, # 4438 +1762,3326,4369,4370, 836,1069,3128, 474,7495,2148,2525, 268,3531,7496,3188,1521, # 4454 +1284,7497,1658,1546,4116,7498,3532,3533,7499,4117,3327,2684,1685,4118, 961,1673, # 4470 +2622, 190,2005,2200,3762,4371,4372,7500, 570,2497,3645,1490,7501,4373,2623,3260, # 4486 +1956,4374, 584,1514, 396,1045,1944,7502,4375,1967,2444,7503,7504,4376,3910, 619, # 4502 +7505,3129,3261, 215,2006,2783,2553,3189,4377,3190,4378, 763,4119,3763,4379,7506, # 4518 +7507,1957,1767,2941,3328,3646,1174, 452,1477,4380,3329,3130,7508,2825,1253,2382, # 4534 +2186,1091,2285,4120, 492,7509, 638,1169,1824,2135,1752,3911, 648, 926,1021,1324, # 4550 +4381, 520,4382, 997, 847,1007, 892,4383,3764,2262,1871,3647,7510,2400,1784,4384, # 4566 +1952,2942,3080,3191,1728,4121,2043,3648,4385,2007,1701,3131,1551, 30,2263,4122, # 4582 +7511,2026,4386,3534,7512, 501,7513,4123, 594,3431,2165,1821,3535,3432,3536,3192, # 4598 + 829,2826,4124,7514,1680,3132,1225,4125,7515,3262,4387,4126,3133,2336,7516,4388, # 4614 +4127,7517,3912,3913,7518,1847,2383,2596,3330,7519,4389, 374,3914, 652,4128,4129, # 4630 + 375,1140, 798,7520,7521,7522,2361,4390,2264, 546,1659, 138,3031,2445,4391,7523, # 4646 +2250, 612,1848, 910, 796,3765,1740,1371, 825,3766,3767,7524,2906,2554,7525, 692, # 4662 + 444,3032,2624, 801,4392,4130,7526,1491, 244,1053,3033,4131,4132, 340,7527,3915, # 4678 +1041,2987, 293,1168, 87,1357,7528,1539, 959,7529,2236, 721, 694,4133,3768, 219, # 4694 +1478, 644,1417,3331,2656,1413,1401,1335,1389,3916,7530,7531,2988,2362,3134,1825, # 4710 + 730,1515, 184,2827, 66,4393,7532,1660,2943, 246,3332, 378,1457, 226,3433, 975, # 4726 +3917,2944,1264,3537, 674, 696,7533, 163,7534,1141,2417,2166, 713,3538,3333,4394, # 4742 +3918,7535,7536,1186, 15,7537,1079,1070,7538,1522,3193,3539, 276,1050,2716, 758, # 4758 +1126, 653,2945,3263,7539,2337, 889,3540,3919,3081,2989, 903,1250,4395,3920,3434, # 4774 +3541,1342,1681,1718, 766,3264, 286, 89,2946,3649,7540,1713,7541,2597,3334,2990, # 4790 +7542,2947,2215,3194,2866,7543,4396,2498,2526, 181, 387,1075,3921, 731,2187,3335, # 4806 +7544,3265, 310, 313,3435,2299, 770,4134, 54,3034, 189,4397,3082,3769,3922,7545, # 4822 +1230,1617,1849, 355,3542,4135,4398,3336, 111,4136,3650,1350,3135,3436,3035,4137, # 4838 +2149,3266,3543,7546,2784,3923,3924,2991, 722,2008,7547,1071, 247,1207,2338,2471, # 4854 +1378,4399,2009, 864,1437,1214,4400, 373,3770,1142,2216, 667,4401, 442,2753,2555, # 4870 +3771,3925,1968,4138,3267,1839, 837, 170,1107, 934,1336,1882,7548,7549,2118,4139, # 4886 +2828, 743,1569,7550,4402,4140, 582,2384,1418,3437,7551,1802,7552, 357,1395,1729, # 4902 +3651,3268,2418,1564,2237,7553,3083,3772,1633,4403,1114,2085,4141,1532,7554, 482, # 4918 +2446,4404,7555,7556,1492, 833,1466,7557,2717,3544,1641,2829,7558,1526,1272,3652, # 4934 +4142,1686,1794, 416,2556,1902,1953,1803,7559,3773,2785,3774,1159,2316,7560,2867, # 4950 +4405,1610,1584,3036,2419,2754, 443,3269,1163,3136,7561,7562,3926,7563,4143,2499, # 4966 +3037,4406,3927,3137,2103,1647,3545,2010,1872,4144,7564,4145, 431,3438,7565, 250, # 4982 + 97, 81,4146,7566,1648,1850,1558, 160, 848,7567, 866, 740,1694,7568,2201,2830, # 4998 +3195,4147,4407,3653,1687, 950,2472, 426, 469,3196,3654,3655,3928,7569,7570,1188, # 5014 + 424,1995, 861,3546,4148,3775,2202,2685, 168,1235,3547,4149,7571,2086,1674,4408, # 5030 +3337,3270, 220,2557,1009,7572,3776, 670,2992, 332,1208, 717,7573,7574,3548,2447, # 5046 +3929,3338,7575, 513,7576,1209,2868,3339,3138,4409,1080,7577,7578,7579,7580,2527, # 5062 +3656,3549, 815,1587,3930,3931,7581,3550,3439,3777,1254,4410,1328,3038,1390,3932, # 5078 +1741,3933,3778,3934,7582, 236,3779,2448,3271,7583,7584,3657,3780,1273,3781,4411, # 5094 +7585, 308,7586,4412, 245,4413,1851,2473,1307,2575, 430, 715,2136,2449,7587, 270, # 5110 + 199,2869,3935,7588,3551,2718,1753, 761,1754, 725,1661,1840,4414,3440,3658,7589, # 5126 +7590, 587, 14,3272, 227,2598, 326, 480,2265, 943,2755,3552, 291, 650,1883,7591, # 5142 +1702,1226, 102,1547, 62,3441, 904,4415,3442,1164,4150,7592,7593,1224,1548,2756, # 5158 + 391, 498,1493,7594,1386,1419,7595,2055,1177,4416, 813, 880,1081,2363, 566,1145, # 5174 +4417,2286,1001,1035,2558,2599,2238, 394,1286,7596,7597,2068,7598, 86,1494,1730, # 5190 +3936, 491,1588, 745, 897,2948, 843,3340,3937,2757,2870,3273,1768, 998,2217,2069, # 5206 + 397,1826,1195,1969,3659,2993,3341, 284,7599,3782,2500,2137,2119,1903,7600,3938, # 5222 +2150,3939,4151,1036,3443,1904, 114,2559,4152, 209,1527,7601,7602,2949,2831,2625, # 5238 +2385,2719,3139, 812,2560,7603,3274,7604,1559, 737,1884,3660,1210, 885, 28,2686, # 5254 +3553,3783,7605,4153,1004,1779,4418,7606, 346,1981,2218,2687,4419,3784,1742, 797, # 5270 +1642,3940,1933,1072,1384,2151, 896,3941,3275,3661,3197,2871,3554,7607,2561,1958, # 5286 +4420,2450,1785,7608,7609,7610,3942,4154,1005,1308,3662,4155,2720,4421,4422,1528, # 5302 +2600, 161,1178,4156,1982, 987,4423,1101,4157, 631,3943,1157,3198,2420,1343,1241, # 5318 +1016,2239,2562, 372, 877,2339,2501,1160, 555,1934, 911,3944,7611, 466,1170, 169, # 5334 +1051,2907,2688,3663,2474,2994,1182,2011,2563,1251,2626,7612, 992,2340,3444,1540, # 5350 +2721,1201,2070,2401,1996,2475,7613,4424, 528,1922,2188,1503,1873,1570,2364,3342, # 5366 +3276,7614, 557,1073,7615,1827,3445,2087,2266,3140,3039,3084, 767,3085,2786,4425, # 5382 +1006,4158,4426,2341,1267,2176,3664,3199, 778,3945,3200,2722,1597,2657,7616,4427, # 5398 +7617,3446,7618,7619,7620,3277,2689,1433,3278, 131, 95,1504,3946, 723,4159,3141, # 5414 +1841,3555,2758,2189,3947,2027,2104,3665,7621,2995,3948,1218,7622,3343,3201,3949, # 5430 +4160,2576, 248,1634,3785, 912,7623,2832,3666,3040,3786, 654, 53,7624,2996,7625, # 5446 +1688,4428, 777,3447,1032,3950,1425,7626, 191, 820,2120,2833, 971,4429, 931,3202, # 5462 + 135, 664, 783,3787,1997, 772,2908,1935,3951,3788,4430,2909,3203, 282,2723, 640, # 5478 +1372,3448,1127, 922, 325,3344,7627,7628, 711,2044,7629,7630,3952,2219,2787,1936, # 5494 +3953,3345,2220,2251,3789,2300,7631,4431,3790,1258,3279,3954,3204,2138,2950,3955, # 5510 +3956,7632,2221, 258,3205,4432, 101,1227,7633,3280,1755,7634,1391,3281,7635,2910, # 5526 +2056, 893,7636,7637,7638,1402,4161,2342,7639,7640,3206,3556,7641,7642, 878,1325, # 5542 +1780,2788,4433, 259,1385,2577, 744,1183,2267,4434,7643,3957,2502,7644, 684,1024, # 5558 +4162,7645, 472,3557,3449,1165,3282,3958,3959, 322,2152, 881, 455,1695,1152,1340, # 5574 + 660, 554,2153,4435,1058,4436,4163, 830,1065,3346,3960,4437,1923,7646,1703,1918, # 5590 +7647, 932,2268, 122,7648,4438, 947, 677,7649,3791,2627, 297,1905,1924,2269,4439, # 5606 +2317,3283,7650,7651,4164,7652,4165, 84,4166, 112, 989,7653, 547,1059,3961, 701, # 5622 +3558,1019,7654,4167,7655,3450, 942, 639, 457,2301,2451, 993,2951, 407, 851, 494, # 5638 +4440,3347, 927,7656,1237,7657,2421,3348, 573,4168, 680, 921,2911,1279,1874, 285, # 5654 + 790,1448,1983, 719,2167,7658,7659,4441,3962,3963,1649,7660,1541, 563,7661,1077, # 5670 +7662,3349,3041,3451, 511,2997,3964,3965,3667,3966,1268,2564,3350,3207,4442,4443, # 5686 +7663, 535,1048,1276,1189,2912,2028,3142,1438,1373,2834,2952,1134,2012,7664,4169, # 5702 +1238,2578,3086,1259,7665, 700,7666,2953,3143,3668,4170,7667,4171,1146,1875,1906, # 5718 +4444,2601,3967, 781,2422, 132,1589, 203, 147, 273,2789,2402, 898,1786,2154,3968, # 5734 +3969,7668,3792,2790,7669,7670,4445,4446,7671,3208,7672,1635,3793, 965,7673,1804, # 5750 +2690,1516,3559,1121,1082,1329,3284,3970,1449,3794, 65,1128,2835,2913,2759,1590, # 5766 +3795,7674,7675, 12,2658, 45, 976,2579,3144,4447, 517,2528,1013,1037,3209,7676, # 5782 +3796,2836,7677,3797,7678,3452,7679,2602, 614,1998,2318,3798,3087,2724,2628,7680, # 5798 +2580,4172, 599,1269,7681,1810,3669,7682,2691,3088, 759,1060, 489,1805,3351,3285, # 5814 +1358,7683,7684,2386,1387,1215,2629,2252, 490,7685,7686,4173,1759,2387,2343,7687, # 5830 +4448,3799,1907,3971,2630,1806,3210,4449,3453,3286,2760,2344, 874,7688,7689,3454, # 5846 +3670,1858, 91,2914,3671,3042,3800,4450,7690,3145,3972,2659,7691,3455,1202,1403, # 5862 +3801,2954,2529,1517,2503,4451,3456,2504,7692,4452,7693,2692,1885,1495,1731,3973, # 5878 +2365,4453,7694,2029,7695,7696,3974,2693,1216, 237,2581,4174,2319,3975,3802,4454, # 5894 +4455,2694,3560,3457, 445,4456,7697,7698,7699,7700,2761, 61,3976,3672,1822,3977, # 5910 +7701, 687,2045, 935, 925, 405,2660, 703,1096,1859,2725,4457,3978,1876,1367,2695, # 5926 +3352, 918,2105,1781,2476, 334,3287,1611,1093,4458, 564,3146,3458,3673,3353, 945, # 5942 +2631,2057,4459,7702,1925, 872,4175,7703,3459,2696,3089, 349,4176,3674,3979,4460, # 5958 +3803,4177,3675,2155,3980,4461,4462,4178,4463,2403,2046, 782,3981, 400, 251,4179, # 5974 +1624,7704,7705, 277,3676, 299,1265, 476,1191,3804,2121,4180,4181,1109, 205,7706, # 5990 +2582,1000,2156,3561,1860,7707,7708,7709,4464,7710,4465,2565, 107,2477,2157,3982, # 6006 +3460,3147,7711,1533, 541,1301, 158, 753,4182,2872,3562,7712,1696, 370,1088,4183, # 6022 +4466,3563, 579, 327, 440, 162,2240, 269,1937,1374,3461, 968,3043, 56,1396,3090, # 6038 +2106,3288,3354,7713,1926,2158,4467,2998,7714,3564,7715,7716,3677,4468,2478,7717, # 6054 +2791,7718,1650,4469,7719,2603,7720,7721,3983,2661,3355,1149,3356,3984,3805,3985, # 6070 +7722,1076, 49,7723, 951,3211,3289,3290, 450,2837, 920,7724,1811,2792,2366,4184, # 6086 +1908,1138,2367,3806,3462,7725,3212,4470,1909,1147,1518,2423,4471,3807,7726,4472, # 6102 +2388,2604, 260,1795,3213,7727,7728,3808,3291, 708,7729,3565,1704,7730,3566,1351, # 6118 +1618,3357,2999,1886, 944,4185,3358,4186,3044,3359,4187,7731,3678, 422, 413,1714, # 6134 +3292, 500,2058,2345,4188,2479,7732,1344,1910, 954,7733,1668,7734,7735,3986,2404, # 6150 +4189,3567,3809,4190,7736,2302,1318,2505,3091, 133,3092,2873,4473, 629, 31,2838, # 6166 +2697,3810,4474, 850, 949,4475,3987,2955,1732,2088,4191,1496,1852,7737,3988, 620, # 6182 +3214, 981,1242,3679,3360,1619,3680,1643,3293,2139,2452,1970,1719,3463,2168,7738, # 6198 +3215,7739,7740,3361,1828,7741,1277,4476,1565,2047,7742,1636,3568,3093,7743, 869, # 6214 +2839, 655,3811,3812,3094,3989,3000,3813,1310,3569,4477,7744,7745,7746,1733, 558, # 6230 +4478,3681, 335,1549,3045,1756,4192,3682,1945,3464,1829,1291,1192, 470,2726,2107, # 6246 +2793, 913,1054,3990,7747,1027,7748,3046,3991,4479, 982,2662,3362,3148,3465,3216, # 6262 +3217,1946,2794,7749, 571,4480,7750,1830,7751,3570,2583,1523,2424,7752,2089, 984, # 6278 +4481,3683,1959,7753,3684, 852, 923,2795,3466,3685, 969,1519, 999,2048,2320,1705, # 6294 +7754,3095, 615,1662, 151, 597,3992,2405,2321,1049, 275,4482,3686,4193, 568,3687, # 6310 +3571,2480,4194,3688,7755,2425,2270, 409,3218,7756,1566,2874,3467,1002, 769,2840, # 6326 + 194,2090,3149,3689,2222,3294,4195, 628,1505,7757,7758,1763,2177,3001,3993, 521, # 6342 +1161,2584,1787,2203,2406,4483,3994,1625,4196,4197, 412, 42,3096, 464,7759,2632, # 6358 +4484,3363,1760,1571,2875,3468,2530,1219,2204,3814,2633,2140,2368,4485,4486,3295, # 6374 +1651,3364,3572,7760,7761,3573,2481,3469,7762,3690,7763,7764,2271,2091, 460,7765, # 6390 +4487,7766,3002, 962, 588,3574, 289,3219,2634,1116, 52,7767,3047,1796,7768,7769, # 6406 +7770,1467,7771,1598,1143,3691,4198,1984,1734,1067,4488,1280,3365, 465,4489,1572, # 6422 + 510,7772,1927,2241,1812,1644,3575,7773,4490,3692,7774,7775,2663,1573,1534,7776, # 6438 +7777,4199, 536,1807,1761,3470,3815,3150,2635,7778,7779,7780,4491,3471,2915,1911, # 6454 +2796,7781,3296,1122, 377,3220,7782, 360,7783,7784,4200,1529, 551,7785,2059,3693, # 6470 +1769,2426,7786,2916,4201,3297,3097,2322,2108,2030,4492,1404, 136,1468,1479, 672, # 6486 +1171,3221,2303, 271,3151,7787,2762,7788,2049, 678,2727, 865,1947,4493,7789,2013, # 6502 +3995,2956,7790,2728,2223,1397,3048,3694,4494,4495,1735,2917,3366,3576,7791,3816, # 6518 + 509,2841,2453,2876,3817,7792,7793,3152,3153,4496,4202,2531,4497,2304,1166,1010, # 6534 + 552, 681,1887,7794,7795,2957,2958,3996,1287,1596,1861,3154, 358, 453, 736, 175, # 6550 + 478,1117, 905,1167,1097,7796,1853,1530,7797,1706,7798,2178,3472,2287,3695,3473, # 6566 +3577,4203,2092,4204,7799,3367,1193,2482,4205,1458,2190,2205,1862,1888,1421,3298, # 6582 +2918,3049,2179,3474, 595,2122,7800,3997,7801,7802,4206,1707,2636, 223,3696,1359, # 6598 + 751,3098, 183,3475,7803,2797,3003, 419,2369, 633, 704,3818,2389, 241,7804,7805, # 6614 +7806, 838,3004,3697,2272,2763,2454,3819,1938,2050,3998,1309,3099,2242,1181,7807, # 6630 +1136,2206,3820,2370,1446,4207,2305,4498,7808,7809,4208,1055,2605, 484,3698,7810, # 6646 +3999, 625,4209,2273,3368,1499,4210,4000,7811,4001,4211,3222,2274,2275,3476,7812, # 6662 +7813,2764, 808,2606,3699,3369,4002,4212,3100,2532, 526,3370,3821,4213, 955,7814, # 6678 +1620,4214,2637,2427,7815,1429,3700,1669,1831, 994, 928,7816,3578,1260,7817,7818, # 6694 +7819,1948,2288, 741,2919,1626,4215,2729,2455, 867,1184, 362,3371,1392,7820,7821, # 6710 +4003,4216,1770,1736,3223,2920,4499,4500,1928,2698,1459,1158,7822,3050,3372,2877, # 6726 +1292,1929,2506,2842,3701,1985,1187,2071,2014,2607,4217,7823,2566,2507,2169,3702, # 6742 +2483,3299,7824,3703,4501,7825,7826, 666,1003,3005,1022,3579,4218,7827,4502,1813, # 6758 +2253, 574,3822,1603, 295,1535, 705,3823,4219, 283, 858, 417,7828,7829,3224,4503, # 6774 +4504,3051,1220,1889,1046,2276,2456,4004,1393,1599, 689,2567, 388,4220,7830,2484, # 6790 + 802,7831,2798,3824,2060,1405,2254,7832,4505,3825,2109,1052,1345,3225,1585,7833, # 6806 + 809,7834,7835,7836, 575,2730,3477, 956,1552,1469,1144,2323,7837,2324,1560,2457, # 6822 +3580,3226,4005, 616,2207,3155,2180,2289,7838,1832,7839,3478,4506,7840,1319,3704, # 6838 +3705,1211,3581,1023,3227,1293,2799,7841,7842,7843,3826, 607,2306,3827, 762,2878, # 6854 +1439,4221,1360,7844,1485,3052,7845,4507,1038,4222,1450,2061,2638,4223,1379,4508, # 6870 +2585,7846,7847,4224,1352,1414,2325,2921,1172,7848,7849,3828,3829,7850,1797,1451, # 6886 +7851,7852,7853,7854,2922,4006,4007,2485,2346, 411,4008,4009,3582,3300,3101,4509, # 6902 +1561,2664,1452,4010,1375,7855,7856, 47,2959, 316,7857,1406,1591,2923,3156,7858, # 6918 +1025,2141,3102,3157, 354,2731, 884,2224,4225,2407, 508,3706, 726,3583, 996,2428, # 6934 +3584, 729,7859, 392,2191,1453,4011,4510,3707,7860,7861,2458,3585,2608,1675,2800, # 6950 + 919,2347,2960,2348,1270,4511,4012, 73,7862,7863, 647,7864,3228,2843,2255,1550, # 6966 +1346,3006,7865,1332, 883,3479,7866,7867,7868,7869,3301,2765,7870,1212, 831,1347, # 6982 +4226,4512,2326,3830,1863,3053, 720,3831,4513,4514,3832,7871,4227,7872,7873,4515, # 6998 +7874,7875,1798,4516,3708,2609,4517,3586,1645,2371,7876,7877,2924, 669,2208,2665, # 7014 +2429,7878,2879,7879,7880,1028,3229,7881,4228,2408,7882,2256,1353,7883,7884,4518, # 7030 +3158, 518,7885,4013,7886,4229,1960,7887,2142,4230,7888,7889,3007,2349,2350,3833, # 7046 + 516,1833,1454,4014,2699,4231,4519,2225,2610,1971,1129,3587,7890,2766,7891,2961, # 7062 +1422, 577,1470,3008,1524,3373,7892,7893, 432,4232,3054,3480,7894,2586,1455,2508, # 7078 +2226,1972,1175,7895,1020,2732,4015,3481,4520,7896,2733,7897,1743,1361,3055,3482, # 7094 +2639,4016,4233,4521,2290, 895, 924,4234,2170, 331,2243,3056, 166,1627,3057,1098, # 7110 +7898,1232,2880,2227,3374,4522, 657, 403,1196,2372, 542,3709,3375,1600,4235,3483, # 7126 +7899,4523,2767,3230, 576, 530,1362,7900,4524,2533,2666,3710,4017,7901, 842,3834, # 7142 +7902,2801,2031,1014,4018, 213,2700,3376, 665, 621,4236,7903,3711,2925,2430,7904, # 7158 +2431,3302,3588,3377,7905,4237,2534,4238,4525,3589,1682,4239,3484,1380,7906, 724, # 7174 +2277, 600,1670,7907,1337,1233,4526,3103,2244,7908,1621,4527,7909, 651,4240,7910, # 7190 +1612,4241,2611,7911,2844,7912,2734,2307,3058,7913, 716,2459,3059, 174,1255,2701, # 7206 +4019,3590, 548,1320,1398, 728,4020,1574,7914,1890,1197,3060,4021,7915,3061,3062, # 7222 +3712,3591,3713, 747,7916, 635,4242,4528,7917,7918,7919,4243,7920,7921,4529,7922, # 7238 +3378,4530,2432, 451,7923,3714,2535,2072,4244,2735,4245,4022,7924,1764,4531,7925, # 7254 +4246, 350,7926,2278,2390,2486,7927,4247,4023,2245,1434,4024, 488,4532, 458,4248, # 7270 +4025,3715, 771,1330,2391,3835,2568,3159,2159,2409,1553,2667,3160,4249,7928,2487, # 7286 +2881,2612,1720,2702,4250,3379,4533,7929,2536,4251,7930,3231,4252,2768,7931,2015, # 7302 +2736,7932,1155,1017,3716,3836,7933,3303,2308, 201,1864,4253,1430,7934,4026,7935, # 7318 +7936,7937,7938,7939,4254,1604,7940, 414,1865, 371,2587,4534,4535,3485,2016,3104, # 7334 +4536,1708, 960,4255, 887, 389,2171,1536,1663,1721,7941,2228,4027,2351,2926,1580, # 7350 +7942,7943,7944,1744,7945,2537,4537,4538,7946,4539,7947,2073,7948,7949,3592,3380, # 7366 +2882,4256,7950,4257,2640,3381,2802, 673,2703,2460, 709,3486,4028,3593,4258,7951, # 7382 +1148, 502, 634,7952,7953,1204,4540,3594,1575,4541,2613,3717,7954,3718,3105, 948, # 7398 +3232, 121,1745,3837,1110,7955,4259,3063,2509,3009,4029,3719,1151,1771,3838,1488, # 7414 +4030,1986,7956,2433,3487,7957,7958,2093,7959,4260,3839,1213,1407,2803, 531,2737, # 7430 +2538,3233,1011,1537,7960,2769,4261,3106,1061,7961,3720,3721,1866,2883,7962,2017, # 7446 + 120,4262,4263,2062,3595,3234,2309,3840,2668,3382,1954,4542,7963,7964,3488,1047, # 7462 +2704,1266,7965,1368,4543,2845, 649,3383,3841,2539,2738,1102,2846,2669,7966,7967, # 7478 +1999,7968,1111,3596,2962,7969,2488,3842,3597,2804,1854,3384,3722,7970,7971,3385, # 7494 +2410,2884,3304,3235,3598,7972,2569,7973,3599,2805,4031,1460, 856,7974,3600,7975, # 7510 +2885,2963,7976,2886,3843,7977,4264, 632,2510, 875,3844,1697,3845,2291,7978,7979, # 7526 +4544,3010,1239, 580,4545,4265,7980, 914, 936,2074,1190,4032,1039,2123,7981,7982, # 7542 +7983,3386,1473,7984,1354,4266,3846,7985,2172,3064,4033, 915,3305,4267,4268,3306, # 7558 +1605,1834,7986,2739, 398,3601,4269,3847,4034, 328,1912,2847,4035,3848,1331,4270, # 7574 +3011, 937,4271,7987,3602,4036,4037,3387,2160,4546,3388, 524, 742, 538,3065,1012, # 7590 +7988,7989,3849,2461,7990, 658,1103, 225,3850,7991,7992,4547,7993,4548,7994,3236, # 7606 +1243,7995,4038, 963,2246,4549,7996,2705,3603,3161,7997,7998,2588,2327,7999,4550, # 7622 +8000,8001,8002,3489,3307, 957,3389,2540,2032,1930,2927,2462, 870,2018,3604,1746, # 7638 +2770,2771,2434,2463,8003,3851,8004,3723,3107,3724,3490,3390,3725,8005,1179,3066, # 7654 +8006,3162,2373,4272,3726,2541,3163,3108,2740,4039,8007,3391,1556,2542,2292, 977, # 7670 +2887,2033,4040,1205,3392,8008,1765,3393,3164,2124,1271,1689, 714,4551,3491,8009, # 7686 +2328,3852, 533,4273,3605,2181, 617,8010,2464,3308,3492,2310,8011,8012,3165,8013, # 7702 +8014,3853,1987, 618, 427,2641,3493,3394,8015,8016,1244,1690,8017,2806,4274,4552, # 7718 +8018,3494,8019,8020,2279,1576, 473,3606,4275,3395, 972,8021,3607,8022,3067,8023, # 7734 +8024,4553,4554,8025,3727,4041,4042,8026, 153,4555, 356,8027,1891,2888,4276,2143, # 7750 + 408, 803,2352,8028,3854,8029,4277,1646,2570,2511,4556,4557,3855,8030,3856,4278, # 7766 +8031,2411,3396, 752,8032,8033,1961,2964,8034, 746,3012,2465,8035,4279,3728, 698, # 7782 +4558,1892,4280,3608,2543,4559,3609,3857,8036,3166,3397,8037,1823,1302,4043,2706, # 7798 +3858,1973,4281,8038,4282,3167, 823,1303,1288,1236,2848,3495,4044,3398, 774,3859, # 7814 +8039,1581,4560,1304,2849,3860,4561,8040,2435,2161,1083,3237,4283,4045,4284, 344, # 7830 +1173, 288,2311, 454,1683,8041,8042,1461,4562,4046,2589,8043,8044,4563, 985, 894, # 7846 +8045,3399,3168,8046,1913,2928,3729,1988,8047,2110,1974,8048,4047,8049,2571,1194, # 7862 + 425,8050,4564,3169,1245,3730,4285,8051,8052,2850,8053, 636,4565,1855,3861, 760, # 7878 +1799,8054,4286,2209,1508,4566,4048,1893,1684,2293,8055,8056,8057,4287,4288,2210, # 7894 + 479,8058,8059, 832,8060,4049,2489,8061,2965,2490,3731, 990,3109, 627,1814,2642, # 7910 +4289,1582,4290,2125,2111,3496,4567,8062, 799,4291,3170,8063,4568,2112,1737,3013, # 7926 +1018, 543, 754,4292,3309,1676,4569,4570,4050,8064,1489,8065,3497,8066,2614,2889, # 7942 +4051,8067,8068,2966,8069,8070,8071,8072,3171,4571,4572,2182,1722,8073,3238,3239, # 7958 +1842,3610,1715, 481, 365,1975,1856,8074,8075,1962,2491,4573,8076,2126,3611,3240, # 7974 + 433,1894,2063,2075,8077, 602,2741,8078,8079,8080,8081,8082,3014,1628,3400,8083, # 7990 +3172,4574,4052,2890,4575,2512,8084,2544,2772,8085,8086,8087,3310,4576,2891,8088, # 8006 +4577,8089,2851,4578,4579,1221,2967,4053,2513,8090,8091,8092,1867,1989,8093,8094, # 8022 +8095,1895,8096,8097,4580,1896,4054, 318,8098,2094,4055,4293,8099,8100, 485,8101, # 8038 + 938,3862, 553,2670, 116,8102,3863,3612,8103,3498,2671,2773,3401,3311,2807,8104, # 8054 +3613,2929,4056,1747,2930,2968,8105,8106, 207,8107,8108,2672,4581,2514,8109,3015, # 8070 + 890,3614,3864,8110,1877,3732,3402,8111,2183,2353,3403,1652,8112,8113,8114, 941, # 8086 +2294, 208,3499,4057,2019, 330,4294,3865,2892,2492,3733,4295,8115,8116,8117,8118, # 8102 +) + diff --git a/venv/lib/python2.7/site-packages/chardet/euctwprober.py b/venv/lib/python2.7/site-packages/chardet/euctwprober.py new file mode 100644 index 0000000..35669cc --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/euctwprober.py @@ -0,0 +1,46 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import EUCTWDistributionAnalysis +from .mbcssm import EUCTW_SM_MODEL + +class EUCTWProber(MultiByteCharSetProber): + def __init__(self): + super(EUCTWProber, self).__init__() + self.coding_sm = CodingStateMachine(EUCTW_SM_MODEL) + self.distribution_analyzer = EUCTWDistributionAnalysis() + self.reset() + + @property + def charset_name(self): + return "EUC-TW" + + @property + def language(self): + return "Taiwan" diff --git a/venv/lib/python2.7/site-packages/chardet/gb2312freq.py b/venv/lib/python2.7/site-packages/chardet/gb2312freq.py new file mode 100644 index 0000000..697837b --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/gb2312freq.py @@ -0,0 +1,283 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# GB2312 most frequently used character table +# +# Char to FreqOrder table , from hz6763 + +# 512 --> 0.79 -- 0.79 +# 1024 --> 0.92 -- 0.13 +# 2048 --> 0.98 -- 0.06 +# 6768 --> 1.00 -- 0.02 +# +# Ideal Distribution Ratio = 0.79135/(1-0.79135) = 3.79 +# Random Distribution Ration = 512 / (3755 - 512) = 0.157 +# +# Typical Distribution Ratio about 25% of Ideal one, still much higher that RDR + +GB2312_TYPICAL_DISTRIBUTION_RATIO = 0.9 + +GB2312_TABLE_SIZE = 3760 + +GB2312_CHAR_TO_FREQ_ORDER = ( +1671, 749,1443,2364,3924,3807,2330,3921,1704,3463,2691,1511,1515, 572,3191,2205, +2361, 224,2558, 479,1711, 963,3162, 440,4060,1905,2966,2947,3580,2647,3961,3842, +2204, 869,4207, 970,2678,5626,2944,2956,1479,4048, 514,3595, 588,1346,2820,3409, + 249,4088,1746,1873,2047,1774, 581,1813, 358,1174,3590,1014,1561,4844,2245, 670, +1636,3112, 889,1286, 953, 556,2327,3060,1290,3141, 613, 185,3477,1367, 850,3820, +1715,2428,2642,2303,2732,3041,2562,2648,3566,3946,1349, 388,3098,2091,1360,3585, + 152,1687,1539, 738,1559, 59,1232,2925,2267,1388,1249,1741,1679,2960, 151,1566, +1125,1352,4271, 924,4296, 385,3166,4459, 310,1245,2850, 70,3285,2729,3534,3575, +2398,3298,3466,1960,2265, 217,3647, 864,1909,2084,4401,2773,1010,3269,5152, 853, +3051,3121,1244,4251,1895, 364,1499,1540,2313,1180,3655,2268, 562, 715,2417,3061, + 544, 336,3768,2380,1752,4075, 950, 280,2425,4382, 183,2759,3272, 333,4297,2155, +1688,2356,1444,1039,4540, 736,1177,3349,2443,2368,2144,2225, 565, 196,1482,3406, + 927,1335,4147, 692, 878,1311,1653,3911,3622,1378,4200,1840,2969,3149,2126,1816, +2534,1546,2393,2760, 737,2494, 13, 447, 245,2747, 38,2765,2129,2589,1079, 606, + 360, 471,3755,2890, 404, 848, 699,1785,1236, 370,2221,1023,3746,2074,2026,2023, +2388,1581,2119, 812,1141,3091,2536,1519, 804,2053, 406,1596,1090, 784, 548,4414, +1806,2264,2936,1100, 343,4114,5096, 622,3358, 743,3668,1510,1626,5020,3567,2513, +3195,4115,5627,2489,2991, 24,2065,2697,1087,2719, 48,1634, 315, 68, 985,2052, + 198,2239,1347,1107,1439, 597,2366,2172, 871,3307, 919,2487,2790,1867, 236,2570, +1413,3794, 906,3365,3381,1701,1982,1818,1524,2924,1205, 616,2586,2072,2004, 575, + 253,3099, 32,1365,1182, 197,1714,2454,1201, 554,3388,3224,2748, 756,2587, 250, +2567,1507,1517,3529,1922,2761,2337,3416,1961,1677,2452,2238,3153, 615, 911,1506, +1474,2495,1265,1906,2749,3756,3280,2161, 898,2714,1759,3450,2243,2444, 563, 26, +3286,2266,3769,3344,2707,3677, 611,1402, 531,1028,2871,4548,1375, 261,2948, 835, +1190,4134, 353, 840,2684,1900,3082,1435,2109,1207,1674, 329,1872,2781,4055,2686, +2104, 608,3318,2423,2957,2768,1108,3739,3512,3271,3985,2203,1771,3520,1418,2054, +1681,1153, 225,1627,2929, 162,2050,2511,3687,1954, 124,1859,2431,1684,3032,2894, + 585,4805,3969,2869,2704,2088,2032,2095,3656,2635,4362,2209, 256, 518,2042,2105, +3777,3657, 643,2298,1148,1779, 190, 989,3544, 414, 11,2135,2063,2979,1471, 403, +3678, 126, 770,1563, 671,2499,3216,2877, 600,1179, 307,2805,4937,1268,1297,2694, + 252,4032,1448,1494,1331,1394, 127,2256, 222,1647,1035,1481,3056,1915,1048, 873, +3651, 210, 33,1608,2516, 200,1520, 415, 102, 0,3389,1287, 817, 91,3299,2940, + 836,1814, 549,2197,1396,1669,2987,3582,2297,2848,4528,1070, 687, 20,1819, 121, +1552,1364,1461,1968,2617,3540,2824,2083, 177, 948,4938,2291, 110,4549,2066, 648, +3359,1755,2110,2114,4642,4845,1693,3937,3308,1257,1869,2123, 208,1804,3159,2992, +2531,2549,3361,2418,1350,2347,2800,2568,1291,2036,2680, 72, 842,1990, 212,1233, +1154,1586, 75,2027,3410,4900,1823,1337,2710,2676, 728,2810,1522,3026,4995, 157, + 755,1050,4022, 710, 785,1936,2194,2085,1406,2777,2400, 150,1250,4049,1206, 807, +1910, 534, 529,3309,1721,1660, 274, 39,2827, 661,2670,1578, 925,3248,3815,1094, +4278,4901,4252, 41,1150,3747,2572,2227,4501,3658,4902,3813,3357,3617,2884,2258, + 887, 538,4187,3199,1294,2439,3042,2329,2343,2497,1255, 107, 543,1527, 521,3478, +3568, 194,5062, 15, 961,3870,1241,1192,2664, 66,5215,3260,2111,1295,1127,2152, +3805,4135, 901,1164,1976, 398,1278, 530,1460, 748, 904,1054,1966,1426, 53,2909, + 509, 523,2279,1534, 536,1019, 239,1685, 460,2353, 673,1065,2401,3600,4298,2272, +1272,2363, 284,1753,3679,4064,1695, 81, 815,2677,2757,2731,1386, 859, 500,4221, +2190,2566, 757,1006,2519,2068,1166,1455, 337,2654,3203,1863,1682,1914,3025,1252, +1409,1366, 847, 714,2834,2038,3209, 964,2970,1901, 885,2553,1078,1756,3049, 301, +1572,3326, 688,2130,1996,2429,1805,1648,2930,3421,2750,3652,3088, 262,1158,1254, + 389,1641,1812, 526,1719, 923,2073,1073,1902, 468, 489,4625,1140, 857,2375,3070, +3319,2863, 380, 116,1328,2693,1161,2244, 273,1212,1884,2769,3011,1775,1142, 461, +3066,1200,2147,2212, 790, 702,2695,4222,1601,1058, 434,2338,5153,3640, 67,2360, +4099,2502, 618,3472,1329, 416,1132, 830,2782,1807,2653,3211,3510,1662, 192,2124, + 296,3979,1739,1611,3684, 23, 118, 324, 446,1239,1225, 293,2520,3814,3795,2535, +3116, 17,1074, 467,2692,2201, 387,2922, 45,1326,3055,1645,3659,2817, 958, 243, +1903,2320,1339,2825,1784,3289, 356, 576, 865,2315,2381,3377,3916,1088,3122,1713, +1655, 935, 628,4689,1034,1327, 441, 800, 720, 894,1979,2183,1528,5289,2702,1071, +4046,3572,2399,1571,3281, 79, 761,1103, 327, 134, 758,1899,1371,1615, 879, 442, + 215,2605,2579, 173,2048,2485,1057,2975,3317,1097,2253,3801,4263,1403,1650,2946, + 814,4968,3487,1548,2644,1567,1285, 2, 295,2636, 97, 946,3576, 832, 141,4257, +3273, 760,3821,3521,3156,2607, 949,1024,1733,1516,1803,1920,2125,2283,2665,3180, +1501,2064,3560,2171,1592, 803,3518,1416, 732,3897,4258,1363,1362,2458, 119,1427, + 602,1525,2608,1605,1639,3175, 694,3064, 10, 465, 76,2000,4846,4208, 444,3781, +1619,3353,2206,1273,3796, 740,2483, 320,1723,2377,3660,2619,1359,1137,1762,1724, +2345,2842,1850,1862, 912, 821,1866, 612,2625,1735,2573,3369,1093, 844, 89, 937, + 930,1424,3564,2413,2972,1004,3046,3019,2011, 711,3171,1452,4178, 428, 801,1943, + 432, 445,2811, 206,4136,1472, 730, 349, 73, 397,2802,2547, 998,1637,1167, 789, + 396,3217, 154,1218, 716,1120,1780,2819,4826,1931,3334,3762,2139,1215,2627, 552, +3664,3628,3232,1405,2383,3111,1356,2652,3577,3320,3101,1703, 640,1045,1370,1246, +4996, 371,1575,2436,1621,2210, 984,4033,1734,2638, 16,4529, 663,2755,3255,1451, +3917,2257,1253,1955,2234,1263,2951, 214,1229, 617, 485, 359,1831,1969, 473,2310, + 750,2058, 165, 80,2864,2419, 361,4344,2416,2479,1134, 796,3726,1266,2943, 860, +2715, 938, 390,2734,1313,1384, 248, 202, 877,1064,2854, 522,3907, 279,1602, 297, +2357, 395,3740, 137,2075, 944,4089,2584,1267,3802, 62,1533,2285, 178, 176, 780, +2440, 201,3707, 590, 478,1560,4354,2117,1075, 30, 74,4643,4004,1635,1441,2745, + 776,2596, 238,1077,1692,1912,2844, 605, 499,1742,3947, 241,3053, 980,1749, 936, +2640,4511,2582, 515,1543,2162,5322,2892,2993, 890,2148,1924, 665,1827,3581,1032, + 968,3163, 339,1044,1896, 270, 583,1791,1720,4367,1194,3488,3669, 43,2523,1657, + 163,2167, 290,1209,1622,3378, 550, 634,2508,2510, 695,2634,2384,2512,1476,1414, + 220,1469,2341,2138,2852,3183,2900,4939,2865,3502,1211,3680, 854,3227,1299,2976, +3172, 186,2998,1459, 443,1067,3251,1495, 321,1932,3054, 909, 753,1410,1828, 436, +2441,1119,1587,3164,2186,1258, 227, 231,1425,1890,3200,3942, 247, 959, 725,5254, +2741, 577,2158,2079, 929, 120, 174, 838,2813, 591,1115, 417,2024, 40,3240,1536, +1037, 291,4151,2354, 632,1298,2406,2500,3535,1825,1846,3451, 205,1171, 345,4238, + 18,1163, 811, 685,2208,1217, 425,1312,1508,1175,4308,2552,1033, 587,1381,3059, +2984,3482, 340,1316,4023,3972, 792,3176, 519, 777,4690, 918, 933,4130,2981,3741, + 90,3360,2911,2200,5184,4550, 609,3079,2030, 272,3379,2736, 363,3881,1130,1447, + 286, 779, 357,1169,3350,3137,1630,1220,2687,2391, 747,1277,3688,2618,2682,2601, +1156,3196,5290,4034,3102,1689,3596,3128, 874, 219,2783, 798, 508,1843,2461, 269, +1658,1776,1392,1913,2983,3287,2866,2159,2372, 829,4076, 46,4253,2873,1889,1894, + 915,1834,1631,2181,2318, 298, 664,2818,3555,2735, 954,3228,3117, 527,3511,2173, + 681,2712,3033,2247,2346,3467,1652, 155,2164,3382, 113,1994, 450, 899, 494, 994, +1237,2958,1875,2336,1926,3727, 545,1577,1550, 633,3473, 204,1305,3072,2410,1956, +2471, 707,2134, 841,2195,2196,2663,3843,1026,4940, 990,3252,4997, 368,1092, 437, +3212,3258,1933,1829, 675,2977,2893, 412, 943,3723,4644,3294,3283,2230,2373,5154, +2389,2241,2661,2323,1404,2524, 593, 787, 677,3008,1275,2059, 438,2709,2609,2240, +2269,2246,1446, 36,1568,1373,3892,1574,2301,1456,3962, 693,2276,5216,2035,1143, +2720,1919,1797,1811,2763,4137,2597,1830,1699,1488,1198,2090, 424,1694, 312,3634, +3390,4179,3335,2252,1214, 561,1059,3243,2295,2561, 975,5155,2321,2751,3772, 472, +1537,3282,3398,1047,2077,2348,2878,1323,3340,3076, 690,2906, 51, 369, 170,3541, +1060,2187,2688,3670,2541,1083,1683, 928,3918, 459, 109,4427, 599,3744,4286, 143, +2101,2730,2490, 82,1588,3036,2121, 281,1860, 477,4035,1238,2812,3020,2716,3312, +1530,2188,2055,1317, 843, 636,1808,1173,3495, 649, 181,1002, 147,3641,1159,2414, +3750,2289,2795, 813,3123,2610,1136,4368, 5,3391,4541,2174, 420, 429,1728, 754, +1228,2115,2219, 347,2223,2733, 735,1518,3003,2355,3134,1764,3948,3329,1888,2424, +1001,1234,1972,3321,3363,1672,1021,1450,1584, 226, 765, 655,2526,3404,3244,2302, +3665, 731, 594,2184, 319,1576, 621, 658,2656,4299,2099,3864,1279,2071,2598,2739, + 795,3086,3699,3908,1707,2352,2402,1382,3136,2475,1465,4847,3496,3865,1085,3004, +2591,1084, 213,2287,1963,3565,2250, 822, 793,4574,3187,1772,1789,3050, 595,1484, +1959,2770,1080,2650, 456, 422,2996, 940,3322,4328,4345,3092,2742, 965,2784, 739, +4124, 952,1358,2498,2949,2565, 332,2698,2378, 660,2260,2473,4194,3856,2919, 535, +1260,2651,1208,1428,1300,1949,1303,2942, 433,2455,2450,1251,1946, 614,1269, 641, +1306,1810,2737,3078,2912, 564,2365,1419,1415,1497,4460,2367,2185,1379,3005,1307, +3218,2175,1897,3063, 682,1157,4040,4005,1712,1160,1941,1399, 394, 402,2952,1573, +1151,2986,2404, 862, 299,2033,1489,3006, 346, 171,2886,3401,1726,2932, 168,2533, + 47,2507,1030,3735,1145,3370,1395,1318,1579,3609,4560,2857,4116,1457,2529,1965, + 504,1036,2690,2988,2405, 745,5871, 849,2397,2056,3081, 863,2359,3857,2096, 99, +1397,1769,2300,4428,1643,3455,1978,1757,3718,1440, 35,4879,3742,1296,4228,2280, + 160,5063,1599,2013, 166, 520,3479,1646,3345,3012, 490,1937,1545,1264,2182,2505, +1096,1188,1369,1436,2421,1667,2792,2460,1270,2122, 727,3167,2143, 806,1706,1012, +1800,3037, 960,2218,1882, 805, 139,2456,1139,1521, 851,1052,3093,3089, 342,2039, + 744,5097,1468,1502,1585,2087, 223, 939, 326,2140,2577, 892,2481,1623,4077, 982, +3708, 135,2131, 87,2503,3114,2326,1106, 876,1616, 547,2997,2831,2093,3441,4530, +4314, 9,3256,4229,4148, 659,1462,1986,1710,2046,2913,2231,4090,4880,5255,3392, +3274,1368,3689,4645,1477, 705,3384,3635,1068,1529,2941,1458,3782,1509, 100,1656, +2548, 718,2339, 408,1590,2780,3548,1838,4117,3719,1345,3530, 717,3442,2778,3220, +2898,1892,4590,3614,3371,2043,1998,1224,3483, 891, 635, 584,2559,3355, 733,1766, +1729,1172,3789,1891,2307, 781,2982,2271,1957,1580,5773,2633,2005,4195,3097,1535, +3213,1189,1934,5693,3262, 586,3118,1324,1598, 517,1564,2217,1868,1893,4445,3728, +2703,3139,1526,1787,1992,3882,2875,1549,1199,1056,2224,1904,2711,5098,4287, 338, +1993,3129,3489,2689,1809,2815,1997, 957,1855,3898,2550,3275,3057,1105,1319, 627, +1505,1911,1883,3526, 698,3629,3456,1833,1431, 746, 77,1261,2017,2296,1977,1885, + 125,1334,1600, 525,1798,1109,2222,1470,1945, 559,2236,1186,3443,2476,1929,1411, +2411,3135,1777,3372,2621,1841,1613,3229, 668,1430,1839,2643,2916, 195,1989,2671, +2358,1387, 629,3205,2293,5256,4439, 123,1310, 888,1879,4300,3021,3605,1003,1162, +3192,2910,2010, 140,2395,2859, 55,1082,2012,2901, 662, 419,2081,1438, 680,2774, +4654,3912,1620,1731,1625,5035,4065,2328, 512,1344, 802,5443,2163,2311,2537, 524, +3399, 98,1155,2103,1918,2606,3925,2816,1393,2465,1504,3773,2177,3963,1478,4346, + 180,1113,4655,3461,2028,1698, 833,2696,1235,1322,1594,4408,3623,3013,3225,2040, +3022, 541,2881, 607,3632,2029,1665,1219, 639,1385,1686,1099,2803,3231,1938,3188, +2858, 427, 676,2772,1168,2025, 454,3253,2486,3556, 230,1950, 580, 791,1991,1280, +1086,1974,2034, 630, 257,3338,2788,4903,1017, 86,4790, 966,2789,1995,1696,1131, + 259,3095,4188,1308, 179,1463,5257, 289,4107,1248, 42,3413,1725,2288, 896,1947, + 774,4474,4254, 604,3430,4264, 392,2514,2588, 452, 237,1408,3018, 988,4531,1970, +3034,3310, 540,2370,1562,1288,2990, 502,4765,1147, 4,1853,2708, 207, 294,2814, +4078,2902,2509, 684, 34,3105,3532,2551, 644, 709,2801,2344, 573,1727,3573,3557, +2021,1081,3100,4315,2100,3681, 199,2263,1837,2385, 146,3484,1195,2776,3949, 997, +1939,3973,1008,1091,1202,1962,1847,1149,4209,5444,1076, 493, 117,5400,2521, 972, +1490,2934,1796,4542,2374,1512,2933,2657, 413,2888,1135,2762,2314,2156,1355,2369, + 766,2007,2527,2170,3124,2491,2593,2632,4757,2437, 234,3125,3591,1898,1750,1376, +1942,3468,3138, 570,2127,2145,3276,4131, 962, 132,1445,4196, 19, 941,3624,3480, +3366,1973,1374,4461,3431,2629, 283,2415,2275, 808,2887,3620,2112,2563,1353,3610, + 955,1089,3103,1053, 96, 88,4097, 823,3808,1583, 399, 292,4091,3313, 421,1128, + 642,4006, 903,2539,1877,2082, 596, 29,4066,1790, 722,2157, 130, 995,1569, 769, +1485, 464, 513,2213, 288,1923,1101,2453,4316, 133, 486,2445, 50, 625, 487,2207, + 57, 423, 481,2962, 159,3729,1558, 491, 303, 482, 501, 240,2837, 112,3648,2392, +1783, 362, 8,3433,3422, 610,2793,3277,1390,1284,1654, 21,3823, 734, 367, 623, + 193, 287, 374,1009,1483, 816, 476, 313,2255,2340,1262,2150,2899,1146,2581, 782, +2116,1659,2018,1880, 255,3586,3314,1110,2867,2137,2564, 986,2767,5185,2006, 650, + 158, 926, 762, 881,3157,2717,2362,3587, 306,3690,3245,1542,3077,2427,1691,2478, +2118,2985,3490,2438, 539,2305, 983, 129,1754, 355,4201,2386, 827,2923, 104,1773, +2838,2771, 411,2905,3919, 376, 767, 122,1114, 828,2422,1817,3506, 266,3460,1007, +1609,4998, 945,2612,4429,2274, 726,1247,1964,2914,2199,2070,4002,4108, 657,3323, +1422, 579, 455,2764,4737,1222,2895,1670, 824,1223,1487,2525, 558, 861,3080, 598, +2659,2515,1967, 752,2583,2376,2214,4180, 977, 704,2464,4999,2622,4109,1210,2961, + 819,1541, 142,2284, 44, 418, 457,1126,3730,4347,4626,1644,1876,3671,1864, 302, +1063,5694, 624, 723,1984,3745,1314,1676,2488,1610,1449,3558,3569,2166,2098, 409, +1011,2325,3704,2306, 818,1732,1383,1824,1844,3757, 999,2705,3497,1216,1423,2683, +2426,2954,2501,2726,2229,1475,2554,5064,1971,1794,1666,2014,1343, 783, 724, 191, +2434,1354,2220,5065,1763,2752,2472,4152, 131, 175,2885,3434, 92,1466,4920,2616, +3871,3872,3866, 128,1551,1632, 669,1854,3682,4691,4125,1230, 188,2973,3290,1302, +1213, 560,3266, 917, 763,3909,3249,1760, 868,1958, 764,1782,2097, 145,2277,3774, +4462, 64,1491,3062, 971,2132,3606,2442, 221,1226,1617, 218, 323,1185,3207,3147, + 571, 619,1473,1005,1744,2281, 449,1887,2396,3685, 275, 375,3816,1743,3844,3731, + 845,1983,2350,4210,1377, 773, 967,3499,3052,3743,2725,4007,1697,1022,3943,1464, +3264,2855,2722,1952,1029,2839,2467, 84,4383,2215, 820,1391,2015,2448,3672, 377, +1948,2168, 797,2545,3536,2578,2645, 94,2874,1678, 405,1259,3071, 771, 546,1315, + 470,1243,3083, 895,2468, 981, 969,2037, 846,4181, 653,1276,2928, 14,2594, 557, +3007,2474, 156, 902,1338,1740,2574, 537,2518, 973,2282,2216,2433,1928, 138,2903, +1293,2631,1612, 646,3457, 839,2935, 111, 496,2191,2847, 589,3186, 149,3994,2060, +4031,2641,4067,3145,1870, 37,3597,2136,1025,2051,3009,3383,3549,1121,1016,3261, +1301, 251,2446,2599,2153, 872,3246, 637, 334,3705, 831, 884, 921,3065,3140,4092, +2198,1944, 246,2964, 108,2045,1152,1921,2308,1031, 203,3173,4170,1907,3890, 810, +1401,2003,1690, 506, 647,1242,2828,1761,1649,3208,2249,1589,3709,2931,5156,1708, + 498, 666,2613, 834,3817,1231, 184,2851,1124, 883,3197,2261,3710,1765,1553,2658, +1178,2639,2351, 93,1193, 942,2538,2141,4402, 235,1821, 870,1591,2192,1709,1871, +3341,1618,4126,2595,2334, 603, 651, 69, 701, 268,2662,3411,2555,1380,1606, 503, + 448, 254,2371,2646, 574,1187,2309,1770, 322,2235,1292,1801, 305, 566,1133, 229, +2067,2057, 706, 167, 483,2002,2672,3295,1820,3561,3067, 316, 378,2746,3452,1112, + 136,1981, 507,1651,2917,1117, 285,4591, 182,2580,3522,1304, 335,3303,1835,2504, +1795,1792,2248, 674,1018,2106,2449,1857,2292,2845, 976,3047,1781,2600,2727,1389, +1281, 52,3152, 153, 265,3950, 672,3485,3951,4463, 430,1183, 365, 278,2169, 27, +1407,1336,2304, 209,1340,1730,2202,1852,2403,2883, 979,1737,1062, 631,2829,2542, +3876,2592, 825,2086,2226,3048,3625, 352,1417,3724, 542, 991, 431,1351,3938,1861, +2294, 826,1361,2927,3142,3503,1738, 463,2462,2723, 582,1916,1595,2808, 400,3845, +3891,2868,3621,2254, 58,2492,1123, 910,2160,2614,1372,1603,1196,1072,3385,1700, +3267,1980, 696, 480,2430, 920, 799,1570,2920,1951,2041,4047,2540,1321,4223,2469, +3562,2228,1271,2602, 401,2833,3351,2575,5157, 907,2312,1256, 410, 263,3507,1582, + 996, 678,1849,2316,1480, 908,3545,2237, 703,2322, 667,1826,2849,1531,2604,2999, +2407,3146,2151,2630,1786,3711, 469,3542, 497,3899,2409, 858, 837,4446,3393,1274, + 786, 620,1845,2001,3311, 484, 308,3367,1204,1815,3691,2332,1532,2557,1842,2020, +2724,1927,2333,4440, 567, 22,1673,2728,4475,1987,1858,1144,1597, 101,1832,3601, + 12, 974,3783,4391, 951,1412, 1,3720, 453,4608,4041, 528,1041,1027,3230,2628, +1129, 875,1051,3291,1203,2262,1069,2860,2799,2149,2615,3278, 144,1758,3040, 31, + 475,1680, 366,2685,3184, 311,1642,4008,2466,5036,1593,1493,2809, 216,1420,1668, + 233, 304,2128,3284, 232,1429,1768,1040,2008,3407,2740,2967,2543, 242,2133, 778, +1565,2022,2620, 505,2189,2756,1098,2273, 372,1614, 708, 553,2846,2094,2278, 169, +3626,2835,4161, 228,2674,3165, 809,1454,1309, 466,1705,1095, 900,3423, 880,2667, +3751,5258,2317,3109,2571,4317,2766,1503,1342, 866,4447,1118, 63,2076, 314,1881, +1348,1061, 172, 978,3515,1747, 532, 511,3970, 6, 601, 905,2699,3300,1751, 276, +1467,3725,2668, 65,4239,2544,2779,2556,1604, 578,2451,1802, 992,2331,2624,1320, +3446, 713,1513,1013, 103,2786,2447,1661, 886,1702, 916, 654,3574,2031,1556, 751, +2178,2821,2179,1498,1538,2176, 271, 914,2251,2080,1325, 638,1953,2937,3877,2432, +2754, 95,3265,1716, 260,1227,4083, 775, 106,1357,3254, 426,1607, 555,2480, 772, +1985, 244,2546, 474, 495,1046,2611,1851,2061, 71,2089,1675,2590, 742,3758,2843, +3222,1433, 267,2180,2576,2826,2233,2092,3913,2435, 956,1745,3075, 856,2113,1116, + 451, 3,1988,2896,1398, 993,2463,1878,2049,1341,2718,2721,2870,2108, 712,2904, +4363,2753,2324, 277,2872,2349,2649, 384, 987, 435, 691,3000, 922, 164,3939, 652, +1500,1184,4153,2482,3373,2165,4848,2335,3775,3508,3154,2806,2830,1554,2102,1664, +2530,1434,2408, 893,1547,2623,3447,2832,2242,2532,3169,2856,3223,2078, 49,3770, +3469, 462, 318, 656,2259,3250,3069, 679,1629,2758, 344,1138,1104,3120,1836,1283, +3115,2154,1437,4448, 934, 759,1999, 794,2862,1038, 533,2560,1722,2342, 855,2626, +1197,1663,4476,3127, 85,4240,2528, 25,1111,1181,3673, 407,3470,4561,2679,2713, + 768,1925,2841,3986,1544,1165, 932, 373,1240,2146,1930,2673, 721,4766, 354,4333, + 391,2963, 187, 61,3364,1442,1102, 330,1940,1767, 341,3809,4118, 393,2496,2062, +2211, 105, 331, 300, 439, 913,1332, 626, 379,3304,1557, 328, 689,3952, 309,1555, + 931, 317,2517,3027, 325, 569, 686,2107,3084, 60,1042,1333,2794, 264,3177,4014, +1628, 258,3712, 7,4464,1176,1043,1778, 683, 114,1975, 78,1492, 383,1886, 510, + 386, 645,5291,2891,2069,3305,4138,3867,2939,2603,2493,1935,1066,1848,3588,1015, +1282,1289,4609, 697,1453,3044,2666,3611,1856,2412, 54, 719,1330, 568,3778,2459, +1748, 788, 492, 551,1191,1000, 488,3394,3763, 282,1799, 348,2016,1523,3155,2390, +1049, 382,2019,1788,1170, 729,2968,3523, 897,3926,2785,2938,3292, 350,2319,3238, +1718,1717,2655,3453,3143,4465, 161,2889,2980,2009,1421, 56,1908,1640,2387,2232, +1917,1874,2477,4921, 148, 83,3438, 592,4245,2882,1822,1055, 741, 115,1496,1624, + 381,1638,4592,1020, 516,3214, 458, 947,4575,1432, 211,1514,2926,1865,2142, 189, + 852,1221,1400,1486, 882,2299,4036, 351, 28,1122, 700,6479,6480,6481,6482,6483, #last 512 +) + diff --git a/venv/lib/python2.7/site-packages/chardet/gb2312prober.py b/venv/lib/python2.7/site-packages/chardet/gb2312prober.py new file mode 100644 index 0000000..8446d2d --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/gb2312prober.py @@ -0,0 +1,46 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import GB2312DistributionAnalysis +from .mbcssm import GB2312_SM_MODEL + +class GB2312Prober(MultiByteCharSetProber): + def __init__(self): + super(GB2312Prober, self).__init__() + self.coding_sm = CodingStateMachine(GB2312_SM_MODEL) + self.distribution_analyzer = GB2312DistributionAnalysis() + self.reset() + + @property + def charset_name(self): + return "GB2312" + + @property + def language(self): + return "Chinese" diff --git a/venv/lib/python2.7/site-packages/chardet/hebrewprober.py b/venv/lib/python2.7/site-packages/chardet/hebrewprober.py new file mode 100644 index 0000000..b0e1bf4 --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/hebrewprober.py @@ -0,0 +1,292 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Shy Shalom +# Portions created by the Initial Developer are Copyright (C) 2005 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetprober import CharSetProber +from .enums import ProbingState + +# This prober doesn't actually recognize a language or a charset. +# It is a helper prober for the use of the Hebrew model probers + +### General ideas of the Hebrew charset recognition ### +# +# Four main charsets exist in Hebrew: +# "ISO-8859-8" - Visual Hebrew +# "windows-1255" - Logical Hebrew +# "ISO-8859-8-I" - Logical Hebrew +# "x-mac-hebrew" - ?? Logical Hebrew ?? +# +# Both "ISO" charsets use a completely identical set of code points, whereas +# "windows-1255" and "x-mac-hebrew" are two different proper supersets of +# these code points. windows-1255 defines additional characters in the range +# 0x80-0x9F as some misc punctuation marks as well as some Hebrew-specific +# diacritics and additional 'Yiddish' ligature letters in the range 0xc0-0xd6. +# x-mac-hebrew defines similar additional code points but with a different +# mapping. +# +# As far as an average Hebrew text with no diacritics is concerned, all four +# charsets are identical with respect to code points. Meaning that for the +# main Hebrew alphabet, all four map the same values to all 27 Hebrew letters +# (including final letters). +# +# The dominant difference between these charsets is their directionality. +# "Visual" directionality means that the text is ordered as if the renderer is +# not aware of a BIDI rendering algorithm. The renderer sees the text and +# draws it from left to right. The text itself when ordered naturally is read +# backwards. A buffer of Visual Hebrew generally looks like so: +# "[last word of first line spelled backwards] [whole line ordered backwards +# and spelled backwards] [first word of first line spelled backwards] +# [end of line] [last word of second line] ... etc' " +# adding punctuation marks, numbers and English text to visual text is +# naturally also "visual" and from left to right. +# +# "Logical" directionality means the text is ordered "naturally" according to +# the order it is read. It is the responsibility of the renderer to display +# the text from right to left. A BIDI algorithm is used to place general +# punctuation marks, numbers and English text in the text. +# +# Texts in x-mac-hebrew are almost impossible to find on the Internet. From +# what little evidence I could find, it seems that its general directionality +# is Logical. +# +# To sum up all of the above, the Hebrew probing mechanism knows about two +# charsets: +# Visual Hebrew - "ISO-8859-8" - backwards text - Words and sentences are +# backwards while line order is natural. For charset recognition purposes +# the line order is unimportant (In fact, for this implementation, even +# word order is unimportant). +# Logical Hebrew - "windows-1255" - normal, naturally ordered text. +# +# "ISO-8859-8-I" is a subset of windows-1255 and doesn't need to be +# specifically identified. +# "x-mac-hebrew" is also identified as windows-1255. A text in x-mac-hebrew +# that contain special punctuation marks or diacritics is displayed with +# some unconverted characters showing as question marks. This problem might +# be corrected using another model prober for x-mac-hebrew. Due to the fact +# that x-mac-hebrew texts are so rare, writing another model prober isn't +# worth the effort and performance hit. +# +#### The Prober #### +# +# The prober is divided between two SBCharSetProbers and a HebrewProber, +# all of which are managed, created, fed data, inquired and deleted by the +# SBCSGroupProber. The two SBCharSetProbers identify that the text is in +# fact some kind of Hebrew, Logical or Visual. The final decision about which +# one is it is made by the HebrewProber by combining final-letter scores +# with the scores of the two SBCharSetProbers to produce a final answer. +# +# The SBCSGroupProber is responsible for stripping the original text of HTML +# tags, English characters, numbers, low-ASCII punctuation characters, spaces +# and new lines. It reduces any sequence of such characters to a single space. +# The buffer fed to each prober in the SBCS group prober is pure text in +# high-ASCII. +# The two SBCharSetProbers (model probers) share the same language model: +# Win1255Model. +# The first SBCharSetProber uses the model normally as any other +# SBCharSetProber does, to recognize windows-1255, upon which this model was +# built. The second SBCharSetProber is told to make the pair-of-letter +# lookup in the language model backwards. This in practice exactly simulates +# a visual Hebrew model using the windows-1255 logical Hebrew model. +# +# The HebrewProber is not using any language model. All it does is look for +# final-letter evidence suggesting the text is either logical Hebrew or visual +# Hebrew. Disjointed from the model probers, the results of the HebrewProber +# alone are meaningless. HebrewProber always returns 0.00 as confidence +# since it never identifies a charset by itself. Instead, the pointer to the +# HebrewProber is passed to the model probers as a helper "Name Prober". +# When the Group prober receives a positive identification from any prober, +# it asks for the name of the charset identified. If the prober queried is a +# Hebrew model prober, the model prober forwards the call to the +# HebrewProber to make the final decision. In the HebrewProber, the +# decision is made according to the final-letters scores maintained and Both +# model probers scores. The answer is returned in the form of the name of the +# charset identified, either "windows-1255" or "ISO-8859-8". + +class HebrewProber(CharSetProber): + # windows-1255 / ISO-8859-8 code points of interest + FINAL_KAF = 0xea + NORMAL_KAF = 0xeb + FINAL_MEM = 0xed + NORMAL_MEM = 0xee + FINAL_NUN = 0xef + NORMAL_NUN = 0xf0 + FINAL_PE = 0xf3 + NORMAL_PE = 0xf4 + FINAL_TSADI = 0xf5 + NORMAL_TSADI = 0xf6 + + # Minimum Visual vs Logical final letter score difference. + # If the difference is below this, don't rely solely on the final letter score + # distance. + MIN_FINAL_CHAR_DISTANCE = 5 + + # Minimum Visual vs Logical model score difference. + # If the difference is below this, don't rely at all on the model score + # distance. + MIN_MODEL_DISTANCE = 0.01 + + VISUAL_HEBREW_NAME = "ISO-8859-8" + LOGICAL_HEBREW_NAME = "windows-1255" + + def __init__(self): + super(HebrewProber, self).__init__() + self._final_char_logical_score = None + self._final_char_visual_score = None + self._prev = None + self._before_prev = None + self._logical_prober = None + self._visual_prober = None + self.reset() + + def reset(self): + self._final_char_logical_score = 0 + self._final_char_visual_score = 0 + # The two last characters seen in the previous buffer, + # mPrev and mBeforePrev are initialized to space in order to simulate + # a word delimiter at the beginning of the data + self._prev = ' ' + self._before_prev = ' ' + # These probers are owned by the group prober. + + def set_model_probers(self, logicalProber, visualProber): + self._logical_prober = logicalProber + self._visual_prober = visualProber + + def is_final(self, c): + return c in [self.FINAL_KAF, self.FINAL_MEM, self.FINAL_NUN, + self.FINAL_PE, self.FINAL_TSADI] + + def is_non_final(self, c): + # The normal Tsadi is not a good Non-Final letter due to words like + # 'lechotet' (to chat) containing an apostrophe after the tsadi. This + # apostrophe is converted to a space in FilterWithoutEnglishLetters + # causing the Non-Final tsadi to appear at an end of a word even + # though this is not the case in the original text. + # The letters Pe and Kaf rarely display a related behavior of not being + # a good Non-Final letter. Words like 'Pop', 'Winamp' and 'Mubarak' + # for example legally end with a Non-Final Pe or Kaf. However, the + # benefit of these letters as Non-Final letters outweighs the damage + # since these words are quite rare. + return c in [self.NORMAL_KAF, self.NORMAL_MEM, + self.NORMAL_NUN, self.NORMAL_PE] + + def feed(self, byte_str): + # Final letter analysis for logical-visual decision. + # Look for evidence that the received buffer is either logical Hebrew + # or visual Hebrew. + # The following cases are checked: + # 1) A word longer than 1 letter, ending with a final letter. This is + # an indication that the text is laid out "naturally" since the + # final letter really appears at the end. +1 for logical score. + # 2) A word longer than 1 letter, ending with a Non-Final letter. In + # normal Hebrew, words ending with Kaf, Mem, Nun, Pe or Tsadi, + # should not end with the Non-Final form of that letter. Exceptions + # to this rule are mentioned above in isNonFinal(). This is an + # indication that the text is laid out backwards. +1 for visual + # score + # 3) A word longer than 1 letter, starting with a final letter. Final + # letters should not appear at the beginning of a word. This is an + # indication that the text is laid out backwards. +1 for visual + # score. + # + # The visual score and logical score are accumulated throughout the + # text and are finally checked against each other in GetCharSetName(). + # No checking for final letters in the middle of words is done since + # that case is not an indication for either Logical or Visual text. + # + # We automatically filter out all 7-bit characters (replace them with + # spaces) so the word boundary detection works properly. [MAP] + + if self.state == ProbingState.NOT_ME: + # Both model probers say it's not them. No reason to continue. + return ProbingState.NOT_ME + + byte_str = self.filter_high_byte_only(byte_str) + + for cur in byte_str: + if cur == ' ': + # We stand on a space - a word just ended + if self._before_prev != ' ': + # next-to-last char was not a space so self._prev is not a + # 1 letter word + if self.is_final(self._prev): + # case (1) [-2:not space][-1:final letter][cur:space] + self._final_char_logical_score += 1 + elif self.is_non_final(self._prev): + # case (2) [-2:not space][-1:Non-Final letter][ + # cur:space] + self._final_char_visual_score += 1 + else: + # Not standing on a space + if ((self._before_prev == ' ') and + (self.is_final(self._prev)) and (cur != ' ')): + # case (3) [-2:space][-1:final letter][cur:not space] + self._final_char_visual_score += 1 + self._before_prev = self._prev + self._prev = cur + + # Forever detecting, till the end or until both model probers return + # ProbingState.NOT_ME (handled above) + return ProbingState.DETECTING + + @property + def charset_name(self): + # Make the decision: is it Logical or Visual? + # If the final letter score distance is dominant enough, rely on it. + finalsub = self._final_char_logical_score - self._final_char_visual_score + if finalsub >= self.MIN_FINAL_CHAR_DISTANCE: + return self.LOGICAL_HEBREW_NAME + if finalsub <= -self.MIN_FINAL_CHAR_DISTANCE: + return self.VISUAL_HEBREW_NAME + + # It's not dominant enough, try to rely on the model scores instead. + modelsub = (self._logical_prober.get_confidence() + - self._visual_prober.get_confidence()) + if modelsub > self.MIN_MODEL_DISTANCE: + return self.LOGICAL_HEBREW_NAME + if modelsub < -self.MIN_MODEL_DISTANCE: + return self.VISUAL_HEBREW_NAME + + # Still no good, back to final letter distance, maybe it'll save the + # day. + if finalsub < 0.0: + return self.VISUAL_HEBREW_NAME + + # (finalsub > 0 - Logical) or (don't know what to do) default to + # Logical. + return self.LOGICAL_HEBREW_NAME + + @property + def language(self): + return 'Hebrew' + + @property + def state(self): + # Remain active as long as any of the model probers are active. + if (self._logical_prober.state == ProbingState.NOT_ME) and \ + (self._visual_prober.state == ProbingState.NOT_ME): + return ProbingState.NOT_ME + return ProbingState.DETECTING diff --git a/venv/lib/python2.7/site-packages/chardet/jisfreq.py b/venv/lib/python2.7/site-packages/chardet/jisfreq.py new file mode 100644 index 0000000..83fc082 --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/jisfreq.py @@ -0,0 +1,325 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# Sampling from about 20M text materials include literature and computer technology +# +# Japanese frequency table, applied to both S-JIS and EUC-JP +# They are sorted in order. + +# 128 --> 0.77094 +# 256 --> 0.85710 +# 512 --> 0.92635 +# 1024 --> 0.97130 +# 2048 --> 0.99431 +# +# Ideal Distribution Ratio = 0.92635 / (1-0.92635) = 12.58 +# Random Distribution Ration = 512 / (2965+62+83+86-512) = 0.191 +# +# Typical Distribution Ratio, 25% of IDR + +JIS_TYPICAL_DISTRIBUTION_RATIO = 3.0 + +# Char to FreqOrder table , +JIS_TABLE_SIZE = 4368 + +JIS_CHAR_TO_FREQ_ORDER = ( + 40, 1, 6, 182, 152, 180, 295,2127, 285, 381,3295,4304,3068,4606,3165,3510, # 16 +3511,1822,2785,4607,1193,2226,5070,4608, 171,2996,1247, 18, 179,5071, 856,1661, # 32 +1262,5072, 619, 127,3431,3512,3230,1899,1700, 232, 228,1294,1298, 284, 283,2041, # 48 +2042,1061,1062, 48, 49, 44, 45, 433, 434,1040,1041, 996, 787,2997,1255,4305, # 64 +2108,4609,1684,1648,5073,5074,5075,5076,5077,5078,3687,5079,4610,5080,3927,3928, # 80 +5081,3296,3432, 290,2285,1471,2187,5082,2580,2825,1303,2140,1739,1445,2691,3375, # 96 +1691,3297,4306,4307,4611, 452,3376,1182,2713,3688,3069,4308,5083,5084,5085,5086, # 112 +5087,5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,5099,5100,5101,5102, # 128 +5103,5104,5105,5106,5107,5108,5109,5110,5111,5112,4097,5113,5114,5115,5116,5117, # 144 +5118,5119,5120,5121,5122,5123,5124,5125,5126,5127,5128,5129,5130,5131,5132,5133, # 160 +5134,5135,5136,5137,5138,5139,5140,5141,5142,5143,5144,5145,5146,5147,5148,5149, # 176 +5150,5151,5152,4612,5153,5154,5155,5156,5157,5158,5159,5160,5161,5162,5163,5164, # 192 +5165,5166,5167,5168,5169,5170,5171,5172,5173,5174,5175,1472, 598, 618, 820,1205, # 208 +1309,1412,1858,1307,1692,5176,5177,5178,5179,5180,5181,5182,1142,1452,1234,1172, # 224 +1875,2043,2149,1793,1382,2973, 925,2404,1067,1241, 960,1377,2935,1491, 919,1217, # 240 +1865,2030,1406,1499,2749,4098,5183,5184,5185,5186,5187,5188,2561,4099,3117,1804, # 256 +2049,3689,4309,3513,1663,5189,3166,3118,3298,1587,1561,3433,5190,3119,1625,2998, # 272 +3299,4613,1766,3690,2786,4614,5191,5192,5193,5194,2161, 26,3377, 2,3929, 20, # 288 +3691, 47,4100, 50, 17, 16, 35, 268, 27, 243, 42, 155, 24, 154, 29, 184, # 304 + 4, 91, 14, 92, 53, 396, 33, 289, 9, 37, 64, 620, 21, 39, 321, 5, # 320 + 12, 11, 52, 13, 3, 208, 138, 0, 7, 60, 526, 141, 151,1069, 181, 275, # 336 +1591, 83, 132,1475, 126, 331, 829, 15, 69, 160, 59, 22, 157, 55,1079, 312, # 352 + 109, 38, 23, 25, 10, 19, 79,5195, 61, 382,1124, 8, 30,5196,5197,5198, # 368 +5199,5200,5201,5202,5203,5204,5205,5206, 89, 62, 74, 34,2416, 112, 139, 196, # 384 + 271, 149, 84, 607, 131, 765, 46, 88, 153, 683, 76, 874, 101, 258, 57, 80, # 400 + 32, 364, 121,1508, 169,1547, 68, 235, 145,2999, 41, 360,3027, 70, 63, 31, # 416 + 43, 259, 262,1383, 99, 533, 194, 66, 93, 846, 217, 192, 56, 106, 58, 565, # 432 + 280, 272, 311, 256, 146, 82, 308, 71, 100, 128, 214, 655, 110, 261, 104,1140, # 448 + 54, 51, 36, 87, 67,3070, 185,2618,2936,2020, 28,1066,2390,2059,5207,5208, # 464 +5209,5210,5211,5212,5213,5214,5215,5216,4615,5217,5218,5219,5220,5221,5222,5223, # 480 +5224,5225,5226,5227,5228,5229,5230,5231,5232,5233,5234,5235,5236,3514,5237,5238, # 496 +5239,5240,5241,5242,5243,5244,2297,2031,4616,4310,3692,5245,3071,5246,3598,5247, # 512 +4617,3231,3515,5248,4101,4311,4618,3808,4312,4102,5249,4103,4104,3599,5250,5251, # 528 +5252,5253,5254,5255,5256,5257,5258,5259,5260,5261,5262,5263,5264,5265,5266,5267, # 544 +5268,5269,5270,5271,5272,5273,5274,5275,5276,5277,5278,5279,5280,5281,5282,5283, # 560 +5284,5285,5286,5287,5288,5289,5290,5291,5292,5293,5294,5295,5296,5297,5298,5299, # 576 +5300,5301,5302,5303,5304,5305,5306,5307,5308,5309,5310,5311,5312,5313,5314,5315, # 592 +5316,5317,5318,5319,5320,5321,5322,5323,5324,5325,5326,5327,5328,5329,5330,5331, # 608 +5332,5333,5334,5335,5336,5337,5338,5339,5340,5341,5342,5343,5344,5345,5346,5347, # 624 +5348,5349,5350,5351,5352,5353,5354,5355,5356,5357,5358,5359,5360,5361,5362,5363, # 640 +5364,5365,5366,5367,5368,5369,5370,5371,5372,5373,5374,5375,5376,5377,5378,5379, # 656 +5380,5381, 363, 642,2787,2878,2788,2789,2316,3232,2317,3434,2011, 165,1942,3930, # 672 +3931,3932,3933,5382,4619,5383,4620,5384,5385,5386,5387,5388,5389,5390,5391,5392, # 688 +5393,5394,5395,5396,5397,5398,5399,5400,5401,5402,5403,5404,5405,5406,5407,5408, # 704 +5409,5410,5411,5412,5413,5414,5415,5416,5417,5418,5419,5420,5421,5422,5423,5424, # 720 +5425,5426,5427,5428,5429,5430,5431,5432,5433,5434,5435,5436,5437,5438,5439,5440, # 736 +5441,5442,5443,5444,5445,5446,5447,5448,5449,5450,5451,5452,5453,5454,5455,5456, # 752 +5457,5458,5459,5460,5461,5462,5463,5464,5465,5466,5467,5468,5469,5470,5471,5472, # 768 +5473,5474,5475,5476,5477,5478,5479,5480,5481,5482,5483,5484,5485,5486,5487,5488, # 784 +5489,5490,5491,5492,5493,5494,5495,5496,5497,5498,5499,5500,5501,5502,5503,5504, # 800 +5505,5506,5507,5508,5509,5510,5511,5512,5513,5514,5515,5516,5517,5518,5519,5520, # 816 +5521,5522,5523,5524,5525,5526,5527,5528,5529,5530,5531,5532,5533,5534,5535,5536, # 832 +5537,5538,5539,5540,5541,5542,5543,5544,5545,5546,5547,5548,5549,5550,5551,5552, # 848 +5553,5554,5555,5556,5557,5558,5559,5560,5561,5562,5563,5564,5565,5566,5567,5568, # 864 +5569,5570,5571,5572,5573,5574,5575,5576,5577,5578,5579,5580,5581,5582,5583,5584, # 880 +5585,5586,5587,5588,5589,5590,5591,5592,5593,5594,5595,5596,5597,5598,5599,5600, # 896 +5601,5602,5603,5604,5605,5606,5607,5608,5609,5610,5611,5612,5613,5614,5615,5616, # 912 +5617,5618,5619,5620,5621,5622,5623,5624,5625,5626,5627,5628,5629,5630,5631,5632, # 928 +5633,5634,5635,5636,5637,5638,5639,5640,5641,5642,5643,5644,5645,5646,5647,5648, # 944 +5649,5650,5651,5652,5653,5654,5655,5656,5657,5658,5659,5660,5661,5662,5663,5664, # 960 +5665,5666,5667,5668,5669,5670,5671,5672,5673,5674,5675,5676,5677,5678,5679,5680, # 976 +5681,5682,5683,5684,5685,5686,5687,5688,5689,5690,5691,5692,5693,5694,5695,5696, # 992 +5697,5698,5699,5700,5701,5702,5703,5704,5705,5706,5707,5708,5709,5710,5711,5712, # 1008 +5713,5714,5715,5716,5717,5718,5719,5720,5721,5722,5723,5724,5725,5726,5727,5728, # 1024 +5729,5730,5731,5732,5733,5734,5735,5736,5737,5738,5739,5740,5741,5742,5743,5744, # 1040 +5745,5746,5747,5748,5749,5750,5751,5752,5753,5754,5755,5756,5757,5758,5759,5760, # 1056 +5761,5762,5763,5764,5765,5766,5767,5768,5769,5770,5771,5772,5773,5774,5775,5776, # 1072 +5777,5778,5779,5780,5781,5782,5783,5784,5785,5786,5787,5788,5789,5790,5791,5792, # 1088 +5793,5794,5795,5796,5797,5798,5799,5800,5801,5802,5803,5804,5805,5806,5807,5808, # 1104 +5809,5810,5811,5812,5813,5814,5815,5816,5817,5818,5819,5820,5821,5822,5823,5824, # 1120 +5825,5826,5827,5828,5829,5830,5831,5832,5833,5834,5835,5836,5837,5838,5839,5840, # 1136 +5841,5842,5843,5844,5845,5846,5847,5848,5849,5850,5851,5852,5853,5854,5855,5856, # 1152 +5857,5858,5859,5860,5861,5862,5863,5864,5865,5866,5867,5868,5869,5870,5871,5872, # 1168 +5873,5874,5875,5876,5877,5878,5879,5880,5881,5882,5883,5884,5885,5886,5887,5888, # 1184 +5889,5890,5891,5892,5893,5894,5895,5896,5897,5898,5899,5900,5901,5902,5903,5904, # 1200 +5905,5906,5907,5908,5909,5910,5911,5912,5913,5914,5915,5916,5917,5918,5919,5920, # 1216 +5921,5922,5923,5924,5925,5926,5927,5928,5929,5930,5931,5932,5933,5934,5935,5936, # 1232 +5937,5938,5939,5940,5941,5942,5943,5944,5945,5946,5947,5948,5949,5950,5951,5952, # 1248 +5953,5954,5955,5956,5957,5958,5959,5960,5961,5962,5963,5964,5965,5966,5967,5968, # 1264 +5969,5970,5971,5972,5973,5974,5975,5976,5977,5978,5979,5980,5981,5982,5983,5984, # 1280 +5985,5986,5987,5988,5989,5990,5991,5992,5993,5994,5995,5996,5997,5998,5999,6000, # 1296 +6001,6002,6003,6004,6005,6006,6007,6008,6009,6010,6011,6012,6013,6014,6015,6016, # 1312 +6017,6018,6019,6020,6021,6022,6023,6024,6025,6026,6027,6028,6029,6030,6031,6032, # 1328 +6033,6034,6035,6036,6037,6038,6039,6040,6041,6042,6043,6044,6045,6046,6047,6048, # 1344 +6049,6050,6051,6052,6053,6054,6055,6056,6057,6058,6059,6060,6061,6062,6063,6064, # 1360 +6065,6066,6067,6068,6069,6070,6071,6072,6073,6074,6075,6076,6077,6078,6079,6080, # 1376 +6081,6082,6083,6084,6085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096, # 1392 +6097,6098,6099,6100,6101,6102,6103,6104,6105,6106,6107,6108,6109,6110,6111,6112, # 1408 +6113,6114,2044,2060,4621, 997,1235, 473,1186,4622, 920,3378,6115,6116, 379,1108, # 1424 +4313,2657,2735,3934,6117,3809, 636,3233, 573,1026,3693,3435,2974,3300,2298,4105, # 1440 + 854,2937,2463, 393,2581,2417, 539, 752,1280,2750,2480, 140,1161, 440, 708,1569, # 1456 + 665,2497,1746,1291,1523,3000, 164,1603, 847,1331, 537,1997, 486, 508,1693,2418, # 1472 +1970,2227, 878,1220, 299,1030, 969, 652,2751, 624,1137,3301,2619, 65,3302,2045, # 1488 +1761,1859,3120,1930,3694,3516, 663,1767, 852, 835,3695, 269, 767,2826,2339,1305, # 1504 + 896,1150, 770,1616,6118, 506,1502,2075,1012,2519, 775,2520,2975,2340,2938,4314, # 1520 +3028,2086,1224,1943,2286,6119,3072,4315,2240,1273,1987,3935,1557, 175, 597, 985, # 1536 +3517,2419,2521,1416,3029, 585, 938,1931,1007,1052,1932,1685,6120,3379,4316,4623, # 1552 + 804, 599,3121,1333,2128,2539,1159,1554,2032,3810, 687,2033,2904, 952, 675,1467, # 1568 +3436,6121,2241,1096,1786,2440,1543,1924, 980,1813,2228, 781,2692,1879, 728,1918, # 1584 +3696,4624, 548,1950,4625,1809,1088,1356,3303,2522,1944, 502, 972, 373, 513,2827, # 1600 + 586,2377,2391,1003,1976,1631,6122,2464,1084, 648,1776,4626,2141, 324, 962,2012, # 1616 +2177,2076,1384, 742,2178,1448,1173,1810, 222, 102, 301, 445, 125,2420, 662,2498, # 1632 + 277, 200,1476,1165,1068, 224,2562,1378,1446, 450,1880, 659, 791, 582,4627,2939, # 1648 +3936,1516,1274, 555,2099,3697,1020,1389,1526,3380,1762,1723,1787,2229, 412,2114, # 1664 +1900,2392,3518, 512,2597, 427,1925,2341,3122,1653,1686,2465,2499, 697, 330, 273, # 1680 + 380,2162, 951, 832, 780, 991,1301,3073, 965,2270,3519, 668,2523,2636,1286, 535, # 1696 +1407, 518, 671, 957,2658,2378, 267, 611,2197,3030,6123, 248,2299, 967,1799,2356, # 1712 + 850,1418,3437,1876,1256,1480,2828,1718,6124,6125,1755,1664,2405,6126,4628,2879, # 1728 +2829, 499,2179, 676,4629, 557,2329,2214,2090, 325,3234, 464, 811,3001, 992,2342, # 1744 +2481,1232,1469, 303,2242, 466,1070,2163, 603,1777,2091,4630,2752,4631,2714, 322, # 1760 +2659,1964,1768, 481,2188,1463,2330,2857,3600,2092,3031,2421,4632,2318,2070,1849, # 1776 +2598,4633,1302,2254,1668,1701,2422,3811,2905,3032,3123,2046,4106,1763,1694,4634, # 1792 +1604, 943,1724,1454, 917, 868,2215,1169,2940, 552,1145,1800,1228,1823,1955, 316, # 1808 +1080,2510, 361,1807,2830,4107,2660,3381,1346,1423,1134,4108,6127, 541,1263,1229, # 1824 +1148,2540, 545, 465,1833,2880,3438,1901,3074,2482, 816,3937, 713,1788,2500, 122, # 1840 +1575, 195,1451,2501,1111,6128, 859, 374,1225,2243,2483,4317, 390,1033,3439,3075, # 1856 +2524,1687, 266, 793,1440,2599, 946, 779, 802, 507, 897,1081, 528,2189,1292, 711, # 1872 +1866,1725,1167,1640, 753, 398,2661,1053, 246, 348,4318, 137,1024,3440,1600,2077, # 1888 +2129, 825,4319, 698, 238, 521, 187,2300,1157,2423,1641,1605,1464,1610,1097,2541, # 1904 +1260,1436, 759,2255,1814,2150, 705,3235, 409,2563,3304, 561,3033,2005,2564, 726, # 1920 +1956,2343,3698,4109, 949,3812,3813,3520,1669, 653,1379,2525, 881,2198, 632,2256, # 1936 +1027, 778,1074, 733,1957, 514,1481,2466, 554,2180, 702,3938,1606,1017,1398,6129, # 1952 +1380,3521, 921, 993,1313, 594, 449,1489,1617,1166, 768,1426,1360, 495,1794,3601, # 1968 +1177,3602,1170,4320,2344, 476, 425,3167,4635,3168,1424, 401,2662,1171,3382,1998, # 1984 +1089,4110, 477,3169, 474,6130,1909, 596,2831,1842, 494, 693,1051,1028,1207,3076, # 2000 + 606,2115, 727,2790,1473,1115, 743,3522, 630, 805,1532,4321,2021, 366,1057, 838, # 2016 + 684,1114,2142,4322,2050,1492,1892,1808,2271,3814,2424,1971,1447,1373,3305,1090, # 2032 +1536,3939,3523,3306,1455,2199, 336, 369,2331,1035, 584,2393, 902, 718,2600,6131, # 2048 +2753, 463,2151,1149,1611,2467, 715,1308,3124,1268, 343,1413,3236,1517,1347,2663, # 2064 +2093,3940,2022,1131,1553,2100,2941,1427,3441,2942,1323,2484,6132,1980, 872,2368, # 2080 +2441,2943, 320,2369,2116,1082, 679,1933,3941,2791,3815, 625,1143,2023, 422,2200, # 2096 +3816,6133, 730,1695, 356,2257,1626,2301,2858,2637,1627,1778, 937, 883,2906,2693, # 2112 +3002,1769,1086, 400,1063,1325,3307,2792,4111,3077, 456,2345,1046, 747,6134,1524, # 2128 + 884,1094,3383,1474,2164,1059, 974,1688,2181,2258,1047, 345,1665,1187, 358, 875, # 2144 +3170, 305, 660,3524,2190,1334,1135,3171,1540,1649,2542,1527, 927, 968,2793, 885, # 2160 +1972,1850, 482, 500,2638,1218,1109,1085,2543,1654,2034, 876, 78,2287,1482,1277, # 2176 + 861,1675,1083,1779, 724,2754, 454, 397,1132,1612,2332, 893, 672,1237, 257,2259, # 2192 +2370, 135,3384, 337,2244, 547, 352, 340, 709,2485,1400, 788,1138,2511, 540, 772, # 2208 +1682,2260,2272,2544,2013,1843,1902,4636,1999,1562,2288,4637,2201,1403,1533, 407, # 2224 + 576,3308,1254,2071, 978,3385, 170, 136,1201,3125,2664,3172,2394, 213, 912, 873, # 2240 +3603,1713,2202, 699,3604,3699, 813,3442, 493, 531,1054, 468,2907,1483, 304, 281, # 2256 +4112,1726,1252,2094, 339,2319,2130,2639, 756,1563,2944, 748, 571,2976,1588,2425, # 2272 +2715,1851,1460,2426,1528,1392,1973,3237, 288,3309, 685,3386, 296, 892,2716,2216, # 2288 +1570,2245, 722,1747,2217, 905,3238,1103,6135,1893,1441,1965, 251,1805,2371,3700, # 2304 +2601,1919,1078, 75,2182,1509,1592,1270,2640,4638,2152,6136,3310,3817, 524, 706, # 2320 +1075, 292,3818,1756,2602, 317, 98,3173,3605,3525,1844,2218,3819,2502, 814, 567, # 2336 + 385,2908,1534,6137, 534,1642,3239, 797,6138,1670,1529, 953,4323, 188,1071, 538, # 2352 + 178, 729,3240,2109,1226,1374,2000,2357,2977, 731,2468,1116,2014,2051,6139,1261, # 2368 +1593, 803,2859,2736,3443, 556, 682, 823,1541,6140,1369,2289,1706,2794, 845, 462, # 2384 +2603,2665,1361, 387, 162,2358,1740, 739,1770,1720,1304,1401,3241,1049, 627,1571, # 2400 +2427,3526,1877,3942,1852,1500, 431,1910,1503, 677, 297,2795, 286,1433,1038,1198, # 2416 +2290,1133,1596,4113,4639,2469,1510,1484,3943,6141,2442, 108, 712,4640,2372, 866, # 2432 +3701,2755,3242,1348, 834,1945,1408,3527,2395,3243,1811, 824, 994,1179,2110,1548, # 2448 +1453, 790,3003, 690,4324,4325,2832,2909,3820,1860,3821, 225,1748, 310, 346,1780, # 2464 +2470, 821,1993,2717,2796, 828, 877,3528,2860,2471,1702,2165,2910,2486,1789, 453, # 2480 + 359,2291,1676, 73,1164,1461,1127,3311, 421, 604, 314,1037, 589, 116,2487, 737, # 2496 + 837,1180, 111, 244, 735,6142,2261,1861,1362, 986, 523, 418, 581,2666,3822, 103, # 2512 + 855, 503,1414,1867,2488,1091, 657,1597, 979, 605,1316,4641,1021,2443,2078,2001, # 2528 +1209, 96, 587,2166,1032, 260,1072,2153, 173, 94, 226,3244, 819,2006,4642,4114, # 2544 +2203, 231,1744, 782, 97,2667, 786,3387, 887, 391, 442,2219,4326,1425,6143,2694, # 2560 + 633,1544,1202, 483,2015, 592,2052,1958,2472,1655, 419, 129,4327,3444,3312,1714, # 2576 +1257,3078,4328,1518,1098, 865,1310,1019,1885,1512,1734, 469,2444, 148, 773, 436, # 2592 +1815,1868,1128,1055,4329,1245,2756,3445,2154,1934,1039,4643, 579,1238, 932,2320, # 2608 + 353, 205, 801, 115,2428, 944,2321,1881, 399,2565,1211, 678, 766,3944, 335,2101, # 2624 +1459,1781,1402,3945,2737,2131,1010, 844, 981,1326,1013, 550,1816,1545,2620,1335, # 2640 +1008, 371,2881, 936,1419,1613,3529,1456,1395,2273,1834,2604,1317,2738,2503, 416, # 2656 +1643,4330, 806,1126, 229, 591,3946,1314,1981,1576,1837,1666, 347,1790, 977,3313, # 2672 + 764,2861,1853, 688,2429,1920,1462, 77, 595, 415,2002,3034, 798,1192,4115,6144, # 2688 +2978,4331,3035,2695,2582,2072,2566, 430,2430,1727, 842,1396,3947,3702, 613, 377, # 2704 + 278, 236,1417,3388,3314,3174, 757,1869, 107,3530,6145,1194, 623,2262, 207,1253, # 2720 +2167,3446,3948, 492,1117,1935, 536,1838,2757,1246,4332, 696,2095,2406,1393,1572, # 2736 +3175,1782, 583, 190, 253,1390,2230, 830,3126,3389, 934,3245,1703,1749,2979,1870, # 2752 +2545,1656,2204, 869,2346,4116,3176,1817, 496,1764,4644, 942,1504, 404,1903,1122, # 2768 +1580,3606,2945,1022, 515, 372,1735, 955,2431,3036,6146,2797,1110,2302,2798, 617, # 2784 +6147, 441, 762,1771,3447,3607,3608,1904, 840,3037, 86, 939,1385, 572,1370,2445, # 2800 +1336, 114,3703, 898, 294, 203,3315, 703,1583,2274, 429, 961,4333,1854,1951,3390, # 2816 +2373,3704,4334,1318,1381, 966,1911,2322,1006,1155, 309, 989, 458,2718,1795,1372, # 2832 +1203, 252,1689,1363,3177, 517,1936, 168,1490, 562, 193,3823,1042,4117,1835, 551, # 2848 + 470,4645, 395, 489,3448,1871,1465,2583,2641, 417,1493, 279,1295, 511,1236,1119, # 2864 + 72,1231,1982,1812,3004, 871,1564, 984,3449,1667,2696,2096,4646,2347,2833,1673, # 2880 +3609, 695,3246,2668, 807,1183,4647, 890, 388,2333,1801,1457,2911,1765,1477,1031, # 2896 +3316,3317,1278,3391,2799,2292,2526, 163,3450,4335,2669,1404,1802,6148,2323,2407, # 2912 +1584,1728,1494,1824,1269, 298, 909,3318,1034,1632, 375, 776,1683,2061, 291, 210, # 2928 +1123, 809,1249,1002,2642,3038, 206,1011,2132, 144, 975, 882,1565, 342, 667, 754, # 2944 +1442,2143,1299,2303,2062, 447, 626,2205,1221,2739,2912,1144,1214,2206,2584, 760, # 2960 +1715, 614, 950,1281,2670,2621, 810, 577,1287,2546,4648, 242,2168, 250,2643, 691, # 2976 + 123,2644, 647, 313,1029, 689,1357,2946,1650, 216, 771,1339,1306, 808,2063, 549, # 2992 + 913,1371,2913,2914,6149,1466,1092,1174,1196,1311,2605,2396,1783,1796,3079, 406, # 3008 +2671,2117,3949,4649, 487,1825,2220,6150,2915, 448,2348,1073,6151,2397,1707, 130, # 3024 + 900,1598, 329, 176,1959,2527,1620,6152,2275,4336,3319,1983,2191,3705,3610,2155, # 3040 +3706,1912,1513,1614,6153,1988, 646, 392,2304,1589,3320,3039,1826,1239,1352,1340, # 3056 +2916, 505,2567,1709,1437,2408,2547, 906,6154,2672, 384,1458,1594,1100,1329, 710, # 3072 + 423,3531,2064,2231,2622,1989,2673,1087,1882, 333, 841,3005,1296,2882,2379, 580, # 3088 +1937,1827,1293,2585, 601, 574, 249,1772,4118,2079,1120, 645, 901,1176,1690, 795, # 3104 +2207, 478,1434, 516,1190,1530, 761,2080, 930,1264, 355, 435,1552, 644,1791, 987, # 3120 + 220,1364,1163,1121,1538, 306,2169,1327,1222, 546,2645, 218, 241, 610,1704,3321, # 3136 +1984,1839,1966,2528, 451,6155,2586,3707,2568, 907,3178, 254,2947, 186,1845,4650, # 3152 + 745, 432,1757, 428,1633, 888,2246,2221,2489,3611,2118,1258,1265, 956,3127,1784, # 3168 +4337,2490, 319, 510, 119, 457,3612, 274,2035,2007,4651,1409,3128, 970,2758, 590, # 3184 +2800, 661,2247,4652,2008,3950,1420,1549,3080,3322,3951,1651,1375,2111, 485,2491, # 3200 +1429,1156,6156,2548,2183,1495, 831,1840,2529,2446, 501,1657, 307,1894,3247,1341, # 3216 + 666, 899,2156,1539,2549,1559, 886, 349,2208,3081,2305,1736,3824,2170,2759,1014, # 3232 +1913,1386, 542,1397,2948, 490, 368, 716, 362, 159, 282,2569,1129,1658,1288,1750, # 3248 +2674, 276, 649,2016, 751,1496, 658,1818,1284,1862,2209,2087,2512,3451, 622,2834, # 3264 + 376, 117,1060,2053,1208,1721,1101,1443, 247,1250,3179,1792,3952,2760,2398,3953, # 3280 +6157,2144,3708, 446,2432,1151,2570,3452,2447,2761,2835,1210,2448,3082, 424,2222, # 3296 +1251,2449,2119,2836, 504,1581,4338, 602, 817, 857,3825,2349,2306, 357,3826,1470, # 3312 +1883,2883, 255, 958, 929,2917,3248, 302,4653,1050,1271,1751,2307,1952,1430,2697, # 3328 +2719,2359, 354,3180, 777, 158,2036,4339,1659,4340,4654,2308,2949,2248,1146,2232, # 3344 +3532,2720,1696,2623,3827,6158,3129,1550,2698,1485,1297,1428, 637, 931,2721,2145, # 3360 + 914,2550,2587, 81,2450, 612, 827,2646,1242,4655,1118,2884, 472,1855,3181,3533, # 3376 +3534, 569,1353,2699,1244,1758,2588,4119,2009,2762,2171,3709,1312,1531,6159,1152, # 3392 +1938, 134,1830, 471,3710,2276,1112,1535,3323,3453,3535, 982,1337,2950, 488, 826, # 3408 + 674,1058,1628,4120,2017, 522,2399, 211, 568,1367,3454, 350, 293,1872,1139,3249, # 3424 +1399,1946,3006,1300,2360,3324, 588, 736,6160,2606, 744, 669,3536,3828,6161,1358, # 3440 + 199, 723, 848, 933, 851,1939,1505,1514,1338,1618,1831,4656,1634,3613, 443,2740, # 3456 +3829, 717,1947, 491,1914,6162,2551,1542,4121,1025,6163,1099,1223, 198,3040,2722, # 3472 + 370, 410,1905,2589, 998,1248,3182,2380, 519,1449,4122,1710, 947, 928,1153,4341, # 3488 +2277, 344,2624,1511, 615, 105, 161,1212,1076,1960,3130,2054,1926,1175,1906,2473, # 3504 + 414,1873,2801,6164,2309, 315,1319,3325, 318,2018,2146,2157, 963, 631, 223,4342, # 3520 +4343,2675, 479,3711,1197,2625,3712,2676,2361,6165,4344,4123,6166,2451,3183,1886, # 3536 +2184,1674,1330,1711,1635,1506, 799, 219,3250,3083,3954,1677,3713,3326,2081,3614, # 3552 +1652,2073,4657,1147,3041,1752, 643,1961, 147,1974,3955,6167,1716,2037, 918,3007, # 3568 +1994, 120,1537, 118, 609,3184,4345, 740,3455,1219, 332,1615,3830,6168,1621,2980, # 3584 +1582, 783, 212, 553,2350,3714,1349,2433,2082,4124, 889,6169,2310,1275,1410, 973, # 3600 + 166,1320,3456,1797,1215,3185,2885,1846,2590,2763,4658, 629, 822,3008, 763, 940, # 3616 +1990,2862, 439,2409,1566,1240,1622, 926,1282,1907,2764, 654,2210,1607, 327,1130, # 3632 +3956,1678,1623,6170,2434,2192, 686, 608,3831,3715, 903,3957,3042,6171,2741,1522, # 3648 +1915,1105,1555,2552,1359, 323,3251,4346,3457, 738,1354,2553,2311,2334,1828,2003, # 3664 +3832,1753,2351,1227,6172,1887,4125,1478,6173,2410,1874,1712,1847, 520,1204,2607, # 3680 + 264,4659, 836,2677,2102, 600,4660,3833,2278,3084,6174,4347,3615,1342, 640, 532, # 3696 + 543,2608,1888,2400,2591,1009,4348,1497, 341,1737,3616,2723,1394, 529,3252,1321, # 3712 + 983,4661,1515,2120, 971,2592, 924, 287,1662,3186,4349,2700,4350,1519, 908,1948, # 3728 +2452, 156, 796,1629,1486,2223,2055, 694,4126,1259,1036,3392,1213,2249,2742,1889, # 3744 +1230,3958,1015, 910, 408, 559,3617,4662, 746, 725, 935,4663,3959,3009,1289, 563, # 3760 + 867,4664,3960,1567,2981,2038,2626, 988,2263,2381,4351, 143,2374, 704,1895,6175, # 3776 +1188,3716,2088, 673,3085,2362,4352, 484,1608,1921,2765,2918, 215, 904,3618,3537, # 3792 + 894, 509, 976,3043,2701,3961,4353,2837,2982, 498,6176,6177,1102,3538,1332,3393, # 3808 +1487,1636,1637, 233, 245,3962, 383, 650, 995,3044, 460,1520,1206,2352, 749,3327, # 3824 + 530, 700, 389,1438,1560,1773,3963,2264, 719,2951,2724,3834, 870,1832,1644,1000, # 3840 + 839,2474,3717, 197,1630,3394, 365,2886,3964,1285,2133, 734, 922, 818,1106, 732, # 3856 + 480,2083,1774,3458, 923,2279,1350, 221,3086, 85,2233,2234,3835,1585,3010,2147, # 3872 +1387,1705,2382,1619,2475, 133, 239,2802,1991,1016,2084,2383, 411,2838,1113, 651, # 3888 +1985,1160,3328, 990,1863,3087,1048,1276,2647, 265,2627,1599,3253,2056, 150, 638, # 3904 +2019, 656, 853, 326,1479, 680,1439,4354,1001,1759, 413,3459,3395,2492,1431, 459, # 3920 +4355,1125,3329,2265,1953,1450,2065,2863, 849, 351,2678,3131,3254,3255,1104,1577, # 3936 + 227,1351,1645,2453,2193,1421,2887, 812,2121, 634, 95,2435, 201,2312,4665,1646, # 3952 +1671,2743,1601,2554,2702,2648,2280,1315,1366,2089,3132,1573,3718,3965,1729,1189, # 3968 + 328,2679,1077,1940,1136, 558,1283, 964,1195, 621,2074,1199,1743,3460,3619,1896, # 3984 +1916,1890,3836,2952,1154,2112,1064, 862, 378,3011,2066,2113,2803,1568,2839,6178, # 4000 +3088,2919,1941,1660,2004,1992,2194, 142, 707,1590,1708,1624,1922,1023,1836,1233, # 4016 +1004,2313, 789, 741,3620,6179,1609,2411,1200,4127,3719,3720,4666,2057,3721, 593, # 4032 +2840, 367,2920,1878,6180,3461,1521, 628,1168, 692,2211,2649, 300, 720,2067,2571, # 4048 +2953,3396, 959,2504,3966,3539,3462,1977, 701,6181, 954,1043, 800, 681, 183,3722, # 4064 +1803,1730,3540,4128,2103, 815,2314, 174, 467, 230,2454,1093,2134, 755,3541,3397, # 4080 +1141,1162,6182,1738,2039, 270,3256,2513,1005,1647,2185,3837, 858,1679,1897,1719, # 4096 +2954,2324,1806, 402, 670, 167,4129,1498,2158,2104, 750,6183, 915, 189,1680,1551, # 4112 + 455,4356,1501,2455, 405,1095,2955, 338,1586,1266,1819, 570, 641,1324, 237,1556, # 4128 +2650,1388,3723,6184,1368,2384,1343,1978,3089,2436, 879,3724, 792,1191, 758,3012, # 4144 +1411,2135,1322,4357, 240,4667,1848,3725,1574,6185, 420,3045,1546,1391, 714,4358, # 4160 +1967, 941,1864, 863, 664, 426, 560,1731,2680,1785,2864,1949,2363, 403,3330,1415, # 4176 +1279,2136,1697,2335, 204, 721,2097,3838, 90,6186,2085,2505, 191,3967, 124,2148, # 4192 +1376,1798,1178,1107,1898,1405, 860,4359,1243,1272,2375,2983,1558,2456,1638, 113, # 4208 +3621, 578,1923,2609, 880, 386,4130, 784,2186,2266,1422,2956,2172,1722, 497, 263, # 4224 +2514,1267,2412,2610, 177,2703,3542, 774,1927,1344, 616,1432,1595,1018, 172,4360, # 4240 +2325, 911,4361, 438,1468,3622, 794,3968,2024,2173,1681,1829,2957, 945, 895,3090, # 4256 + 575,2212,2476, 475,2401,2681, 785,2744,1745,2293,2555,1975,3133,2865, 394,4668, # 4272 +3839, 635,4131, 639, 202,1507,2195,2766,1345,1435,2572,3726,1908,1184,1181,2457, # 4288 +3727,3134,4362, 843,2611, 437, 916,4669, 234, 769,1884,3046,3047,3623, 833,6187, # 4304 +1639,2250,2402,1355,1185,2010,2047, 999, 525,1732,1290,1488,2612, 948,1578,3728, # 4320 +2413,2477,1216,2725,2159, 334,3840,1328,3624,2921,1525,4132, 564,1056, 891,4363, # 4336 +1444,1698,2385,2251,3729,1365,2281,2235,1717,6188, 864,3841,2515, 444, 527,2767, # 4352 +2922,3625, 544, 461,6189, 566, 209,2437,3398,2098,1065,2068,3331,3626,3257,2137, # 4368 #last 512 +) + + diff --git a/venv/lib/python2.7/site-packages/chardet/jpcntx.py b/venv/lib/python2.7/site-packages/chardet/jpcntx.py new file mode 100644 index 0000000..20044e4 --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/jpcntx.py @@ -0,0 +1,233 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + + +# This is hiragana 2-char sequence table, the number in each cell represents its frequency category +jp2CharContext = ( +(0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1), +(2,4,0,4,0,3,0,4,0,3,4,4,4,2,4,3,3,4,3,2,3,3,4,2,3,3,3,2,4,1,4,3,3,1,5,4,3,4,3,4,3,5,3,0,3,5,4,2,0,3,1,0,3,3,0,3,3,0,1,1,0,4,3,0,3,3,0,4,0,2,0,3,5,5,5,5,4,0,4,1,0,3,4), +(0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2), +(0,4,0,5,0,5,0,4,0,4,5,4,4,3,5,3,5,1,5,3,4,3,4,4,3,4,3,3,4,3,5,4,4,3,5,5,3,5,5,5,3,5,5,3,4,5,5,3,1,3,2,0,3,4,0,4,2,0,4,2,1,5,3,2,3,5,0,4,0,2,0,5,4,4,5,4,5,0,4,0,0,4,4), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +(0,3,0,4,0,3,0,3,0,4,5,4,3,3,3,3,4,3,5,4,4,3,5,4,4,3,4,3,4,4,4,4,5,3,4,4,3,4,5,5,4,5,5,1,4,5,4,3,0,3,3,1,3,3,0,4,4,0,3,3,1,5,3,3,3,5,0,4,0,3,0,4,4,3,4,3,3,0,4,1,1,3,4), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +(0,4,0,3,0,3,0,4,0,3,4,4,3,2,2,1,2,1,3,1,3,3,3,3,3,4,3,1,3,3,5,3,3,0,4,3,0,5,4,3,3,5,4,4,3,4,4,5,0,1,2,0,1,2,0,2,2,0,1,0,0,5,2,2,1,4,0,3,0,1,0,4,4,3,5,4,3,0,2,1,0,4,3), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +(0,3,0,5,0,4,0,2,1,4,4,2,4,1,4,2,4,2,4,3,3,3,4,3,3,3,3,1,4,2,3,3,3,1,4,4,1,1,1,4,3,3,2,0,2,4,3,2,0,3,3,0,3,1,1,0,0,0,3,3,0,4,2,2,3,4,0,4,0,3,0,4,4,5,3,4,4,0,3,0,0,1,4), +(1,4,0,4,0,4,0,4,0,3,5,4,4,3,4,3,5,4,3,3,4,3,5,4,4,4,4,3,4,2,4,3,3,1,5,4,3,2,4,5,4,5,5,4,4,5,4,4,0,3,2,2,3,3,0,4,3,1,3,2,1,4,3,3,4,5,0,3,0,2,0,4,5,5,4,5,4,0,4,0,0,5,4), +(0,5,0,5,0,4,0,3,0,4,4,3,4,3,3,3,4,0,4,4,4,3,4,3,4,3,3,1,4,2,4,3,4,0,5,4,1,4,5,4,4,5,3,2,4,3,4,3,2,4,1,3,3,3,2,3,2,0,4,3,3,4,3,3,3,4,0,4,0,3,0,4,5,4,4,4,3,0,4,1,0,1,3), +(0,3,1,4,0,3,0,2,0,3,4,4,3,1,4,2,3,3,4,3,4,3,4,3,4,4,3,2,3,1,5,4,4,1,4,4,3,5,4,4,3,5,5,4,3,4,4,3,1,2,3,1,2,2,0,3,2,0,3,1,0,5,3,3,3,4,3,3,3,3,4,4,4,4,5,4,2,0,3,3,2,4,3), +(0,2,0,3,0,1,0,1,0,0,3,2,0,0,2,0,1,0,2,1,3,3,3,1,2,3,1,0,1,0,4,2,1,1,3,3,0,4,3,3,1,4,3,3,0,3,3,2,0,0,0,0,1,0,0,2,0,0,0,0,0,4,1,0,2,3,2,2,2,1,3,3,3,4,4,3,2,0,3,1,0,3,3), +(0,4,0,4,0,3,0,3,0,4,4,4,3,3,3,3,3,3,4,3,4,2,4,3,4,3,3,2,4,3,4,5,4,1,4,5,3,5,4,5,3,5,4,0,3,5,5,3,1,3,3,2,2,3,0,3,4,1,3,3,2,4,3,3,3,4,0,4,0,3,0,4,5,4,4,5,3,0,4,1,0,3,4), +(0,2,0,3,0,3,0,0,0,2,2,2,1,0,1,0,0,0,3,0,3,0,3,0,1,3,1,0,3,1,3,3,3,1,3,3,3,0,1,3,1,3,4,0,0,3,1,1,0,3,2,0,0,0,0,1,3,0,1,0,0,3,3,2,0,3,0,0,0,0,0,3,4,3,4,3,3,0,3,0,0,2,3), +(2,3,0,3,0,2,0,1,0,3,3,4,3,1,3,1,1,1,3,1,4,3,4,3,3,3,0,0,3,1,5,4,3,1,4,3,2,5,5,4,4,4,4,3,3,4,4,4,0,2,1,1,3,2,0,1,2,0,0,1,0,4,1,3,3,3,0,3,0,1,0,4,4,4,5,5,3,0,2,0,0,4,4), +(0,2,0,1,0,3,1,3,0,2,3,3,3,0,3,1,0,0,3,0,3,2,3,1,3,2,1,1,0,0,4,2,1,0,2,3,1,4,3,2,0,4,4,3,1,3,1,3,0,1,0,0,1,0,0,0,1,0,0,0,0,4,1,1,1,2,0,3,0,0,0,3,4,2,4,3,2,0,1,0,0,3,3), +(0,1,0,4,0,5,0,4,0,2,4,4,2,3,3,2,3,3,5,3,3,3,4,3,4,2,3,0,4,3,3,3,4,1,4,3,2,1,5,5,3,4,5,1,3,5,4,2,0,3,3,0,1,3,0,4,2,0,1,3,1,4,3,3,3,3,0,3,0,1,0,3,4,4,4,5,5,0,3,0,1,4,5), +(0,2,0,3,0,3,0,0,0,2,3,1,3,0,4,0,1,1,3,0,3,4,3,2,3,1,0,3,3,2,3,1,3,0,2,3,0,2,1,4,1,2,2,0,0,3,3,0,0,2,0,0,0,1,0,0,0,0,2,2,0,3,2,1,3,3,0,2,0,2,0,0,3,3,1,2,4,0,3,0,2,2,3), +(2,4,0,5,0,4,0,4,0,2,4,4,4,3,4,3,3,3,1,2,4,3,4,3,4,4,5,0,3,3,3,3,2,0,4,3,1,4,3,4,1,4,4,3,3,4,4,3,1,2,3,0,4,2,0,4,1,0,3,3,0,4,3,3,3,4,0,4,0,2,0,3,5,3,4,5,2,0,3,0,0,4,5), +(0,3,0,4,0,1,0,1,0,1,3,2,2,1,3,0,3,0,2,0,2,0,3,0,2,0,0,0,1,0,1,1,0,0,3,1,0,0,0,4,0,3,1,0,2,1,3,0,0,0,0,0,0,3,0,0,0,0,0,0,0,4,2,2,3,1,0,3,0,0,0,1,4,4,4,3,0,0,4,0,0,1,4), +(1,4,1,5,0,3,0,3,0,4,5,4,4,3,5,3,3,4,4,3,4,1,3,3,3,3,2,1,4,1,5,4,3,1,4,4,3,5,4,4,3,5,4,3,3,4,4,4,0,3,3,1,2,3,0,3,1,0,3,3,0,5,4,4,4,4,4,4,3,3,5,4,4,3,3,5,4,0,3,2,0,4,4), +(0,2,0,3,0,1,0,0,0,1,3,3,3,2,4,1,3,0,3,1,3,0,2,2,1,1,0,0,2,0,4,3,1,0,4,3,0,4,4,4,1,4,3,1,1,3,3,1,0,2,0,0,1,3,0,0,0,0,2,0,0,4,3,2,4,3,5,4,3,3,3,4,3,3,4,3,3,0,2,1,0,3,3), +(0,2,0,4,0,3,0,2,0,2,5,5,3,4,4,4,4,1,4,3,3,0,4,3,4,3,1,3,3,2,4,3,0,3,4,3,0,3,4,4,2,4,4,0,4,5,3,3,2,2,1,1,1,2,0,1,5,0,3,3,2,4,3,3,3,4,0,3,0,2,0,4,4,3,5,5,0,0,3,0,2,3,3), +(0,3,0,4,0,3,0,1,0,3,4,3,3,1,3,3,3,0,3,1,3,0,4,3,3,1,1,0,3,0,3,3,0,0,4,4,0,1,5,4,3,3,5,0,3,3,4,3,0,2,0,1,1,1,0,1,3,0,1,2,1,3,3,2,3,3,0,3,0,1,0,1,3,3,4,4,1,0,1,2,2,1,3), +(0,1,0,4,0,4,0,3,0,1,3,3,3,2,3,1,1,0,3,0,3,3,4,3,2,4,2,0,1,0,4,3,2,0,4,3,0,5,3,3,2,4,4,4,3,3,3,4,0,1,3,0,0,1,0,0,1,0,0,0,0,4,2,3,3,3,0,3,0,0,0,4,4,4,5,3,2,0,3,3,0,3,5), +(0,2,0,3,0,0,0,3,0,1,3,0,2,0,0,0,1,0,3,1,1,3,3,0,0,3,0,0,3,0,2,3,1,0,3,1,0,3,3,2,0,4,2,2,0,2,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,2,1,2,0,1,0,1,0,0,0,1,3,1,2,0,0,0,1,0,0,1,4), +(0,3,0,3,0,5,0,1,0,2,4,3,1,3,3,2,1,1,5,2,1,0,5,1,2,0,0,0,3,3,2,2,3,2,4,3,0,0,3,3,1,3,3,0,2,5,3,4,0,3,3,0,1,2,0,2,2,0,3,2,0,2,2,3,3,3,0,2,0,1,0,3,4,4,2,5,4,0,3,0,0,3,5), +(0,3,0,3,0,3,0,1,0,3,3,3,3,0,3,0,2,0,2,1,1,0,2,0,1,0,0,0,2,1,0,0,1,0,3,2,0,0,3,3,1,2,3,1,0,3,3,0,0,1,0,0,0,0,0,2,0,0,0,0,0,2,3,1,2,3,0,3,0,1,0,3,2,1,0,4,3,0,1,1,0,3,3), +(0,4,0,5,0,3,0,3,0,4,5,5,4,3,5,3,4,3,5,3,3,2,5,3,4,4,4,3,4,3,4,5,5,3,4,4,3,4,4,5,4,4,4,3,4,5,5,4,2,3,4,2,3,4,0,3,3,1,4,3,2,4,3,3,5,5,0,3,0,3,0,5,5,5,5,4,4,0,4,0,1,4,4), +(0,4,0,4,0,3,0,3,0,3,5,4,4,2,3,2,5,1,3,2,5,1,4,2,3,2,3,3,4,3,3,3,3,2,5,4,1,3,3,5,3,4,4,0,4,4,3,1,1,3,1,0,2,3,0,2,3,0,3,0,0,4,3,1,3,4,0,3,0,2,0,4,4,4,3,4,5,0,4,0,0,3,4), +(0,3,0,3,0,3,1,2,0,3,4,4,3,3,3,0,2,2,4,3,3,1,3,3,3,1,1,0,3,1,4,3,2,3,4,4,2,4,4,4,3,4,4,3,2,4,4,3,1,3,3,1,3,3,0,4,1,0,2,2,1,4,3,2,3,3,5,4,3,3,5,4,4,3,3,0,4,0,3,2,2,4,4), +(0,2,0,1,0,0,0,0,0,1,2,1,3,0,0,0,0,0,2,0,1,2,1,0,0,1,0,0,0,0,3,0,0,1,0,1,1,3,1,0,0,0,1,1,0,1,1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,1,1,2,2,0,3,4,0,0,0,1,1,0,0,1,0,0,0,0,0,1,1), +(0,1,0,0,0,1,0,0,0,0,4,0,4,1,4,0,3,0,4,0,3,0,4,0,3,0,3,0,4,1,5,1,4,0,0,3,0,5,0,5,2,0,1,0,0,0,2,1,4,0,1,3,0,0,3,0,0,3,1,1,4,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0), +(1,4,0,5,0,3,0,2,0,3,5,4,4,3,4,3,5,3,4,3,3,0,4,3,3,3,3,3,3,2,4,4,3,1,3,4,4,5,4,4,3,4,4,1,3,5,4,3,3,3,1,2,2,3,3,1,3,1,3,3,3,5,3,3,4,5,0,3,0,3,0,3,4,3,4,4,3,0,3,0,2,4,3), +(0,1,0,4,0,0,0,0,0,1,4,0,4,1,4,2,4,0,3,0,1,0,1,0,0,0,0,0,2,0,3,1,1,1,0,3,0,0,0,1,2,1,0,0,1,1,1,1,0,1,0,0,0,1,0,0,3,0,0,0,0,3,2,0,2,2,0,1,0,0,0,2,3,2,3,3,0,0,0,0,2,1,0), +(0,5,1,5,0,3,0,3,0,5,4,4,5,1,5,3,3,0,4,3,4,3,5,3,4,3,3,2,4,3,4,3,3,0,3,3,1,4,4,3,4,4,4,3,4,5,5,3,2,3,1,1,3,3,1,3,1,1,3,3,2,4,5,3,3,5,0,4,0,3,0,4,4,3,5,3,3,0,3,4,0,4,3), +(0,5,0,5,0,3,0,2,0,4,4,3,5,2,4,3,3,3,4,4,4,3,5,3,5,3,3,1,4,0,4,3,3,0,3,3,0,4,4,4,4,5,4,3,3,5,5,3,2,3,1,2,3,2,0,1,0,0,3,2,2,4,4,3,1,5,0,4,0,3,0,4,3,1,3,2,1,0,3,3,0,3,3), +(0,4,0,5,0,5,0,4,0,4,5,5,5,3,4,3,3,2,5,4,4,3,5,3,5,3,4,0,4,3,4,4,3,2,4,4,3,4,5,4,4,5,5,0,3,5,5,4,1,3,3,2,3,3,1,3,1,0,4,3,1,4,4,3,4,5,0,4,0,2,0,4,3,4,4,3,3,0,4,0,0,5,5), +(0,4,0,4,0,5,0,1,1,3,3,4,4,3,4,1,3,0,5,1,3,0,3,1,3,1,1,0,3,0,3,3,4,0,4,3,0,4,4,4,3,4,4,0,3,5,4,1,0,3,0,0,2,3,0,3,1,0,3,1,0,3,2,1,3,5,0,3,0,1,0,3,2,3,3,4,4,0,2,2,0,4,4), +(2,4,0,5,0,4,0,3,0,4,5,5,4,3,5,3,5,3,5,3,5,2,5,3,4,3,3,4,3,4,5,3,2,1,5,4,3,2,3,4,5,3,4,1,2,5,4,3,0,3,3,0,3,2,0,2,3,0,4,1,0,3,4,3,3,5,0,3,0,1,0,4,5,5,5,4,3,0,4,2,0,3,5), +(0,5,0,4,0,4,0,2,0,5,4,3,4,3,4,3,3,3,4,3,4,2,5,3,5,3,4,1,4,3,4,4,4,0,3,5,0,4,4,4,4,5,3,1,3,4,5,3,3,3,3,3,3,3,0,2,2,0,3,3,2,4,3,3,3,5,3,4,1,3,3,5,3,2,0,0,0,0,4,3,1,3,3), +(0,1,0,3,0,3,0,1,0,1,3,3,3,2,3,3,3,0,3,0,0,0,3,1,3,0,0,0,2,2,2,3,0,0,3,2,0,1,2,4,1,3,3,0,0,3,3,3,0,1,0,0,2,1,0,0,3,0,3,1,0,3,0,0,1,3,0,2,0,1,0,3,3,1,3,3,0,0,1,1,0,3,3), +(0,2,0,3,0,2,1,4,0,2,2,3,1,1,3,1,1,0,2,0,3,1,2,3,1,3,0,0,1,0,4,3,2,3,3,3,1,4,2,3,3,3,3,1,0,3,1,4,0,1,1,0,1,2,0,1,1,0,1,1,0,3,1,3,2,2,0,1,0,0,0,2,3,3,3,1,0,0,0,0,0,2,3), +(0,5,0,4,0,5,0,2,0,4,5,5,3,3,4,3,3,1,5,4,4,2,4,4,4,3,4,2,4,3,5,5,4,3,3,4,3,3,5,5,4,5,5,1,3,4,5,3,1,4,3,1,3,3,0,3,3,1,4,3,1,4,5,3,3,5,0,4,0,3,0,5,3,3,1,4,3,0,4,0,1,5,3), +(0,5,0,5,0,4,0,2,0,4,4,3,4,3,3,3,3,3,5,4,4,4,4,4,4,5,3,3,5,2,4,4,4,3,4,4,3,3,4,4,5,5,3,3,4,3,4,3,3,4,3,3,3,3,1,2,2,1,4,3,3,5,4,4,3,4,0,4,0,3,0,4,4,4,4,4,1,0,4,2,0,2,4), +(0,4,0,4,0,3,0,1,0,3,5,2,3,0,3,0,2,1,4,2,3,3,4,1,4,3,3,2,4,1,3,3,3,0,3,3,0,0,3,3,3,5,3,3,3,3,3,2,0,2,0,0,2,0,0,2,0,0,1,0,0,3,1,2,2,3,0,3,0,2,0,4,4,3,3,4,1,0,3,0,0,2,4), +(0,0,0,4,0,0,0,0,0,0,1,0,1,0,2,0,0,0,0,0,1,0,2,0,1,0,0,0,0,0,3,1,3,0,3,2,0,0,0,1,0,3,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,4,0,2,0,0,0,0,0,0,2), +(0,2,1,3,0,2,0,2,0,3,3,3,3,1,3,1,3,3,3,3,3,3,4,2,2,1,2,1,4,0,4,3,1,3,3,3,2,4,3,5,4,3,3,3,3,3,3,3,0,1,3,0,2,0,0,1,0,0,1,0,0,4,2,0,2,3,0,3,3,0,3,3,4,2,3,1,4,0,1,2,0,2,3), +(0,3,0,3,0,1,0,3,0,2,3,3,3,0,3,1,2,0,3,3,2,3,3,2,3,2,3,1,3,0,4,3,2,0,3,3,1,4,3,3,2,3,4,3,1,3,3,1,1,0,1,1,0,1,0,1,0,1,0,0,0,4,1,1,0,3,0,3,1,0,2,3,3,3,3,3,1,0,0,2,0,3,3), +(0,0,0,0,0,0,0,0,0,0,3,0,2,0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,3,0,3,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,2,0,2,3,0,0,0,0,0,0,0,0,3), +(0,2,0,3,1,3,0,3,0,2,3,3,3,1,3,1,3,1,3,1,3,3,3,1,3,0,2,3,1,1,4,3,3,2,3,3,1,2,2,4,1,3,3,0,1,4,2,3,0,1,3,0,3,0,0,1,3,0,2,0,0,3,3,2,1,3,0,3,0,2,0,3,4,4,4,3,1,0,3,0,0,3,3), +(0,2,0,1,0,2,0,0,0,1,3,2,2,1,3,0,1,1,3,0,3,2,3,1,2,0,2,0,1,1,3,3,3,0,3,3,1,1,2,3,2,3,3,1,2,3,2,0,0,1,0,0,0,0,0,0,3,0,1,0,0,2,1,2,1,3,0,3,0,0,0,3,4,4,4,3,2,0,2,0,0,2,4), +(0,0,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,2,2,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,3,1,0,0,0,0,0,0,0,3), +(0,3,0,3,0,2,0,3,0,3,3,3,2,3,2,2,2,0,3,1,3,3,3,2,3,3,0,0,3,0,3,2,2,0,2,3,1,4,3,4,3,3,2,3,1,5,4,4,0,3,1,2,1,3,0,3,1,1,2,0,2,3,1,3,1,3,0,3,0,1,0,3,3,4,4,2,1,0,2,1,0,2,4), +(0,1,0,3,0,1,0,2,0,1,4,2,5,1,4,0,2,0,2,1,3,1,4,0,2,1,0,0,2,1,4,1,1,0,3,3,0,5,1,3,2,3,3,1,0,3,2,3,0,1,0,0,0,0,0,0,1,0,0,0,0,4,0,1,0,3,0,2,0,1,0,3,3,3,4,3,3,0,0,0,0,2,3), +(0,0,0,1,0,0,0,0,0,0,2,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,0,0,1,0,0,0,0,0,3), +(0,1,0,3,0,4,0,3,0,2,4,3,1,0,3,2,2,1,3,1,2,2,3,1,1,1,2,1,3,0,1,2,0,1,3,2,1,3,0,5,5,1,0,0,1,3,2,1,0,3,0,0,1,0,0,0,0,0,3,4,0,1,1,1,3,2,0,2,0,1,0,2,3,3,1,2,3,0,1,0,1,0,4), +(0,0,0,1,0,3,0,3,0,2,2,1,0,0,4,0,3,0,3,1,3,0,3,0,3,0,1,0,3,0,3,1,3,0,3,3,0,0,1,2,1,1,1,0,1,2,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,2,2,1,2,0,0,2,0,0,0,0,2,3,3,3,3,0,0,0,0,1,4), +(0,0,0,3,0,3,0,0,0,0,3,1,1,0,3,0,1,0,2,0,1,0,0,0,0,0,0,0,1,0,3,0,2,0,2,3,0,0,2,2,3,1,2,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,2,0,0,0,0,2,3), +(2,4,0,5,0,5,0,4,0,3,4,3,3,3,4,3,3,3,4,3,4,4,5,4,5,5,5,2,3,0,5,5,4,1,5,4,3,1,5,4,3,4,4,3,3,4,3,3,0,3,2,0,2,3,0,3,0,0,3,3,0,5,3,2,3,3,0,3,0,3,0,3,4,5,4,5,3,0,4,3,0,3,4), +(0,3,0,3,0,3,0,3,0,3,3,4,3,2,3,2,3,0,4,3,3,3,3,3,3,3,3,0,3,2,4,3,3,1,3,4,3,4,4,4,3,4,4,3,2,4,4,1,0,2,0,0,1,1,0,2,0,0,3,1,0,5,3,2,1,3,0,3,0,1,2,4,3,2,4,3,3,0,3,2,0,4,4), +(0,3,0,3,0,1,0,0,0,1,4,3,3,2,3,1,3,1,4,2,3,2,4,2,3,4,3,0,2,2,3,3,3,0,3,3,3,0,3,4,1,3,3,0,3,4,3,3,0,1,1,0,1,0,0,0,4,0,3,0,0,3,1,2,1,3,0,4,0,1,0,4,3,3,4,3,3,0,2,0,0,3,3), +(0,3,0,4,0,1,0,3,0,3,4,3,3,0,3,3,3,1,3,1,3,3,4,3,3,3,0,0,3,1,5,3,3,1,3,3,2,5,4,3,3,4,5,3,2,5,3,4,0,1,0,0,0,0,0,2,0,0,1,1,0,4,2,2,1,3,0,3,0,2,0,4,4,3,5,3,2,0,1,1,0,3,4), +(0,5,0,4,0,5,0,2,0,4,4,3,3,2,3,3,3,1,4,3,4,1,5,3,4,3,4,0,4,2,4,3,4,1,5,4,0,4,4,4,4,5,4,1,3,5,4,2,1,4,1,1,3,2,0,3,1,0,3,2,1,4,3,3,3,4,0,4,0,3,0,4,4,4,3,3,3,0,4,2,0,3,4), +(1,4,0,4,0,3,0,1,0,3,3,3,1,1,3,3,2,2,3,3,1,0,3,2,2,1,2,0,3,1,2,1,2,0,3,2,0,2,2,3,3,4,3,0,3,3,1,2,0,1,1,3,1,2,0,0,3,0,1,1,0,3,2,2,3,3,0,3,0,0,0,2,3,3,4,3,3,0,1,0,0,1,4), +(0,4,0,4,0,4,0,0,0,3,4,4,3,1,4,2,3,2,3,3,3,1,4,3,4,0,3,0,4,2,3,3,2,2,5,4,2,1,3,4,3,4,3,1,3,3,4,2,0,2,1,0,3,3,0,0,2,0,3,1,0,4,4,3,4,3,0,4,0,1,0,2,4,4,4,4,4,0,3,2,0,3,3), +(0,0,0,1,0,4,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,3,2,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,2), +(0,2,0,3,0,4,0,4,0,1,3,3,3,0,4,0,2,1,2,1,1,1,2,0,3,1,1,0,1,0,3,1,0,0,3,3,2,0,1,1,0,0,0,0,0,1,0,2,0,2,2,0,3,1,0,0,1,0,1,1,0,1,2,0,3,0,0,0,0,1,0,0,3,3,4,3,1,0,1,0,3,0,2), +(0,0,0,3,0,5,0,0,0,0,1,0,2,0,3,1,0,1,3,0,0,0,2,0,0,0,1,0,0,0,1,1,0,0,4,0,0,0,2,3,0,1,4,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,1,0,0,0,0,0,0,0,2,0,0,3,0,0,0,0,0,3), +(0,2,0,5,0,5,0,1,0,2,4,3,3,2,5,1,3,2,3,3,3,0,4,1,2,0,3,0,4,0,2,2,1,1,5,3,0,0,1,4,2,3,2,0,3,3,3,2,0,2,4,1,1,2,0,1,1,0,3,1,0,1,3,1,2,3,0,2,0,0,0,1,3,5,4,4,4,0,3,0,0,1,3), +(0,4,0,5,0,4,0,4,0,4,5,4,3,3,4,3,3,3,4,3,4,4,5,3,4,5,4,2,4,2,3,4,3,1,4,4,1,3,5,4,4,5,5,4,4,5,5,5,2,3,3,1,4,3,1,3,3,0,3,3,1,4,3,4,4,4,0,3,0,4,0,3,3,4,4,5,0,0,4,3,0,4,5), +(0,4,0,4,0,3,0,3,0,3,4,4,4,3,3,2,4,3,4,3,4,3,5,3,4,3,2,1,4,2,4,4,3,1,3,4,2,4,5,5,3,4,5,4,1,5,4,3,0,3,2,2,3,2,1,3,1,0,3,3,3,5,3,3,3,5,4,4,2,3,3,4,3,3,3,2,1,0,3,2,1,4,3), +(0,4,0,5,0,4,0,3,0,3,5,5,3,2,4,3,4,0,5,4,4,1,4,4,4,3,3,3,4,3,5,5,2,3,3,4,1,2,5,5,3,5,5,2,3,5,5,4,0,3,2,0,3,3,1,1,5,1,4,1,0,4,3,2,3,5,0,4,0,3,0,5,4,3,4,3,0,0,4,1,0,4,4), +(1,3,0,4,0,2,0,2,0,2,5,5,3,3,3,3,3,0,4,2,3,4,4,4,3,4,0,0,3,4,5,4,3,3,3,3,2,5,5,4,5,5,5,4,3,5,5,5,1,3,1,0,1,0,0,3,2,0,4,2,0,5,2,3,2,4,1,3,0,3,0,4,5,4,5,4,3,0,4,2,0,5,4), +(0,3,0,4,0,5,0,3,0,3,4,4,3,2,3,2,3,3,3,3,3,2,4,3,3,2,2,0,3,3,3,3,3,1,3,3,3,0,4,4,3,4,4,1,1,4,4,2,0,3,1,0,1,1,0,4,1,0,2,3,1,3,3,1,3,4,0,3,0,1,0,3,1,3,0,0,1,0,2,0,0,4,4), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +(0,3,0,3,0,2,0,3,0,1,5,4,3,3,3,1,4,2,1,2,3,4,4,2,4,4,5,0,3,1,4,3,4,0,4,3,3,3,2,3,2,5,3,4,3,2,2,3,0,0,3,0,2,1,0,1,2,0,0,0,0,2,1,1,3,1,0,2,0,4,0,3,4,4,4,5,2,0,2,0,0,1,3), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,0,0,1,1,0,0,0,4,2,1,1,0,1,0,3,2,0,0,3,1,1,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,1,0,0,0,2,0,0,0,1,4,0,4,2,1,0,0,0,0,0,1), +(0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,3,1,0,0,0,2,0,2,1,0,0,1,2,1,0,1,1,0,0,3,0,0,0,0,0,0,0,0,0,0,0,1,3,1,0,0,0,0,0,1,0,0,2,1,0,0,0,0,0,0,0,0,2), +(0,4,0,4,0,4,0,3,0,4,4,3,4,2,4,3,2,0,4,4,4,3,5,3,5,3,3,2,4,2,4,3,4,3,1,4,0,2,3,4,4,4,3,3,3,4,4,4,3,4,1,3,4,3,2,1,2,1,3,3,3,4,4,3,3,5,0,4,0,3,0,4,3,3,3,2,1,0,3,0,0,3,3), +(0,4,0,3,0,3,0,3,0,3,5,5,3,3,3,3,4,3,4,3,3,3,4,4,4,3,3,3,3,4,3,5,3,3,1,3,2,4,5,5,5,5,4,3,4,5,5,3,2,2,3,3,3,3,2,3,3,1,2,3,2,4,3,3,3,4,0,4,0,2,0,4,3,2,2,1,2,0,3,0,0,4,1), +) + +class JapaneseContextAnalysis(object): + NUM_OF_CATEGORY = 6 + DONT_KNOW = -1 + ENOUGH_REL_THRESHOLD = 100 + MAX_REL_THRESHOLD = 1000 + MINIMUM_DATA_THRESHOLD = 4 + + def __init__(self): + self._total_rel = None + self._rel_sample = None + self._need_to_skip_char_num = None + self._last_char_order = None + self._done = None + self.reset() + + def reset(self): + self._total_rel = 0 # total sequence received + # category counters, each integer counts sequence in its category + self._rel_sample = [0] * self.NUM_OF_CATEGORY + # if last byte in current buffer is not the last byte of a character, + # we need to know how many bytes to skip in next buffer + self._need_to_skip_char_num = 0 + self._last_char_order = -1 # The order of previous char + # If this flag is set to True, detection is done and conclusion has + # been made + self._done = False + + def feed(self, byte_str, num_bytes): + if self._done: + return + + # The buffer we got is byte oriented, and a character may span in more than one + # buffers. In case the last one or two byte in last buffer is not + # complete, we record how many byte needed to complete that character + # and skip these bytes here. We can choose to record those bytes as + # well and analyse the character once it is complete, but since a + # character will not make much difference, by simply skipping + # this character will simply our logic and improve performance. + i = self._need_to_skip_char_num + while i < num_bytes: + order, char_len = self.get_order(byte_str[i:i + 2]) + i += char_len + if i > num_bytes: + self._need_to_skip_char_num = i - num_bytes + self._last_char_order = -1 + else: + if (order != -1) and (self._last_char_order != -1): + self._total_rel += 1 + if self._total_rel > self.MAX_REL_THRESHOLD: + self._done = True + break + self._rel_sample[jp2CharContext[self._last_char_order][order]] += 1 + self._last_char_order = order + + def got_enough_data(self): + return self._total_rel > self.ENOUGH_REL_THRESHOLD + + def get_confidence(self): + # This is just one way to calculate confidence. It works well for me. + if self._total_rel > self.MINIMUM_DATA_THRESHOLD: + return (self._total_rel - self._rel_sample[0]) / self._total_rel + else: + return self.DONT_KNOW + + def get_order(self, byte_str): + return -1, 1 + +class SJISContextAnalysis(JapaneseContextAnalysis): + def __init__(self): + super(SJISContextAnalysis, self).__init__() + self._charset_name = "SHIFT_JIS" + + @property + def charset_name(self): + return self._charset_name + + def get_order(self, byte_str): + if not byte_str: + return -1, 1 + # find out current char's byte length + first_char = byte_str[0] + if (0x81 <= first_char <= 0x9F) or (0xE0 <= first_char <= 0xFC): + char_len = 2 + if (first_char == 0x87) or (0xFA <= first_char <= 0xFC): + self._charset_name = "CP932" + else: + char_len = 1 + + # return its order if it is hiragana + if len(byte_str) > 1: + second_char = byte_str[1] + if (first_char == 202) and (0x9F <= second_char <= 0xF1): + return second_char - 0x9F, char_len + + return -1, char_len + +class EUCJPContextAnalysis(JapaneseContextAnalysis): + def get_order(self, byte_str): + if not byte_str: + return -1, 1 + # find out current char's byte length + first_char = byte_str[0] + if (first_char == 0x8E) or (0xA1 <= first_char <= 0xFE): + char_len = 2 + elif first_char == 0x8F: + char_len = 3 + else: + char_len = 1 + + # return its order if it is hiragana + if len(byte_str) > 1: + second_char = byte_str[1] + if (first_char == 0xA4) and (0xA1 <= second_char <= 0xF3): + return second_char - 0xA1, char_len + + return -1, char_len + + diff --git a/venv/lib/python2.7/site-packages/chardet/langbulgarianmodel.py b/venv/lib/python2.7/site-packages/chardet/langbulgarianmodel.py new file mode 100644 index 0000000..2aa4fb2 --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/langbulgarianmodel.py @@ -0,0 +1,228 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +# this table is modified base on win1251BulgarianCharToOrderMap, so +# only number <64 is sure valid + +Latin5_BulgarianCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 77, 90, 99,100, 72,109,107,101, 79,185, 81,102, 76, 94, 82, # 40 +110,186,108, 91, 74,119, 84, 96,111,187,115,253,253,253,253,253, # 50 +253, 65, 69, 70, 66, 63, 68,112,103, 92,194,104, 95, 86, 87, 71, # 60 +116,195, 85, 93, 97,113,196,197,198,199,200,253,253,253,253,253, # 70 +194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209, # 80 +210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225, # 90 + 81,226,227,228,229,230,105,231,232,233,234,235,236, 45,237,238, # a0 + 31, 32, 35, 43, 37, 44, 55, 47, 40, 59, 33, 46, 38, 36, 41, 30, # b0 + 39, 28, 34, 51, 48, 49, 53, 50, 54, 57, 61,239, 67,240, 60, 56, # c0 + 1, 18, 9, 20, 11, 3, 23, 15, 2, 26, 12, 10, 14, 6, 4, 13, # d0 + 7, 8, 5, 19, 29, 25, 22, 21, 27, 24, 17, 75, 52,241, 42, 16, # e0 + 62,242,243,244, 58,245, 98,246,247,248,249,250,251, 91,252,253, # f0 +) + +win1251BulgarianCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 77, 90, 99,100, 72,109,107,101, 79,185, 81,102, 76, 94, 82, # 40 +110,186,108, 91, 74,119, 84, 96,111,187,115,253,253,253,253,253, # 50 +253, 65, 69, 70, 66, 63, 68,112,103, 92,194,104, 95, 86, 87, 71, # 60 +116,195, 85, 93, 97,113,196,197,198,199,200,253,253,253,253,253, # 70 +206,207,208,209,210,211,212,213,120,214,215,216,217,218,219,220, # 80 +221, 78, 64, 83,121, 98,117,105,222,223,224,225,226,227,228,229, # 90 + 88,230,231,232,233,122, 89,106,234,235,236,237,238, 45,239,240, # a0 + 73, 80,118,114,241,242,243,244,245, 62, 58,246,247,248,249,250, # b0 + 31, 32, 35, 43, 37, 44, 55, 47, 40, 59, 33, 46, 38, 36, 41, 30, # c0 + 39, 28, 34, 51, 48, 49, 53, 50, 54, 57, 61,251, 67,252, 60, 56, # d0 + 1, 18, 9, 20, 11, 3, 23, 15, 2, 26, 12, 10, 14, 6, 4, 13, # e0 + 7, 8, 5, 19, 29, 25, 22, 21, 27, 24, 17, 75, 52,253, 42, 16, # f0 +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 96.9392% +# first 1024 sequences:3.0618% +# rest sequences: 0.2992% +# negative sequences: 0.0020% +BulgarianLangModel = ( +0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,2,3,3,3,3,3, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,2,2,3,2,2,1,2,2, +3,1,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,3,3,3,3,3,3,3,0,3,0,1, +0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,2,3,3,3,3,3,3,3,3,0,3,1,0, +0,1,0,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,2,3,3,3,3,3,3,3,3,0,3,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,1,3,2,3,3,3,3,3,3,3,3,0,3,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,2,3,2,2,1,3,3,3,3,2,2,2,1,1,2,0,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,2,3,2,2,3,3,1,1,2,3,3,2,3,3,3,3,2,1,2,0,2,0,3,0,0, +0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,1,3,3,3,3,3,2,3,2,3,3,3,3,3,2,3,3,1,3,0,3,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,1,3,3,2,3,3,3,1,3,3,2,3,2,2,2,0,0,2,0,2,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,0,3,3,3,2,2,3,3,3,1,2,2,3,2,1,1,2,0,2,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,2,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,2,3,3,1,2,3,2,2,2,3,3,3,3,3,2,2,3,1,2,0,2,1,2,0,0, +0,0,0,0,0,0,0,0,0,0,3,0,0,1,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,1,3,3,3,3,3,2,3,3,3,2,3,3,2,3,2,2,2,3,1,2,0,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,3,3,1,1,1,2,2,1,3,1,3,2,2,3,0,0,1,0,1,0,1,0,0, +0,0,0,1,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,2,2,3,2,2,3,1,2,1,1,1,2,3,1,3,1,2,2,0,1,1,1,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,1,3,2,2,3,3,1,2,3,1,1,3,3,3,3,1,2,2,1,1,1,0,2,0,2,0,1, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,2,2,3,3,3,2,2,1,1,2,0,2,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,0,1,2,1,3,3,2,3,3,3,3,3,2,3,2,1,0,3,1,2,1,2,1,2,3,2,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,1,2,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3,1,3,3,2,3,3,2,2,2,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,0,3,3,3,3,3,2,1,1,2,1,3,3,0,3,1,1,1,1,3,2,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,2,2,2,3,3,3,3,3,3,3,3,3,3,3,1,1,3,1,3,3,2,3,2,2,2,3,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,2,3,3,2,2,3,2,1,1,1,1,1,3,1,3,1,1,0,0,0,1,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,2,3,2,0,3,2,0,3,0,2,0,0,2,1,3,1,0,0,1,0,0,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,2,1,1,1,1,2,1,1,2,1,1,1,2,2,1,2,1,1,1,0,1,1,0,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,2,1,3,1,1,2,1,3,2,1,1,0,1,2,3,2,1,1,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,2,2,1,0,1,0,0,1,0,0,0,2,1,0,3,0,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,2,3,2,3,3,1,3,2,1,1,1,2,1,1,2,1,3,0,1,0,0,0,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,2,2,3,3,2,3,2,2,2,3,1,2,2,1,1,2,1,1,2,2,0,1,1,0,1,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,1,3,1,0,2,2,1,3,2,1,0,0,2,0,2,0,1,0,0,0,0,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,1,2,0,2,3,1,2,3,2,0,1,3,1,2,1,1,1,0,0,1,0,0,2,2,2,3, +2,2,2,2,1,2,1,1,2,2,1,1,2,0,1,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,0,1, +3,3,3,3,3,2,1,2,2,1,2,0,2,0,1,0,1,2,1,2,1,1,0,0,0,1,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,2,3,3,1,1,3,1,0,3,2,1,0,0,0,1,2,0,2,0,1,0,0,0,1,0,1,2,1,2,2, +1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,0,1,2,1,1,1,0,0,0,0,0,1,1,0,0, +3,1,0,1,0,2,3,2,2,2,3,2,2,2,2,2,1,0,2,1,2,1,1,1,0,1,2,1,2,2,2,1, +1,1,2,2,2,2,1,2,1,1,0,1,2,1,2,2,2,1,1,1,0,1,1,1,1,2,0,1,0,0,0,0, +2,3,2,3,3,0,0,2,1,0,2,1,0,0,0,0,2,3,0,2,0,0,0,0,0,1,0,0,2,0,1,2, +2,1,2,1,2,2,1,1,1,2,1,1,1,0,1,2,2,1,1,1,1,1,0,1,1,1,0,0,1,2,0,0, +3,3,2,2,3,0,2,3,1,1,2,0,0,0,1,0,0,2,0,2,0,0,0,1,0,1,0,1,2,0,2,2, +1,1,1,1,2,1,0,1,2,2,2,1,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,1,1,0,0, +2,3,2,3,3,0,0,3,0,1,1,0,1,0,0,0,2,2,1,2,0,0,0,0,0,0,0,0,2,0,1,2, +2,2,1,1,1,1,1,2,2,2,1,0,2,0,1,0,1,0,0,1,0,1,0,0,1,0,0,0,0,1,0,0, +3,3,3,3,2,2,2,2,2,0,2,1,1,1,1,2,1,2,1,1,0,2,0,1,0,1,0,0,2,0,1,2, +1,1,1,1,1,1,1,2,2,1,1,0,2,0,1,0,2,0,0,1,1,1,0,0,2,0,0,0,1,1,0,0, +2,3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,2,0,0,1,1,0,0,0,0,0,0,1,2,0,1,2, +2,2,2,1,1,2,1,1,2,2,2,1,2,0,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,0,0, +2,3,3,3,3,0,2,2,0,2,1,0,0,0,1,1,1,2,0,2,0,0,0,3,0,0,0,0,2,0,2,2, +1,1,1,2,1,2,1,1,2,2,2,1,2,0,1,1,1,0,1,1,1,1,0,2,1,0,0,0,1,1,0,0, +2,3,3,3,3,0,2,1,0,0,2,0,0,0,0,0,1,2,0,2,0,0,0,0,0,0,0,0,2,0,1,2, +1,1,1,2,1,1,1,1,2,2,2,0,1,0,1,1,1,0,0,1,1,1,0,0,1,0,0,0,0,1,0,0, +3,3,2,2,3,0,1,0,1,0,0,0,0,0,0,0,1,1,0,3,0,0,0,0,0,0,0,0,1,0,2,2, +1,1,1,1,1,2,1,1,2,2,1,2,2,1,0,1,1,1,1,1,0,1,0,0,1,0,0,0,1,1,0,0, +3,1,0,1,0,2,2,2,2,3,2,1,1,1,2,3,0,0,1,0,2,1,1,0,1,1,1,1,2,1,1,1, +1,2,2,1,2,1,2,2,1,1,0,1,2,1,2,2,1,1,1,0,0,1,1,1,2,1,0,1,0,0,0,0, +2,1,0,1,0,3,1,2,2,2,2,1,2,2,1,1,1,0,2,1,2,2,1,1,2,1,1,0,2,1,1,1, +1,2,2,2,2,2,2,2,1,2,0,1,1,0,2,1,1,1,1,1,0,0,1,1,1,1,0,1,0,0,0,0, +2,1,1,1,1,2,2,2,2,1,2,2,2,1,2,2,1,1,2,1,2,3,2,2,1,1,1,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,3,2,0,1,2,0,1,2,1,1,0,1,0,1,2,1,2,0,0,0,1,1,0,0,0,1,0,0,2, +1,1,0,0,1,1,0,1,1,1,1,0,2,0,1,1,1,0,0,1,1,0,0,0,0,1,0,0,0,1,0,0, +2,0,0,0,0,1,2,2,2,2,2,2,2,1,2,1,1,1,1,1,1,1,0,1,1,1,1,1,2,1,1,1, +1,2,2,2,2,1,1,2,1,2,1,1,1,0,2,1,2,1,1,1,0,2,1,1,1,1,0,1,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, +1,1,0,1,0,1,1,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,3,2,0,0,0,0,1,0,0,0,0,0,0,1,1,0,2,0,0,0,0,0,0,0,0,1,0,1,2, +1,1,1,1,1,1,0,0,2,2,2,2,2,0,1,1,0,1,1,1,1,1,0,0,1,0,0,0,1,1,0,1, +2,3,1,2,1,0,1,1,0,2,2,2,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,0,1,2, +1,1,1,1,2,1,1,1,1,1,1,1,1,0,1,1,0,1,0,1,0,1,0,0,1,0,0,0,0,1,0,0, +2,2,2,2,2,0,0,2,0,0,2,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,2,0,2,2, +1,1,1,1,1,0,0,1,2,1,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,0,2,0,1,1,0,0,0,1,0,0,2,0,2,0,0,0,0,0,0,0,0,0,0,1,1, +0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,3,2,0,0,1,0,0,1,0,0,0,0,0,0,1,0,2,0,0,0,1,0,0,0,0,0,0,0,2, +1,1,0,0,1,0,0,0,1,1,0,0,1,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +2,1,2,2,2,1,2,1,2,2,1,1,2,1,1,1,0,1,1,1,1,2,0,1,0,1,1,1,1,0,1,1, +1,1,2,1,1,1,1,1,1,0,0,1,2,1,1,1,1,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0, +1,0,0,1,3,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,1,0,0,1,0,2,0,0,0,0,0,1,1,1,0,1,0,0,0,0,0,0,0,0,2,0,0,1, +0,2,0,1,0,0,1,1,2,0,1,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,1,1,0,2,1,0,1,1,1,0,0,1,0,2,0,1,0,0,0,0,0,0,0,0,0,1, +0,1,0,0,1,0,0,0,1,1,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,2,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1, +0,1,0,1,1,1,0,0,1,1,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +2,0,1,0,0,1,2,1,1,1,1,1,1,2,2,1,0,0,1,0,1,0,0,0,0,1,1,1,1,0,0,0, +1,1,2,1,1,1,1,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,1,2,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1, +0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +0,1,1,0,1,1,1,0,0,1,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0, +1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,2,0,0,2,0,1,0,0,1,0,0,1, +1,1,0,0,1,1,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, +1,1,1,1,1,1,1,2,0,0,0,0,0,0,2,1,0,1,1,0,0,1,1,1,0,1,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +) + +Latin5BulgarianModel = { + 'char_to_order_map': Latin5_BulgarianCharToOrderMap, + 'precedence_matrix': BulgarianLangModel, + 'typical_positive_ratio': 0.969392, + 'keep_english_letter': False, + 'charset_name': "ISO-8859-5", + 'language': 'Bulgairan', +} + +Win1251BulgarianModel = { + 'char_to_order_map': win1251BulgarianCharToOrderMap, + 'precedence_matrix': BulgarianLangModel, + 'typical_positive_ratio': 0.969392, + 'keep_english_letter': False, + 'charset_name': "windows-1251", + 'language': 'Bulgarian', +} diff --git a/venv/lib/python2.7/site-packages/chardet/langcyrillicmodel.py b/venv/lib/python2.7/site-packages/chardet/langcyrillicmodel.py new file mode 100644 index 0000000..e5f9a1f --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/langcyrillicmodel.py @@ -0,0 +1,333 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# KOI8-R language model +# Character Mapping Table: +KOI8R_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, # 80 +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, # 90 +223,224,225, 68,226,227,228,229,230,231,232,233,234,235,236,237, # a0 +238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253, # b0 + 27, 3, 21, 28, 13, 2, 39, 19, 26, 4, 23, 11, 8, 12, 5, 1, # c0 + 15, 16, 9, 7, 6, 14, 24, 10, 17, 18, 20, 25, 30, 29, 22, 54, # d0 + 59, 37, 44, 58, 41, 48, 53, 46, 55, 42, 60, 36, 49, 38, 31, 34, # e0 + 35, 43, 45, 32, 40, 52, 56, 33, 61, 62, 51, 57, 47, 63, 50, 70, # f0 +) + +win1251_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, +239,240,241,242,243,244,245,246, 68,247,248,249,250,251,252,253, + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, +) + +latin5_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, +239, 68,240,241,242,243,244,245,246,247,248,249,250,251,252,255, +) + +macCyrillic_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, +239,240,241,242,243,244,245,246,247,248,249,250,251,252, 68, 16, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27,255, +) + +IBM855_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194, 68,195,196,197,198,199,200,201,202,203,204,205, +206,207,208,209,210,211,212,213,214,215,216,217, 27, 59, 54, 70, + 3, 37, 21, 44, 28, 58, 13, 41, 2, 48, 39, 53, 19, 46,218,219, +220,221,222,223,224, 26, 55, 4, 42,225,226,227,228, 23, 60,229, +230,231,232,233,234,235, 11, 36,236,237,238,239,240,241,242,243, + 8, 49, 12, 38, 5, 31, 1, 34, 15,244,245,246,247, 35, 16,248, + 43, 9, 45, 7, 32, 6, 40, 14, 52, 24, 56, 10, 33, 17, 61,249, +250, 18, 62, 20, 51, 25, 57, 30, 47, 29, 63, 22, 50,251,252,255, +) + +IBM866_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, +239, 68,240,241,242,243,244,245,246,247,248,249,250,251,252,255, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 97.6601% +# first 1024 sequences: 2.3389% +# rest sequences: 0.1237% +# negative sequences: 0.0009% +RussianLangModel = ( +0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,1,3,3,3,2,3,2,3,3, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,2,2,2,2,2,0,0,2, +3,3,3,2,3,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,3,2,3,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,2,2,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,2,3,3,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3,3,3,3,3,3,3,3,3,3,3,2,1, +0,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,3,3,3,2,1, +0,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,2,2,2,3,1,3,3,1,3,3,3,3,2,2,3,0,2,2,2,3,3,2,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,3,3,3,2,2,3,2,3,3,3,2,1,2,2,0,1,2,2,2,2,2,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,3,0,2,2,3,3,2,1,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,1,2,3,2,2,3,2,3,3,3,3,2,2,3,0,3,2,2,3,1,1,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,2,3,3,3,3,2,2,2,0,3,3,3,2,2,2,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,2,3,2,3,3,3,3,3,3,2,3,2,2,0,1,3,2,1,2,2,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,2,1,1,3,0,1,1,1,1,2,1,1,0,2,2,2,1,2,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,2,2,2,2,1,3,2,3,2,3,2,1,2,2,0,1,1,2,1,2,1,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,2,2,3,2,3,3,3,2,2,2,2,0,2,2,2,2,3,1,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,2,3,2,2,3,3,3,3,3,3,3,3,3,1,3,2,0,0,3,3,3,3,2,3,3,3,3,2,3,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,3,2,2,3,3,0,2,1,0,3,2,3,2,3,0,0,1,2,0,0,1,0,1,2,1,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,3,0,2,3,3,3,3,2,3,3,3,3,1,2,2,0,0,2,3,2,2,2,3,2,3,2,2,3,0,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,0,2,3,2,3,0,1,2,3,3,2,0,2,3,0,0,2,3,2,2,0,1,3,1,3,2,2,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,3,0,2,3,3,3,3,3,3,3,3,2,1,3,2,0,0,2,2,3,3,3,2,3,3,0,2,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,2,3,3,2,2,2,3,3,0,0,1,1,1,1,1,2,0,0,1,1,1,1,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,2,3,3,3,3,3,3,3,0,3,2,3,3,2,3,2,0,2,1,0,1,1,0,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,3,2,2,2,2,3,1,3,2,3,1,1,2,1,0,2,2,2,2,1,3,1,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +2,2,3,3,3,3,3,1,2,2,1,3,1,0,3,0,0,3,0,0,0,1,1,0,1,2,1,0,0,0,0,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,2,1,1,3,3,3,2,2,1,2,2,3,1,1,2,0,0,2,2,1,3,0,0,2,1,1,2,1,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,3,3,3,1,2,2,2,1,2,1,3,3,1,1,2,1,2,1,2,2,0,2,0,0,1,1,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,3,2,1,3,2,2,3,2,0,3,2,0,3,0,1,0,1,1,0,0,1,1,1,1,0,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,2,3,3,3,2,2,2,3,3,1,2,1,2,1,0,1,0,1,1,0,1,0,0,2,1,1,1,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +3,1,1,2,1,2,3,3,2,2,1,2,2,3,0,2,1,0,0,2,2,3,2,1,2,2,2,2,2,3,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,1,1,0,1,1,2,2,1,1,3,0,0,1,3,1,1,1,0,0,0,1,0,1,1,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,3,3,3,2,0,0,0,2,1,0,1,0,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,1,0,0,2,3,2,2,2,1,2,2,2,1,2,1,0,0,1,1,1,0,2,0,1,1,1,0,0,1,1, +1,0,0,0,0,0,1,2,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,0,0,0,0,1,0,0,0,0,3,0,1,2,1,0,0,0,0,0,0,0,1,1,0,0,1,1, +1,0,1,0,1,2,0,0,1,1,2,1,0,1,1,1,1,0,1,1,1,1,0,1,0,0,1,0,0,1,1,0, +2,2,3,2,2,2,3,1,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,0,1,0,1,1,1,0,2,1, +1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,0,1,1,0, +3,3,3,2,2,2,2,3,2,2,1,1,2,2,2,2,1,1,3,1,2,1,2,0,0,1,1,0,1,0,2,1, +1,1,1,1,1,2,1,0,1,1,1,1,0,1,0,0,1,1,0,0,1,0,1,0,0,1,0,0,0,1,1,0, +2,0,0,1,0,3,2,2,2,2,1,2,1,2,1,2,0,0,0,2,1,2,2,1,1,2,2,0,1,1,0,2, +1,1,1,1,1,0,1,1,1,2,1,1,1,2,1,0,1,2,1,1,1,1,0,1,1,1,0,0,1,0,0,1, +1,3,2,2,2,1,1,1,2,3,0,0,0,0,2,0,2,2,1,0,0,0,0,0,0,1,0,0,0,0,1,1, +1,0,1,1,0,1,0,1,1,0,1,1,0,2,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0, +2,3,2,3,2,1,2,2,2,2,1,0,0,0,2,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,2,1, +1,1,2,1,0,2,0,0,1,0,1,0,0,1,0,0,1,1,0,1,1,0,0,0,0,0,1,0,0,0,0,0, +3,0,0,1,0,2,2,2,3,2,2,2,2,2,2,2,0,0,0,2,1,2,1,1,1,2,2,0,0,0,1,2, +1,1,1,1,1,0,1,2,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,1, +2,3,2,3,3,2,0,1,1,1,0,0,1,0,2,0,1,1,3,1,0,0,0,0,0,0,0,1,0,0,2,1, +1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,0,0,1,1,0,1,0,0,0,0,0,0,1,0, +2,3,3,3,3,1,2,2,2,2,0,1,1,0,2,1,1,1,2,1,0,1,1,0,0,1,0,1,0,0,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,2,0,0,1,1,2,2,1,0,0,2,0,1,1,3,0,0,1,0,0,0,0,0,1,0,1,2,1, +1,1,2,0,1,1,1,0,1,0,1,1,0,1,0,1,1,1,1,0,1,0,0,0,0,0,0,1,0,1,1,0, +1,3,2,3,2,1,0,0,2,2,2,0,1,0,2,0,1,1,1,0,1,0,0,0,3,0,1,1,0,0,2,1, +1,1,1,0,1,1,0,0,0,0,1,1,0,1,0,0,2,1,1,0,1,0,0,0,1,0,1,0,0,1,1,0, +3,1,2,1,1,2,2,2,2,2,2,1,2,2,1,1,0,0,0,2,2,2,0,0,0,1,2,1,0,1,0,1, +2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,2,1,1,1,0,1,0,1,1,0,1,1,1,0,0,1, +3,0,0,0,0,2,0,1,1,1,1,1,1,1,0,1,0,0,0,1,1,1,0,1,0,1,1,0,0,1,0,1, +1,1,0,0,1,0,0,0,1,0,1,1,0,0,1,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,1, +1,3,3,2,2,0,0,0,2,2,0,0,0,1,2,0,1,1,2,0,0,0,0,0,0,0,0,1,0,0,2,1, +0,1,1,0,0,1,1,0,0,0,1,1,0,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0, +2,3,2,3,2,0,0,0,0,1,1,0,0,0,2,0,2,0,2,0,0,0,0,0,1,0,0,1,0,0,1,1, +1,1,2,0,1,2,1,0,1,1,2,1,1,1,1,1,2,1,1,0,1,0,0,1,1,1,1,1,0,1,1,0, +1,3,2,2,2,1,0,0,2,2,1,0,1,2,2,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1,1, +0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,0,2,3,1,2,2,2,2,2,2,1,1,0,0,0,1,0,1,0,2,1,1,1,0,0,0,0,1, +1,1,0,1,1,0,1,1,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +2,0,2,0,0,1,0,3,2,1,2,1,2,2,0,1,0,0,0,2,1,0,0,2,1,1,1,1,0,2,0,2, +2,1,1,1,1,1,1,1,1,1,1,1,1,2,1,0,1,1,1,1,0,0,0,1,1,1,1,0,1,0,0,1, +1,2,2,2,2,1,0,0,1,0,0,0,0,0,2,0,1,1,1,1,0,0,0,0,1,0,1,2,0,0,2,0, +1,0,1,1,1,2,1,0,1,0,1,1,0,0,1,0,1,1,1,0,1,0,0,0,1,0,0,1,0,1,1,0, +2,1,2,2,2,0,3,0,1,1,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +0,0,0,1,1,1,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0, +1,2,2,3,2,2,0,0,1,1,2,0,1,2,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1, +0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0, +2,2,1,1,2,1,2,2,2,2,2,1,2,2,0,1,0,0,0,1,2,2,2,1,2,1,1,1,1,1,2,1, +1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,1,0,0,0,0,1,1,1,0,1,1,0,0,1, +1,2,2,2,2,0,1,0,2,2,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0, +0,0,1,0,0,1,0,0,0,0,1,0,1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,0,0,2,2,2,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1, +0,1,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,0,0,0,1,0,0,1,1,2,0,0,0,0,1,0,1,0,0,1,0,0,2,0,0,0,1, +0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,1,1,2,0,2,1,1,1,1,0,2,2,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1, +0,0,1,0,1,1,0,0,0,0,1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +1,0,2,1,2,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0, +0,0,1,0,1,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0, +1,0,0,0,0,2,0,1,2,1,0,1,1,1,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1, +0,0,0,0,0,1,0,0,1,1,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1, +2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,1,1,0,1,0,1,0,0,1,1,1,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,1,0,1,1,0,1,0,1,0,0,0,0,1,1,0,1,1,0,0,0,0,0,1,0,1,1,0,1,0,0,0, +0,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, +) + +Koi8rModel = { + 'char_to_order_map': KOI8R_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "KOI8-R", + 'language': 'Russian', +} + +Win1251CyrillicModel = { + 'char_to_order_map': win1251_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "windows-1251", + 'language': 'Russian', +} + +Latin5CyrillicModel = { + 'char_to_order_map': latin5_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "ISO-8859-5", + 'language': 'Russian', +} + +MacCyrillicModel = { + 'char_to_order_map': macCyrillic_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "MacCyrillic", + 'language': 'Russian', +} + +Ibm866Model = { + 'char_to_order_map': IBM866_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "IBM866", + 'language': 'Russian', +} + +Ibm855Model = { + 'char_to_order_map': IBM855_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "IBM855", + 'language': 'Russian', +} diff --git a/venv/lib/python2.7/site-packages/chardet/langgreekmodel.py b/venv/lib/python2.7/site-packages/chardet/langgreekmodel.py new file mode 100644 index 0000000..5332221 --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/langgreekmodel.py @@ -0,0 +1,225 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +Latin7_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 82,100,104, 94, 98,101,116,102,111,187,117, 92, 88,113, 85, # 40 + 79,118,105, 83, 67,114,119, 95, 99,109,188,253,253,253,253,253, # 50 +253, 72, 70, 80, 81, 60, 96, 93, 89, 68,120, 97, 77, 86, 69, 55, # 60 + 78,115, 65, 66, 58, 76,106,103, 87,107,112,253,253,253,253,253, # 70 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 80 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 90 +253,233, 90,253,253,253,253,253,253,253,253,253,253, 74,253,253, # a0 +253,253,253,253,247,248, 61, 36, 46, 71, 73,253, 54,253,108,123, # b0 +110, 31, 51, 43, 41, 34, 91, 40, 52, 47, 44, 53, 38, 49, 59, 39, # c0 + 35, 48,250, 37, 33, 45, 56, 50, 84, 57,120,121, 17, 18, 22, 15, # d0 +124, 1, 29, 20, 21, 3, 32, 13, 25, 5, 11, 16, 10, 6, 30, 4, # e0 + 9, 8, 14, 7, 2, 12, 28, 23, 42, 24, 64, 75, 19, 26, 27,253, # f0 +) + +win1253_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 82,100,104, 94, 98,101,116,102,111,187,117, 92, 88,113, 85, # 40 + 79,118,105, 83, 67,114,119, 95, 99,109,188,253,253,253,253,253, # 50 +253, 72, 70, 80, 81, 60, 96, 93, 89, 68,120, 97, 77, 86, 69, 55, # 60 + 78,115, 65, 66, 58, 76,106,103, 87,107,112,253,253,253,253,253, # 70 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 80 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 90 +253,233, 61,253,253,253,253,253,253,253,253,253,253, 74,253,253, # a0 +253,253,253,253,247,253,253, 36, 46, 71, 73,253, 54,253,108,123, # b0 +110, 31, 51, 43, 41, 34, 91, 40, 52, 47, 44, 53, 38, 49, 59, 39, # c0 + 35, 48,250, 37, 33, 45, 56, 50, 84, 57,120,121, 17, 18, 22, 15, # d0 +124, 1, 29, 20, 21, 3, 32, 13, 25, 5, 11, 16, 10, 6, 30, 4, # e0 + 9, 8, 14, 7, 2, 12, 28, 23, 42, 24, 64, 75, 19, 26, 27,253, # f0 +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 98.2851% +# first 1024 sequences:1.7001% +# rest sequences: 0.0359% +# negative sequences: 0.0148% +GreekLangModel = ( +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,2,2,3,3,3,3,3,3,3,3,1,3,3,3,0,2,2,3,3,0,3,0,3,2,0,3,3,3,0, +3,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,0,3,3,0,3,2,3,3,0,3,2,3,3,3,0,0,3,0,3,0,3,3,2,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +0,2,3,2,2,3,3,3,3,3,3,3,3,0,3,3,3,3,0,2,3,3,0,3,3,3,3,2,3,3,3,0, +2,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,0,2,1,3,3,3,3,2,3,3,2,3,3,2,0, +0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,0,3,3,3,3,3,3,0,3,3,0,3,3,3,3,3,3,3,3,3,3,0,3,2,3,3,0, +2,0,1,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,3,0,0,0,0,3,3,0,3,1,3,3,3,0,3,3,0,3,3,3,3,0,0,0,0, +2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,0,3,0,3,3,3,3,3,0,3,2,2,2,3,0,2,3,3,3,3,3,2,3,3,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,3,2,2,2,3,3,3,3,0,3,1,3,3,3,3,2,3,3,3,3,3,3,3,2,2,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,0,3,0,0,0,3,3,2,3,3,3,3,3,0,0,3,2,3,0,2,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,3,0,0,3,3,0,2,3,0,3,0,3,3,3,0,0,3,0,3,0,2,2,3,3,0,0, +0,0,1,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,0,3,2,3,3,3,3,0,3,3,3,3,3,0,3,3,2,3,2,3,3,2,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,2,3,2,3,3,3,3,3,3,0,2,3,2,3,2,2,2,3,2,3,3,2,3,0,2,2,2,3,0, +2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,0,3,3,3,2,3,3,0,0,3,0,3,0,0,0,3,2,0,3,0,3,0,0,2,0,2,0, +0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,0,3,3,3,3,3,3,0,3,3,0,3,0,0,0,3,3,0,3,3,3,0,0,1,2,3,0, +3,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,0,0,3,2,2,3,3,0,3,3,3,3,3,2,1,3,0,3,2,3,3,2,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,3,0,2,3,3,3,3,3,3,0,0,3,0,3,0,0,0,3,3,0,3,2,3,0,0,3,3,3,0, +3,0,0,0,2,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,0,3,3,3,3,3,3,0,0,3,0,3,0,0,0,3,2,0,3,2,3,0,0,3,2,3,0, +2,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,1,2,2,3,3,3,3,3,3,0,2,3,0,3,0,0,0,3,3,0,3,0,2,0,0,2,3,1,0, +2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,3,0,3,0,3,3,2,3,0,3,3,3,3,3,3,0,3,3,3,0,2,3,0,0,3,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,0,0,3,0,0,0,3,3,0,3,0,2,3,3,0,0,3,0,3,0,3,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,0,3,3,3,3,3,3,0,0,3,0,2,0,0,0,3,3,0,3,0,3,0,0,2,0,2,0, +0,0,0,0,1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,3,0,3,0,2,0,3,2,0,3,2,3,2,3,0,0,3,2,3,2,3,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,2,3,3,3,3,3,0,0,0,3,0,2,1,0,0,3,2,2,2,0,3,0,0,2,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,2,0,3,0,3,0,3,3,0,2,1,2,3,3,0,0,3,0,3,0,3,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,3,3,3,0,3,3,3,3,3,3,0,2,3,0,3,0,0,0,2,1,0,2,2,3,0,0,2,2,2,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,2,3,3,3,2,3,0,0,1,3,0,2,0,0,0,0,3,0,1,0,2,0,0,1,1,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,1,0,3,0,0,0,3,2,0,3,2,3,3,3,0,0,3,0,3,2,2,2,1,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,0,0,3,0,0,0,0,2,0,2,3,3,2,2,2,2,3,0,2,0,2,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,2,0,0,0,0,0,0,2,3,0,2,0,2,3,2,0,0,3,0,3,0,3,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,3,2,3,3,2,2,3,0,2,0,3,0,0,0,2,0,0,0,0,1,2,0,2,0,2,0, +0,2,0,2,0,2,2,0,0,1,0,2,2,2,0,2,2,2,0,2,2,2,0,0,2,0,0,1,0,0,0,0, +0,2,0,3,3,2,0,0,0,0,0,0,1,3,0,2,0,2,2,2,0,0,2,0,3,0,0,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,2,3,2,0,2,2,0,2,0,2,2,0,2,0,2,2,2,0,0,0,0,0,0,2,3,0,0,0,2, +0,1,2,0,0,0,0,2,2,0,0,0,2,1,0,2,2,0,0,0,0,0,0,1,0,2,0,0,0,0,0,0, +0,0,2,1,0,2,3,2,2,3,2,3,2,0,0,3,3,3,0,0,3,2,0,0,0,1,1,0,2,0,2,2, +0,2,0,2,0,2,2,0,0,2,0,2,2,2,0,2,2,2,2,0,0,2,0,0,0,2,0,1,0,0,0,0, +0,3,0,3,3,2,2,0,3,0,0,0,2,2,0,2,2,2,1,2,0,0,1,2,2,0,0,3,0,0,0,2, +0,1,2,0,0,0,1,2,0,0,0,0,0,0,0,2,2,0,1,0,0,2,0,0,0,2,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,3,3,2,2,0,0,0,2,0,2,3,3,0,2,0,0,0,0,0,0,2,2,2,0,2,2,0,2,0,2, +0,2,2,0,0,2,2,2,2,1,0,0,2,2,0,2,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0, +0,2,0,3,2,3,0,0,0,3,0,0,2,2,0,2,0,2,2,2,0,0,2,0,0,0,0,0,0,0,0,2, +0,0,2,2,0,0,2,2,2,0,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,3,2,0,2,2,2,2,2,0,0,0,2,0,0,0,0,2,0,1,0,0,2,0,1,0,0,0, +0,2,2,2,0,2,2,0,1,2,0,2,2,2,0,2,2,2,2,1,2,2,0,0,2,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,2,0,2,0,2,2,0,0,0,0,1,2,1,0,0,2,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,3,2,3,0,0,2,0,0,0,2,2,0,2,0,0,0,1,0,0,2,0,2,0,2,2,0,0,0,0, +0,0,2,0,0,0,0,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0, +0,2,2,3,2,2,0,0,0,0,0,0,1,3,0,2,0,2,2,0,0,0,1,0,2,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,0,2,0,3,2,0,2,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +0,0,2,0,0,0,0,1,1,0,0,2,1,2,0,2,2,0,1,0,0,1,0,0,0,2,0,0,0,0,0,0, +0,3,0,2,2,2,0,0,2,0,0,0,2,0,0,0,2,3,0,2,0,0,0,0,0,0,2,2,0,0,0,2, +0,1,2,0,0,0,1,2,2,1,0,0,0,2,0,0,2,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,1,2,0,2,2,0,2,0,0,2,0,0,0,0,1,2,1,0,2,1,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,0,3,1,2,2,0,2,0,0,0,0,2,0,0,0,2,0,0,3,0,0,0,0,2,2,2,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,1,0,2,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,2, +0,2,2,0,0,2,2,2,2,2,0,1,2,0,0,0,2,2,0,1,0,2,0,0,2,2,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,3,0,0,2,0,0,0,0,0,0,0,0,2,0,2,0,0,0,0,2, +0,1,2,0,0,0,0,2,2,1,0,1,0,1,0,2,2,2,1,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,2,0,1,2,0,0,0,0,0,0,0,0,0,0,2,0,0,2,2,0,0,0,0,1,0,0,0,0,0,0,2, +0,2,2,0,0,0,0,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0, +0,2,2,2,2,0,0,0,3,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0,1, +0,0,2,0,0,0,0,1,2,0,0,0,0,0,0,2,2,1,1,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,2,0,2,2,2,0,0,2,0,0,0,0,0,0,0,2,2,2,0,0,0,2,0,0,0,0,0,0,0,0,2, +0,0,1,0,0,0,0,2,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +0,3,0,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,2, +0,0,2,0,0,0,0,2,2,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,0,2,2,1,0,0,0,0,0,0,2,0,0,2,0,2,2,2,0,0,0,0,0,0,2,0,0,0,0,2, +0,0,2,0,0,2,0,2,2,0,0,0,0,2,0,2,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0, +0,0,3,0,0,0,2,2,0,2,2,0,0,0,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0,0,0, +0,2,2,2,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1, +0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,2,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,2,0,0,0,2,0,0,0,0,0,1,0,0,0,0,2,2,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,2,0,0,0, +0,2,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,2,0,2,0,0,0, +0,0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,2,0,0,0,1,2,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +) + +Latin7GreekModel = { + 'char_to_order_map': Latin7_char_to_order_map, + 'precedence_matrix': GreekLangModel, + 'typical_positive_ratio': 0.982851, + 'keep_english_letter': False, + 'charset_name': "ISO-8859-7", + 'language': 'Greek', +} + +Win1253GreekModel = { + 'char_to_order_map': win1253_char_to_order_map, + 'precedence_matrix': GreekLangModel, + 'typical_positive_ratio': 0.982851, + 'keep_english_letter': False, + 'charset_name': "windows-1253", + 'language': 'Greek', +} diff --git a/venv/lib/python2.7/site-packages/chardet/langhebrewmodel.py b/venv/lib/python2.7/site-packages/chardet/langhebrewmodel.py new file mode 100644 index 0000000..58f4c87 --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/langhebrewmodel.py @@ -0,0 +1,200 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Simon Montagu +# Portions created by the Initial Developer are Copyright (C) 2005 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# Shoshannah Forbes - original C code (?) +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Windows-1255 language model +# Character Mapping Table: +WIN1255_CHAR_TO_ORDER_MAP = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 69, 91, 79, 80, 92, 89, 97, 90, 68,111,112, 82, 73, 95, 85, # 40 + 78,121, 86, 71, 67,102,107, 84,114,103,115,253,253,253,253,253, # 50 +253, 50, 74, 60, 61, 42, 76, 70, 64, 53,105, 93, 56, 65, 54, 49, # 60 + 66,110, 51, 43, 44, 63, 81, 77, 98, 75,108,253,253,253,253,253, # 70 +124,202,203,204,205, 40, 58,206,207,208,209,210,211,212,213,214, +215, 83, 52, 47, 46, 72, 32, 94,216,113,217,109,218,219,220,221, + 34,116,222,118,100,223,224,117,119,104,125,225,226, 87, 99,227, +106,122,123,228, 55,229,230,101,231,232,120,233, 48, 39, 57,234, + 30, 59, 41, 88, 33, 37, 36, 31, 29, 35,235, 62, 28,236,126,237, +238, 38, 45,239,240,241,242,243,127,244,245,246,247,248,249,250, + 9, 8, 20, 16, 3, 2, 24, 14, 22, 1, 25, 15, 4, 11, 6, 23, + 12, 19, 13, 26, 18, 27, 21, 17, 7, 10, 5,251,252,128, 96,253, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 98.4004% +# first 1024 sequences: 1.5981% +# rest sequences: 0.087% +# negative sequences: 0.0015% +HEBREW_LANG_MODEL = ( +0,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,2,3,2,1,2,0,1,0,0, +3,0,3,1,0,0,1,3,2,0,1,1,2,0,2,2,2,1,1,1,1,2,1,1,1,2,0,0,2,2,0,1, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2, +1,2,1,2,1,2,0,0,2,0,0,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2, +1,2,1,3,1,1,0,0,2,0,0,0,1,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,0,1,2,2,1,3, +1,2,1,1,2,2,0,0,2,2,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,1,0,1,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,2,2,2,2,3,2, +1,2,1,2,2,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,2,3,2,2,3,2,2,2,1,2,2,2,2, +1,2,1,1,2,2,0,1,2,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,2,2,2,2,2, +0,2,0,2,2,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,0,2,2,2, +0,2,1,2,2,2,0,0,2,1,0,0,0,0,1,0,1,0,0,0,0,0,0,2,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,2,1,2,3,2,2,2, +1,2,1,2,2,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,1,0,2,0,2, +0,2,1,2,2,2,0,0,1,2,0,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,2,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,2,3,2,2,3,2,1,2,1,1,1, +0,1,1,1,1,1,3,0,1,0,0,0,0,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,0,1,0,0,1,0,0,0,0, +0,0,1,0,0,0,0,0,2,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2, +0,2,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,2,1,2,3,3,2,3,3,3,3,2,3,2,1,2,0,2,1,2, +0,2,0,2,2,2,0,0,1,2,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,1,2,2,3,3,2,3,2,3,2,2,3,1,2,2,0,2,2,2, +0,2,1,2,2,2,0,0,1,2,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,2,2,2,3,3,3,3,1,3,2,2,2, +0,2,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,3,3,3,2,3,2,2,2,1,2,2,0,2,2,2,2, +0,2,0,2,2,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,1,3,2,3,3,2,3,3,2,2,1,2,2,2,2,2,2, +0,2,1,2,1,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,2,3,3,2,3,3,3,3,2,3,2,3,3,3,3,3,2,2,2,2,2,2,2,1, +0,2,0,1,2,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,2,1,2,3,3,3,3,3,3,3,2,3,2,3,2,1,2,3,0,2,1,2,2, +0,2,1,1,2,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,2,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,3,2,1,3,1,2,2,2,1,2,3,3,1,2,1,2,2,2,2, +0,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,0,2,3,3,3,1,3,3,3,1,2,2,2,2,1,1,2,2,2,2,2,2, +0,2,0,1,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,3,3,2,2,3,3,3,2,1,2,3,2,3,2,2,2,2,1,2,1,1,1,2,2, +0,2,1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,1,0,0,0,0,0, +1,0,1,0,0,0,0,0,2,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,2,3,3,2,3,1,2,2,2,2,3,2,3,1,1,2,2,1,2,2,1,1,0,2,2,2,2, +0,1,0,1,2,2,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,0,0,1,1,0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,2,0, +0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,1,0,1,0,1,1,0,1,1,0,0,0,1,1,0,1,1,1,0,0,0,0,0,0,1,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +3,2,2,1,2,2,2,2,2,2,2,1,2,2,1,2,2,1,1,1,1,1,1,1,1,2,1,1,0,3,3,3, +0,3,0,2,2,2,2,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +2,2,2,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,1,2,2,2,1,1,1,2,0,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,0,0,0,0,0,0, +0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,0,2,1,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +0,3,1,1,2,2,2,2,2,1,2,2,2,1,1,2,2,2,2,2,2,2,1,2,2,1,0,1,1,1,1,0, +0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,1,1,1,1,2,1,1,2,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0, +0,0,2,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,0,0, +2,1,1,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,1,2,1,2,1,1,1,1,0,0,0,0, +0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,1,2,2,2,2,2,2,2,2,2,2,1,2,1,2,1,1,2,1,1,1,2,1,2,1,2,0,1,0,1, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,1,2,2,2,1,2,2,2,2,2,2,2,2,1,2,1,1,1,1,1,1,2,1,2,1,1,0,1,0,1, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2, +0,2,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,1,1,1,1,1,1,0,1,1,0,1,0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,2,0,1,1,1,0,1,0,0,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0, +0,1,1,1,2,1,2,2,2,0,2,0,2,0,1,1,2,1,1,1,1,2,1,0,1,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,1,0,0,0,0,0,1,0,1,2,2,0,1,0,0,1,1,2,2,1,2,0,2,0,0,0,1,2,0,1, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,2,0,2,1,2,0,2,0,0,1,1,1,1,1,1,0,1,0,0,0,1,0,0,1, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,0,1,0,2,1,1,0,1,0,0,1,1,1,2,2,0,0,1,0,0,0,1,0,0,1, +1,1,2,1,0,1,1,1,0,1,0,1,1,1,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,2,2,1, +0,2,0,1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,0,0,1,0,1,1,1,1,0,0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,1,1,1,1,1,1,1,2,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,1,1,0,1,0,0,0,1,1,0,1, +2,0,1,0,1,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,0,1,1,2,1,1,2,0,1,0,0,0,1,1,0,1, +1,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,2,0,1,0,0,0,0,2,1,1,2,0,2,0,0,0,1,1,0,1, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,2,1,1,0,1,0,0,2,2,1,2,1,1,0,1,0,0,0,1,1,0,1, +2,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,2,2,0,0,0,0,0,1,1,0,1,0,0,1,0,0,0,0,1,0,1, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,2,2,0,0,0,0,2,1,1,1,0,2,1,1,0,0,0,2,1,0,1, +1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,2,0,1,0,0,1,1,0,2,1,1,0,1,0,0,0,1,1,0,1, +2,2,1,1,1,0,1,1,0,1,1,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,2,1,1,0,1,0,0,1,1,0,1,2,1,0,2,0,0,0,1,1,0,1, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0, +0,1,0,0,2,0,2,1,1,0,1,0,1,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,2,0,1,0,0,1,1,1,0,1,0,0,1,0,0,0,1,0,0,1, +1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,0,0,0,0,0,1,0,1,1,0,0,1,0,0,2,1,1,1,1,1,0,1,0,0,0,0,1,0,1, +0,1,1,1,2,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,2,1,0,0,0,0,0,1,1,1,1,1,0,1,0,0,0,1,1,0,0, +) + +Win1255HebrewModel = { + 'char_to_order_map': WIN1255_CHAR_TO_ORDER_MAP, + 'precedence_matrix': HEBREW_LANG_MODEL, + 'typical_positive_ratio': 0.984004, + 'keep_english_letter': False, + 'charset_name': "windows-1255", + 'language': 'Hebrew', +} diff --git a/venv/lib/python2.7/site-packages/chardet/langhungarianmodel.py b/venv/lib/python2.7/site-packages/chardet/langhungarianmodel.py new file mode 100644 index 0000000..bb7c095 --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/langhungarianmodel.py @@ -0,0 +1,225 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +Latin2_HungarianCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 28, 40, 54, 45, 32, 50, 49, 38, 39, 53, 36, 41, 34, 35, 47, + 46, 71, 43, 33, 37, 57, 48, 64, 68, 55, 52,253,253,253,253,253, +253, 2, 18, 26, 17, 1, 27, 12, 20, 9, 22, 7, 6, 13, 4, 8, + 23, 67, 10, 5, 3, 21, 19, 65, 62, 16, 11,253,253,253,253,253, +159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174, +175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190, +191,192,193,194,195,196,197, 75,198,199,200,201,202,203,204,205, + 79,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220, +221, 51, 81,222, 78,223,224,225,226, 44,227,228,229, 61,230,231, +232,233,234, 58,235, 66, 59,236,237,238, 60, 69, 63,239,240,241, + 82, 14, 74,242, 70, 80,243, 72,244, 15, 83, 77, 84, 30, 76, 85, +245,246,247, 25, 73, 42, 24,248,249,250, 31, 56, 29,251,252,253, +) + +win1250HungarianCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 28, 40, 54, 45, 32, 50, 49, 38, 39, 53, 36, 41, 34, 35, 47, + 46, 72, 43, 33, 37, 57, 48, 64, 68, 55, 52,253,253,253,253,253, +253, 2, 18, 26, 17, 1, 27, 12, 20, 9, 22, 7, 6, 13, 4, 8, + 23, 67, 10, 5, 3, 21, 19, 65, 62, 16, 11,253,253,253,253,253, +161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176, +177,178,179,180, 78,181, 69,182,183,184,185,186,187,188,189,190, +191,192,193,194,195,196,197, 76,198,199,200,201,202,203,204,205, + 81,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220, +221, 51, 83,222, 80,223,224,225,226, 44,227,228,229, 61,230,231, +232,233,234, 58,235, 66, 59,236,237,238, 60, 70, 63,239,240,241, + 84, 14, 75,242, 71, 82,243, 73,244, 15, 85, 79, 86, 30, 77, 87, +245,246,247, 25, 74, 42, 24,248,249,250, 31, 56, 29,251,252,253, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 94.7368% +# first 1024 sequences:5.2623% +# rest sequences: 0.8894% +# negative sequences: 0.0009% +HungarianLangModel = ( +0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,2,2,3,3,1,1,2,2,2,2,2,1,2, +3,2,2,3,3,3,3,3,2,3,3,3,3,3,3,1,2,3,3,3,3,2,3,3,1,1,3,3,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0, +3,2,1,3,3,3,3,3,2,3,3,3,3,3,1,1,2,3,3,3,3,3,3,3,1,1,3,2,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,1,1,2,3,3,3,1,3,3,3,3,3,1,3,3,2,2,0,3,2,3, +0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,3,2,3,3,2,3,3,3,3,3,2,3,3,2,2,3,2,3,2,0,3,2,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,3,3,3,3,2,3,3,3,1,2,3,2,2,3,1,2,3,3,2,2,0,3,3,3, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,3,2,3,3,3,3,2,3,3,3,3,0,2,3,2, +0,0,0,1,1,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,1,1,1,3,3,2,1,3,2,2,3,2,1,3,2,2,1,0,3,3,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,2,2,3,3,3,3,3,1,2,3,3,3,3,1,2,1,3,3,3,3,2,2,3,1,1,3,2,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,2,1,3,3,3,3,3,2,2,1,3,3,3,0,1,1,2, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,2,3,3,3,2,0,3,2,3, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,3,3,2,3,2,3,3,3,1,3,2,2,2,3,1,1,3,3,1,1,0,3,3,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,2,3,3,3,2,3,2,3,3,3,2,3,3,3,3,3,1,2,3,2,2,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,2,2,2,3,1,3,3,2,2,1,3,3,3,1,1,3,1,2,3,2,3,2,2,2,1,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +3,1,1,3,3,3,3,3,1,2,3,3,3,3,1,2,1,3,3,3,2,2,3,2,1,0,3,2,0,1,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,3,3,3,3,3,1,2,3,3,3,3,1,1,0,3,3,3,3,0,2,3,0,0,2,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,2,3,3,2,2,2,2,3,3,0,1,2,3,2,3,2,2,3,2,1,2,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +3,3,3,3,3,3,1,2,3,3,3,2,1,2,3,3,2,2,2,3,2,3,3,1,3,3,1,1,0,2,3,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,1,2,2,2,2,3,3,3,1,1,1,3,3,1,1,3,1,1,3,2,1,2,3,1,1,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,2,1,2,1,1,3,3,1,1,1,1,3,3,1,1,2,2,1,2,1,1,2,2,1,1,0,2,2,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,1,1,2,1,1,3,3,1,0,1,1,3,3,2,0,1,1,2,3,1,0,2,2,1,0,0,1,3,2, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,2,1,3,3,3,3,3,1,2,3,2,3,3,2,1,1,3,2,3,2,1,2,2,0,1,2,1,0,0,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,2,2,2,2,3,1,2,2,1,1,3,3,0,3,2,1,2,3,2,1,3,3,1,1,0,2,1,3, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,2,2,2,3,2,3,3,3,2,1,1,3,3,1,1,1,2,2,3,2,3,2,2,2,1,0,2,2,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +1,0,0,3,3,3,3,3,0,0,3,3,2,3,0,0,0,2,3,3,1,0,1,2,0,0,1,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,2,3,3,3,3,3,1,2,3,3,2,2,1,1,0,3,3,2,2,1,2,2,1,0,2,2,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,2,2,1,3,1,2,3,3,2,2,1,1,2,2,1,1,1,1,3,2,1,1,1,1,2,1,0,1,2,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +2,3,3,1,1,1,1,1,3,3,3,0,1,1,3,3,1,1,1,1,1,2,2,0,3,1,1,2,0,2,1,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,1,0,1,2,1,2,2,0,1,2,3,1,2,0,0,0,2,1,1,1,1,1,2,0,0,1,1,0,0,0,0, +1,2,1,2,2,2,1,2,1,2,0,2,0,2,2,1,1,2,1,1,2,1,1,1,0,1,0,0,0,1,1,0, +1,1,1,2,3,2,3,3,0,1,2,2,3,1,0,1,0,2,1,2,2,0,1,1,0,0,1,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,3,3,2,2,1,0,0,3,2,3,2,0,0,0,1,1,3,0,0,1,1,0,0,2,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,2,2,3,3,1,0,1,3,2,3,1,1,1,0,1,1,1,1,1,3,1,0,0,2,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,1,2,2,2,1,0,1,2,3,3,2,0,0,0,2,1,1,1,2,1,1,1,0,1,1,1,0,0,0, +1,2,2,2,2,2,1,1,1,2,0,2,1,1,1,1,1,2,1,1,1,1,1,1,0,1,1,1,0,0,1,1, +3,2,2,1,0,0,1,1,2,2,0,3,0,1,2,1,1,0,0,1,1,1,0,1,1,1,1,0,2,1,1,1, +2,2,1,1,1,2,1,2,1,1,1,1,1,1,1,2,1,1,1,2,3,1,1,1,1,1,1,1,1,1,0,1, +2,3,3,0,1,0,0,0,3,3,1,0,0,1,2,2,1,0,0,0,0,2,0,0,1,1,1,0,2,1,1,1, +2,1,1,1,1,1,1,2,1,1,0,1,1,0,1,1,1,0,1,2,1,1,0,1,1,1,1,1,1,1,0,1, +2,3,3,0,1,0,0,0,2,2,0,0,0,0,1,2,2,0,0,0,0,1,0,0,1,1,0,0,2,0,1,0, +2,1,1,1,1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,2,0,1,1,1,1,1,0,1, +3,2,2,0,1,0,1,0,2,3,2,0,0,1,2,2,1,0,0,1,1,1,0,0,2,1,0,1,2,2,1,1, +2,1,1,1,1,1,1,2,1,1,1,1,1,1,0,2,1,0,1,1,0,1,1,1,0,1,1,2,1,1,0,1, +2,2,2,0,0,1,0,0,2,2,1,1,0,0,2,1,1,0,0,0,1,2,0,0,2,1,0,0,2,1,1,1, +2,1,1,1,1,2,1,2,1,1,1,2,2,1,1,2,1,1,1,2,1,1,1,1,1,1,1,1,1,1,0,1, +1,2,3,0,0,0,1,0,3,2,1,0,0,1,2,1,1,0,0,0,0,2,1,0,1,1,0,0,2,1,2,1, +1,1,0,0,0,1,0,1,1,1,1,1,2,0,0,1,0,0,0,2,0,0,1,1,1,1,1,1,1,1,0,1, +3,0,0,2,1,2,2,1,0,0,2,1,2,2,0,0,0,2,1,1,1,0,1,1,0,0,1,1,2,0,0,0, +1,2,1,2,2,1,1,2,1,2,0,1,1,1,1,1,1,1,1,1,2,1,1,0,0,1,1,1,1,0,0,1, +1,3,2,0,0,0,1,0,2,2,2,0,0,0,2,2,1,0,0,0,0,3,1,1,1,1,0,0,2,1,1,1, +2,1,0,1,1,1,0,1,1,1,1,1,1,1,0,2,1,0,0,1,0,1,1,0,1,1,1,1,1,1,0,1, +2,3,2,0,0,0,1,0,2,2,0,0,0,0,2,1,1,0,0,0,0,2,1,0,1,1,0,0,2,1,1,0, +2,1,1,1,1,2,1,2,1,2,0,1,1,1,0,2,1,1,1,2,1,1,1,1,0,1,1,1,1,1,0,1, +3,1,1,2,2,2,3,2,1,1,2,2,1,1,0,1,0,2,2,1,1,1,1,1,0,0,1,1,0,1,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,0,0,0,0,0,2,2,0,0,0,0,2,2,1,0,0,0,1,1,0,0,1,2,0,0,2,1,1,1, +2,2,1,1,1,2,1,2,1,1,0,1,1,1,1,2,1,1,1,2,1,1,1,1,0,1,2,1,1,1,0,1, +1,0,0,1,2,3,2,1,0,0,2,0,1,1,0,0,0,1,1,1,1,0,1,1,0,0,1,0,0,0,0,0, +1,2,1,2,1,2,1,1,1,2,0,2,1,1,1,0,1,2,0,0,1,1,1,0,0,0,0,0,0,0,0,0, +2,3,2,0,0,0,0,0,1,1,2,1,0,0,1,1,1,0,0,0,0,2,0,0,1,1,0,0,2,1,1,1, +2,1,1,1,1,1,1,2,1,0,1,1,1,1,0,2,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1, +1,2,2,0,1,1,1,0,2,2,2,0,0,0,3,2,1,0,0,0,1,1,0,0,1,1,0,1,1,1,0,0, +1,1,0,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1,1,1,0,0,1,1,1,0,1,0,1, +2,1,0,2,1,1,2,2,1,1,2,1,1,1,0,0,0,1,1,0,1,1,1,1,0,0,1,1,1,0,0,0, +1,2,2,2,2,2,1,1,1,2,0,2,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,1,0, +1,2,3,0,0,0,1,0,2,2,0,0,0,0,2,2,0,0,0,0,0,1,0,0,1,0,0,0,2,0,1,0, +2,1,1,1,1,1,0,2,0,0,0,1,2,1,1,1,1,0,1,2,0,1,0,1,0,1,1,1,0,1,0,1, +2,2,2,0,0,0,1,0,2,1,2,0,0,0,1,1,2,0,0,0,0,1,0,0,1,1,0,0,2,1,0,1, +2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,0,1,1,1,1,1,0,1, +1,2,2,0,0,0,1,0,2,2,2,0,0,0,1,1,0,0,0,0,0,1,1,0,2,0,0,1,1,1,0,1, +1,0,1,1,1,1,1,1,0,1,1,1,1,0,0,1,0,0,1,1,0,1,0,1,1,1,1,1,0,0,0,1, +1,0,0,1,0,1,2,1,0,0,1,1,1,2,0,0,0,1,1,0,1,0,1,1,0,0,1,0,0,0,0,0, +0,2,1,2,1,1,1,1,1,2,0,2,0,1,1,0,1,2,1,0,1,1,1,0,0,0,0,0,0,1,0,0, +2,1,1,0,1,2,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,1,0,0,1,0,0,0,2,1,0,1, +2,2,1,1,1,1,1,2,1,1,0,1,1,1,1,2,1,1,1,2,1,1,0,1,0,1,1,1,1,1,0,1, +1,2,2,0,0,0,0,0,1,1,0,0,0,0,2,1,0,0,0,0,0,2,0,0,2,2,0,0,2,0,0,1, +2,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,0,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1, +1,1,2,0,0,3,1,0,2,1,1,1,0,0,1,1,1,0,0,0,1,1,0,0,0,1,0,0,1,0,1,0, +1,2,1,0,1,1,1,2,1,1,0,1,1,1,1,1,0,0,0,1,1,1,1,1,0,1,0,0,0,1,0,0, +2,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,2,0,0,0, +2,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,2,1,1,0,0,1,1,1,1,1,0,1, +2,1,1,1,2,1,1,1,0,1,1,2,1,0,0,0,0,1,1,1,1,0,1,0,0,0,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,0,1,1,1,1,1,0,0,1,1,2,1,0,0,0,1,1,0,0,0,1,1,0,0,1,0,1,0,0,0, +1,2,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,1,0,0, +2,0,0,0,1,1,1,1,0,0,1,1,0,0,0,0,0,1,1,1,2,0,0,1,0,0,1,0,1,0,0,0, +0,1,1,1,1,1,1,1,1,2,0,1,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,1,1,0,0,2,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0, +0,1,1,1,1,1,1,0,1,1,0,1,0,1,1,0,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +0,1,1,1,1,1,0,0,1,1,0,1,0,1,0,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0, +0,0,0,1,0,0,0,0,0,0,1,1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,1,1,0,1,0,0,1,1,0,1,0,1,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0, +2,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,0,0,1,0,1,0,1,1,1,0,0,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,1,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,1,1,1,1,1,0,1,1,0,1,0,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0, +) + +Latin2HungarianModel = { + 'char_to_order_map': Latin2_HungarianCharToOrderMap, + 'precedence_matrix': HungarianLangModel, + 'typical_positive_ratio': 0.947368, + 'keep_english_letter': True, + 'charset_name': "ISO-8859-2", + 'language': 'Hungarian', +} + +Win1250HungarianModel = { + 'char_to_order_map': win1250HungarianCharToOrderMap, + 'precedence_matrix': HungarianLangModel, + 'typical_positive_ratio': 0.947368, + 'keep_english_letter': True, + 'charset_name': "windows-1250", + 'language': 'Hungarian', +} diff --git a/venv/lib/python2.7/site-packages/chardet/langthaimodel.py b/venv/lib/python2.7/site-packages/chardet/langthaimodel.py new file mode 100644 index 0000000..15f94c2 --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/langthaimodel.py @@ -0,0 +1,199 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# The following result for thai was collected from a limited sample (1M). + +# Character Mapping Table: +TIS620CharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,182,106,107,100,183,184,185,101, 94,186,187,108,109,110,111, # 40 +188,189,190, 89, 95,112,113,191,192,193,194,253,253,253,253,253, # 50 +253, 64, 72, 73,114, 74,115,116,102, 81,201,117, 90,103, 78, 82, # 60 + 96,202, 91, 79, 84,104,105, 97, 98, 92,203,253,253,253,253,253, # 70 +209,210,211,212,213, 88,214,215,216,217,218,219,220,118,221,222, +223,224, 99, 85, 83,225,226,227,228,229,230,231,232,233,234,235, +236, 5, 30,237, 24,238, 75, 8, 26, 52, 34, 51,119, 47, 58, 57, + 49, 53, 55, 43, 20, 19, 44, 14, 48, 3, 17, 25, 39, 62, 31, 54, + 45, 9, 16, 2, 61, 15,239, 12, 42, 46, 18, 21, 76, 4, 66, 63, + 22, 10, 1, 36, 23, 13, 40, 27, 32, 35, 86,240,241,242,243,244, + 11, 28, 41, 29, 33,245, 50, 37, 6, 7, 67, 77, 38, 93,246,247, + 68, 56, 59, 65, 69, 60, 70, 80, 71, 87,248,249,250,251,252,253, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 92.6386% +# first 1024 sequences:7.3177% +# rest sequences: 1.0230% +# negative sequences: 0.0436% +ThaiLangModel = ( +0,1,3,3,3,3,0,0,3,3,0,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3,3,0,3,3,3,3, +0,3,3,0,0,0,1,3,0,3,3,2,3,3,0,1,2,3,3,3,3,0,2,0,2,0,0,3,2,1,2,2, +3,0,3,3,2,3,0,0,3,3,0,3,3,0,3,3,3,3,3,3,3,3,3,0,3,2,3,0,2,2,2,3, +0,2,3,0,0,0,0,1,0,1,2,3,1,1,3,2,2,0,1,1,0,0,1,0,0,0,0,0,0,0,1,1, +3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,3,3,2,3,2,3,3,2,2,2, +3,1,2,3,0,3,3,2,2,1,2,3,3,1,2,0,1,3,0,1,0,0,1,0,0,0,0,0,0,0,1,1, +3,3,2,2,3,3,3,3,1,2,3,3,3,3,3,2,2,2,2,3,3,2,2,3,3,2,2,3,2,3,2,2, +3,3,1,2,3,1,2,2,3,3,1,0,2,1,0,0,3,1,2,1,0,0,1,0,0,0,0,0,0,1,0,1, +3,3,3,3,3,3,2,2,3,3,3,3,2,3,2,2,3,3,2,2,3,2,2,2,2,1,1,3,1,2,1,1, +3,2,1,0,2,1,0,1,0,1,1,0,1,1,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0, +3,3,3,2,3,2,3,3,2,2,3,2,3,3,2,3,1,1,2,3,2,2,2,3,2,2,2,2,2,1,2,1, +2,2,1,1,3,3,2,1,0,1,2,2,0,1,3,0,0,0,1,1,0,0,0,0,0,2,3,0,0,2,1,1, +3,3,2,3,3,2,0,0,3,3,0,3,3,0,2,2,3,1,2,2,1,1,1,0,2,2,2,0,2,2,1,1, +0,2,1,0,2,0,0,2,0,1,0,0,1,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,2,3,3,2,0,0,3,3,0,2,3,0,2,1,2,2,2,2,1,2,0,0,2,2,2,0,2,2,1,1, +0,2,1,0,2,0,0,2,0,1,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0, +3,3,2,3,2,3,2,0,2,2,1,3,2,1,3,2,1,2,3,2,2,3,0,2,3,2,2,1,2,2,2,2, +1,2,2,0,0,0,0,2,0,1,2,0,1,1,1,0,1,0,3,1,1,0,0,0,0,0,0,0,0,0,1,0, +3,3,2,3,3,2,3,2,2,2,3,2,2,3,2,2,1,2,3,2,2,3,1,3,2,2,2,3,2,2,2,3, +3,2,1,3,0,1,1,1,0,2,1,1,1,1,1,0,1,0,1,1,0,0,0,0,0,0,0,0,0,2,0,0, +1,0,0,3,0,3,3,3,3,3,0,0,3,0,2,2,3,3,3,3,3,0,0,0,1,1,3,0,0,0,0,2, +0,0,1,0,0,0,0,0,0,0,2,3,0,0,0,3,0,2,0,0,0,0,0,3,0,0,0,0,0,0,0,0, +2,0,3,3,3,3,0,0,2,3,0,0,3,0,3,3,2,3,3,3,3,3,0,0,3,3,3,0,0,0,3,3, +0,0,3,0,0,0,0,2,0,0,2,1,1,3,0,0,1,0,0,2,3,0,1,0,0,0,0,0,0,0,1,0, +3,3,3,3,2,3,3,3,3,3,3,3,1,2,1,3,3,2,2,1,2,2,2,3,1,1,2,0,2,1,2,1, +2,2,1,0,0,0,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0, +3,0,2,1,2,3,3,3,0,2,0,2,2,0,2,1,3,2,2,1,2,1,0,0,2,2,1,0,2,1,2,2, +0,1,1,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,1,3,3,1,1,3,0,2,3,1,1,3,2,1,1,2,0,2,2,3,2,1,1,1,1,1,2, +3,0,0,1,3,1,2,1,2,0,3,0,0,0,1,0,3,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, +3,3,1,1,3,2,3,3,3,1,3,2,1,3,2,1,3,2,2,2,2,1,3,3,1,2,1,3,1,2,3,0, +2,1,1,3,2,2,2,1,2,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2, +3,3,2,3,2,3,3,2,3,2,3,2,3,3,2,1,0,3,2,2,2,1,2,2,2,1,2,2,1,2,1,1, +2,2,2,3,0,1,3,1,1,1,1,0,1,1,0,2,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,3,2,2,1,1,3,2,3,2,3,2,0,3,2,2,1,2,0,2,2,2,1,2,2,2,2,1, +3,2,1,2,2,1,0,2,0,1,0,0,1,1,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,2,3,1,2,3,3,2,2,3,0,1,1,2,0,3,3,2,2,3,0,1,1,3,0,0,0,0, +3,1,0,3,3,0,2,0,2,1,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,2,3,2,3,3,0,1,3,1,1,2,1,2,1,1,3,1,1,0,2,3,1,1,1,1,1,1,1,1, +3,1,1,2,2,2,2,1,1,1,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,2,2,1,1,2,1,3,3,2,3,2,2,3,2,2,3,1,2,2,1,2,0,3,2,1,2,2,2,2,2,1, +3,2,1,2,2,2,1,1,1,1,0,0,1,1,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,1,3,3,0,2,1,0,3,2,0,0,3,1,0,1,1,0,1,0,0,0,0,0,1, +1,0,0,1,0,3,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,2,2,2,3,0,0,1,3,0,3,2,0,3,2,2,3,3,3,3,3,1,0,2,2,2,0,2,2,1,2, +0,2,3,0,0,0,0,1,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,0,2,3,1,3,3,2,3,3,0,3,3,0,3,2,2,3,2,3,3,3,0,0,2,2,3,0,1,1,1,3, +0,0,3,0,0,0,2,2,0,1,3,0,1,2,2,2,3,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1, +3,2,3,3,2,0,3,3,2,2,3,1,3,2,1,3,2,0,1,2,2,0,2,3,2,1,0,3,0,0,0,0, +3,0,0,2,3,1,3,0,0,3,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,3,2,2,2,1,2,0,1,3,1,1,3,1,3,0,0,2,1,1,1,1,2,1,1,1,0,2,1,0,1, +1,2,0,0,0,3,1,1,0,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,0,3,1,0,0,0,1,0, +3,3,3,3,2,2,2,2,2,1,3,1,1,1,2,0,1,1,2,1,2,1,3,2,0,0,3,1,1,1,1,1, +3,1,0,2,3,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,2,3,0,3,3,0,2,0,0,0,0,0,0,0,3,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,3,1,3,0,0,1,2,0,0,2,0,3,3,2,3,3,3,2,3,0,0,2,2,2,0,0,0,2,2, +0,0,1,0,0,0,0,3,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +0,0,0,3,0,2,0,0,0,0,0,0,0,0,0,0,1,2,3,1,3,3,0,0,1,0,3,0,0,0,0,0, +0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,1,2,3,1,2,3,1,0,3,0,2,2,1,0,2,1,1,2,0,1,0,0,1,1,1,1,0,1,0,0, +1,0,0,0,0,1,1,0,3,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,1,0,1,1,1,3,1,2,2,2,2,2,2,1,1,1,1,0,3,1,0,1,3,1,1,1,1, +1,1,0,2,0,1,3,1,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1, +3,0,2,2,1,3,3,2,3,3,0,1,1,0,2,2,1,2,1,3,3,1,0,0,3,2,0,0,0,0,2,1, +0,1,0,0,0,0,1,2,0,1,1,3,1,1,2,2,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,0,3,0,0,1,0,0,0,3,0,0,3,0,3,1,0,1,1,1,3,2,0,0,0,3,0,0,0,0,2,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,1,3,2,1,3,3,1,2,2,0,1,2,1,0,1,2,0,0,0,0,0,3,0,0,0,3,0,0,0,0, +3,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,1,2,0,3,3,3,2,2,0,1,1,0,1,3,0,0,0,2,2,0,0,0,0,3,1,0,1,0,0,0, +0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,2,3,1,2,0,0,2,1,0,3,1,0,1,2,0,1,1,1,1,3,0,0,3,1,1,0,2,2,1,1, +0,2,0,0,0,0,0,1,0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,3,1,2,0,0,2,2,0,1,2,0,1,0,1,3,1,2,1,0,0,0,2,0,3,0,0,0,1,0, +0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,1,1,2,2,0,0,0,2,0,2,1,0,1,1,0,1,1,1,2,1,0,0,1,1,1,0,2,1,1,1, +0,1,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1, +0,0,0,2,0,1,3,1,1,1,1,0,0,0,0,3,2,0,1,0,0,0,1,2,0,0,0,1,0,0,0,0, +0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,2,3,2,2,0,0,0,1,0,0,0,0,2,3,2,1,2,2,3,0,0,0,2,3,1,0,0,0,1,1, +0,0,1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0, +3,3,2,2,0,1,0,0,0,0,2,0,2,0,1,0,0,0,1,1,0,0,0,2,1,0,1,0,1,1,0,0, +0,1,0,2,0,0,1,0,3,0,1,0,0,0,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,1,0,0,1,0,0,0,0,0,1,1,2,0,0,0,0,1,0,0,1,3,1,0,0,0,0,1,1,0,0, +0,1,0,0,0,0,3,0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0, +3,3,1,1,1,1,2,3,0,0,2,1,1,1,1,1,0,2,1,1,0,0,0,2,1,0,1,2,1,1,0,1, +2,1,0,3,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,3,1,0,0,0,0,0,0,0,3,0,0,0,3,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1, +0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,2,0,0,0,0,0,0,1,2,1,0,1,1,0,2,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,2,0,0,0,1,3,0,1,0,0,0,2,0,0,0,0,0,0,0,1,2,0,0,0,0,0, +3,3,0,0,1,1,2,0,0,1,2,1,0,1,1,1,0,1,1,0,0,2,1,1,0,1,0,0,1,1,1,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,1,0,0,0,0,1,0,0,0,0,3,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,0,0,1,1,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,0,1,2,0,1,2,0,0,1,1,0,2,0,1,0,0,1,0,0,0,0,1,0,0,0,2,0,0,0,0, +1,0,0,1,0,1,1,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,0,0,0,0,0,0,0,1,1,0,1,1,0,2,1,3,0,0,0,0,1,1,0,0,0,0,0,0,0,3, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,1,0,1,0,0,2,0,0,2,0,0,1,1,2,0,0,1,1,0,0,0,1,0,0,0,1,1,0,0,0, +1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +1,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,1,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,3,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,0,0,0,0, +1,0,0,0,0,0,0,0,0,1,0,0,0,0,2,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,1,0,0,2,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +) + +TIS620ThaiModel = { + 'char_to_order_map': TIS620CharToOrderMap, + 'precedence_matrix': ThaiLangModel, + 'typical_positive_ratio': 0.926386, + 'keep_english_letter': False, + 'charset_name': "TIS-620", + 'language': 'Thai', +} diff --git a/venv/lib/python2.7/site-packages/chardet/langturkishmodel.py b/venv/lib/python2.7/site-packages/chardet/langturkishmodel.py new file mode 100644 index 0000000..a427a45 --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/langturkishmodel.py @@ -0,0 +1,193 @@ +# -*- coding: utf-8 -*- +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Özgür Baskın - Turkish Language Model +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +Latin5_TurkishCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255, 23, 37, 47, 39, 29, 52, 36, 45, 53, 60, 16, 49, 20, 46, 42, + 48, 69, 44, 35, 31, 51, 38, 62, 65, 43, 56,255,255,255,255,255, +255, 1, 21, 28, 12, 2, 18, 27, 25, 3, 24, 10, 5, 13, 4, 15, + 26, 64, 7, 8, 9, 14, 32, 57, 58, 11, 22,255,255,255,255,255, +180,179,178,177,176,175,174,173,172,171,170,169,168,167,166,165, +164,163,162,161,160,159,101,158,157,156,155,154,153,152,151,106, +150,149,148,147,146,145,144,100,143,142,141,140,139,138,137,136, + 94, 80, 93,135,105,134,133, 63,132,131,130,129,128,127,126,125, +124,104, 73, 99, 79, 85,123, 54,122, 98, 92,121,120, 91,103,119, + 68,118,117, 97,116,115, 50, 90,114,113,112,111, 55, 41, 40, 86, + 89, 70, 59, 78, 71, 82, 88, 33, 77, 66, 84, 83,110, 75, 61, 96, + 30, 67,109, 74, 87,102, 34, 95, 81,108, 76, 72, 17, 6, 19,107, +) + +TurkishLangModel = ( +3,2,3,3,3,1,3,3,3,3,3,3,3,3,2,1,1,3,3,1,3,3,0,3,3,3,3,3,0,3,1,3, +3,2,1,0,0,1,1,0,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,2,2,0,0,1,0,0,1, +3,2,2,3,3,0,3,3,3,3,3,3,3,2,3,1,0,3,3,1,3,3,0,3,3,3,3,3,0,3,0,3, +3,1,1,0,1,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,2,2,0,0,0,1,0,1, +3,3,2,3,3,0,3,3,3,3,3,3,3,2,3,1,1,3,3,0,3,3,1,2,3,3,3,3,0,3,0,3, +3,1,1,0,0,0,1,0,0,0,0,1,1,0,1,2,1,0,0,0,1,0,0,0,0,2,0,0,0,0,0,1, +3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,1,3,3,2,0,3,2,1,2,2,1,3,3,0,0,0,2, +2,2,0,1,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,1,0,0,1, +3,3,3,2,3,3,1,2,3,3,3,3,3,3,3,1,3,2,1,0,3,2,0,1,2,3,3,2,1,0,0,2, +2,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,0,0,0, +1,0,1,3,3,1,3,3,3,3,3,3,3,1,2,0,0,2,3,0,2,3,0,0,2,2,2,3,0,3,0,1, +2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,0,3,2,0,2,3,2,3,3,1,0,0,2, +3,2,0,0,1,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,0,2,0,0,1, +3,3,3,2,3,3,2,3,3,3,3,2,3,3,3,0,3,3,0,0,2,1,0,0,2,3,2,2,0,0,0,2, +2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,1,0,2,0,0,1, +3,3,3,2,3,3,3,3,3,3,3,2,3,3,3,0,3,2,0,1,3,2,1,1,3,2,3,2,1,0,0,2, +2,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0, +3,3,3,2,3,3,3,3,3,3,3,2,3,3,3,0,3,2,2,0,2,3,0,0,2,2,2,2,0,0,0,2, +3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,0,1,0,0,0, +3,3,3,3,3,3,3,2,2,2,2,3,2,3,3,0,3,3,1,1,2,2,0,0,2,2,3,2,0,0,1,3, +0,3,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1, +3,3,3,2,3,3,3,2,1,2,2,3,2,3,3,0,3,2,0,0,1,1,0,1,1,2,1,2,0,0,0,1, +0,3,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0, +3,3,3,2,3,3,2,3,2,2,2,3,3,3,3,1,3,1,1,0,3,2,1,1,3,3,2,3,1,0,0,1, +1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,0,0,1, +3,2,2,3,3,0,3,3,3,3,3,3,3,2,2,1,0,3,3,1,3,3,0,1,3,3,2,3,0,3,0,3, +2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, +2,2,2,3,3,0,3,3,3,3,3,3,3,3,3,0,0,3,2,0,3,3,0,3,2,3,3,3,0,3,1,3, +2,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,1,0,0,0,0,0,0,0,2,2,0,0,1,0,0,1, +3,3,3,1,2,3,3,1,0,0,1,0,0,3,3,2,3,0,0,2,0,0,2,0,2,0,0,0,2,0,2,0, +0,3,1,0,1,0,0,0,2,2,1,0,1,1,2,1,2,2,2,0,2,1,1,0,0,0,2,0,0,0,0,0, +1,2,1,3,3,0,3,3,3,3,3,2,3,0,0,0,0,2,3,0,2,3,1,0,2,3,1,3,0,3,0,2, +3,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,1,3,3,2,2,3,2,2,0,1,2,3,0,1,2,1,0,1,0,0,0,1,0,2,2,0,0,0,1, +1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0, +3,3,3,1,3,3,1,1,3,3,1,1,3,3,1,0,2,1,2,0,2,1,0,0,1,1,2,1,0,0,0,2, +2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,1,0,2,1,3,0,0,2,0,0,3,3,0,3,0,0,1,0,1,2,0,0,1,1,2,2,0,1,0, +0,1,2,1,1,0,1,0,1,1,1,1,1,0,1,1,1,2,2,1,2,0,1,0,0,0,0,0,0,1,0,0, +3,3,3,2,3,2,3,3,0,2,2,2,3,3,3,0,3,0,0,0,2,2,0,1,2,1,1,1,0,0,0,1, +0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +3,3,3,3,3,3,2,1,2,2,3,3,3,3,2,0,2,0,0,0,2,2,0,0,2,1,3,3,0,0,1,1, +1,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0, +1,1,2,3,3,0,3,3,3,3,3,3,2,2,0,2,0,2,3,2,3,2,2,2,2,2,2,2,1,3,2,3, +2,0,2,1,2,2,2,2,1,1,2,2,1,2,2,1,2,0,0,2,1,1,0,2,1,0,0,1,0,0,0,1, +2,3,3,1,1,1,0,1,1,1,2,3,2,1,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0, +0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,2,2,2,3,2,3,2,2,1,3,3,3,0,2,1,2,0,2,1,0,0,1,1,1,1,1,0,0,1, +2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,2,0,1,0,0,0, +3,3,3,2,3,3,3,3,3,2,3,1,2,3,3,1,2,0,0,0,0,0,0,0,3,2,1,1,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, +3,3,3,2,2,3,3,2,1,1,1,1,1,3,3,0,3,1,0,0,1,1,0,0,3,1,2,1,0,0,0,0, +0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0, +3,3,3,2,2,3,2,2,2,3,2,1,1,3,3,0,3,0,0,0,0,1,0,0,3,1,1,2,0,0,0,1, +1,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,1,1,3,3,0,3,3,3,3,3,2,2,2,1,2,0,2,1,2,2,1,1,0,1,2,2,2,2,2,2,2, +0,0,2,1,2,1,2,1,0,1,1,3,1,2,1,1,2,0,0,2,0,1,0,1,0,1,0,0,0,1,0,1, +3,3,3,1,3,3,3,0,1,1,0,2,2,3,1,0,3,0,0,0,1,0,0,0,1,0,0,1,0,1,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,2,0,0,2,2,1,0,0,1,0,0,3,3,1,3,0,0,1,1,0,2,0,3,0,0,0,2,0,1,1, +0,1,2,0,1,2,2,0,2,2,2,2,1,0,2,1,1,0,2,0,2,1,2,0,0,0,0,0,0,0,0,0, +3,3,3,1,3,2,3,2,0,2,2,2,1,3,2,0,2,1,2,0,1,2,0,0,1,0,2,2,0,0,0,2, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0, +3,3,3,0,3,3,1,1,2,3,1,0,3,2,3,0,3,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0, +1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,3,3,0,3,3,2,3,3,2,2,0,0,0,0,1,2,0,1,3,0,0,0,3,1,1,0,3,0,2, +2,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,1,2,2,1,0,3,1,1,1,1,3,3,2,3,0,0,1,0,1,2,0,2,2,0,2,2,0,2,1, +0,2,2,1,1,1,1,0,2,1,1,0,1,1,1,1,2,1,2,1,2,0,1,0,1,0,0,0,0,0,0,0, +3,3,3,0,1,1,3,0,0,1,1,0,0,2,2,0,3,0,0,1,1,0,1,0,0,0,0,0,2,0,0,0, +0,3,1,0,1,0,1,0,2,0,0,1,0,1,0,1,1,1,2,1,1,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,0,2,0,2,0,1,1,1,0,0,3,3,0,2,0,0,1,0,0,2,1,1,0,1,0,1,0,1,0, +0,2,0,1,2,0,2,0,2,1,1,0,1,0,2,1,1,0,2,1,1,0,1,0,0,0,1,1,0,0,0,0, +3,2,3,0,1,0,0,0,0,0,0,0,0,1,2,0,1,0,0,1,0,0,1,0,0,0,0,0,2,0,0,0, +0,0,1,1,0,0,1,0,1,0,0,1,0,0,0,2,1,0,1,0,2,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,0,0,2,3,0,0,1,0,1,0,2,3,2,3,0,0,1,3,0,2,1,0,0,0,0,2,0,1,0, +0,2,1,0,0,1,1,0,2,1,0,0,1,0,0,1,1,0,1,1,2,0,1,0,0,0,0,1,0,0,0,0, +3,2,2,0,0,1,1,0,0,0,0,0,0,3,1,1,1,0,0,0,0,0,1,0,0,0,0,0,2,0,1,0, +0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,3,3,0,2,3,2,2,1,2,2,1,1,2,0,1,3,2,2,2,0,0,2,2,0,0,0,1,2,1, +3,0,2,1,1,0,1,1,1,0,1,2,2,2,1,1,2,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0, +0,1,1,2,3,0,3,3,3,2,2,2,2,1,0,1,0,1,0,1,2,2,0,0,2,2,1,3,1,1,2,1, +0,0,1,1,2,0,1,1,0,0,1,2,0,2,1,1,2,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0, +3,3,2,0,0,3,1,0,0,0,0,0,0,3,2,1,2,0,0,1,0,0,2,0,0,0,0,0,2,0,1,0, +0,2,1,1,0,0,1,0,1,2,0,0,1,1,0,0,2,1,1,1,1,0,2,0,0,0,0,0,0,0,0,0, +3,3,2,0,0,1,0,0,0,0,1,0,0,3,3,2,2,0,0,1,0,0,2,0,1,0,0,0,2,0,1,0, +0,0,1,1,0,0,2,0,2,1,0,0,1,1,2,1,2,0,2,1,2,1,1,1,0,0,1,1,0,0,0,0, +3,3,2,0,0,2,2,0,0,0,1,1,0,2,2,1,3,1,0,1,0,1,2,0,0,0,0,0,1,0,1,0, +0,1,1,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,2,0,0,0,1,0,0,1,0,0,2,3,1,2,0,0,1,0,0,2,0,0,0,1,0,2,0,2,0, +0,1,1,2,2,1,2,0,2,1,1,0,0,1,1,0,1,1,1,1,2,1,1,0,0,0,0,0,0,0,0,0, +3,3,3,0,2,1,2,1,0,0,1,1,0,3,3,1,2,0,0,1,0,0,2,0,2,0,1,1,2,0,0,0, +0,0,1,1,1,1,2,0,1,1,0,1,1,1,1,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,0, +3,3,3,0,2,2,3,2,0,0,1,0,0,2,3,1,0,0,0,0,0,0,2,0,2,0,0,0,2,0,0,0, +0,1,1,0,0,0,1,0,0,1,0,1,1,0,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,0,0,0,0,0,0,0,1,0,0,2,2,2,2,0,0,1,0,0,2,0,0,0,0,0,2,0,1,0, +0,0,2,1,1,0,1,0,2,1,1,0,0,1,1,2,1,0,2,0,2,0,1,0,0,0,2,0,0,0,0,0, +0,0,0,2,2,0,2,1,1,1,1,2,2,0,0,1,0,1,0,0,1,3,0,0,0,0,1,0,0,2,1,0, +0,0,1,0,1,0,0,0,0,0,2,1,0,1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +2,0,0,2,3,0,2,3,1,2,2,0,2,0,0,2,0,2,1,1,1,2,1,0,0,1,2,1,1,2,1,0, +1,0,2,0,1,0,1,1,0,0,2,2,1,2,1,1,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,0,2,1,2,0,0,0,1,0,0,3,2,0,1,0,0,1,0,0,2,0,0,0,1,2,1,0,1,0, +0,0,0,0,1,0,1,0,0,1,0,0,0,0,1,0,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,2,2,0,2,2,1,1,0,1,1,1,1,1,0,0,1,2,1,1,1,0,1,0,0,0,1,1,1,1, +0,0,2,1,0,1,1,1,0,1,1,2,1,2,1,1,2,0,1,1,2,1,0,2,0,0,0,0,0,0,0,0, +3,2,2,0,0,2,0,0,0,0,0,0,0,2,2,0,2,0,0,1,0,0,2,0,0,0,0,0,2,0,0,0, +0,2,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,3,2,0,2,2,0,1,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0, +2,0,1,0,1,0,1,1,0,0,1,2,0,1,0,1,1,0,0,1,0,1,0,2,0,0,0,0,0,0,0,0, +2,2,2,0,1,1,0,0,0,1,0,0,0,1,2,0,1,0,0,1,0,0,1,0,0,0,0,1,2,0,1,0, +0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0,1,0,2,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,1,0,1,1,1,0,0,0,0,1,2,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +1,1,2,0,1,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,2,0,0,0,0,0,1, +0,0,1,2,2,0,2,1,2,1,1,2,2,0,0,0,0,1,0,0,1,1,0,0,2,0,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +2,2,2,0,0,0,1,0,0,0,0,0,0,2,2,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,0,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +) + +Latin5TurkishModel = { + 'char_to_order_map': Latin5_TurkishCharToOrderMap, + 'precedence_matrix': TurkishLangModel, + 'typical_positive_ratio': 0.970290, + 'keep_english_letter': True, + 'charset_name': "ISO-8859-9", + 'language': 'Turkish', +} diff --git a/venv/lib/python2.7/site-packages/chardet/latin1prober.py b/venv/lib/python2.7/site-packages/chardet/latin1prober.py new file mode 100644 index 0000000..7d1e8c2 --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/latin1prober.py @@ -0,0 +1,145 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetprober import CharSetProber +from .enums import ProbingState + +FREQ_CAT_NUM = 4 + +UDF = 0 # undefined +OTH = 1 # other +ASC = 2 # ascii capital letter +ASS = 3 # ascii small letter +ACV = 4 # accent capital vowel +ACO = 5 # accent capital other +ASV = 6 # accent small vowel +ASO = 7 # accent small other +CLASS_NUM = 8 # total classes + +Latin1_CharToClass = ( + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 00 - 07 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 08 - 0F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 10 - 17 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 18 - 1F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 20 - 27 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 28 - 2F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 30 - 37 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 38 - 3F + OTH, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 40 - 47 + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 48 - 4F + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 50 - 57 + ASC, ASC, ASC, OTH, OTH, OTH, OTH, OTH, # 58 - 5F + OTH, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 60 - 67 + ASS, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 68 - 6F + ASS, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 70 - 77 + ASS, ASS, ASS, OTH, OTH, OTH, OTH, OTH, # 78 - 7F + OTH, UDF, OTH, ASO, OTH, OTH, OTH, OTH, # 80 - 87 + OTH, OTH, ACO, OTH, ACO, UDF, ACO, UDF, # 88 - 8F + UDF, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 90 - 97 + OTH, OTH, ASO, OTH, ASO, UDF, ASO, ACO, # 98 - 9F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # A0 - A7 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # A8 - AF + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # B0 - B7 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # B8 - BF + ACV, ACV, ACV, ACV, ACV, ACV, ACO, ACO, # C0 - C7 + ACV, ACV, ACV, ACV, ACV, ACV, ACV, ACV, # C8 - CF + ACO, ACO, ACV, ACV, ACV, ACV, ACV, OTH, # D0 - D7 + ACV, ACV, ACV, ACV, ACV, ACO, ACO, ACO, # D8 - DF + ASV, ASV, ASV, ASV, ASV, ASV, ASO, ASO, # E0 - E7 + ASV, ASV, ASV, ASV, ASV, ASV, ASV, ASV, # E8 - EF + ASO, ASO, ASV, ASV, ASV, ASV, ASV, OTH, # F0 - F7 + ASV, ASV, ASV, ASV, ASV, ASO, ASO, ASO, # F8 - FF +) + +# 0 : illegal +# 1 : very unlikely +# 2 : normal +# 3 : very likely +Latin1ClassModel = ( +# UDF OTH ASC ASS ACV ACO ASV ASO + 0, 0, 0, 0, 0, 0, 0, 0, # UDF + 0, 3, 3, 3, 3, 3, 3, 3, # OTH + 0, 3, 3, 3, 3, 3, 3, 3, # ASC + 0, 3, 3, 3, 1, 1, 3, 3, # ASS + 0, 3, 3, 3, 1, 2, 1, 2, # ACV + 0, 3, 3, 3, 3, 3, 3, 3, # ACO + 0, 3, 1, 3, 1, 1, 1, 3, # ASV + 0, 3, 1, 3, 1, 1, 3, 3, # ASO +) + + +class Latin1Prober(CharSetProber): + def __init__(self): + super(Latin1Prober, self).__init__() + self._last_char_class = None + self._freq_counter = None + self.reset() + + def reset(self): + self._last_char_class = OTH + self._freq_counter = [0] * FREQ_CAT_NUM + CharSetProber.reset(self) + + @property + def charset_name(self): + return "ISO-8859-1" + + @property + def language(self): + return "" + + def feed(self, byte_str): + byte_str = self.filter_with_english_letters(byte_str) + for c in byte_str: + char_class = Latin1_CharToClass[c] + freq = Latin1ClassModel[(self._last_char_class * CLASS_NUM) + + char_class] + if freq == 0: + self._state = ProbingState.NOT_ME + break + self._freq_counter[freq] += 1 + self._last_char_class = char_class + + return self.state + + def get_confidence(self): + if self.state == ProbingState.NOT_ME: + return 0.01 + + total = sum(self._freq_counter) + if total < 0.01: + confidence = 0.0 + else: + confidence = ((self._freq_counter[3] - self._freq_counter[1] * 20.0) + / total) + if confidence < 0.0: + confidence = 0.0 + # lower the confidence of latin1 so that other more accurate + # detector can take priority. + confidence = confidence * 0.73 + return confidence diff --git a/venv/lib/python2.7/site-packages/chardet/mbcharsetprober.py b/venv/lib/python2.7/site-packages/chardet/mbcharsetprober.py new file mode 100644 index 0000000..6256ecf --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/mbcharsetprober.py @@ -0,0 +1,91 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# Proofpoint, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetprober import CharSetProber +from .enums import ProbingState, MachineState + + +class MultiByteCharSetProber(CharSetProber): + """ + MultiByteCharSetProber + """ + + def __init__(self, lang_filter=None): + super(MultiByteCharSetProber, self).__init__(lang_filter=lang_filter) + self.distribution_analyzer = None + self.coding_sm = None + self._last_char = [0, 0] + + def reset(self): + super(MultiByteCharSetProber, self).reset() + if self.coding_sm: + self.coding_sm.reset() + if self.distribution_analyzer: + self.distribution_analyzer.reset() + self._last_char = [0, 0] + + @property + def charset_name(self): + raise NotImplementedError + + @property + def language(self): + raise NotImplementedError + + def feed(self, byte_str): + for i in range(len(byte_str)): + coding_state = self.coding_sm.next_state(byte_str[i]) + if coding_state == MachineState.ERROR: + self.logger.debug('%s %s prober hit error at byte %s', + self.charset_name, self.language, i) + self._state = ProbingState.NOT_ME + break + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + break + elif coding_state == MachineState.START: + char_len = self.coding_sm.get_current_charlen() + if i == 0: + self._last_char[1] = byte_str[0] + self.distribution_analyzer.feed(self._last_char, char_len) + else: + self.distribution_analyzer.feed(byte_str[i - 1:i + 1], + char_len) + + self._last_char[0] = byte_str[-1] + + if self.state == ProbingState.DETECTING: + if (self.distribution_analyzer.got_enough_data() and + (self.get_confidence() > self.SHORTCUT_THRESHOLD)): + self._state = ProbingState.FOUND_IT + + return self.state + + def get_confidence(self): + return self.distribution_analyzer.get_confidence() diff --git a/venv/lib/python2.7/site-packages/chardet/mbcsgroupprober.py b/venv/lib/python2.7/site-packages/chardet/mbcsgroupprober.py new file mode 100644 index 0000000..530abe7 --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/mbcsgroupprober.py @@ -0,0 +1,54 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# Proofpoint, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetgroupprober import CharSetGroupProber +from .utf8prober import UTF8Prober +from .sjisprober import SJISProber +from .eucjpprober import EUCJPProber +from .gb2312prober import GB2312Prober +from .euckrprober import EUCKRProber +from .cp949prober import CP949Prober +from .big5prober import Big5Prober +from .euctwprober import EUCTWProber + + +class MBCSGroupProber(CharSetGroupProber): + def __init__(self, lang_filter=None): + super(MBCSGroupProber, self).__init__(lang_filter=lang_filter) + self.probers = [ + UTF8Prober(), + SJISProber(), + EUCJPProber(), + GB2312Prober(), + EUCKRProber(), + CP949Prober(), + Big5Prober(), + EUCTWProber() + ] + self.reset() diff --git a/venv/lib/python2.7/site-packages/chardet/mbcssm.py b/venv/lib/python2.7/site-packages/chardet/mbcssm.py new file mode 100644 index 0000000..8360d0f --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/mbcssm.py @@ -0,0 +1,572 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .enums import MachineState + +# BIG5 + +BIG5_CLS = ( + 1,1,1,1,1,1,1,1, # 00 - 07 #allow 0x00 as legal value + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,1, # 78 - 7f + 4,4,4,4,4,4,4,4, # 80 - 87 + 4,4,4,4,4,4,4,4, # 88 - 8f + 4,4,4,4,4,4,4,4, # 90 - 97 + 4,4,4,4,4,4,4,4, # 98 - 9f + 4,3,3,3,3,3,3,3, # a0 - a7 + 3,3,3,3,3,3,3,3, # a8 - af + 3,3,3,3,3,3,3,3, # b0 - b7 + 3,3,3,3,3,3,3,3, # b8 - bf + 3,3,3,3,3,3,3,3, # c0 - c7 + 3,3,3,3,3,3,3,3, # c8 - cf + 3,3,3,3,3,3,3,3, # d0 - d7 + 3,3,3,3,3,3,3,3, # d8 - df + 3,3,3,3,3,3,3,3, # e0 - e7 + 3,3,3,3,3,3,3,3, # e8 - ef + 3,3,3,3,3,3,3,3, # f0 - f7 + 3,3,3,3,3,3,3,0 # f8 - ff +) + +BIG5_ST = ( + MachineState.ERROR,MachineState.START,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,#08-0f + MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START#10-17 +) + +BIG5_CHAR_LEN_TABLE = (0, 1, 1, 2, 0) + +BIG5_SM_MODEL = {'class_table': BIG5_CLS, + 'class_factor': 5, + 'state_table': BIG5_ST, + 'char_len_table': BIG5_CHAR_LEN_TABLE, + 'name': 'Big5'} + +# CP949 + +CP949_CLS = ( + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,0,0, # 00 - 0f + 1,1,1,1,1,1,1,1, 1,1,1,0,1,1,1,1, # 10 - 1f + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, # 20 - 2f + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, # 30 - 3f + 1,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4, # 40 - 4f + 4,4,5,5,5,5,5,5, 5,5,5,1,1,1,1,1, # 50 - 5f + 1,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5, # 60 - 6f + 5,5,5,5,5,5,5,5, 5,5,5,1,1,1,1,1, # 70 - 7f + 0,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6, # 80 - 8f + 6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6, # 90 - 9f + 6,7,7,7,7,7,7,7, 7,7,7,7,7,8,8,8, # a0 - af + 7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7, # b0 - bf + 7,7,7,7,7,7,9,2, 2,3,2,2,2,2,2,2, # c0 - cf + 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, # d0 - df + 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, # e0 - ef + 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,0, # f0 - ff +) + +CP949_ST = ( +#cls= 0 1 2 3 4 5 6 7 8 9 # previous state = + MachineState.ERROR,MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START, 4, 5,MachineState.ERROR, 6, # MachineState.START + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, # MachineState.ERROR + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME, # MachineState.ITS_ME + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START, # 3 + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, # 4 + MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, # 5 + MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START, # 6 +) + +CP949_CHAR_LEN_TABLE = (0, 1, 2, 0, 1, 1, 2, 2, 0, 2) + +CP949_SM_MODEL = {'class_table': CP949_CLS, + 'class_factor': 10, + 'state_table': CP949_ST, + 'char_len_table': CP949_CHAR_LEN_TABLE, + 'name': 'CP949'} + +# EUC-JP + +EUCJP_CLS = ( + 4,4,4,4,4,4,4,4, # 00 - 07 + 4,4,4,4,4,4,5,5, # 08 - 0f + 4,4,4,4,4,4,4,4, # 10 - 17 + 4,4,4,5,4,4,4,4, # 18 - 1f + 4,4,4,4,4,4,4,4, # 20 - 27 + 4,4,4,4,4,4,4,4, # 28 - 2f + 4,4,4,4,4,4,4,4, # 30 - 37 + 4,4,4,4,4,4,4,4, # 38 - 3f + 4,4,4,4,4,4,4,4, # 40 - 47 + 4,4,4,4,4,4,4,4, # 48 - 4f + 4,4,4,4,4,4,4,4, # 50 - 57 + 4,4,4,4,4,4,4,4, # 58 - 5f + 4,4,4,4,4,4,4,4, # 60 - 67 + 4,4,4,4,4,4,4,4, # 68 - 6f + 4,4,4,4,4,4,4,4, # 70 - 77 + 4,4,4,4,4,4,4,4, # 78 - 7f + 5,5,5,5,5,5,5,5, # 80 - 87 + 5,5,5,5,5,5,1,3, # 88 - 8f + 5,5,5,5,5,5,5,5, # 90 - 97 + 5,5,5,5,5,5,5,5, # 98 - 9f + 5,2,2,2,2,2,2,2, # a0 - a7 + 2,2,2,2,2,2,2,2, # a8 - af + 2,2,2,2,2,2,2,2, # b0 - b7 + 2,2,2,2,2,2,2,2, # b8 - bf + 2,2,2,2,2,2,2,2, # c0 - c7 + 2,2,2,2,2,2,2,2, # c8 - cf + 2,2,2,2,2,2,2,2, # d0 - d7 + 2,2,2,2,2,2,2,2, # d8 - df + 0,0,0,0,0,0,0,0, # e0 - e7 + 0,0,0,0,0,0,0,0, # e8 - ef + 0,0,0,0,0,0,0,0, # f0 - f7 + 0,0,0,0,0,0,0,5 # f8 - ff +) + +EUCJP_ST = ( + 3, 4, 3, 5,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.START,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#10-17 + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 3,MachineState.ERROR,#18-1f + 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START#20-27 +) + +EUCJP_CHAR_LEN_TABLE = (2, 2, 2, 3, 1, 0) + +EUCJP_SM_MODEL = {'class_table': EUCJP_CLS, + 'class_factor': 6, + 'state_table': EUCJP_ST, + 'char_len_table': EUCJP_CHAR_LEN_TABLE, + 'name': 'EUC-JP'} + +# EUC-KR + +EUCKR_CLS = ( + 1,1,1,1,1,1,1,1, # 00 - 07 + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 1,1,1,1,1,1,1,1, # 40 - 47 + 1,1,1,1,1,1,1,1, # 48 - 4f + 1,1,1,1,1,1,1,1, # 50 - 57 + 1,1,1,1,1,1,1,1, # 58 - 5f + 1,1,1,1,1,1,1,1, # 60 - 67 + 1,1,1,1,1,1,1,1, # 68 - 6f + 1,1,1,1,1,1,1,1, # 70 - 77 + 1,1,1,1,1,1,1,1, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,0,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,2,2,2,2,2,2,2, # a0 - a7 + 2,2,2,2,2,3,3,3, # a8 - af + 2,2,2,2,2,2,2,2, # b0 - b7 + 2,2,2,2,2,2,2,2, # b8 - bf + 2,2,2,2,2,2,2,2, # c0 - c7 + 2,3,2,2,2,2,2,2, # c8 - cf + 2,2,2,2,2,2,2,2, # d0 - d7 + 2,2,2,2,2,2,2,2, # d8 - df + 2,2,2,2,2,2,2,2, # e0 - e7 + 2,2,2,2,2,2,2,2, # e8 - ef + 2,2,2,2,2,2,2,2, # f0 - f7 + 2,2,2,2,2,2,2,0 # f8 - ff +) + +EUCKR_ST = ( + MachineState.ERROR,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START #08-0f +) + +EUCKR_CHAR_LEN_TABLE = (0, 1, 2, 0) + +EUCKR_SM_MODEL = {'class_table': EUCKR_CLS, + 'class_factor': 4, + 'state_table': EUCKR_ST, + 'char_len_table': EUCKR_CHAR_LEN_TABLE, + 'name': 'EUC-KR'} + +# EUC-TW + +EUCTW_CLS = ( + 2,2,2,2,2,2,2,2, # 00 - 07 + 2,2,2,2,2,2,0,0, # 08 - 0f + 2,2,2,2,2,2,2,2, # 10 - 17 + 2,2,2,0,2,2,2,2, # 18 - 1f + 2,2,2,2,2,2,2,2, # 20 - 27 + 2,2,2,2,2,2,2,2, # 28 - 2f + 2,2,2,2,2,2,2,2, # 30 - 37 + 2,2,2,2,2,2,2,2, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,2, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,6,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,3,4,4,4,4,4,4, # a0 - a7 + 5,5,1,1,1,1,1,1, # a8 - af + 1,1,1,1,1,1,1,1, # b0 - b7 + 1,1,1,1,1,1,1,1, # b8 - bf + 1,1,3,1,3,3,3,3, # c0 - c7 + 3,3,3,3,3,3,3,3, # c8 - cf + 3,3,3,3,3,3,3,3, # d0 - d7 + 3,3,3,3,3,3,3,3, # d8 - df + 3,3,3,3,3,3,3,3, # e0 - e7 + 3,3,3,3,3,3,3,3, # e8 - ef + 3,3,3,3,3,3,3,3, # f0 - f7 + 3,3,3,3,3,3,3,0 # f8 - ff +) + +EUCTW_ST = ( + MachineState.ERROR,MachineState.ERROR,MachineState.START, 3, 3, 3, 4,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,MachineState.ERROR,#10-17 + MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#18-1f + 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.START,MachineState.START,#20-27 + MachineState.START,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START #28-2f +) + +EUCTW_CHAR_LEN_TABLE = (0, 0, 1, 2, 2, 2, 3) + +EUCTW_SM_MODEL = {'class_table': EUCTW_CLS, + 'class_factor': 7, + 'state_table': EUCTW_ST, + 'char_len_table': EUCTW_CHAR_LEN_TABLE, + 'name': 'x-euc-tw'} + +# GB2312 + +GB2312_CLS = ( + 1,1,1,1,1,1,1,1, # 00 - 07 + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 3,3,3,3,3,3,3,3, # 30 - 37 + 3,3,1,1,1,1,1,1, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,4, # 78 - 7f + 5,6,6,6,6,6,6,6, # 80 - 87 + 6,6,6,6,6,6,6,6, # 88 - 8f + 6,6,6,6,6,6,6,6, # 90 - 97 + 6,6,6,6,6,6,6,6, # 98 - 9f + 6,6,6,6,6,6,6,6, # a0 - a7 + 6,6,6,6,6,6,6,6, # a8 - af + 6,6,6,6,6,6,6,6, # b0 - b7 + 6,6,6,6,6,6,6,6, # b8 - bf + 6,6,6,6,6,6,6,6, # c0 - c7 + 6,6,6,6,6,6,6,6, # c8 - cf + 6,6,6,6,6,6,6,6, # d0 - d7 + 6,6,6,6,6,6,6,6, # d8 - df + 6,6,6,6,6,6,6,6, # e0 - e7 + 6,6,6,6,6,6,6,6, # e8 - ef + 6,6,6,6,6,6,6,6, # f0 - f7 + 6,6,6,6,6,6,6,0 # f8 - ff +) + +GB2312_ST = ( + MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, 3,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,#10-17 + 4,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#18-1f + MachineState.ERROR,MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,#20-27 + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START #28-2f +) + +# To be accurate, the length of class 6 can be either 2 or 4. +# But it is not necessary to discriminate between the two since +# it is used for frequency analysis only, and we are validating +# each code range there as well. So it is safe to set it to be +# 2 here. +GB2312_CHAR_LEN_TABLE = (0, 1, 1, 1, 1, 1, 2) + +GB2312_SM_MODEL = {'class_table': GB2312_CLS, + 'class_factor': 7, + 'state_table': GB2312_ST, + 'char_len_table': GB2312_CHAR_LEN_TABLE, + 'name': 'GB2312'} + +# Shift_JIS + +SJIS_CLS = ( + 1,1,1,1,1,1,1,1, # 00 - 07 + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,1, # 78 - 7f + 3,3,3,3,3,2,2,3, # 80 - 87 + 3,3,3,3,3,3,3,3, # 88 - 8f + 3,3,3,3,3,3,3,3, # 90 - 97 + 3,3,3,3,3,3,3,3, # 98 - 9f + #0xa0 is illegal in sjis encoding, but some pages does + #contain such byte. We need to be more error forgiven. + 2,2,2,2,2,2,2,2, # a0 - a7 + 2,2,2,2,2,2,2,2, # a8 - af + 2,2,2,2,2,2,2,2, # b0 - b7 + 2,2,2,2,2,2,2,2, # b8 - bf + 2,2,2,2,2,2,2,2, # c0 - c7 + 2,2,2,2,2,2,2,2, # c8 - cf + 2,2,2,2,2,2,2,2, # d0 - d7 + 2,2,2,2,2,2,2,2, # d8 - df + 3,3,3,3,3,3,3,3, # e0 - e7 + 3,3,3,3,3,4,4,4, # e8 - ef + 3,3,3,3,3,3,3,3, # f0 - f7 + 3,3,3,3,3,0,0,0) # f8 - ff + + +SJIS_ST = ( + MachineState.ERROR,MachineState.START,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START #10-17 +) + +SJIS_CHAR_LEN_TABLE = (0, 1, 1, 2, 0, 0) + +SJIS_SM_MODEL = {'class_table': SJIS_CLS, + 'class_factor': 6, + 'state_table': SJIS_ST, + 'char_len_table': SJIS_CHAR_LEN_TABLE, + 'name': 'Shift_JIS'} + +# UCS2-BE + +UCS2BE_CLS = ( + 0,0,0,0,0,0,0,0, # 00 - 07 + 0,0,1,0,0,2,0,0, # 08 - 0f + 0,0,0,0,0,0,0,0, # 10 - 17 + 0,0,0,3,0,0,0,0, # 18 - 1f + 0,0,0,0,0,0,0,0, # 20 - 27 + 0,3,3,3,3,3,0,0, # 28 - 2f + 0,0,0,0,0,0,0,0, # 30 - 37 + 0,0,0,0,0,0,0,0, # 38 - 3f + 0,0,0,0,0,0,0,0, # 40 - 47 + 0,0,0,0,0,0,0,0, # 48 - 4f + 0,0,0,0,0,0,0,0, # 50 - 57 + 0,0,0,0,0,0,0,0, # 58 - 5f + 0,0,0,0,0,0,0,0, # 60 - 67 + 0,0,0,0,0,0,0,0, # 68 - 6f + 0,0,0,0,0,0,0,0, # 70 - 77 + 0,0,0,0,0,0,0,0, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,0,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,0,0,0,0,0,0,0, # a0 - a7 + 0,0,0,0,0,0,0,0, # a8 - af + 0,0,0,0,0,0,0,0, # b0 - b7 + 0,0,0,0,0,0,0,0, # b8 - bf + 0,0,0,0,0,0,0,0, # c0 - c7 + 0,0,0,0,0,0,0,0, # c8 - cf + 0,0,0,0,0,0,0,0, # d0 - d7 + 0,0,0,0,0,0,0,0, # d8 - df + 0,0,0,0,0,0,0,0, # e0 - e7 + 0,0,0,0,0,0,0,0, # e8 - ef + 0,0,0,0,0,0,0,0, # f0 - f7 + 0,0,0,0,0,0,4,5 # f8 - ff +) + +UCS2BE_ST = ( + 5, 7, 7,MachineState.ERROR, 4, 3,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME, 6, 6, 6, 6,MachineState.ERROR,MachineState.ERROR,#10-17 + 6, 6, 6, 6, 6,MachineState.ITS_ME, 6, 6,#18-1f + 6, 6, 6, 6, 5, 7, 7,MachineState.ERROR,#20-27 + 5, 8, 6, 6,MachineState.ERROR, 6, 6, 6,#28-2f + 6, 6, 6, 6,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START #30-37 +) + +UCS2BE_CHAR_LEN_TABLE = (2, 2, 2, 0, 2, 2) + +UCS2BE_SM_MODEL = {'class_table': UCS2BE_CLS, + 'class_factor': 6, + 'state_table': UCS2BE_ST, + 'char_len_table': UCS2BE_CHAR_LEN_TABLE, + 'name': 'UTF-16BE'} + +# UCS2-LE + +UCS2LE_CLS = ( + 0,0,0,0,0,0,0,0, # 00 - 07 + 0,0,1,0,0,2,0,0, # 08 - 0f + 0,0,0,0,0,0,0,0, # 10 - 17 + 0,0,0,3,0,0,0,0, # 18 - 1f + 0,0,0,0,0,0,0,0, # 20 - 27 + 0,3,3,3,3,3,0,0, # 28 - 2f + 0,0,0,0,0,0,0,0, # 30 - 37 + 0,0,0,0,0,0,0,0, # 38 - 3f + 0,0,0,0,0,0,0,0, # 40 - 47 + 0,0,0,0,0,0,0,0, # 48 - 4f + 0,0,0,0,0,0,0,0, # 50 - 57 + 0,0,0,0,0,0,0,0, # 58 - 5f + 0,0,0,0,0,0,0,0, # 60 - 67 + 0,0,0,0,0,0,0,0, # 68 - 6f + 0,0,0,0,0,0,0,0, # 70 - 77 + 0,0,0,0,0,0,0,0, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,0,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,0,0,0,0,0,0,0, # a0 - a7 + 0,0,0,0,0,0,0,0, # a8 - af + 0,0,0,0,0,0,0,0, # b0 - b7 + 0,0,0,0,0,0,0,0, # b8 - bf + 0,0,0,0,0,0,0,0, # c0 - c7 + 0,0,0,0,0,0,0,0, # c8 - cf + 0,0,0,0,0,0,0,0, # d0 - d7 + 0,0,0,0,0,0,0,0, # d8 - df + 0,0,0,0,0,0,0,0, # e0 - e7 + 0,0,0,0,0,0,0,0, # e8 - ef + 0,0,0,0,0,0,0,0, # f0 - f7 + 0,0,0,0,0,0,4,5 # f8 - ff +) + +UCS2LE_ST = ( + 6, 6, 7, 6, 4, 3,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME, 5, 5, 5,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,#10-17 + 5, 5, 5,MachineState.ERROR, 5,MachineState.ERROR, 6, 6,#18-1f + 7, 6, 8, 8, 5, 5, 5,MachineState.ERROR,#20-27 + 5, 5, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5, 5,#28-2f + 5, 5, 5,MachineState.ERROR, 5,MachineState.ERROR,MachineState.START,MachineState.START #30-37 +) + +UCS2LE_CHAR_LEN_TABLE = (2, 2, 2, 2, 2, 2) + +UCS2LE_SM_MODEL = {'class_table': UCS2LE_CLS, + 'class_factor': 6, + 'state_table': UCS2LE_ST, + 'char_len_table': UCS2LE_CHAR_LEN_TABLE, + 'name': 'UTF-16LE'} + +# UTF-8 + +UTF8_CLS = ( + 1,1,1,1,1,1,1,1, # 00 - 07 #allow 0x00 as a legal value + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 1,1,1,1,1,1,1,1, # 40 - 47 + 1,1,1,1,1,1,1,1, # 48 - 4f + 1,1,1,1,1,1,1,1, # 50 - 57 + 1,1,1,1,1,1,1,1, # 58 - 5f + 1,1,1,1,1,1,1,1, # 60 - 67 + 1,1,1,1,1,1,1,1, # 68 - 6f + 1,1,1,1,1,1,1,1, # 70 - 77 + 1,1,1,1,1,1,1,1, # 78 - 7f + 2,2,2,2,3,3,3,3, # 80 - 87 + 4,4,4,4,4,4,4,4, # 88 - 8f + 4,4,4,4,4,4,4,4, # 90 - 97 + 4,4,4,4,4,4,4,4, # 98 - 9f + 5,5,5,5,5,5,5,5, # a0 - a7 + 5,5,5,5,5,5,5,5, # a8 - af + 5,5,5,5,5,5,5,5, # b0 - b7 + 5,5,5,5,5,5,5,5, # b8 - bf + 0,0,6,6,6,6,6,6, # c0 - c7 + 6,6,6,6,6,6,6,6, # c8 - cf + 6,6,6,6,6,6,6,6, # d0 - d7 + 6,6,6,6,6,6,6,6, # d8 - df + 7,8,8,8,8,8,8,8, # e0 - e7 + 8,8,8,8,8,9,8,8, # e8 - ef + 10,11,11,11,11,11,11,11, # f0 - f7 + 12,13,13,13,14,15,0,0 # f8 - ff +) + +UTF8_ST = ( + MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 12, 10,#00-07 + 9, 11, 8, 7, 6, 5, 4, 3,#08-0f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#10-17 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#18-1f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#20-27 + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#28-2f + MachineState.ERROR,MachineState.ERROR, 5, 5, 5, 5,MachineState.ERROR,MachineState.ERROR,#30-37 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#38-3f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5, 5, 5,MachineState.ERROR,MachineState.ERROR,#40-47 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#48-4f + MachineState.ERROR,MachineState.ERROR, 7, 7, 7, 7,MachineState.ERROR,MachineState.ERROR,#50-57 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#58-5f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 7, 7,MachineState.ERROR,MachineState.ERROR,#60-67 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#68-6f + MachineState.ERROR,MachineState.ERROR, 9, 9, 9, 9,MachineState.ERROR,MachineState.ERROR,#70-77 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#78-7f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 9,MachineState.ERROR,MachineState.ERROR,#80-87 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#88-8f + MachineState.ERROR,MachineState.ERROR, 12, 12, 12, 12,MachineState.ERROR,MachineState.ERROR,#90-97 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#98-9f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 12,MachineState.ERROR,MachineState.ERROR,#a0-a7 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#a8-af + MachineState.ERROR,MachineState.ERROR, 12, 12, 12,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#b0-b7 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#b8-bf + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,#c0-c7 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR #c8-cf +) + +UTF8_CHAR_LEN_TABLE = (0, 1, 0, 0, 0, 0, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6) + +UTF8_SM_MODEL = {'class_table': UTF8_CLS, + 'class_factor': 16, + 'state_table': UTF8_ST, + 'char_len_table': UTF8_CHAR_LEN_TABLE, + 'name': 'UTF-8'} diff --git a/venv/lib/python2.7/site-packages/chardet/sbcharsetprober.py b/venv/lib/python2.7/site-packages/chardet/sbcharsetprober.py new file mode 100644 index 0000000..0adb51d --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/sbcharsetprober.py @@ -0,0 +1,132 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetprober import CharSetProber +from .enums import CharacterCategory, ProbingState, SequenceLikelihood + + +class SingleByteCharSetProber(CharSetProber): + SAMPLE_SIZE = 64 + SB_ENOUGH_REL_THRESHOLD = 1024 # 0.25 * SAMPLE_SIZE^2 + POSITIVE_SHORTCUT_THRESHOLD = 0.95 + NEGATIVE_SHORTCUT_THRESHOLD = 0.05 + + def __init__(self, model, reversed=False, name_prober=None): + super(SingleByteCharSetProber, self).__init__() + self._model = model + # TRUE if we need to reverse every pair in the model lookup + self._reversed = reversed + # Optional auxiliary prober for name decision + self._name_prober = name_prober + self._last_order = None + self._seq_counters = None + self._total_seqs = None + self._total_char = None + self._freq_char = None + self.reset() + + def reset(self): + super(SingleByteCharSetProber, self).reset() + # char order of last character + self._last_order = 255 + self._seq_counters = [0] * SequenceLikelihood.get_num_categories() + self._total_seqs = 0 + self._total_char = 0 + # characters that fall in our sampling range + self._freq_char = 0 + + @property + def charset_name(self): + if self._name_prober: + return self._name_prober.charset_name + else: + return self._model['charset_name'] + + @property + def language(self): + if self._name_prober: + return self._name_prober.language + else: + return self._model.get('language') + + def feed(self, byte_str): + if not self._model['keep_english_letter']: + byte_str = self.filter_international_words(byte_str) + if not byte_str: + return self.state + char_to_order_map = self._model['char_to_order_map'] + for i, c in enumerate(byte_str): + # XXX: Order is in range 1-64, so one would think we want 0-63 here, + # but that leads to 27 more test failures than before. + order = char_to_order_map[c] + # XXX: This was SYMBOL_CAT_ORDER before, with a value of 250, but + # CharacterCategory.SYMBOL is actually 253, so we use CONTROL + # to make it closer to the original intent. The only difference + # is whether or not we count digits and control characters for + # _total_char purposes. + if order < CharacterCategory.CONTROL: + self._total_char += 1 + if order < self.SAMPLE_SIZE: + self._freq_char += 1 + if self._last_order < self.SAMPLE_SIZE: + self._total_seqs += 1 + if not self._reversed: + i = (self._last_order * self.SAMPLE_SIZE) + order + model = self._model['precedence_matrix'][i] + else: # reverse the order of the letters in the lookup + i = (order * self.SAMPLE_SIZE) + self._last_order + model = self._model['precedence_matrix'][i] + self._seq_counters[model] += 1 + self._last_order = order + + charset_name = self._model['charset_name'] + if self.state == ProbingState.DETECTING: + if self._total_seqs > self.SB_ENOUGH_REL_THRESHOLD: + confidence = self.get_confidence() + if confidence > self.POSITIVE_SHORTCUT_THRESHOLD: + self.logger.debug('%s confidence = %s, we have a winner', + charset_name, confidence) + self._state = ProbingState.FOUND_IT + elif confidence < self.NEGATIVE_SHORTCUT_THRESHOLD: + self.logger.debug('%s confidence = %s, below negative ' + 'shortcut threshhold %s', charset_name, + confidence, + self.NEGATIVE_SHORTCUT_THRESHOLD) + self._state = ProbingState.NOT_ME + + return self.state + + def get_confidence(self): + r = 0.01 + if self._total_seqs > 0: + r = ((1.0 * self._seq_counters[SequenceLikelihood.POSITIVE]) / + self._total_seqs / self._model['typical_positive_ratio']) + r = r * self._freq_char / self._total_char + if r >= 1.0: + r = 0.99 + return r diff --git a/venv/lib/python2.7/site-packages/chardet/sbcsgroupprober.py b/venv/lib/python2.7/site-packages/chardet/sbcsgroupprober.py new file mode 100644 index 0000000..98e95dc --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/sbcsgroupprober.py @@ -0,0 +1,73 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetgroupprober import CharSetGroupProber +from .sbcharsetprober import SingleByteCharSetProber +from .langcyrillicmodel import (Win1251CyrillicModel, Koi8rModel, + Latin5CyrillicModel, MacCyrillicModel, + Ibm866Model, Ibm855Model) +from .langgreekmodel import Latin7GreekModel, Win1253GreekModel +from .langbulgarianmodel import Latin5BulgarianModel, Win1251BulgarianModel +# from .langhungarianmodel import Latin2HungarianModel, Win1250HungarianModel +from .langthaimodel import TIS620ThaiModel +from .langhebrewmodel import Win1255HebrewModel +from .hebrewprober import HebrewProber +from .langturkishmodel import Latin5TurkishModel + + +class SBCSGroupProber(CharSetGroupProber): + def __init__(self): + super(SBCSGroupProber, self).__init__() + self.probers = [ + SingleByteCharSetProber(Win1251CyrillicModel), + SingleByteCharSetProber(Koi8rModel), + SingleByteCharSetProber(Latin5CyrillicModel), + SingleByteCharSetProber(MacCyrillicModel), + SingleByteCharSetProber(Ibm866Model), + SingleByteCharSetProber(Ibm855Model), + SingleByteCharSetProber(Latin7GreekModel), + SingleByteCharSetProber(Win1253GreekModel), + SingleByteCharSetProber(Latin5BulgarianModel), + SingleByteCharSetProber(Win1251BulgarianModel), + # TODO: Restore Hungarian encodings (iso-8859-2 and windows-1250) + # after we retrain model. + # SingleByteCharSetProber(Latin2HungarianModel), + # SingleByteCharSetProber(Win1250HungarianModel), + SingleByteCharSetProber(TIS620ThaiModel), + SingleByteCharSetProber(Latin5TurkishModel), + ] + hebrew_prober = HebrewProber() + logical_hebrew_prober = SingleByteCharSetProber(Win1255HebrewModel, + False, hebrew_prober) + visual_hebrew_prober = SingleByteCharSetProber(Win1255HebrewModel, True, + hebrew_prober) + hebrew_prober.set_model_probers(logical_hebrew_prober, visual_hebrew_prober) + self.probers.extend([hebrew_prober, logical_hebrew_prober, + visual_hebrew_prober]) + + self.reset() diff --git a/venv/lib/python2.7/site-packages/chardet/sjisprober.py b/venv/lib/python2.7/site-packages/chardet/sjisprober.py new file mode 100644 index 0000000..9e29623 --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/sjisprober.py @@ -0,0 +1,92 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import SJISDistributionAnalysis +from .jpcntx import SJISContextAnalysis +from .mbcssm import SJIS_SM_MODEL +from .enums import ProbingState, MachineState + + +class SJISProber(MultiByteCharSetProber): + def __init__(self): + super(SJISProber, self).__init__() + self.coding_sm = CodingStateMachine(SJIS_SM_MODEL) + self.distribution_analyzer = SJISDistributionAnalysis() + self.context_analyzer = SJISContextAnalysis() + self.reset() + + def reset(self): + super(SJISProber, self).reset() + self.context_analyzer.reset() + + @property + def charset_name(self): + return self.context_analyzer.charset_name + + @property + def language(self): + return "Japanese" + + def feed(self, byte_str): + for i in range(len(byte_str)): + coding_state = self.coding_sm.next_state(byte_str[i]) + if coding_state == MachineState.ERROR: + self.logger.debug('%s %s prober hit error at byte %s', + self.charset_name, self.language, i) + self._state = ProbingState.NOT_ME + break + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + break + elif coding_state == MachineState.START: + char_len = self.coding_sm.get_current_charlen() + if i == 0: + self._last_char[1] = byte_str[0] + self.context_analyzer.feed(self._last_char[2 - char_len:], + char_len) + self.distribution_analyzer.feed(self._last_char, char_len) + else: + self.context_analyzer.feed(byte_str[i + 1 - char_len:i + 3 + - char_len], char_len) + self.distribution_analyzer.feed(byte_str[i - 1:i + 1], + char_len) + + self._last_char[0] = byte_str[-1] + + if self.state == ProbingState.DETECTING: + if (self.context_analyzer.got_enough_data() and + (self.get_confidence() > self.SHORTCUT_THRESHOLD)): + self._state = ProbingState.FOUND_IT + + return self.state + + def get_confidence(self): + context_conf = self.context_analyzer.get_confidence() + distrib_conf = self.distribution_analyzer.get_confidence() + return max(context_conf, distrib_conf) diff --git a/venv/lib/python2.7/site-packages/chardet/universaldetector.py b/venv/lib/python2.7/site-packages/chardet/universaldetector.py new file mode 100644 index 0000000..7b4e92d --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/universaldetector.py @@ -0,0 +1,286 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### +""" +Module containing the UniversalDetector detector class, which is the primary +class a user of ``chardet`` should use. + +:author: Mark Pilgrim (initial port to Python) +:author: Shy Shalom (original C code) +:author: Dan Blanchard (major refactoring for 3.0) +:author: Ian Cordasco +""" + + +import codecs +import logging +import re + +from .charsetgroupprober import CharSetGroupProber +from .enums import InputState, LanguageFilter, ProbingState +from .escprober import EscCharSetProber +from .latin1prober import Latin1Prober +from .mbcsgroupprober import MBCSGroupProber +from .sbcsgroupprober import SBCSGroupProber + + +class UniversalDetector(object): + """ + The ``UniversalDetector`` class underlies the ``chardet.detect`` function + and coordinates all of the different charset probers. + + To get a ``dict`` containing an encoding and its confidence, you can simply + run: + + .. code:: + + u = UniversalDetector() + u.feed(some_bytes) + u.close() + detected = u.result + + """ + + MINIMUM_THRESHOLD = 0.20 + HIGH_BYTE_DETECTOR = re.compile(b'[\x80-\xFF]') + ESC_DETECTOR = re.compile(b'(\033|~{)') + WIN_BYTE_DETECTOR = re.compile(b'[\x80-\x9F]') + ISO_WIN_MAP = {'iso-8859-1': 'Windows-1252', + 'iso-8859-2': 'Windows-1250', + 'iso-8859-5': 'Windows-1251', + 'iso-8859-6': 'Windows-1256', + 'iso-8859-7': 'Windows-1253', + 'iso-8859-8': 'Windows-1255', + 'iso-8859-9': 'Windows-1254', + 'iso-8859-13': 'Windows-1257'} + + def __init__(self, lang_filter=LanguageFilter.ALL): + self._esc_charset_prober = None + self._charset_probers = [] + self.result = None + self.done = None + self._got_data = None + self._input_state = None + self._last_char = None + self.lang_filter = lang_filter + self.logger = logging.getLogger(__name__) + self._has_win_bytes = None + self.reset() + + def reset(self): + """ + Reset the UniversalDetector and all of its probers back to their + initial states. This is called by ``__init__``, so you only need to + call this directly in between analyses of different documents. + """ + self.result = {'encoding': None, 'confidence': 0.0, 'language': None} + self.done = False + self._got_data = False + self._has_win_bytes = False + self._input_state = InputState.PURE_ASCII + self._last_char = b'' + if self._esc_charset_prober: + self._esc_charset_prober.reset() + for prober in self._charset_probers: + prober.reset() + + def feed(self, byte_str): + """ + Takes a chunk of a document and feeds it through all of the relevant + charset probers. + + After calling ``feed``, you can check the value of the ``done`` + attribute to see if you need to continue feeding the + ``UniversalDetector`` more data, or if it has made a prediction + (in the ``result`` attribute). + + .. note:: + You should always call ``close`` when you're done feeding in your + document if ``done`` is not already ``True``. + """ + if self.done: + return + + if not len(byte_str): + return + + if not isinstance(byte_str, bytearray): + byte_str = bytearray(byte_str) + + # First check for known BOMs, since these are guaranteed to be correct + if not self._got_data: + # If the data starts with BOM, we know it is UTF + if byte_str.startswith(codecs.BOM_UTF8): + # EF BB BF UTF-8 with BOM + self.result = {'encoding': "UTF-8-SIG", + 'confidence': 1.0, + 'language': ''} + elif byte_str.startswith((codecs.BOM_UTF32_LE, + codecs.BOM_UTF32_BE)): + # FF FE 00 00 UTF-32, little-endian BOM + # 00 00 FE FF UTF-32, big-endian BOM + self.result = {'encoding': "UTF-32", + 'confidence': 1.0, + 'language': ''} + elif byte_str.startswith(b'\xFE\xFF\x00\x00'): + # FE FF 00 00 UCS-4, unusual octet order BOM (3412) + self.result = {'encoding': "X-ISO-10646-UCS-4-3412", + 'confidence': 1.0, + 'language': ''} + elif byte_str.startswith(b'\x00\x00\xFF\xFE'): + # 00 00 FF FE UCS-4, unusual octet order BOM (2143) + self.result = {'encoding': "X-ISO-10646-UCS-4-2143", + 'confidence': 1.0, + 'language': ''} + elif byte_str.startswith((codecs.BOM_LE, codecs.BOM_BE)): + # FF FE UTF-16, little endian BOM + # FE FF UTF-16, big endian BOM + self.result = {'encoding': "UTF-16", + 'confidence': 1.0, + 'language': ''} + + self._got_data = True + if self.result['encoding'] is not None: + self.done = True + return + + # If none of those matched and we've only see ASCII so far, check + # for high bytes and escape sequences + if self._input_state == InputState.PURE_ASCII: + if self.HIGH_BYTE_DETECTOR.search(byte_str): + self._input_state = InputState.HIGH_BYTE + elif self._input_state == InputState.PURE_ASCII and \ + self.ESC_DETECTOR.search(self._last_char + byte_str): + self._input_state = InputState.ESC_ASCII + + self._last_char = byte_str[-1:] + + # If we've seen escape sequences, use the EscCharSetProber, which + # uses a simple state machine to check for known escape sequences in + # HZ and ISO-2022 encodings, since those are the only encodings that + # use such sequences. + if self._input_state == InputState.ESC_ASCII: + if not self._esc_charset_prober: + self._esc_charset_prober = EscCharSetProber(self.lang_filter) + if self._esc_charset_prober.feed(byte_str) == ProbingState.FOUND_IT: + self.result = {'encoding': + self._esc_charset_prober.charset_name, + 'confidence': + self._esc_charset_prober.get_confidence(), + 'language': + self._esc_charset_prober.language} + self.done = True + # If we've seen high bytes (i.e., those with values greater than 127), + # we need to do more complicated checks using all our multi-byte and + # single-byte probers that are left. The single-byte probers + # use character bigram distributions to determine the encoding, whereas + # the multi-byte probers use a combination of character unigram and + # bigram distributions. + elif self._input_state == InputState.HIGH_BYTE: + if not self._charset_probers: + self._charset_probers = [MBCSGroupProber(self.lang_filter)] + # If we're checking non-CJK encodings, use single-byte prober + if self.lang_filter & LanguageFilter.NON_CJK: + self._charset_probers.append(SBCSGroupProber()) + self._charset_probers.append(Latin1Prober()) + for prober in self._charset_probers: + if prober.feed(byte_str) == ProbingState.FOUND_IT: + self.result = {'encoding': prober.charset_name, + 'confidence': prober.get_confidence(), + 'language': prober.language} + self.done = True + break + if self.WIN_BYTE_DETECTOR.search(byte_str): + self._has_win_bytes = True + + def close(self): + """ + Stop analyzing the current document and come up with a final + prediction. + + :returns: The ``result`` attribute, a ``dict`` with the keys + `encoding`, `confidence`, and `language`. + """ + # Don't bother with checks if we're already done + if self.done: + return self.result + self.done = True + + if not self._got_data: + self.logger.debug('no data received!') + + # Default to ASCII if it is all we've seen so far + elif self._input_state == InputState.PURE_ASCII: + self.result = {'encoding': 'ascii', + 'confidence': 1.0, + 'language': ''} + + # If we have seen non-ASCII, return the best that met MINIMUM_THRESHOLD + elif self._input_state == InputState.HIGH_BYTE: + prober_confidence = None + max_prober_confidence = 0.0 + max_prober = None + for prober in self._charset_probers: + if not prober: + continue + prober_confidence = prober.get_confidence() + if prober_confidence > max_prober_confidence: + max_prober_confidence = prober_confidence + max_prober = prober + if max_prober and (max_prober_confidence > self.MINIMUM_THRESHOLD): + charset_name = max_prober.charset_name + lower_charset_name = max_prober.charset_name.lower() + confidence = max_prober.get_confidence() + # Use Windows encoding name instead of ISO-8859 if we saw any + # extra Windows-specific bytes + if lower_charset_name.startswith('iso-8859'): + if self._has_win_bytes: + charset_name = self.ISO_WIN_MAP.get(lower_charset_name, + charset_name) + self.result = {'encoding': charset_name, + 'confidence': confidence, + 'language': max_prober.language} + + # Log all prober confidences if none met MINIMUM_THRESHOLD + if self.logger.getEffectiveLevel() == logging.DEBUG: + if self.result['encoding'] is None: + self.logger.debug('no probers hit minimum threshold') + for group_prober in self._charset_probers: + if not group_prober: + continue + if isinstance(group_prober, CharSetGroupProber): + for prober in group_prober.probers: + self.logger.debug('%s %s confidence = %s', + prober.charset_name, + prober.language, + prober.get_confidence()) + else: + self.logger.debug('%s %s confidence = %s', + prober.charset_name, + prober.language, + prober.get_confidence()) + return self.result diff --git a/venv/lib/python2.7/site-packages/chardet/utf8prober.py b/venv/lib/python2.7/site-packages/chardet/utf8prober.py new file mode 100644 index 0000000..6c3196c --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/utf8prober.py @@ -0,0 +1,82 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetprober import CharSetProber +from .enums import ProbingState, MachineState +from .codingstatemachine import CodingStateMachine +from .mbcssm import UTF8_SM_MODEL + + + +class UTF8Prober(CharSetProber): + ONE_CHAR_PROB = 0.5 + + def __init__(self): + super(UTF8Prober, self).__init__() + self.coding_sm = CodingStateMachine(UTF8_SM_MODEL) + self._num_mb_chars = None + self.reset() + + def reset(self): + super(UTF8Prober, self).reset() + self.coding_sm.reset() + self._num_mb_chars = 0 + + @property + def charset_name(self): + return "utf-8" + + @property + def language(self): + return "" + + def feed(self, byte_str): + for c in byte_str: + coding_state = self.coding_sm.next_state(c) + if coding_state == MachineState.ERROR: + self._state = ProbingState.NOT_ME + break + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + break + elif coding_state == MachineState.START: + if self.coding_sm.get_current_charlen() >= 2: + self._num_mb_chars += 1 + + if self.state == ProbingState.DETECTING: + if self.get_confidence() > self.SHORTCUT_THRESHOLD: + self._state = ProbingState.FOUND_IT + + return self.state + + def get_confidence(self): + unlike = 0.99 + if self._num_mb_chars < 6: + unlike *= self.ONE_CHAR_PROB ** self._num_mb_chars + return 1.0 - unlike + else: + return unlike diff --git a/venv/lib/python2.7/site-packages/chardet/version.py b/venv/lib/python2.7/site-packages/chardet/version.py new file mode 100644 index 0000000..bb2a34a --- /dev/null +++ b/venv/lib/python2.7/site-packages/chardet/version.py @@ -0,0 +1,9 @@ +""" +This module exists only to simplify retrieving the version number of chardet +from within setup.py and from chardet subpackages. + +:author: Dan Blanchard (dan.blanchard@gmail.com) +""" + +__version__ = "3.0.4" +VERSION = __version__.split('.') diff --git a/venv/lib/python2.7/site-packages/click-6.7.dist-info/DESCRIPTION.rst b/venv/lib/python2.7/site-packages/click-6.7.dist-info/DESCRIPTION.rst new file mode 100644 index 0000000..e118723 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click-6.7.dist-info/DESCRIPTION.rst @@ -0,0 +1,3 @@ +UNKNOWN + + diff --git a/venv/lib/python2.7/site-packages/click-6.7.dist-info/INSTALLER b/venv/lib/python2.7/site-packages/click-6.7.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python2.7/site-packages/click-6.7.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python2.7/site-packages/click-6.7.dist-info/METADATA b/venv/lib/python2.7/site-packages/click-6.7.dist-info/METADATA new file mode 100644 index 0000000..1f10885 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click-6.7.dist-info/METADATA @@ -0,0 +1,16 @@ +Metadata-Version: 2.0 +Name: click +Version: 6.7 +Summary: A simple wrapper around optparse for powerful command line utilities. +Home-page: http://github.com/mitsuhiko/click +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +License: UNKNOWN +Platform: UNKNOWN +Classifier: License :: OSI Approved :: BSD License +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 + +UNKNOWN + + diff --git a/venv/lib/python2.7/site-packages/click-6.7.dist-info/RECORD b/venv/lib/python2.7/site-packages/click-6.7.dist-info/RECORD new file mode 100644 index 0000000..716a5c5 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click-6.7.dist-info/RECORD @@ -0,0 +1,41 @@ +click/__init__.py,sha256=k8R00cFKWI8dhDVKQeLBlAdNh1CxerMEDRiGnr32gdw,2858 +click/_bashcomplete.py,sha256=82rMiibtEurdwBq60NHXVCBuGXJHDpblFO9o2YxJDF0,2423 +click/_compat.py,sha256=j59MpzxYGE-fTGj0A5sg8UI8GhHod1XMojiCA0jvbL0,21011 +click/_termui_impl.py,sha256=Ol1JJhvBRw3l8j1WIU0tOWjQtxxmwGE44lFDbzDqzoA,16395 +click/_textwrap.py,sha256=gwS4m7bdQiJnzaDG8osFcRb-5vn4t4l2qSCy-5csCEc,1198 +click/_unicodefun.py,sha256=A3UOzJw6lEZyol2SBg3fNXgweTutaOzkJ61OB7vik3Y,4204 +click/_winconsole.py,sha256=MzG46DEYPoRyx4SO7EIhFuFZHESgooAfJLIukbB6p5c,7790 +click/core.py,sha256=M0nJ6Kkye7XZXYG7HCbkJWSfy14WHV6bQmGLACrOhKw,70254 +click/decorators.py,sha256=y7CX2needh8iRWafj-QS_hGQFsN24eyXAhx5Y2ATwas,10941 +click/exceptions.py,sha256=rOa0pP3PbSy0_AAPOW9irBEM8AJ3BySN-4z2VUwFVo4,6788 +click/formatting.py,sha256=eh-cypTUAhpI3HD-K4ZpR3vCiURIO62xXvKkR3tNUTM,8889 +click/globals.py,sha256=PAgnKvGxq4YuEIldw3lgYOGBLYwsyxnm1IByBX3BFXo,1515 +click/parser.py,sha256=i01xgYuIA6AwQWEXjshwHSwnTR3gUep4FxJIfyW4ta4,15510 +click/termui.py,sha256=Bp99MSWQtyoWe1_7HggDmA77n--3KLxu7NsZMFMaCUo,21008 +click/testing.py,sha256=kJ9mjtJgwNAlkgKcFf9-ISxufmaPDbbuOHVC9WIvKdY,11002 +click/types.py,sha256=ZGb2lmFs5Vwd9loTRIMbGcqhPVOql8mGoBhWBRT6V4E,18864 +click/utils.py,sha256=1jalPlkUU28JReTEQeeSFtbJd-SirYWBNfjtELBKzT4,14916 +click-6.7.dist-info/DESCRIPTION.rst,sha256=OCTuuN6LcWulhHS3d5rfjdsQtW22n7HENFRh6jC6ego,10 +click-6.7.dist-info/METADATA,sha256=l6lAyogIUXiHKUK_rWguef-EMcvO5C6bXzFCNCcblbQ,424 +click-6.7.dist-info/RECORD,, +click-6.7.dist-info/WHEEL,sha256=5wvfB7GvgZAbKBSE9uX9Zbi6LCL-_KgezgHblXhCRnM,113 +click-6.7.dist-info/metadata.json,sha256=qg0uO6amNHkIkOxnmWX7Xa_DNQMQ62Q6drivuP9Gh1c,571 +click-6.7.dist-info/top_level.txt,sha256=J1ZQogalYS4pphY_lPECoNMfw0HzTSrZglC4Yfwo4xA,6 +click-6.7.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +click/exceptions.pyc,, +click/_unicodefun.pyc,, +click/_termui_impl.pyc,, +click/_compat.pyc,, +click/_textwrap.pyc,, +click/_winconsole.pyc,, +click/decorators.pyc,, +click/_bashcomplete.pyc,, +click/parser.pyc,, +click/testing.pyc,, +click/utils.pyc,, +click/types.pyc,, +click/termui.pyc,, +click/core.pyc,, +click/formatting.pyc,, +click/__init__.pyc,, +click/globals.pyc,, diff --git a/venv/lib/python2.7/site-packages/click-6.7.dist-info/WHEEL b/venv/lib/python2.7/site-packages/click-6.7.dist-info/WHEEL new file mode 100644 index 0000000..7bf9daa --- /dev/null +++ b/venv/lib/python2.7/site-packages/click-6.7.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.30.0.a0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/lib/python2.7/site-packages/click-6.7.dist-info/metadata.json b/venv/lib/python2.7/site-packages/click-6.7.dist-info/metadata.json new file mode 100644 index 0000000..0a4cfb1 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click-6.7.dist-info/metadata.json @@ -0,0 +1 @@ +{"classifiers": ["License :: OSI Approved :: BSD License", "Programming Language :: Python", "Programming Language :: Python :: 3"], "extensions": {"python.details": {"contacts": [{"email": "armin.ronacher@active-4.com", "name": "Armin Ronacher", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "http://github.com/mitsuhiko/click"}}}, "generator": "bdist_wheel (0.30.0.a0)", "metadata_version": "2.0", "name": "click", "summary": "A simple wrapper around optparse for powerful command line utilities.", "version": "6.7"} \ No newline at end of file diff --git a/venv/lib/python2.7/site-packages/click-6.7.dist-info/top_level.txt b/venv/lib/python2.7/site-packages/click-6.7.dist-info/top_level.txt new file mode 100644 index 0000000..dca9a90 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click-6.7.dist-info/top_level.txt @@ -0,0 +1 @@ +click diff --git a/venv/lib/python2.7/site-packages/click/__init__.py b/venv/lib/python2.7/site-packages/click/__init__.py new file mode 100644 index 0000000..971e55d --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/__init__.py @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- +""" + click + ~~~~~ + + Click is a simple Python module that wraps the stdlib's optparse to make + writing command line scripts fun. Unlike other modules, it's based around + a simple API that does not come with too much magic and is composable. + + In case optparse ever gets removed from the stdlib, it will be shipped by + this module. + + :copyright: (c) 2014 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" + +# Core classes +from .core import Context, BaseCommand, Command, MultiCommand, Group, \ + CommandCollection, Parameter, Option, Argument + +# Globals +from .globals import get_current_context + +# Decorators +from .decorators import pass_context, pass_obj, make_pass_decorator, \ + command, group, argument, option, confirmation_option, \ + password_option, version_option, help_option + +# Types +from .types import ParamType, File, Path, Choice, IntRange, Tuple, \ + STRING, INT, FLOAT, BOOL, UUID, UNPROCESSED + +# Utilities +from .utils import echo, get_binary_stream, get_text_stream, open_file, \ + format_filename, get_app_dir, get_os_args + +# Terminal functions +from .termui import prompt, confirm, get_terminal_size, echo_via_pager, \ + progressbar, clear, style, unstyle, secho, edit, launch, getchar, \ + pause + +# Exceptions +from .exceptions import ClickException, UsageError, BadParameter, \ + FileError, Abort, NoSuchOption, BadOptionUsage, BadArgumentUsage, \ + MissingParameter + +# Formatting +from .formatting import HelpFormatter, wrap_text + +# Parsing +from .parser import OptionParser + + +__all__ = [ + # Core classes + 'Context', 'BaseCommand', 'Command', 'MultiCommand', 'Group', + 'CommandCollection', 'Parameter', 'Option', 'Argument', + + # Globals + 'get_current_context', + + # Decorators + 'pass_context', 'pass_obj', 'make_pass_decorator', 'command', 'group', + 'argument', 'option', 'confirmation_option', 'password_option', + 'version_option', 'help_option', + + # Types + 'ParamType', 'File', 'Path', 'Choice', 'IntRange', 'Tuple', 'STRING', + 'INT', 'FLOAT', 'BOOL', 'UUID', 'UNPROCESSED', + + # Utilities + 'echo', 'get_binary_stream', 'get_text_stream', 'open_file', + 'format_filename', 'get_app_dir', 'get_os_args', + + # Terminal functions + 'prompt', 'confirm', 'get_terminal_size', 'echo_via_pager', + 'progressbar', 'clear', 'style', 'unstyle', 'secho', 'edit', 'launch', + 'getchar', 'pause', + + # Exceptions + 'ClickException', 'UsageError', 'BadParameter', 'FileError', + 'Abort', 'NoSuchOption', 'BadOptionUsage', 'BadArgumentUsage', + 'MissingParameter', + + # Formatting + 'HelpFormatter', 'wrap_text', + + # Parsing + 'OptionParser', +] + + +# Controls if click should emit the warning about the use of unicode +# literals. +disable_unicode_literals_warning = False + + +__version__ = '6.7' diff --git a/venv/lib/python2.7/site-packages/click/_bashcomplete.py b/venv/lib/python2.7/site-packages/click/_bashcomplete.py new file mode 100644 index 0000000..d9d26d2 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/_bashcomplete.py @@ -0,0 +1,83 @@ +import os +import re +from .utils import echo +from .parser import split_arg_string +from .core import MultiCommand, Option + + +COMPLETION_SCRIPT = ''' +%(complete_func)s() { + COMPREPLY=( $( env COMP_WORDS="${COMP_WORDS[*]}" \\ + COMP_CWORD=$COMP_CWORD \\ + %(autocomplete_var)s=complete $1 ) ) + return 0 +} + +complete -F %(complete_func)s -o default %(script_names)s +''' + +_invalid_ident_char_re = re.compile(r'[^a-zA-Z0-9_]') + + +def get_completion_script(prog_name, complete_var): + cf_name = _invalid_ident_char_re.sub('', prog_name.replace('-', '_')) + return (COMPLETION_SCRIPT % { + 'complete_func': '_%s_completion' % cf_name, + 'script_names': prog_name, + 'autocomplete_var': complete_var, + }).strip() + ';' + + +def resolve_ctx(cli, prog_name, args): + ctx = cli.make_context(prog_name, args, resilient_parsing=True) + while ctx.protected_args + ctx.args and isinstance(ctx.command, MultiCommand): + a = ctx.protected_args + ctx.args + cmd = ctx.command.get_command(ctx, a[0]) + if cmd is None: + return None + ctx = cmd.make_context(a[0], a[1:], parent=ctx, resilient_parsing=True) + return ctx + + +def get_choices(cli, prog_name, args, incomplete): + ctx = resolve_ctx(cli, prog_name, args) + if ctx is None: + return + + choices = [] + if incomplete and not incomplete[:1].isalnum(): + for param in ctx.command.params: + if not isinstance(param, Option): + continue + choices.extend(param.opts) + choices.extend(param.secondary_opts) + elif isinstance(ctx.command, MultiCommand): + choices.extend(ctx.command.list_commands(ctx)) + + for item in choices: + if item.startswith(incomplete): + yield item + + +def do_complete(cli, prog_name): + cwords = split_arg_string(os.environ['COMP_WORDS']) + cword = int(os.environ['COMP_CWORD']) + args = cwords[1:cword] + try: + incomplete = cwords[cword] + except IndexError: + incomplete = '' + + for item in get_choices(cli, prog_name, args, incomplete): + echo(item) + + return True + + +def bashcomplete(cli, prog_name, complete_var, complete_instr): + if complete_instr == 'source': + echo(get_completion_script(prog_name, complete_var)) + return True + elif complete_instr == 'complete': + return do_complete(cli, prog_name) + return False diff --git a/venv/lib/python2.7/site-packages/click/_compat.py b/venv/lib/python2.7/site-packages/click/_compat.py new file mode 100644 index 0000000..2b43412 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/_compat.py @@ -0,0 +1,648 @@ +import re +import io +import os +import sys +import codecs +from weakref import WeakKeyDictionary + + +PY2 = sys.version_info[0] == 2 +WIN = sys.platform.startswith('win') +DEFAULT_COLUMNS = 80 + + +_ansi_re = re.compile('\033\[((?:\d|;)*)([a-zA-Z])') + + +def get_filesystem_encoding(): + return sys.getfilesystemencoding() or sys.getdefaultencoding() + + +def _make_text_stream(stream, encoding, errors): + if encoding is None: + encoding = get_best_encoding(stream) + if errors is None: + errors = 'replace' + return _NonClosingTextIOWrapper(stream, encoding, errors, + line_buffering=True) + + +def is_ascii_encoding(encoding): + """Checks if a given encoding is ascii.""" + try: + return codecs.lookup(encoding).name == 'ascii' + except LookupError: + return False + + +def get_best_encoding(stream): + """Returns the default stream encoding if not found.""" + rv = getattr(stream, 'encoding', None) or sys.getdefaultencoding() + if is_ascii_encoding(rv): + return 'utf-8' + return rv + + +class _NonClosingTextIOWrapper(io.TextIOWrapper): + + def __init__(self, stream, encoding, errors, **extra): + self._stream = stream = _FixupStream(stream) + io.TextIOWrapper.__init__(self, stream, encoding, errors, **extra) + + # The io module is a place where the Python 3 text behavior + # was forced upon Python 2, so we need to unbreak + # it to look like Python 2. + if PY2: + def write(self, x): + if isinstance(x, str) or is_bytes(x): + try: + self.flush() + except Exception: + pass + return self.buffer.write(str(x)) + return io.TextIOWrapper.write(self, x) + + def writelines(self, lines): + for line in lines: + self.write(line) + + def __del__(self): + try: + self.detach() + except Exception: + pass + + def isatty(self): + # https://bitbucket.org/pypy/pypy/issue/1803 + return self._stream.isatty() + + +class _FixupStream(object): + """The new io interface needs more from streams than streams + traditionally implement. As such, this fix-up code is necessary in + some circumstances. + """ + + def __init__(self, stream): + self._stream = stream + + def __getattr__(self, name): + return getattr(self._stream, name) + + def read1(self, size): + f = getattr(self._stream, 'read1', None) + if f is not None: + return f(size) + # We only dispatch to readline instead of read in Python 2 as we + # do not want cause problems with the different implementation + # of line buffering. + if PY2: + return self._stream.readline(size) + return self._stream.read(size) + + def readable(self): + x = getattr(self._stream, 'readable', None) + if x is not None: + return x() + try: + self._stream.read(0) + except Exception: + return False + return True + + def writable(self): + x = getattr(self._stream, 'writable', None) + if x is not None: + return x() + try: + self._stream.write('') + except Exception: + try: + self._stream.write(b'') + except Exception: + return False + return True + + def seekable(self): + x = getattr(self._stream, 'seekable', None) + if x is not None: + return x() + try: + self._stream.seek(self._stream.tell()) + except Exception: + return False + return True + + +if PY2: + text_type = unicode + bytes = str + raw_input = raw_input + string_types = (str, unicode) + iteritems = lambda x: x.iteritems() + range_type = xrange + + def is_bytes(x): + return isinstance(x, (buffer, bytearray)) + + _identifier_re = re.compile(r'^[a-zA-Z_][a-zA-Z0-9_]*$') + + # For Windows, we need to force stdout/stdin/stderr to binary if it's + # fetched for that. This obviously is not the most correct way to do + # it as it changes global state. Unfortunately, there does not seem to + # be a clear better way to do it as just reopening the file in binary + # mode does not change anything. + # + # An option would be to do what Python 3 does and to open the file as + # binary only, patch it back to the system, and then use a wrapper + # stream that converts newlines. It's not quite clear what's the + # correct option here. + # + # This code also lives in _winconsole for the fallback to the console + # emulation stream. + # + # There are also Windows environments where the `msvcrt` module is not + # available (which is why we use try-catch instead of the WIN variable + # here), such as the Google App Engine development server on Windows. In + # those cases there is just nothing we can do. + try: + import msvcrt + except ImportError: + set_binary_mode = lambda x: x + else: + def set_binary_mode(f): + try: + fileno = f.fileno() + except Exception: + pass + else: + msvcrt.setmode(fileno, os.O_BINARY) + return f + + def isidentifier(x): + return _identifier_re.search(x) is not None + + def get_binary_stdin(): + return set_binary_mode(sys.stdin) + + def get_binary_stdout(): + return set_binary_mode(sys.stdout) + + def get_binary_stderr(): + return set_binary_mode(sys.stderr) + + def get_text_stdin(encoding=None, errors=None): + rv = _get_windows_console_stream(sys.stdin, encoding, errors) + if rv is not None: + return rv + return _make_text_stream(sys.stdin, encoding, errors) + + def get_text_stdout(encoding=None, errors=None): + rv = _get_windows_console_stream(sys.stdout, encoding, errors) + if rv is not None: + return rv + return _make_text_stream(sys.stdout, encoding, errors) + + def get_text_stderr(encoding=None, errors=None): + rv = _get_windows_console_stream(sys.stderr, encoding, errors) + if rv is not None: + return rv + return _make_text_stream(sys.stderr, encoding, errors) + + def filename_to_ui(value): + if isinstance(value, bytes): + value = value.decode(get_filesystem_encoding(), 'replace') + return value +else: + import io + text_type = str + raw_input = input + string_types = (str,) + range_type = range + isidentifier = lambda x: x.isidentifier() + iteritems = lambda x: iter(x.items()) + + def is_bytes(x): + return isinstance(x, (bytes, memoryview, bytearray)) + + def _is_binary_reader(stream, default=False): + try: + return isinstance(stream.read(0), bytes) + except Exception: + return default + # This happens in some cases where the stream was already + # closed. In this case, we assume the default. + + def _is_binary_writer(stream, default=False): + try: + stream.write(b'') + except Exception: + try: + stream.write('') + return False + except Exception: + pass + return default + return True + + def _find_binary_reader(stream): + # We need to figure out if the given stream is already binary. + # This can happen because the official docs recommend detaching + # the streams to get binary streams. Some code might do this, so + # we need to deal with this case explicitly. + if _is_binary_reader(stream, False): + return stream + + buf = getattr(stream, 'buffer', None) + + # Same situation here; this time we assume that the buffer is + # actually binary in case it's closed. + if buf is not None and _is_binary_reader(buf, True): + return buf + + def _find_binary_writer(stream): + # We need to figure out if the given stream is already binary. + # This can happen because the official docs recommend detatching + # the streams to get binary streams. Some code might do this, so + # we need to deal with this case explicitly. + if _is_binary_writer(stream, False): + return stream + + buf = getattr(stream, 'buffer', None) + + # Same situation here; this time we assume that the buffer is + # actually binary in case it's closed. + if buf is not None and _is_binary_writer(buf, True): + return buf + + def _stream_is_misconfigured(stream): + """A stream is misconfigured if its encoding is ASCII.""" + # If the stream does not have an encoding set, we assume it's set + # to ASCII. This appears to happen in certain unittest + # environments. It's not quite clear what the correct behavior is + # but this at least will force Click to recover somehow. + return is_ascii_encoding(getattr(stream, 'encoding', None) or 'ascii') + + def _is_compatible_text_stream(stream, encoding, errors): + stream_encoding = getattr(stream, 'encoding', None) + stream_errors = getattr(stream, 'errors', None) + + # Perfect match. + if stream_encoding == encoding and stream_errors == errors: + return True + + # Otherwise, it's only a compatible stream if we did not ask for + # an encoding. + if encoding is None: + return stream_encoding is not None + + return False + + def _force_correct_text_reader(text_reader, encoding, errors): + if _is_binary_reader(text_reader, False): + binary_reader = text_reader + else: + # If there is no target encoding set, we need to verify that the + # reader is not actually misconfigured. + if encoding is None and not _stream_is_misconfigured(text_reader): + return text_reader + + if _is_compatible_text_stream(text_reader, encoding, errors): + return text_reader + + # If the reader has no encoding, we try to find the underlying + # binary reader for it. If that fails because the environment is + # misconfigured, we silently go with the same reader because this + # is too common to happen. In that case, mojibake is better than + # exceptions. + binary_reader = _find_binary_reader(text_reader) + if binary_reader is None: + return text_reader + + # At this point, we default the errors to replace instead of strict + # because nobody handles those errors anyways and at this point + # we're so fundamentally fucked that nothing can repair it. + if errors is None: + errors = 'replace' + return _make_text_stream(binary_reader, encoding, errors) + + def _force_correct_text_writer(text_writer, encoding, errors): + if _is_binary_writer(text_writer, False): + binary_writer = text_writer + else: + # If there is no target encoding set, we need to verify that the + # writer is not actually misconfigured. + if encoding is None and not _stream_is_misconfigured(text_writer): + return text_writer + + if _is_compatible_text_stream(text_writer, encoding, errors): + return text_writer + + # If the writer has no encoding, we try to find the underlying + # binary writer for it. If that fails because the environment is + # misconfigured, we silently go with the same writer because this + # is too common to happen. In that case, mojibake is better than + # exceptions. + binary_writer = _find_binary_writer(text_writer) + if binary_writer is None: + return text_writer + + # At this point, we default the errors to replace instead of strict + # because nobody handles those errors anyways and at this point + # we're so fundamentally fucked that nothing can repair it. + if errors is None: + errors = 'replace' + return _make_text_stream(binary_writer, encoding, errors) + + def get_binary_stdin(): + reader = _find_binary_reader(sys.stdin) + if reader is None: + raise RuntimeError('Was not able to determine binary ' + 'stream for sys.stdin.') + return reader + + def get_binary_stdout(): + writer = _find_binary_writer(sys.stdout) + if writer is None: + raise RuntimeError('Was not able to determine binary ' + 'stream for sys.stdout.') + return writer + + def get_binary_stderr(): + writer = _find_binary_writer(sys.stderr) + if writer is None: + raise RuntimeError('Was not able to determine binary ' + 'stream for sys.stderr.') + return writer + + def get_text_stdin(encoding=None, errors=None): + rv = _get_windows_console_stream(sys.stdin, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_reader(sys.stdin, encoding, errors) + + def get_text_stdout(encoding=None, errors=None): + rv = _get_windows_console_stream(sys.stdout, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_writer(sys.stdout, encoding, errors) + + def get_text_stderr(encoding=None, errors=None): + rv = _get_windows_console_stream(sys.stderr, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_writer(sys.stderr, encoding, errors) + + def filename_to_ui(value): + if isinstance(value, bytes): + value = value.decode(get_filesystem_encoding(), 'replace') + else: + value = value.encode('utf-8', 'surrogateescape') \ + .decode('utf-8', 'replace') + return value + + +def get_streerror(e, default=None): + if hasattr(e, 'strerror'): + msg = e.strerror + else: + if default is not None: + msg = default + else: + msg = str(e) + if isinstance(msg, bytes): + msg = msg.decode('utf-8', 'replace') + return msg + + +def open_stream(filename, mode='r', encoding=None, errors='strict', + atomic=False): + # Standard streams first. These are simple because they don't need + # special handling for the atomic flag. It's entirely ignored. + if filename == '-': + if 'w' in mode: + if 'b' in mode: + return get_binary_stdout(), False + return get_text_stdout(encoding=encoding, errors=errors), False + if 'b' in mode: + return get_binary_stdin(), False + return get_text_stdin(encoding=encoding, errors=errors), False + + # Non-atomic writes directly go out through the regular open functions. + if not atomic: + if encoding is None: + return open(filename, mode), True + return io.open(filename, mode, encoding=encoding, errors=errors), True + + # Some usability stuff for atomic writes + if 'a' in mode: + raise ValueError( + 'Appending to an existing file is not supported, because that ' + 'would involve an expensive `copy`-operation to a temporary ' + 'file. Open the file in normal `w`-mode and copy explicitly ' + 'if that\'s what you\'re after.' + ) + if 'x' in mode: + raise ValueError('Use the `overwrite`-parameter instead.') + if 'w' not in mode: + raise ValueError('Atomic writes only make sense with `w`-mode.') + + # Atomic writes are more complicated. They work by opening a file + # as a proxy in the same folder and then using the fdopen + # functionality to wrap it in a Python file. Then we wrap it in an + # atomic file that moves the file over on close. + import tempfile + fd, tmp_filename = tempfile.mkstemp(dir=os.path.dirname(filename), + prefix='.__atomic-write') + + if encoding is not None: + f = io.open(fd, mode, encoding=encoding, errors=errors) + else: + f = os.fdopen(fd, mode) + + return _AtomicFile(f, tmp_filename, filename), True + + +# Used in a destructor call, needs extra protection from interpreter cleanup. +if hasattr(os, 'replace'): + _replace = os.replace + _can_replace = True +else: + _replace = os.rename + _can_replace = not WIN + + +class _AtomicFile(object): + + def __init__(self, f, tmp_filename, real_filename): + self._f = f + self._tmp_filename = tmp_filename + self._real_filename = real_filename + self.closed = False + + @property + def name(self): + return self._real_filename + + def close(self, delete=False): + if self.closed: + return + self._f.close() + if not _can_replace: + try: + os.remove(self._real_filename) + except OSError: + pass + _replace(self._tmp_filename, self._real_filename) + self.closed = True + + def __getattr__(self, name): + return getattr(self._f, name) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, tb): + self.close(delete=exc_type is not None) + + def __repr__(self): + return repr(self._f) + + +auto_wrap_for_ansi = None +colorama = None +get_winterm_size = None + + +def strip_ansi(value): + return _ansi_re.sub('', value) + + +def should_strip_ansi(stream=None, color=None): + if color is None: + if stream is None: + stream = sys.stdin + return not isatty(stream) + return not color + + +# If we're on Windows, we provide transparent integration through +# colorama. This will make ANSI colors through the echo function +# work automatically. +if WIN: + # Windows has a smaller terminal + DEFAULT_COLUMNS = 79 + + from ._winconsole import _get_windows_console_stream + + def _get_argv_encoding(): + import locale + return locale.getpreferredencoding() + + if PY2: + def raw_input(prompt=''): + sys.stderr.flush() + if prompt: + stdout = _default_text_stdout() + stdout.write(prompt) + stdin = _default_text_stdin() + return stdin.readline().rstrip('\r\n') + + try: + import colorama + except ImportError: + pass + else: + _ansi_stream_wrappers = WeakKeyDictionary() + + def auto_wrap_for_ansi(stream, color=None): + """This function wraps a stream so that calls through colorama + are issued to the win32 console API to recolor on demand. It + also ensures to reset the colors if a write call is interrupted + to not destroy the console afterwards. + """ + try: + cached = _ansi_stream_wrappers.get(stream) + except Exception: + cached = None + if cached is not None: + return cached + strip = should_strip_ansi(stream, color) + ansi_wrapper = colorama.AnsiToWin32(stream, strip=strip) + rv = ansi_wrapper.stream + _write = rv.write + + def _safe_write(s): + try: + return _write(s) + except: + ansi_wrapper.reset_all() + raise + + rv.write = _safe_write + try: + _ansi_stream_wrappers[stream] = rv + except Exception: + pass + return rv + + def get_winterm_size(): + win = colorama.win32.GetConsoleScreenBufferInfo( + colorama.win32.STDOUT).srWindow + return win.Right - win.Left, win.Bottom - win.Top +else: + def _get_argv_encoding(): + return getattr(sys.stdin, 'encoding', None) or get_filesystem_encoding() + + _get_windows_console_stream = lambda *x: None + + +def term_len(x): + return len(strip_ansi(x)) + + +def isatty(stream): + try: + return stream.isatty() + except Exception: + return False + + +def _make_cached_stream_func(src_func, wrapper_func): + cache = WeakKeyDictionary() + def func(): + stream = src_func() + try: + rv = cache.get(stream) + except Exception: + rv = None + if rv is not None: + return rv + rv = wrapper_func() + try: + cache[stream] = rv + except Exception: + pass + return rv + return func + + +_default_text_stdin = _make_cached_stream_func( + lambda: sys.stdin, get_text_stdin) +_default_text_stdout = _make_cached_stream_func( + lambda: sys.stdout, get_text_stdout) +_default_text_stderr = _make_cached_stream_func( + lambda: sys.stderr, get_text_stderr) + + +binary_streams = { + 'stdin': get_binary_stdin, + 'stdout': get_binary_stdout, + 'stderr': get_binary_stderr, +} + +text_streams = { + 'stdin': get_text_stdin, + 'stdout': get_text_stdout, + 'stderr': get_text_stderr, +} diff --git a/venv/lib/python2.7/site-packages/click/_termui_impl.py b/venv/lib/python2.7/site-packages/click/_termui_impl.py new file mode 100644 index 0000000..7cfd3d5 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/_termui_impl.py @@ -0,0 +1,547 @@ +""" + click._termui_impl + ~~~~~~~~~~~~~~~~~~ + + This module contains implementations for the termui module. To keep the + import time of Click down, some infrequently used functionality is placed + in this module and only imported as needed. + + :copyright: (c) 2014 by Armin Ronacher. + :license: BSD, see LICENSE for more details. +""" +import os +import sys +import time +import math +from ._compat import _default_text_stdout, range_type, PY2, isatty, \ + open_stream, strip_ansi, term_len, get_best_encoding, WIN +from .utils import echo +from .exceptions import ClickException + + +if os.name == 'nt': + BEFORE_BAR = '\r' + AFTER_BAR = '\n' +else: + BEFORE_BAR = '\r\033[?25l' + AFTER_BAR = '\033[?25h\n' + + +def _length_hint(obj): + """Returns the length hint of an object.""" + try: + return len(obj) + except (AttributeError, TypeError): + try: + get_hint = type(obj).__length_hint__ + except AttributeError: + return None + try: + hint = get_hint(obj) + except TypeError: + return None + if hint is NotImplemented or \ + not isinstance(hint, (int, long)) or \ + hint < 0: + return None + return hint + + +class ProgressBar(object): + + def __init__(self, iterable, length=None, fill_char='#', empty_char=' ', + bar_template='%(bar)s', info_sep=' ', show_eta=True, + show_percent=None, show_pos=False, item_show_func=None, + label=None, file=None, color=None, width=30): + self.fill_char = fill_char + self.empty_char = empty_char + self.bar_template = bar_template + self.info_sep = info_sep + self.show_eta = show_eta + self.show_percent = show_percent + self.show_pos = show_pos + self.item_show_func = item_show_func + self.label = label or '' + if file is None: + file = _default_text_stdout() + self.file = file + self.color = color + self.width = width + self.autowidth = width == 0 + + if length is None: + length = _length_hint(iterable) + if iterable is None: + if length is None: + raise TypeError('iterable or length is required') + iterable = range_type(length) + self.iter = iter(iterable) + self.length = length + self.length_known = length is not None + self.pos = 0 + self.avg = [] + self.start = self.last_eta = time.time() + self.eta_known = False + self.finished = False + self.max_width = None + self.entered = False + self.current_item = None + self.is_hidden = not isatty(self.file) + self._last_line = None + + def __enter__(self): + self.entered = True + self.render_progress() + return self + + def __exit__(self, exc_type, exc_value, tb): + self.render_finish() + + def __iter__(self): + if not self.entered: + raise RuntimeError('You need to use progress bars in a with block.') + self.render_progress() + return self + + def render_finish(self): + if self.is_hidden: + return + self.file.write(AFTER_BAR) + self.file.flush() + + @property + def pct(self): + if self.finished: + return 1.0 + return min(self.pos / (float(self.length) or 1), 1.0) + + @property + def time_per_iteration(self): + if not self.avg: + return 0.0 + return sum(self.avg) / float(len(self.avg)) + + @property + def eta(self): + if self.length_known and not self.finished: + return self.time_per_iteration * (self.length - self.pos) + return 0.0 + + def format_eta(self): + if self.eta_known: + t = self.eta + 1 + seconds = t % 60 + t /= 60 + minutes = t % 60 + t /= 60 + hours = t % 24 + t /= 24 + if t > 0: + days = t + return '%dd %02d:%02d:%02d' % (days, hours, minutes, seconds) + else: + return '%02d:%02d:%02d' % (hours, minutes, seconds) + return '' + + def format_pos(self): + pos = str(self.pos) + if self.length_known: + pos += '/%s' % self.length + return pos + + def format_pct(self): + return ('% 4d%%' % int(self.pct * 100))[1:] + + def format_progress_line(self): + show_percent = self.show_percent + + info_bits = [] + if self.length_known: + bar_length = int(self.pct * self.width) + bar = self.fill_char * bar_length + bar += self.empty_char * (self.width - bar_length) + if show_percent is None: + show_percent = not self.show_pos + else: + if self.finished: + bar = self.fill_char * self.width + else: + bar = list(self.empty_char * (self.width or 1)) + if self.time_per_iteration != 0: + bar[int((math.cos(self.pos * self.time_per_iteration) + / 2.0 + 0.5) * self.width)] = self.fill_char + bar = ''.join(bar) + + if self.show_pos: + info_bits.append(self.format_pos()) + if show_percent: + info_bits.append(self.format_pct()) + if self.show_eta and self.eta_known and not self.finished: + info_bits.append(self.format_eta()) + if self.item_show_func is not None: + item_info = self.item_show_func(self.current_item) + if item_info is not None: + info_bits.append(item_info) + + return (self.bar_template % { + 'label': self.label, + 'bar': bar, + 'info': self.info_sep.join(info_bits) + }).rstrip() + + def render_progress(self): + from .termui import get_terminal_size + nl = False + + if self.is_hidden: + buf = [self.label] + nl = True + else: + buf = [] + # Update width in case the terminal has been resized + if self.autowidth: + old_width = self.width + self.width = 0 + clutter_length = term_len(self.format_progress_line()) + new_width = max(0, get_terminal_size()[0] - clutter_length) + if new_width < old_width: + buf.append(BEFORE_BAR) + buf.append(' ' * self.max_width) + self.max_width = new_width + self.width = new_width + + clear_width = self.width + if self.max_width is not None: + clear_width = self.max_width + + buf.append(BEFORE_BAR) + line = self.format_progress_line() + line_len = term_len(line) + if self.max_width is None or self.max_width < line_len: + self.max_width = line_len + buf.append(line) + + buf.append(' ' * (clear_width - line_len)) + line = ''.join(buf) + + # Render the line only if it changed. + if line != self._last_line: + self._last_line = line + echo(line, file=self.file, color=self.color, nl=nl) + self.file.flush() + + def make_step(self, n_steps): + self.pos += n_steps + if self.length_known and self.pos >= self.length: + self.finished = True + + if (time.time() - self.last_eta) < 1.0: + return + + self.last_eta = time.time() + self.avg = self.avg[-6:] + [-(self.start - time.time()) / (self.pos)] + + self.eta_known = self.length_known + + def update(self, n_steps): + self.make_step(n_steps) + self.render_progress() + + def finish(self): + self.eta_known = 0 + self.current_item = None + self.finished = True + + def next(self): + if self.is_hidden: + return next(self.iter) + try: + rv = next(self.iter) + self.current_item = rv + except StopIteration: + self.finish() + self.render_progress() + raise StopIteration() + else: + self.update(1) + return rv + + if not PY2: + __next__ = next + del next + + +def pager(text, color=None): + """Decide what method to use for paging through text.""" + stdout = _default_text_stdout() + if not isatty(sys.stdin) or not isatty(stdout): + return _nullpager(stdout, text, color) + pager_cmd = (os.environ.get('PAGER', None) or '').strip() + if pager_cmd: + if WIN: + return _tempfilepager(text, pager_cmd, color) + return _pipepager(text, pager_cmd, color) + if os.environ.get('TERM') in ('dumb', 'emacs'): + return _nullpager(stdout, text, color) + if WIN or sys.platform.startswith('os2'): + return _tempfilepager(text, 'more <', color) + if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0: + return _pipepager(text, 'less', color) + + import tempfile + fd, filename = tempfile.mkstemp() + os.close(fd) + try: + if hasattr(os, 'system') and os.system('more "%s"' % filename) == 0: + return _pipepager(text, 'more', color) + return _nullpager(stdout, text, color) + finally: + os.unlink(filename) + + +def _pipepager(text, cmd, color): + """Page through text by feeding it to another program. Invoking a + pager through this might support colors. + """ + import subprocess + env = dict(os.environ) + + # If we're piping to less we might support colors under the + # condition that + cmd_detail = cmd.rsplit('/', 1)[-1].split() + if color is None and cmd_detail[0] == 'less': + less_flags = os.environ.get('LESS', '') + ' '.join(cmd_detail[1:]) + if not less_flags: + env['LESS'] = '-R' + color = True + elif 'r' in less_flags or 'R' in less_flags: + color = True + + if not color: + text = strip_ansi(text) + + c = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, + env=env) + encoding = get_best_encoding(c.stdin) + try: + c.stdin.write(text.encode(encoding, 'replace')) + c.stdin.close() + except (IOError, KeyboardInterrupt): + pass + + # Less doesn't respect ^C, but catches it for its own UI purposes (aborting + # search or other commands inside less). + # + # That means when the user hits ^C, the parent process (click) terminates, + # but less is still alive, paging the output and messing up the terminal. + # + # If the user wants to make the pager exit on ^C, they should set + # `LESS='-K'`. It's not our decision to make. + while True: + try: + c.wait() + except KeyboardInterrupt: + pass + else: + break + + +def _tempfilepager(text, cmd, color): + """Page through text by invoking a program on a temporary file.""" + import tempfile + filename = tempfile.mktemp() + if not color: + text = strip_ansi(text) + encoding = get_best_encoding(sys.stdout) + with open_stream(filename, 'wb')[0] as f: + f.write(text.encode(encoding)) + try: + os.system(cmd + ' "' + filename + '"') + finally: + os.unlink(filename) + + +def _nullpager(stream, text, color): + """Simply print unformatted text. This is the ultimate fallback.""" + if not color: + text = strip_ansi(text) + stream.write(text) + + +class Editor(object): + + def __init__(self, editor=None, env=None, require_save=True, + extension='.txt'): + self.editor = editor + self.env = env + self.require_save = require_save + self.extension = extension + + def get_editor(self): + if self.editor is not None: + return self.editor + for key in 'VISUAL', 'EDITOR': + rv = os.environ.get(key) + if rv: + return rv + if WIN: + return 'notepad' + for editor in 'vim', 'nano': + if os.system('which %s >/dev/null 2>&1' % editor) == 0: + return editor + return 'vi' + + def edit_file(self, filename): + import subprocess + editor = self.get_editor() + if self.env: + environ = os.environ.copy() + environ.update(self.env) + else: + environ = None + try: + c = subprocess.Popen('%s "%s"' % (editor, filename), + env=environ, shell=True) + exit_code = c.wait() + if exit_code != 0: + raise ClickException('%s: Editing failed!' % editor) + except OSError as e: + raise ClickException('%s: Editing failed: %s' % (editor, e)) + + def edit(self, text): + import tempfile + + text = text or '' + if text and not text.endswith('\n'): + text += '\n' + + fd, name = tempfile.mkstemp(prefix='editor-', suffix=self.extension) + try: + if WIN: + encoding = 'utf-8-sig' + text = text.replace('\n', '\r\n') + else: + encoding = 'utf-8' + text = text.encode(encoding) + + f = os.fdopen(fd, 'wb') + f.write(text) + f.close() + timestamp = os.path.getmtime(name) + + self.edit_file(name) + + if self.require_save \ + and os.path.getmtime(name) == timestamp: + return None + + f = open(name, 'rb') + try: + rv = f.read() + finally: + f.close() + return rv.decode('utf-8-sig').replace('\r\n', '\n') + finally: + os.unlink(name) + + +def open_url(url, wait=False, locate=False): + import subprocess + + def _unquote_file(url): + try: + import urllib + except ImportError: + import urllib + if url.startswith('file://'): + url = urllib.unquote(url[7:]) + return url + + if sys.platform == 'darwin': + args = ['open'] + if wait: + args.append('-W') + if locate: + args.append('-R') + args.append(_unquote_file(url)) + null = open('/dev/null', 'w') + try: + return subprocess.Popen(args, stderr=null).wait() + finally: + null.close() + elif WIN: + if locate: + url = _unquote_file(url) + args = 'explorer /select,"%s"' % _unquote_file( + url.replace('"', '')) + else: + args = 'start %s "" "%s"' % ( + wait and '/WAIT' or '', url.replace('"', '')) + return os.system(args) + + try: + if locate: + url = os.path.dirname(_unquote_file(url)) or '.' + else: + url = _unquote_file(url) + c = subprocess.Popen(['xdg-open', url]) + if wait: + return c.wait() + return 0 + except OSError: + if url.startswith(('http://', 'https://')) and not locate and not wait: + import webbrowser + webbrowser.open(url) + return 0 + return 1 + + +def _translate_ch_to_exc(ch): + if ch == '\x03': + raise KeyboardInterrupt() + if ch == '\x04': + raise EOFError() + + +if WIN: + import msvcrt + + def getchar(echo): + rv = msvcrt.getch() + if echo: + msvcrt.putchar(rv) + _translate_ch_to_exc(rv) + if PY2: + enc = getattr(sys.stdin, 'encoding', None) + if enc is not None: + rv = rv.decode(enc, 'replace') + else: + rv = rv.decode('cp1252', 'replace') + return rv +else: + import tty + import termios + + def getchar(echo): + if not isatty(sys.stdin): + f = open('/dev/tty') + fd = f.fileno() + else: + fd = sys.stdin.fileno() + f = None + try: + old_settings = termios.tcgetattr(fd) + try: + tty.setraw(fd) + ch = os.read(fd, 32) + if echo and isatty(sys.stdout): + sys.stdout.write(ch) + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + sys.stdout.flush() + if f is not None: + f.close() + except termios.error: + pass + _translate_ch_to_exc(ch) + return ch.decode(get_best_encoding(sys.stdin), 'replace') diff --git a/venv/lib/python2.7/site-packages/click/_textwrap.py b/venv/lib/python2.7/site-packages/click/_textwrap.py new file mode 100644 index 0000000..7e77603 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/_textwrap.py @@ -0,0 +1,38 @@ +import textwrap +from contextlib import contextmanager + + +class TextWrapper(textwrap.TextWrapper): + + def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width): + space_left = max(width - cur_len, 1) + + if self.break_long_words: + last = reversed_chunks[-1] + cut = last[:space_left] + res = last[space_left:] + cur_line.append(cut) + reversed_chunks[-1] = res + elif not cur_line: + cur_line.append(reversed_chunks.pop()) + + @contextmanager + def extra_indent(self, indent): + old_initial_indent = self.initial_indent + old_subsequent_indent = self.subsequent_indent + self.initial_indent += indent + self.subsequent_indent += indent + try: + yield + finally: + self.initial_indent = old_initial_indent + self.subsequent_indent = old_subsequent_indent + + def indent_only(self, text): + rv = [] + for idx, line in enumerate(text.splitlines()): + indent = self.initial_indent + if idx > 0: + indent = self.subsequent_indent + rv.append(indent + line) + return '\n'.join(rv) diff --git a/venv/lib/python2.7/site-packages/click/_unicodefun.py b/venv/lib/python2.7/site-packages/click/_unicodefun.py new file mode 100644 index 0000000..9e17a38 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/_unicodefun.py @@ -0,0 +1,118 @@ +import os +import sys +import codecs + +from ._compat import PY2 + + +# If someone wants to vendor click, we want to ensure the +# correct package is discovered. Ideally we could use a +# relative import here but unfortunately Python does not +# support that. +click = sys.modules[__name__.rsplit('.', 1)[0]] + + +def _find_unicode_literals_frame(): + import __future__ + frm = sys._getframe(1) + idx = 1 + while frm is not None: + if frm.f_globals.get('__name__', '').startswith('click.'): + frm = frm.f_back + idx += 1 + elif frm.f_code.co_flags & __future__.unicode_literals.compiler_flag: + return idx + else: + break + return 0 + + +def _check_for_unicode_literals(): + if not __debug__: + return + if not PY2 or click.disable_unicode_literals_warning: + return + bad_frame = _find_unicode_literals_frame() + if bad_frame <= 0: + return + from warnings import warn + warn(Warning('Click detected the use of the unicode_literals ' + '__future__ import. This is heavily discouraged ' + 'because it can introduce subtle bugs in your ' + 'code. You should instead use explicit u"" literals ' + 'for your unicode strings. For more information see ' + 'http://click.pocoo.org/python3/'), + stacklevel=bad_frame) + + +def _verify_python3_env(): + """Ensures that the environment is good for unicode on Python 3.""" + if PY2: + return + try: + import locale + fs_enc = codecs.lookup(locale.getpreferredencoding()).name + except Exception: + fs_enc = 'ascii' + if fs_enc != 'ascii': + return + + extra = '' + if os.name == 'posix': + import subprocess + rv = subprocess.Popen(['locale', '-a'], stdout=subprocess.PIPE, + stderr=subprocess.PIPE).communicate()[0] + good_locales = set() + has_c_utf8 = False + + # Make sure we're operating on text here. + if isinstance(rv, bytes): + rv = rv.decode('ascii', 'replace') + + for line in rv.splitlines(): + locale = line.strip() + if locale.lower().endswith(('.utf-8', '.utf8')): + good_locales.add(locale) + if locale.lower() in ('c.utf8', 'c.utf-8'): + has_c_utf8 = True + + extra += '\n\n' + if not good_locales: + extra += ( + 'Additional information: on this system no suitable UTF-8\n' + 'locales were discovered. This most likely requires resolving\n' + 'by reconfiguring the locale system.' + ) + elif has_c_utf8: + extra += ( + 'This system supports the C.UTF-8 locale which is recommended.\n' + 'You might be able to resolve your issue by exporting the\n' + 'following environment variables:\n\n' + ' export LC_ALL=C.UTF-8\n' + ' export LANG=C.UTF-8' + ) + else: + extra += ( + 'This system lists a couple of UTF-8 supporting locales that\n' + 'you can pick from. The following suitable locales where\n' + 'discovered: %s' + ) % ', '.join(sorted(good_locales)) + + bad_locale = None + for locale in os.environ.get('LC_ALL'), os.environ.get('LANG'): + if locale and locale.lower().endswith(('.utf-8', '.utf8')): + bad_locale = locale + if locale is not None: + break + if bad_locale is not None: + extra += ( + '\n\nClick discovered that you exported a UTF-8 locale\n' + 'but the locale system could not pick up from it because\n' + 'it does not exist. The exported locale is "%s" but it\n' + 'is not supported' + ) % bad_locale + + raise RuntimeError('Click will abort further execution because Python 3 ' + 'was configured to use ASCII as encoding for the ' + 'environment. Consult http://click.pocoo.org/python3/' + 'for mitigation steps.' + extra) diff --git a/venv/lib/python2.7/site-packages/click/_winconsole.py b/venv/lib/python2.7/site-packages/click/_winconsole.py new file mode 100644 index 0000000..9aed942 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/_winconsole.py @@ -0,0 +1,273 @@ +# -*- coding: utf-8 -*- +# This module is based on the excellent work by Adam Bartoš who +# provided a lot of what went into the implementation here in +# the discussion to issue1602 in the Python bug tracker. +# +# There are some general differences in regards to how this works +# compared to the original patches as we do not need to patch +# the entire interpreter but just work in our little world of +# echo and prmopt. + +import io +import os +import sys +import zlib +import time +import ctypes +import msvcrt +from click._compat import _NonClosingTextIOWrapper, text_type, PY2 +from ctypes import byref, POINTER, c_int, c_char, c_char_p, \ + c_void_p, py_object, c_ssize_t, c_ulong, windll, WINFUNCTYPE +try: + from ctypes import pythonapi + PyObject_GetBuffer = pythonapi.PyObject_GetBuffer + PyBuffer_Release = pythonapi.PyBuffer_Release +except ImportError: + pythonapi = None +from ctypes.wintypes import LPWSTR, LPCWSTR + + +c_ssize_p = POINTER(c_ssize_t) + +kernel32 = windll.kernel32 +GetStdHandle = kernel32.GetStdHandle +ReadConsoleW = kernel32.ReadConsoleW +WriteConsoleW = kernel32.WriteConsoleW +GetLastError = kernel32.GetLastError +GetCommandLineW = WINFUNCTYPE(LPWSTR)( + ('GetCommandLineW', windll.kernel32)) +CommandLineToArgvW = WINFUNCTYPE( + POINTER(LPWSTR), LPCWSTR, POINTER(c_int))( + ('CommandLineToArgvW', windll.shell32)) + + +STDIN_HANDLE = GetStdHandle(-10) +STDOUT_HANDLE = GetStdHandle(-11) +STDERR_HANDLE = GetStdHandle(-12) + + +PyBUF_SIMPLE = 0 +PyBUF_WRITABLE = 1 + +ERROR_SUCCESS = 0 +ERROR_NOT_ENOUGH_MEMORY = 8 +ERROR_OPERATION_ABORTED = 995 + +STDIN_FILENO = 0 +STDOUT_FILENO = 1 +STDERR_FILENO = 2 + +EOF = b'\x1a' +MAX_BYTES_WRITTEN = 32767 + + +class Py_buffer(ctypes.Structure): + _fields_ = [ + ('buf', c_void_p), + ('obj', py_object), + ('len', c_ssize_t), + ('itemsize', c_ssize_t), + ('readonly', c_int), + ('ndim', c_int), + ('format', c_char_p), + ('shape', c_ssize_p), + ('strides', c_ssize_p), + ('suboffsets', c_ssize_p), + ('internal', c_void_p) + ] + + if PY2: + _fields_.insert(-1, ('smalltable', c_ssize_t * 2)) + + +# On PyPy we cannot get buffers so our ability to operate here is +# serverly limited. +if pythonapi is None: + get_buffer = None +else: + def get_buffer(obj, writable=False): + buf = Py_buffer() + flags = PyBUF_WRITABLE if writable else PyBUF_SIMPLE + PyObject_GetBuffer(py_object(obj), byref(buf), flags) + try: + buffer_type = c_char * buf.len + return buffer_type.from_address(buf.buf) + finally: + PyBuffer_Release(byref(buf)) + + +class _WindowsConsoleRawIOBase(io.RawIOBase): + + def __init__(self, handle): + self.handle = handle + + def isatty(self): + io.RawIOBase.isatty(self) + return True + + +class _WindowsConsoleReader(_WindowsConsoleRawIOBase): + + def readable(self): + return True + + def readinto(self, b): + bytes_to_be_read = len(b) + if not bytes_to_be_read: + return 0 + elif bytes_to_be_read % 2: + raise ValueError('cannot read odd number of bytes from ' + 'UTF-16-LE encoded console') + + buffer = get_buffer(b, writable=True) + code_units_to_be_read = bytes_to_be_read // 2 + code_units_read = c_ulong() + + rv = ReadConsoleW(self.handle, buffer, code_units_to_be_read, + byref(code_units_read), None) + if GetLastError() == ERROR_OPERATION_ABORTED: + # wait for KeyboardInterrupt + time.sleep(0.1) + if not rv: + raise OSError('Windows error: %s' % GetLastError()) + + if buffer[0] == EOF: + return 0 + return 2 * code_units_read.value + + +class _WindowsConsoleWriter(_WindowsConsoleRawIOBase): + + def writable(self): + return True + + @staticmethod + def _get_error_message(errno): + if errno == ERROR_SUCCESS: + return 'ERROR_SUCCESS' + elif errno == ERROR_NOT_ENOUGH_MEMORY: + return 'ERROR_NOT_ENOUGH_MEMORY' + return 'Windows error %s' % errno + + def write(self, b): + bytes_to_be_written = len(b) + buf = get_buffer(b) + code_units_to_be_written = min(bytes_to_be_written, + MAX_BYTES_WRITTEN) // 2 + code_units_written = c_ulong() + + WriteConsoleW(self.handle, buf, code_units_to_be_written, + byref(code_units_written), None) + bytes_written = 2 * code_units_written.value + + if bytes_written == 0 and bytes_to_be_written > 0: + raise OSError(self._get_error_message(GetLastError())) + return bytes_written + + +class ConsoleStream(object): + + def __init__(self, text_stream, byte_stream): + self._text_stream = text_stream + self.buffer = byte_stream + + @property + def name(self): + return self.buffer.name + + def write(self, x): + if isinstance(x, text_type): + return self._text_stream.write(x) + try: + self.flush() + except Exception: + pass + return self.buffer.write(x) + + def writelines(self, lines): + for line in lines: + self.write(line) + + def __getattr__(self, name): + return getattr(self._text_stream, name) + + def isatty(self): + return self.buffer.isatty() + + def __repr__(self): + return '' % ( + self.name, + self.encoding, + ) + + +def _get_text_stdin(buffer_stream): + text_stream = _NonClosingTextIOWrapper( + io.BufferedReader(_WindowsConsoleReader(STDIN_HANDLE)), + 'utf-16-le', 'strict', line_buffering=True) + return ConsoleStream(text_stream, buffer_stream) + + +def _get_text_stdout(buffer_stream): + text_stream = _NonClosingTextIOWrapper( + _WindowsConsoleWriter(STDOUT_HANDLE), + 'utf-16-le', 'strict', line_buffering=True) + return ConsoleStream(text_stream, buffer_stream) + + +def _get_text_stderr(buffer_stream): + text_stream = _NonClosingTextIOWrapper( + _WindowsConsoleWriter(STDERR_HANDLE), + 'utf-16-le', 'strict', line_buffering=True) + return ConsoleStream(text_stream, buffer_stream) + + +if PY2: + def _hash_py_argv(): + return zlib.crc32('\x00'.join(sys.argv[1:])) + + _initial_argv_hash = _hash_py_argv() + + def _get_windows_argv(): + argc = c_int(0) + argv_unicode = CommandLineToArgvW(GetCommandLineW(), byref(argc)) + argv = [argv_unicode[i] for i in range(0, argc.value)] + + if not hasattr(sys, 'frozen'): + argv = argv[1:] + while len(argv) > 0: + arg = argv[0] + if not arg.startswith('-') or arg == '-': + break + argv = argv[1:] + if arg.startswith(('-c', '-m')): + break + + return argv[1:] + + +_stream_factories = { + 0: _get_text_stdin, + 1: _get_text_stdout, + 2: _get_text_stderr, +} + + +def _get_windows_console_stream(f, encoding, errors): + if get_buffer is not None and \ + encoding in ('utf-16-le', None) \ + and errors in ('strict', None) and \ + hasattr(f, 'isatty') and f.isatty(): + func = _stream_factories.get(f.fileno()) + if func is not None: + if not PY2: + f = getattr(f, 'buffer') + if f is None: + return None + else: + # If we are on Python 2 we need to set the stream that we + # deal with to binary mode as otherwise the exercise if a + # bit moot. The same problems apply as for + # get_binary_stdin and friends from _compat. + msvcrt.setmode(f.fileno(), os.O_BINARY) + return func(f) diff --git a/venv/lib/python2.7/site-packages/click/core.py b/venv/lib/python2.7/site-packages/click/core.py new file mode 100644 index 0000000..7456451 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/core.py @@ -0,0 +1,1744 @@ +import errno +import os +import sys +from contextlib import contextmanager +from itertools import repeat +from functools import update_wrapper + +from .types import convert_type, IntRange, BOOL +from .utils import make_str, make_default_short_help, echo, get_os_args +from .exceptions import ClickException, UsageError, BadParameter, Abort, \ + MissingParameter +from .termui import prompt, confirm +from .formatting import HelpFormatter, join_options +from .parser import OptionParser, split_opt +from .globals import push_context, pop_context + +from ._compat import PY2, isidentifier, iteritems +from ._unicodefun import _check_for_unicode_literals, _verify_python3_env + + +_missing = object() + + +SUBCOMMAND_METAVAR = 'COMMAND [ARGS]...' +SUBCOMMANDS_METAVAR = 'COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]...' + + +def _bashcomplete(cmd, prog_name, complete_var=None): + """Internal handler for the bash completion support.""" + if complete_var is None: + complete_var = '_%s_COMPLETE' % (prog_name.replace('-', '_')).upper() + complete_instr = os.environ.get(complete_var) + if not complete_instr: + return + + from ._bashcomplete import bashcomplete + if bashcomplete(cmd, prog_name, complete_var, complete_instr): + sys.exit(1) + + +def _check_multicommand(base_command, cmd_name, cmd, register=False): + if not base_command.chain or not isinstance(cmd, MultiCommand): + return + if register: + hint = 'It is not possible to add multi commands as children to ' \ + 'another multi command that is in chain mode' + else: + hint = 'Found a multi command as subcommand to a multi command ' \ + 'that is in chain mode. This is not supported' + raise RuntimeError('%s. Command "%s" is set to chain and "%s" was ' + 'added as subcommand but it in itself is a ' + 'multi command. ("%s" is a %s within a chained ' + '%s named "%s"). This restriction was supposed to ' + 'be lifted in 6.0 but the fix was flawed. This ' + 'will be fixed in Click 7.0' % ( + hint, base_command.name, cmd_name, + cmd_name, cmd.__class__.__name__, + base_command.__class__.__name__, + base_command.name)) + + +def batch(iterable, batch_size): + return list(zip(*repeat(iter(iterable), batch_size))) + + +def invoke_param_callback(callback, ctx, param, value): + code = getattr(callback, '__code__', None) + args = getattr(code, 'co_argcount', 3) + + if args < 3: + # This will become a warning in Click 3.0: + from warnings import warn + warn(Warning('Invoked legacy parameter callback "%s". The new ' + 'signature for such callbacks starting with ' + 'click 2.0 is (ctx, param, value).' + % callback), stacklevel=3) + return callback(ctx, value) + return callback(ctx, param, value) + + +@contextmanager +def augment_usage_errors(ctx, param=None): + """Context manager that attaches extra information to exceptions that + fly. + """ + try: + yield + except BadParameter as e: + if e.ctx is None: + e.ctx = ctx + if param is not None and e.param is None: + e.param = param + raise + except UsageError as e: + if e.ctx is None: + e.ctx = ctx + raise + + +def iter_params_for_processing(invocation_order, declaration_order): + """Given a sequence of parameters in the order as should be considered + for processing and an iterable of parameters that exist, this returns + a list in the correct order as they should be processed. + """ + def sort_key(item): + try: + idx = invocation_order.index(item) + except ValueError: + idx = float('inf') + return (not item.is_eager, idx) + + return sorted(declaration_order, key=sort_key) + + +class Context(object): + """The context is a special internal object that holds state relevant + for the script execution at every single level. It's normally invisible + to commands unless they opt-in to getting access to it. + + The context is useful as it can pass internal objects around and can + control special execution features such as reading data from + environment variables. + + A context can be used as context manager in which case it will call + :meth:`close` on teardown. + + .. versionadded:: 2.0 + Added the `resilient_parsing`, `help_option_names`, + `token_normalize_func` parameters. + + .. versionadded:: 3.0 + Added the `allow_extra_args` and `allow_interspersed_args` + parameters. + + .. versionadded:: 4.0 + Added the `color`, `ignore_unknown_options`, and + `max_content_width` parameters. + + :param command: the command class for this context. + :param parent: the parent context. + :param info_name: the info name for this invocation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it is usually + the name of the script, for commands below it it's + the name of the script. + :param obj: an arbitrary object of user data. + :param auto_envvar_prefix: the prefix to use for automatic environment + variables. If this is `None` then reading + from environment variables is disabled. This + does not affect manually set environment + variables which are always read. + :param default_map: a dictionary (like object) with default values + for parameters. + :param terminal_width: the width of the terminal. The default is + inherit from parent context. If no context + defines the terminal width then auto + detection will be applied. + :param max_content_width: the maximum width for content rendered by + Click (this currently only affects help + pages). This defaults to 80 characters if + not overridden. In other words: even if the + terminal is larger than that, Click will not + format things wider than 80 characters by + default. In addition to that, formatters might + add some safety mapping on the right. + :param resilient_parsing: if this flag is enabled then Click will + parse without any interactivity or callback + invocation. This is useful for implementing + things such as completion support. + :param allow_extra_args: if this is set to `True` then extra arguments + at the end will not raise an error and will be + kept on the context. The default is to inherit + from the command. + :param allow_interspersed_args: if this is set to `False` then options + and arguments cannot be mixed. The + default is to inherit from the command. + :param ignore_unknown_options: instructs click to ignore options it does + not know and keeps them for later + processing. + :param help_option_names: optionally a list of strings that define how + the default help parameter is named. The + default is ``['--help']``. + :param token_normalize_func: an optional function that is used to + normalize tokens (options, choices, + etc.). This for instance can be used to + implement case insensitive behavior. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are used in texts that Click prints which is by + default not the case. This for instance would affect + help output. + """ + + def __init__(self, command, parent=None, info_name=None, obj=None, + auto_envvar_prefix=None, default_map=None, + terminal_width=None, max_content_width=None, + resilient_parsing=False, allow_extra_args=None, + allow_interspersed_args=None, + ignore_unknown_options=None, help_option_names=None, + token_normalize_func=None, color=None): + #: the parent context or `None` if none exists. + self.parent = parent + #: the :class:`Command` for this context. + self.command = command + #: the descriptive information name + self.info_name = info_name + #: the parsed parameters except if the value is hidden in which + #: case it's not remembered. + self.params = {} + #: the leftover arguments. + self.args = [] + #: protected arguments. These are arguments that are prepended + #: to `args` when certain parsing scenarios are encountered but + #: must be never propagated to another arguments. This is used + #: to implement nested parsing. + self.protected_args = [] + if obj is None and parent is not None: + obj = parent.obj + #: the user object stored. + self.obj = obj + self._meta = getattr(parent, 'meta', {}) + + #: A dictionary (-like object) with defaults for parameters. + if default_map is None \ + and parent is not None \ + and parent.default_map is not None: + default_map = parent.default_map.get(info_name) + self.default_map = default_map + + #: This flag indicates if a subcommand is going to be executed. A + #: group callback can use this information to figure out if it's + #: being executed directly or because the execution flow passes + #: onwards to a subcommand. By default it's None, but it can be + #: the name of the subcommand to execute. + #: + #: If chaining is enabled this will be set to ``'*'`` in case + #: any commands are executed. It is however not possible to + #: figure out which ones. If you require this knowledge you + #: should use a :func:`resultcallback`. + self.invoked_subcommand = None + + if terminal_width is None and parent is not None: + terminal_width = parent.terminal_width + #: The width of the terminal (None is autodetection). + self.terminal_width = terminal_width + + if max_content_width is None and parent is not None: + max_content_width = parent.max_content_width + #: The maximum width of formatted content (None implies a sensible + #: default which is 80 for most things). + self.max_content_width = max_content_width + + if allow_extra_args is None: + allow_extra_args = command.allow_extra_args + #: Indicates if the context allows extra args or if it should + #: fail on parsing. + #: + #: .. versionadded:: 3.0 + self.allow_extra_args = allow_extra_args + + if allow_interspersed_args is None: + allow_interspersed_args = command.allow_interspersed_args + #: Indicates if the context allows mixing of arguments and + #: options or not. + #: + #: .. versionadded:: 3.0 + self.allow_interspersed_args = allow_interspersed_args + + if ignore_unknown_options is None: + ignore_unknown_options = command.ignore_unknown_options + #: Instructs click to ignore options that a command does not + #: understand and will store it on the context for later + #: processing. This is primarily useful for situations where you + #: want to call into external programs. Generally this pattern is + #: strongly discouraged because it's not possibly to losslessly + #: forward all arguments. + #: + #: .. versionadded:: 4.0 + self.ignore_unknown_options = ignore_unknown_options + + if help_option_names is None: + if parent is not None: + help_option_names = parent.help_option_names + else: + help_option_names = ['--help'] + + #: The names for the help options. + self.help_option_names = help_option_names + + if token_normalize_func is None and parent is not None: + token_normalize_func = parent.token_normalize_func + + #: An optional normalization function for tokens. This is + #: options, choices, commands etc. + self.token_normalize_func = token_normalize_func + + #: Indicates if resilient parsing is enabled. In that case Click + #: will do its best to not cause any failures. + self.resilient_parsing = resilient_parsing + + # If there is no envvar prefix yet, but the parent has one and + # the command on this level has a name, we can expand the envvar + # prefix automatically. + if auto_envvar_prefix is None: + if parent is not None \ + and parent.auto_envvar_prefix is not None and \ + self.info_name is not None: + auto_envvar_prefix = '%s_%s' % (parent.auto_envvar_prefix, + self.info_name.upper()) + else: + self.auto_envvar_prefix = auto_envvar_prefix.upper() + self.auto_envvar_prefix = auto_envvar_prefix + + if color is None and parent is not None: + color = parent.color + + #: Controls if styling output is wanted or not. + self.color = color + + self._close_callbacks = [] + self._depth = 0 + + def __enter__(self): + self._depth += 1 + push_context(self) + return self + + def __exit__(self, exc_type, exc_value, tb): + self._depth -= 1 + if self._depth == 0: + self.close() + pop_context() + + @contextmanager + def scope(self, cleanup=True): + """This helper method can be used with the context object to promote + it to the current thread local (see :func:`get_current_context`). + The default behavior of this is to invoke the cleanup functions which + can be disabled by setting `cleanup` to `False`. The cleanup + functions are typically used for things such as closing file handles. + + If the cleanup is intended the context object can also be directly + used as a context manager. + + Example usage:: + + with ctx.scope(): + assert get_current_context() is ctx + + This is equivalent:: + + with ctx: + assert get_current_context() is ctx + + .. versionadded:: 5.0 + + :param cleanup: controls if the cleanup functions should be run or + not. The default is to run these functions. In + some situations the context only wants to be + temporarily pushed in which case this can be disabled. + Nested pushes automatically defer the cleanup. + """ + if not cleanup: + self._depth += 1 + try: + with self as rv: + yield rv + finally: + if not cleanup: + self._depth -= 1 + + @property + def meta(self): + """This is a dictionary which is shared with all the contexts + that are nested. It exists so that click utiltiies can store some + state here if they need to. It is however the responsibility of + that code to manage this dictionary well. + + The keys are supposed to be unique dotted strings. For instance + module paths are a good choice for it. What is stored in there is + irrelevant for the operation of click. However what is important is + that code that places data here adheres to the general semantics of + the system. + + Example usage:: + + LANG_KEY = __name__ + '.lang' + + def set_language(value): + ctx = get_current_context() + ctx.meta[LANG_KEY] = value + + def get_language(): + return get_current_context().meta.get(LANG_KEY, 'en_US') + + .. versionadded:: 5.0 + """ + return self._meta + + def make_formatter(self): + """Creates the formatter for the help and usage output.""" + return HelpFormatter(width=self.terminal_width, + max_width=self.max_content_width) + + def call_on_close(self, f): + """This decorator remembers a function as callback that should be + executed when the context tears down. This is most useful to bind + resource handling to the script execution. For instance, file objects + opened by the :class:`File` type will register their close callbacks + here. + + :param f: the function to execute on teardown. + """ + self._close_callbacks.append(f) + return f + + def close(self): + """Invokes all close callbacks.""" + for cb in self._close_callbacks: + cb() + self._close_callbacks = [] + + @property + def command_path(self): + """The computed command path. This is used for the ``usage`` + information on the help page. It's automatically created by + combining the info names of the chain of contexts to the root. + """ + rv = '' + if self.info_name is not None: + rv = self.info_name + if self.parent is not None: + rv = self.parent.command_path + ' ' + rv + return rv.lstrip() + + def find_root(self): + """Finds the outermost context.""" + node = self + while node.parent is not None: + node = node.parent + return node + + def find_object(self, object_type): + """Finds the closest object of a given type.""" + node = self + while node is not None: + if isinstance(node.obj, object_type): + return node.obj + node = node.parent + + def ensure_object(self, object_type): + """Like :meth:`find_object` but sets the innermost object to a + new instance of `object_type` if it does not exist. + """ + rv = self.find_object(object_type) + if rv is None: + self.obj = rv = object_type() + return rv + + def lookup_default(self, name): + """Looks up the default for a parameter name. This by default + looks into the :attr:`default_map` if available. + """ + if self.default_map is not None: + rv = self.default_map.get(name) + if callable(rv): + rv = rv() + return rv + + def fail(self, message): + """Aborts the execution of the program with a specific error + message. + + :param message: the error message to fail with. + """ + raise UsageError(message, self) + + def abort(self): + """Aborts the script.""" + raise Abort() + + def exit(self, code=0): + """Exits the application with a given exit code.""" + sys.exit(code) + + def get_usage(self): + """Helper method to get formatted usage string for the current + context and command. + """ + return self.command.get_usage(self) + + def get_help(self): + """Helper method to get formatted help page for the current + context and command. + """ + return self.command.get_help(self) + + def invoke(*args, **kwargs): + """Invokes a command callback in exactly the way it expects. There + are two ways to invoke this method: + + 1. the first argument can be a callback and all other arguments and + keyword arguments are forwarded directly to the function. + 2. the first argument is a click command object. In that case all + arguments are forwarded as well but proper click parameters + (options and click arguments) must be keyword arguments and Click + will fill in defaults. + + Note that before Click 3.2 keyword arguments were not properly filled + in against the intention of this code and no context was created. For + more information about this change and why it was done in a bugfix + release see :ref:`upgrade-to-3.2`. + """ + self, callback = args[:2] + ctx = self + + # It's also possible to invoke another command which might or + # might not have a callback. In that case we also fill + # in defaults and make a new context for this command. + if isinstance(callback, Command): + other_cmd = callback + callback = other_cmd.callback + ctx = Context(other_cmd, info_name=other_cmd.name, parent=self) + if callback is None: + raise TypeError('The given command does not have a ' + 'callback that can be invoked.') + + for param in other_cmd.params: + if param.name not in kwargs and param.expose_value: + kwargs[param.name] = param.get_default(ctx) + + args = args[2:] + with augment_usage_errors(self): + with ctx: + return callback(*args, **kwargs) + + def forward(*args, **kwargs): + """Similar to :meth:`invoke` but fills in default keyword + arguments from the current context if the other command expects + it. This cannot invoke callbacks directly, only other commands. + """ + self, cmd = args[:2] + + # It's also possible to invoke another command which might or + # might not have a callback. + if not isinstance(cmd, Command): + raise TypeError('Callback is not a command.') + + for param in self.params: + if param not in kwargs: + kwargs[param] = self.params[param] + + return self.invoke(cmd, **kwargs) + + +class BaseCommand(object): + """The base command implements the minimal API contract of commands. + Most code will never use this as it does not implement a lot of useful + functionality but it can act as the direct subclass of alternative + parsing methods that do not depend on the Click parser. + + For instance, this can be used to bridge Click and other systems like + argparse or docopt. + + Because base commands do not implement a lot of the API that other + parts of Click take for granted, they are not supported for all + operations. For instance, they cannot be used with the decorators + usually and they have no built-in callback system. + + .. versionchanged:: 2.0 + Added the `context_settings` parameter. + + :param name: the name of the command to use unless a group overrides it. + :param context_settings: an optional dictionary with defaults that are + passed to the context object. + """ + #: the default for the :attr:`Context.allow_extra_args` flag. + allow_extra_args = False + #: the default for the :attr:`Context.allow_interspersed_args` flag. + allow_interspersed_args = True + #: the default for the :attr:`Context.ignore_unknown_options` flag. + ignore_unknown_options = False + + def __init__(self, name, context_settings=None): + #: the name the command thinks it has. Upon registering a command + #: on a :class:`Group` the group will default the command name + #: with this information. You should instead use the + #: :class:`Context`\'s :attr:`~Context.info_name` attribute. + self.name = name + if context_settings is None: + context_settings = {} + #: an optional dictionary with defaults passed to the context. + self.context_settings = context_settings + + def get_usage(self, ctx): + raise NotImplementedError('Base commands cannot get usage') + + def get_help(self, ctx): + raise NotImplementedError('Base commands cannot get help') + + def make_context(self, info_name, args, parent=None, **extra): + """This function when given an info name and arguments will kick + off the parsing and create a new :class:`Context`. It does not + invoke the actual command callback though. + + :param info_name: the info name for this invokation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it's usually + the name of the script, for commands below it it's + the name of the script. + :param args: the arguments to parse as list of strings. + :param parent: the parent context if available. + :param extra: extra keyword arguments forwarded to the context + constructor. + """ + for key, value in iteritems(self.context_settings): + if key not in extra: + extra[key] = value + ctx = Context(self, info_name=info_name, parent=parent, **extra) + with ctx.scope(cleanup=False): + self.parse_args(ctx, args) + return ctx + + def parse_args(self, ctx, args): + """Given a context and a list of arguments this creates the parser + and parses the arguments, then modifies the context as necessary. + This is automatically invoked by :meth:`make_context`. + """ + raise NotImplementedError('Base commands do not know how to parse ' + 'arguments.') + + def invoke(self, ctx): + """Given a context, this invokes the command. The default + implementation is raising a not implemented error. + """ + raise NotImplementedError('Base commands are not invokable by default') + + def main(self, args=None, prog_name=None, complete_var=None, + standalone_mode=True, **extra): + """This is the way to invoke a script with all the bells and + whistles as a command line application. This will always terminate + the application after a call. If this is not wanted, ``SystemExit`` + needs to be caught. + + This method is also available by directly calling the instance of + a :class:`Command`. + + .. versionadded:: 3.0 + Added the `standalone_mode` flag to control the standalone mode. + + :param args: the arguments that should be used for parsing. If not + provided, ``sys.argv[1:]`` is used. + :param prog_name: the program name that should be used. By default + the program name is constructed by taking the file + name from ``sys.argv[0]``. + :param complete_var: the environment variable that controls the + bash completion support. The default is + ``"__COMPLETE"`` with prog name in + uppercase. + :param standalone_mode: the default behavior is to invoke the script + in standalone mode. Click will then + handle exceptions and convert them into + error messages and the function will never + return but shut down the interpreter. If + this is set to `False` they will be + propagated to the caller and the return + value of this function is the return value + of :meth:`invoke`. + :param extra: extra keyword arguments are forwarded to the context + constructor. See :class:`Context` for more information. + """ + # If we are in Python 3, we will verify that the environment is + # sane at this point of reject further execution to avoid a + # broken script. + if not PY2: + _verify_python3_env() + else: + _check_for_unicode_literals() + + if args is None: + args = get_os_args() + else: + args = list(args) + + if prog_name is None: + prog_name = make_str(os.path.basename( + sys.argv and sys.argv[0] or __file__)) + + # Hook for the Bash completion. This only activates if the Bash + # completion is actually enabled, otherwise this is quite a fast + # noop. + _bashcomplete(self, prog_name, complete_var) + + try: + try: + with self.make_context(prog_name, args, **extra) as ctx: + rv = self.invoke(ctx) + if not standalone_mode: + return rv + ctx.exit() + except (EOFError, KeyboardInterrupt): + echo(file=sys.stderr) + raise Abort() + except ClickException as e: + if not standalone_mode: + raise + e.show() + sys.exit(e.exit_code) + except IOError as e: + if e.errno == errno.EPIPE: + sys.exit(1) + else: + raise + except Abort: + if not standalone_mode: + raise + echo('Aborted!', file=sys.stderr) + sys.exit(1) + + def __call__(self, *args, **kwargs): + """Alias for :meth:`main`.""" + return self.main(*args, **kwargs) + + +class Command(BaseCommand): + """Commands are the basic building block of command line interfaces in + Click. A basic command handles command line parsing and might dispatch + more parsing to commands nested below it. + + .. versionchanged:: 2.0 + Added the `context_settings` parameter. + + :param name: the name of the command to use unless a group overrides it. + :param context_settings: an optional dictionary with defaults that are + passed to the context object. + :param callback: the callback to invoke. This is optional. + :param params: the parameters to register with this command. This can + be either :class:`Option` or :class:`Argument` objects. + :param help: the help string to use for this command. + :param epilog: like the help string but it's printed at the end of the + help page after everything else. + :param short_help: the short help to use for this command. This is + shown on the command listing of the parent command. + :param add_help_option: by default each command registers a ``--help`` + option. This can be disabled by this parameter. + """ + + def __init__(self, name, context_settings=None, callback=None, + params=None, help=None, epilog=None, short_help=None, + options_metavar='[OPTIONS]', add_help_option=True): + BaseCommand.__init__(self, name, context_settings) + #: the callback to execute when the command fires. This might be + #: `None` in which case nothing happens. + self.callback = callback + #: the list of parameters for this command in the order they + #: should show up in the help page and execute. Eager parameters + #: will automatically be handled before non eager ones. + self.params = params or [] + self.help = help + self.epilog = epilog + self.options_metavar = options_metavar + if short_help is None and help: + short_help = make_default_short_help(help) + self.short_help = short_help + self.add_help_option = add_help_option + + def get_usage(self, ctx): + formatter = ctx.make_formatter() + self.format_usage(ctx, formatter) + return formatter.getvalue().rstrip('\n') + + def get_params(self, ctx): + rv = self.params + help_option = self.get_help_option(ctx) + if help_option is not None: + rv = rv + [help_option] + return rv + + def format_usage(self, ctx, formatter): + """Writes the usage line into the formatter.""" + pieces = self.collect_usage_pieces(ctx) + formatter.write_usage(ctx.command_path, ' '.join(pieces)) + + def collect_usage_pieces(self, ctx): + """Returns all the pieces that go into the usage line and returns + it as a list of strings. + """ + rv = [self.options_metavar] + for param in self.get_params(ctx): + rv.extend(param.get_usage_pieces(ctx)) + return rv + + def get_help_option_names(self, ctx): + """Returns the names for the help option.""" + all_names = set(ctx.help_option_names) + for param in self.params: + all_names.difference_update(param.opts) + all_names.difference_update(param.secondary_opts) + return all_names + + def get_help_option(self, ctx): + """Returns the help option object.""" + help_options = self.get_help_option_names(ctx) + if not help_options or not self.add_help_option: + return + + def show_help(ctx, param, value): + if value and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + return Option(help_options, is_flag=True, + is_eager=True, expose_value=False, + callback=show_help, + help='Show this message and exit.') + + def make_parser(self, ctx): + """Creates the underlying option parser for this command.""" + parser = OptionParser(ctx) + parser.allow_interspersed_args = ctx.allow_interspersed_args + parser.ignore_unknown_options = ctx.ignore_unknown_options + for param in self.get_params(ctx): + param.add_to_parser(parser, ctx) + return parser + + def get_help(self, ctx): + """Formats the help into a string and returns it. This creates a + formatter and will call into the following formatting methods: + """ + formatter = ctx.make_formatter() + self.format_help(ctx, formatter) + return formatter.getvalue().rstrip('\n') + + def format_help(self, ctx, formatter): + """Writes the help into the formatter if it exists. + + This calls into the following methods: + + - :meth:`format_usage` + - :meth:`format_help_text` + - :meth:`format_options` + - :meth:`format_epilog` + """ + self.format_usage(ctx, formatter) + self.format_help_text(ctx, formatter) + self.format_options(ctx, formatter) + self.format_epilog(ctx, formatter) + + def format_help_text(self, ctx, formatter): + """Writes the help text to the formatter if it exists.""" + if self.help: + formatter.write_paragraph() + with formatter.indentation(): + formatter.write_text(self.help) + + def format_options(self, ctx, formatter): + """Writes all the options into the formatter if they exist.""" + opts = [] + for param in self.get_params(ctx): + rv = param.get_help_record(ctx) + if rv is not None: + opts.append(rv) + + if opts: + with formatter.section('Options'): + formatter.write_dl(opts) + + def format_epilog(self, ctx, formatter): + """Writes the epilog into the formatter if it exists.""" + if self.epilog: + formatter.write_paragraph() + with formatter.indentation(): + formatter.write_text(self.epilog) + + def parse_args(self, ctx, args): + parser = self.make_parser(ctx) + opts, args, param_order = parser.parse_args(args=args) + + for param in iter_params_for_processing( + param_order, self.get_params(ctx)): + value, args = param.handle_parse_result(ctx, opts, args) + + if args and not ctx.allow_extra_args and not ctx.resilient_parsing: + ctx.fail('Got unexpected extra argument%s (%s)' + % (len(args) != 1 and 's' or '', + ' '.join(map(make_str, args)))) + + ctx.args = args + return args + + def invoke(self, ctx): + """Given a context, this invokes the attached callback (if it exists) + in the right way. + """ + if self.callback is not None: + return ctx.invoke(self.callback, **ctx.params) + + +class MultiCommand(Command): + """A multi command is the basic implementation of a command that + dispatches to subcommands. The most common version is the + :class:`Group`. + + :param invoke_without_command: this controls how the multi command itself + is invoked. By default it's only invoked + if a subcommand is provided. + :param no_args_is_help: this controls what happens if no arguments are + provided. This option is enabled by default if + `invoke_without_command` is disabled or disabled + if it's enabled. If enabled this will add + ``--help`` as argument if no arguments are + passed. + :param subcommand_metavar: the string that is used in the documentation + to indicate the subcommand place. + :param chain: if this is set to `True` chaining of multiple subcommands + is enabled. This restricts the form of commands in that + they cannot have optional arguments but it allows + multiple commands to be chained together. + :param result_callback: the result callback to attach to this multi + command. + """ + allow_extra_args = True + allow_interspersed_args = False + + def __init__(self, name=None, invoke_without_command=False, + no_args_is_help=None, subcommand_metavar=None, + chain=False, result_callback=None, **attrs): + Command.__init__(self, name, **attrs) + if no_args_is_help is None: + no_args_is_help = not invoke_without_command + self.no_args_is_help = no_args_is_help + self.invoke_without_command = invoke_without_command + if subcommand_metavar is None: + if chain: + subcommand_metavar = SUBCOMMANDS_METAVAR + else: + subcommand_metavar = SUBCOMMAND_METAVAR + self.subcommand_metavar = subcommand_metavar + self.chain = chain + #: The result callback that is stored. This can be set or + #: overridden with the :func:`resultcallback` decorator. + self.result_callback = result_callback + + if self.chain: + for param in self.params: + if isinstance(param, Argument) and not param.required: + raise RuntimeError('Multi commands in chain mode cannot ' + 'have optional arguments.') + + def collect_usage_pieces(self, ctx): + rv = Command.collect_usage_pieces(self, ctx) + rv.append(self.subcommand_metavar) + return rv + + def format_options(self, ctx, formatter): + Command.format_options(self, ctx, formatter) + self.format_commands(ctx, formatter) + + def resultcallback(self, replace=False): + """Adds a result callback to the chain command. By default if a + result callback is already registered this will chain them but + this can be disabled with the `replace` parameter. The result + callback is invoked with the return value of the subcommand + (or the list of return values from all subcommands if chaining + is enabled) as well as the parameters as they would be passed + to the main callback. + + Example:: + + @click.group() + @click.option('-i', '--input', default=23) + def cli(input): + return 42 + + @cli.resultcallback() + def process_result(result, input): + return result + input + + .. versionadded:: 3.0 + + :param replace: if set to `True` an already existing result + callback will be removed. + """ + def decorator(f): + old_callback = self.result_callback + if old_callback is None or replace: + self.result_callback = f + return f + def function(__value, *args, **kwargs): + return f(old_callback(__value, *args, **kwargs), + *args, **kwargs) + self.result_callback = rv = update_wrapper(function, f) + return rv + return decorator + + def format_commands(self, ctx, formatter): + """Extra format methods for multi methods that adds all the commands + after the options. + """ + rows = [] + for subcommand in self.list_commands(ctx): + cmd = self.get_command(ctx, subcommand) + # What is this, the tool lied about a command. Ignore it + if cmd is None: + continue + + help = cmd.short_help or '' + rows.append((subcommand, help)) + + if rows: + with formatter.section('Commands'): + formatter.write_dl(rows) + + def parse_args(self, ctx, args): + if not args and self.no_args_is_help and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + rest = Command.parse_args(self, ctx, args) + if self.chain: + ctx.protected_args = rest + ctx.args = [] + elif rest: + ctx.protected_args, ctx.args = rest[:1], rest[1:] + + return ctx.args + + def invoke(self, ctx): + def _process_result(value): + if self.result_callback is not None: + value = ctx.invoke(self.result_callback, value, + **ctx.params) + return value + + if not ctx.protected_args: + # If we are invoked without command the chain flag controls + # how this happens. If we are not in chain mode, the return + # value here is the return value of the command. + # If however we are in chain mode, the return value is the + # return value of the result processor invoked with an empty + # list (which means that no subcommand actually was executed). + if self.invoke_without_command: + if not self.chain: + return Command.invoke(self, ctx) + with ctx: + Command.invoke(self, ctx) + return _process_result([]) + ctx.fail('Missing command.') + + # Fetch args back out + args = ctx.protected_args + ctx.args + ctx.args = [] + ctx.protected_args = [] + + # If we're not in chain mode, we only allow the invocation of a + # single command but we also inform the current context about the + # name of the command to invoke. + if not self.chain: + # Make sure the context is entered so we do not clean up + # resources until the result processor has worked. + with ctx: + cmd_name, cmd, args = self.resolve_command(ctx, args) + ctx.invoked_subcommand = cmd_name + Command.invoke(self, ctx) + sub_ctx = cmd.make_context(cmd_name, args, parent=ctx) + with sub_ctx: + return _process_result(sub_ctx.command.invoke(sub_ctx)) + + # In chain mode we create the contexts step by step, but after the + # base command has been invoked. Because at that point we do not + # know the subcommands yet, the invoked subcommand attribute is + # set to ``*`` to inform the command that subcommands are executed + # but nothing else. + with ctx: + ctx.invoked_subcommand = args and '*' or None + Command.invoke(self, ctx) + + # Otherwise we make every single context and invoke them in a + # chain. In that case the return value to the result processor + # is the list of all invoked subcommand's results. + contexts = [] + while args: + cmd_name, cmd, args = self.resolve_command(ctx, args) + sub_ctx = cmd.make_context(cmd_name, args, parent=ctx, + allow_extra_args=True, + allow_interspersed_args=False) + contexts.append(sub_ctx) + args, sub_ctx.args = sub_ctx.args, [] + + rv = [] + for sub_ctx in contexts: + with sub_ctx: + rv.append(sub_ctx.command.invoke(sub_ctx)) + return _process_result(rv) + + def resolve_command(self, ctx, args): + cmd_name = make_str(args[0]) + original_cmd_name = cmd_name + + # Get the command + cmd = self.get_command(ctx, cmd_name) + + # If we can't find the command but there is a normalization + # function available, we try with that one. + if cmd is None and ctx.token_normalize_func is not None: + cmd_name = ctx.token_normalize_func(cmd_name) + cmd = self.get_command(ctx, cmd_name) + + # If we don't find the command we want to show an error message + # to the user that it was not provided. However, there is + # something else we should do: if the first argument looks like + # an option we want to kick off parsing again for arguments to + # resolve things like --help which now should go to the main + # place. + if cmd is None: + if split_opt(cmd_name)[0]: + self.parse_args(ctx, ctx.args) + ctx.fail('No such command "%s".' % original_cmd_name) + + return cmd_name, cmd, args[1:] + + def get_command(self, ctx, cmd_name): + """Given a context and a command name, this returns a + :class:`Command` object if it exists or returns `None`. + """ + raise NotImplementedError() + + def list_commands(self, ctx): + """Returns a list of subcommand names in the order they should + appear. + """ + return [] + + +class Group(MultiCommand): + """A group allows a command to have subcommands attached. This is the + most common way to implement nesting in Click. + + :param commands: a dictionary of commands. + """ + + def __init__(self, name=None, commands=None, **attrs): + MultiCommand.__init__(self, name, **attrs) + #: the registered subcommands by their exported names. + self.commands = commands or {} + + def add_command(self, cmd, name=None): + """Registers another :class:`Command` with this group. If the name + is not provided, the name of the command is used. + """ + name = name or cmd.name + if name is None: + raise TypeError('Command has no name.') + _check_multicommand(self, name, cmd, register=True) + self.commands[name] = cmd + + def command(self, *args, **kwargs): + """A shortcut decorator for declaring and attaching a command to + the group. This takes the same arguments as :func:`command` but + immediately registers the created command with this instance by + calling into :meth:`add_command`. + """ + def decorator(f): + cmd = command(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + return decorator + + def group(self, *args, **kwargs): + """A shortcut decorator for declaring and attaching a group to + the group. This takes the same arguments as :func:`group` but + immediately registers the created command with this instance by + calling into :meth:`add_command`. + """ + def decorator(f): + cmd = group(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + return decorator + + def get_command(self, ctx, cmd_name): + return self.commands.get(cmd_name) + + def list_commands(self, ctx): + return sorted(self.commands) + + +class CommandCollection(MultiCommand): + """A command collection is a multi command that merges multiple multi + commands together into one. This is a straightforward implementation + that accepts a list of different multi commands as sources and + provides all the commands for each of them. + """ + + def __init__(self, name=None, sources=None, **attrs): + MultiCommand.__init__(self, name, **attrs) + #: The list of registered multi commands. + self.sources = sources or [] + + def add_source(self, multi_cmd): + """Adds a new multi command to the chain dispatcher.""" + self.sources.append(multi_cmd) + + def get_command(self, ctx, cmd_name): + for source in self.sources: + rv = source.get_command(ctx, cmd_name) + if rv is not None: + if self.chain: + _check_multicommand(self, cmd_name, rv) + return rv + + def list_commands(self, ctx): + rv = set() + for source in self.sources: + rv.update(source.list_commands(ctx)) + return sorted(rv) + + +class Parameter(object): + """A parameter to a command comes in two versions: they are either + :class:`Option`\s or :class:`Argument`\s. Other subclasses are currently + not supported by design as some of the internals for parsing are + intentionally not finalized. + + Some settings are supported by both options and arguments. + + .. versionchanged:: 2.0 + Changed signature for parameter callback to also be passed the + parameter. In Click 2.0, the old callback format will still work, + but it will raise a warning to give you change to migrate the + code easier. + + :param param_decls: the parameter declarations for this option or + argument. This is a list of flags or argument + names. + :param type: the type that should be used. Either a :class:`ParamType` + or a Python type. The later is converted into the former + automatically if supported. + :param required: controls if this is optional or not. + :param default: the default value if omitted. This can also be a callable, + in which case it's invoked when the default is needed + without any arguments. + :param callback: a callback that should be executed after the parameter + was matched. This is called as ``fn(ctx, param, + value)`` and needs to return the value. Before Click + 2.0, the signature was ``(ctx, value)``. + :param nargs: the number of arguments to match. If not ``1`` the return + value is a tuple instead of single value. The default for + nargs is ``1`` (except if the type is a tuple, then it's + the arity of the tuple). + :param metavar: how the value is represented in the help page. + :param expose_value: if this is `True` then the value is passed onwards + to the command callback and stored on the context, + otherwise it's skipped. + :param is_eager: eager values are processed before non eager ones. This + should not be set for arguments or it will inverse the + order of processing. + :param envvar: a string or list of strings that are environment variables + that should be checked. + """ + param_type_name = 'parameter' + + def __init__(self, param_decls=None, type=None, required=False, + default=None, callback=None, nargs=None, metavar=None, + expose_value=True, is_eager=False, envvar=None): + self.name, self.opts, self.secondary_opts = \ + self._parse_decls(param_decls or (), expose_value) + + self.type = convert_type(type, default) + + # Default nargs to what the type tells us if we have that + # information available. + if nargs is None: + if self.type.is_composite: + nargs = self.type.arity + else: + nargs = 1 + + self.required = required + self.callback = callback + self.nargs = nargs + self.multiple = False + self.expose_value = expose_value + self.default = default + self.is_eager = is_eager + self.metavar = metavar + self.envvar = envvar + + @property + def human_readable_name(self): + """Returns the human readable name of this parameter. This is the + same as the name for options, but the metavar for arguments. + """ + return self.name + + def make_metavar(self): + if self.metavar is not None: + return self.metavar + metavar = self.type.get_metavar(self) + if metavar is None: + metavar = self.type.name.upper() + if self.nargs != 1: + metavar += '...' + return metavar + + def get_default(self, ctx): + """Given a context variable this calculates the default value.""" + # Otherwise go with the regular default. + if callable(self.default): + rv = self.default() + else: + rv = self.default + return self.type_cast_value(ctx, rv) + + def add_to_parser(self, parser, ctx): + pass + + def consume_value(self, ctx, opts): + value = opts.get(self.name) + if value is None: + value = ctx.lookup_default(self.name) + if value is None: + value = self.value_from_envvar(ctx) + return value + + def type_cast_value(self, ctx, value): + """Given a value this runs it properly through the type system. + This automatically handles things like `nargs` and `multiple` as + well as composite types. + """ + if self.type.is_composite: + if self.nargs <= 1: + raise TypeError('Attempted to invoke composite type ' + 'but nargs has been set to %s. This is ' + 'not supported; nargs needs to be set to ' + 'a fixed value > 1.' % self.nargs) + if self.multiple: + return tuple(self.type(x or (), self, ctx) for x in value or ()) + return self.type(value or (), self, ctx) + + def _convert(value, level): + if level == 0: + return self.type(value, self, ctx) + return tuple(_convert(x, level - 1) for x in value or ()) + return _convert(value, (self.nargs != 1) + bool(self.multiple)) + + def process_value(self, ctx, value): + """Given a value and context this runs the logic to convert the + value as necessary. + """ + # If the value we were given is None we do nothing. This way + # code that calls this can easily figure out if something was + # not provided. Otherwise it would be converted into an empty + # tuple for multiple invocations which is inconvenient. + if value is not None: + return self.type_cast_value(ctx, value) + + def value_is_missing(self, value): + if value is None: + return True + if (self.nargs != 1 or self.multiple) and value == (): + return True + return False + + def full_process_value(self, ctx, value): + value = self.process_value(ctx, value) + + if value is None: + value = self.get_default(ctx) + + if self.required and self.value_is_missing(value): + raise MissingParameter(ctx=ctx, param=self) + + return value + + def resolve_envvar_value(self, ctx): + if self.envvar is None: + return + if isinstance(self.envvar, (tuple, list)): + for envvar in self.envvar: + rv = os.environ.get(envvar) + if rv is not None: + return rv + else: + return os.environ.get(self.envvar) + + def value_from_envvar(self, ctx): + rv = self.resolve_envvar_value(ctx) + if rv is not None and self.nargs != 1: + rv = self.type.split_envvar_value(rv) + return rv + + def handle_parse_result(self, ctx, opts, args): + with augment_usage_errors(ctx, param=self): + value = self.consume_value(ctx, opts) + try: + value = self.full_process_value(ctx, value) + except Exception: + if not ctx.resilient_parsing: + raise + value = None + if self.callback is not None: + try: + value = invoke_param_callback( + self.callback, ctx, self, value) + except Exception: + if not ctx.resilient_parsing: + raise + + if self.expose_value: + ctx.params[self.name] = value + return value, args + + def get_help_record(self, ctx): + pass + + def get_usage_pieces(self, ctx): + return [] + + +class Option(Parameter): + """Options are usually optional values on the command line and + have some extra features that arguments don't have. + + All other parameters are passed onwards to the parameter constructor. + + :param show_default: controls if the default value should be shown on the + help page. Normally, defaults are not shown. + :param prompt: if set to `True` or a non empty string then the user will + be prompted for input if not set. If set to `True` the + prompt will be the option name capitalized. + :param confirmation_prompt: if set then the value will need to be confirmed + if it was prompted for. + :param hide_input: if this is `True` then the input on the prompt will be + hidden from the user. This is useful for password + input. + :param is_flag: forces this option to act as a flag. The default is + auto detection. + :param flag_value: which value should be used for this flag if it's + enabled. This is set to a boolean automatically if + the option string contains a slash to mark two options. + :param multiple: if this is set to `True` then the argument is accepted + multiple times and recorded. This is similar to ``nargs`` + in how it works but supports arbitrary number of + arguments. + :param count: this flag makes an option increment an integer. + :param allow_from_autoenv: if this is enabled then the value of this + parameter will be pulled from an environment + variable in case a prefix is defined on the + context. + :param help: the help string. + """ + param_type_name = 'option' + + def __init__(self, param_decls=None, show_default=False, + prompt=False, confirmation_prompt=False, + hide_input=False, is_flag=None, flag_value=None, + multiple=False, count=False, allow_from_autoenv=True, + type=None, help=None, **attrs): + default_is_missing = attrs.get('default', _missing) is _missing + Parameter.__init__(self, param_decls, type=type, **attrs) + + if prompt is True: + prompt_text = self.name.replace('_', ' ').capitalize() + elif prompt is False: + prompt_text = None + else: + prompt_text = prompt + self.prompt = prompt_text + self.confirmation_prompt = confirmation_prompt + self.hide_input = hide_input + + # Flags + if is_flag is None: + if flag_value is not None: + is_flag = True + else: + is_flag = bool(self.secondary_opts) + if is_flag and default_is_missing: + self.default = False + if flag_value is None: + flag_value = not self.default + self.is_flag = is_flag + self.flag_value = flag_value + if self.is_flag and isinstance(self.flag_value, bool) \ + and type is None: + self.type = BOOL + self.is_bool_flag = True + else: + self.is_bool_flag = False + + # Counting + self.count = count + if count: + if type is None: + self.type = IntRange(min=0) + if default_is_missing: + self.default = 0 + + self.multiple = multiple + self.allow_from_autoenv = allow_from_autoenv + self.help = help + self.show_default = show_default + + # Sanity check for stuff we don't support + if __debug__: + if self.nargs < 0: + raise TypeError('Options cannot have nargs < 0') + if self.prompt and self.is_flag and not self.is_bool_flag: + raise TypeError('Cannot prompt for flags that are not bools.') + if not self.is_bool_flag and self.secondary_opts: + raise TypeError('Got secondary option for non boolean flag.') + if self.is_bool_flag and self.hide_input \ + and self.prompt is not None: + raise TypeError('Hidden input does not work with boolean ' + 'flag prompts.') + if self.count: + if self.multiple: + raise TypeError('Options cannot be multiple and count ' + 'at the same time.') + elif self.is_flag: + raise TypeError('Options cannot be count and flags at ' + 'the same time.') + + def _parse_decls(self, decls, expose_value): + opts = [] + secondary_opts = [] + name = None + possible_names = [] + + for decl in decls: + if isidentifier(decl): + if name is not None: + raise TypeError('Name defined twice') + name = decl + else: + split_char = decl[:1] == '/' and ';' or '/' + if split_char in decl: + first, second = decl.split(split_char, 1) + first = first.rstrip() + if first: + possible_names.append(split_opt(first)) + opts.append(first) + second = second.lstrip() + if second: + secondary_opts.append(second.lstrip()) + else: + possible_names.append(split_opt(decl)) + opts.append(decl) + + if name is None and possible_names: + possible_names.sort(key=lambda x: len(x[0])) + name = possible_names[-1][1].replace('-', '_').lower() + if not isidentifier(name): + name = None + + if name is None: + if not expose_value: + return None, opts, secondary_opts + raise TypeError('Could not determine name for option') + + if not opts and not secondary_opts: + raise TypeError('No options defined but a name was passed (%s). ' + 'Did you mean to declare an argument instead ' + 'of an option?' % name) + + return name, opts, secondary_opts + + def add_to_parser(self, parser, ctx): + kwargs = { + 'dest': self.name, + 'nargs': self.nargs, + 'obj': self, + } + + if self.multiple: + action = 'append' + elif self.count: + action = 'count' + else: + action = 'store' + + if self.is_flag: + kwargs.pop('nargs', None) + if self.is_bool_flag and self.secondary_opts: + parser.add_option(self.opts, action=action + '_const', + const=True, **kwargs) + parser.add_option(self.secondary_opts, action=action + + '_const', const=False, **kwargs) + else: + parser.add_option(self.opts, action=action + '_const', + const=self.flag_value, + **kwargs) + else: + kwargs['action'] = action + parser.add_option(self.opts, **kwargs) + + def get_help_record(self, ctx): + any_prefix_is_slash = [] + + def _write_opts(opts): + rv, any_slashes = join_options(opts) + if any_slashes: + any_prefix_is_slash[:] = [True] + if not self.is_flag and not self.count: + rv += ' ' + self.make_metavar() + return rv + + rv = [_write_opts(self.opts)] + if self.secondary_opts: + rv.append(_write_opts(self.secondary_opts)) + + help = self.help or '' + extra = [] + if self.default is not None and self.show_default: + extra.append('default: %s' % ( + ', '.join('%s' % d for d in self.default) + if isinstance(self.default, (list, tuple)) + else self.default, )) + if self.required: + extra.append('required') + if extra: + help = '%s[%s]' % (help and help + ' ' or '', '; '.join(extra)) + + return ((any_prefix_is_slash and '; ' or ' / ').join(rv), help) + + def get_default(self, ctx): + # If we're a non boolean flag out default is more complex because + # we need to look at all flags in the same group to figure out + # if we're the the default one in which case we return the flag + # value as default. + if self.is_flag and not self.is_bool_flag: + for param in ctx.command.params: + if param.name == self.name and param.default: + return param.flag_value + return None + return Parameter.get_default(self, ctx) + + def prompt_for_value(self, ctx): + """This is an alternative flow that can be activated in the full + value processing if a value does not exist. It will prompt the + user until a valid value exists and then returns the processed + value as result. + """ + # Calculate the default before prompting anything to be stable. + default = self.get_default(ctx) + + # If this is a prompt for a flag we need to handle this + # differently. + if self.is_bool_flag: + return confirm(self.prompt, default) + + return prompt(self.prompt, default=default, + hide_input=self.hide_input, + confirmation_prompt=self.confirmation_prompt, + value_proc=lambda x: self.process_value(ctx, x)) + + def resolve_envvar_value(self, ctx): + rv = Parameter.resolve_envvar_value(self, ctx) + if rv is not None: + return rv + if self.allow_from_autoenv and \ + ctx.auto_envvar_prefix is not None: + envvar = '%s_%s' % (ctx.auto_envvar_prefix, self.name.upper()) + return os.environ.get(envvar) + + def value_from_envvar(self, ctx): + rv = self.resolve_envvar_value(ctx) + if rv is None: + return None + value_depth = (self.nargs != 1) + bool(self.multiple) + if value_depth > 0 and rv is not None: + rv = self.type.split_envvar_value(rv) + if self.multiple and self.nargs != 1: + rv = batch(rv, self.nargs) + return rv + + def full_process_value(self, ctx, value): + if value is None and self.prompt is not None \ + and not ctx.resilient_parsing: + return self.prompt_for_value(ctx) + return Parameter.full_process_value(self, ctx, value) + + +class Argument(Parameter): + """Arguments are positional parameters to a command. They generally + provide fewer features than options but can have infinite ``nargs`` + and are required by default. + + All parameters are passed onwards to the parameter constructor. + """ + param_type_name = 'argument' + + def __init__(self, param_decls, required=None, **attrs): + if required is None: + if attrs.get('default') is not None: + required = False + else: + required = attrs.get('nargs', 1) > 0 + Parameter.__init__(self, param_decls, required=required, **attrs) + if self.default is not None and self.nargs < 0: + raise TypeError('nargs=-1 in combination with a default value ' + 'is not supported.') + + @property + def human_readable_name(self): + if self.metavar is not None: + return self.metavar + return self.name.upper() + + def make_metavar(self): + if self.metavar is not None: + return self.metavar + var = self.name.upper() + if not self.required: + var = '[%s]' % var + if self.nargs != 1: + var += '...' + return var + + def _parse_decls(self, decls, expose_value): + if not decls: + if not expose_value: + return None, [], [] + raise TypeError('Could not determine name for argument') + if len(decls) == 1: + name = arg = decls[0] + name = name.replace('-', '_').lower() + elif len(decls) == 2: + name, arg = decls + else: + raise TypeError('Arguments take exactly one or two ' + 'parameter declarations, got %d' % len(decls)) + return name, [arg], [] + + def get_usage_pieces(self, ctx): + return [self.make_metavar()] + + def add_to_parser(self, parser, ctx): + parser.add_argument(dest=self.name, nargs=self.nargs, + obj=self) + + +# Circular dependency between decorators and core +from .decorators import command, group diff --git a/venv/lib/python2.7/site-packages/click/decorators.py b/venv/lib/python2.7/site-packages/click/decorators.py new file mode 100644 index 0000000..9893452 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/decorators.py @@ -0,0 +1,304 @@ +import sys +import inspect + +from functools import update_wrapper + +from ._compat import iteritems +from ._unicodefun import _check_for_unicode_literals +from .utils import echo +from .globals import get_current_context + + +def pass_context(f): + """Marks a callback as wanting to receive the current context + object as first argument. + """ + def new_func(*args, **kwargs): + return f(get_current_context(), *args, **kwargs) + return update_wrapper(new_func, f) + + +def pass_obj(f): + """Similar to :func:`pass_context`, but only pass the object on the + context onwards (:attr:`Context.obj`). This is useful if that object + represents the state of a nested system. + """ + def new_func(*args, **kwargs): + return f(get_current_context().obj, *args, **kwargs) + return update_wrapper(new_func, f) + + +def make_pass_decorator(object_type, ensure=False): + """Given an object type this creates a decorator that will work + similar to :func:`pass_obj` but instead of passing the object of the + current context, it will find the innermost context of type + :func:`object_type`. + + This generates a decorator that works roughly like this:: + + from functools import update_wrapper + + def decorator(f): + @pass_context + def new_func(ctx, *args, **kwargs): + obj = ctx.find_object(object_type) + return ctx.invoke(f, obj, *args, **kwargs) + return update_wrapper(new_func, f) + return decorator + + :param object_type: the type of the object to pass. + :param ensure: if set to `True`, a new object will be created and + remembered on the context if it's not there yet. + """ + def decorator(f): + def new_func(*args, **kwargs): + ctx = get_current_context() + if ensure: + obj = ctx.ensure_object(object_type) + else: + obj = ctx.find_object(object_type) + if obj is None: + raise RuntimeError('Managed to invoke callback without a ' + 'context object of type %r existing' + % object_type.__name__) + return ctx.invoke(f, obj, *args[1:], **kwargs) + return update_wrapper(new_func, f) + return decorator + + +def _make_command(f, name, attrs, cls): + if isinstance(f, Command): + raise TypeError('Attempted to convert a callback into a ' + 'command twice.') + try: + params = f.__click_params__ + params.reverse() + del f.__click_params__ + except AttributeError: + params = [] + help = attrs.get('help') + if help is None: + help = inspect.getdoc(f) + if isinstance(help, bytes): + help = help.decode('utf-8') + else: + help = inspect.cleandoc(help) + attrs['help'] = help + _check_for_unicode_literals() + return cls(name=name or f.__name__.lower(), + callback=f, params=params, **attrs) + + +def command(name=None, cls=None, **attrs): + """Creates a new :class:`Command` and uses the decorated function as + callback. This will also automatically attach all decorated + :func:`option`\s and :func:`argument`\s as parameters to the command. + + The name of the command defaults to the name of the function. If you + want to change that, you can pass the intended name as the first + argument. + + All keyword arguments are forwarded to the underlying command class. + + Once decorated the function turns into a :class:`Command` instance + that can be invoked as a command line utility or be attached to a + command :class:`Group`. + + :param name: the name of the command. This defaults to the function + name. + :param cls: the command class to instantiate. This defaults to + :class:`Command`. + """ + if cls is None: + cls = Command + def decorator(f): + cmd = _make_command(f, name, attrs, cls) + cmd.__doc__ = f.__doc__ + return cmd + return decorator + + +def group(name=None, **attrs): + """Creates a new :class:`Group` with a function as callback. This + works otherwise the same as :func:`command` just that the `cls` + parameter is set to :class:`Group`. + """ + attrs.setdefault('cls', Group) + return command(name, **attrs) + + +def _param_memo(f, param): + if isinstance(f, Command): + f.params.append(param) + else: + if not hasattr(f, '__click_params__'): + f.__click_params__ = [] + f.__click_params__.append(param) + + +def argument(*param_decls, **attrs): + """Attaches an argument to the command. All positional arguments are + passed as parameter declarations to :class:`Argument`; all keyword + arguments are forwarded unchanged (except ``cls``). + This is equivalent to creating an :class:`Argument` instance manually + and attaching it to the :attr:`Command.params` list. + + :param cls: the argument class to instantiate. This defaults to + :class:`Argument`. + """ + def decorator(f): + ArgumentClass = attrs.pop('cls', Argument) + _param_memo(f, ArgumentClass(param_decls, **attrs)) + return f + return decorator + + +def option(*param_decls, **attrs): + """Attaches an option to the command. All positional arguments are + passed as parameter declarations to :class:`Option`; all keyword + arguments are forwarded unchanged (except ``cls``). + This is equivalent to creating an :class:`Option` instance manually + and attaching it to the :attr:`Command.params` list. + + :param cls: the option class to instantiate. This defaults to + :class:`Option`. + """ + def decorator(f): + if 'help' in attrs: + attrs['help'] = inspect.cleandoc(attrs['help']) + OptionClass = attrs.pop('cls', Option) + _param_memo(f, OptionClass(param_decls, **attrs)) + return f + return decorator + + +def confirmation_option(*param_decls, **attrs): + """Shortcut for confirmation prompts that can be ignored by passing + ``--yes`` as parameter. + + This is equivalent to decorating a function with :func:`option` with + the following parameters:: + + def callback(ctx, param, value): + if not value: + ctx.abort() + + @click.command() + @click.option('--yes', is_flag=True, callback=callback, + expose_value=False, prompt='Do you want to continue?') + def dropdb(): + pass + """ + def decorator(f): + def callback(ctx, param, value): + if not value: + ctx.abort() + attrs.setdefault('is_flag', True) + attrs.setdefault('callback', callback) + attrs.setdefault('expose_value', False) + attrs.setdefault('prompt', 'Do you want to continue?') + attrs.setdefault('help', 'Confirm the action without prompting.') + return option(*(param_decls or ('--yes',)), **attrs)(f) + return decorator + + +def password_option(*param_decls, **attrs): + """Shortcut for password prompts. + + This is equivalent to decorating a function with :func:`option` with + the following parameters:: + + @click.command() + @click.option('--password', prompt=True, confirmation_prompt=True, + hide_input=True) + def changeadmin(password): + pass + """ + def decorator(f): + attrs.setdefault('prompt', True) + attrs.setdefault('confirmation_prompt', True) + attrs.setdefault('hide_input', True) + return option(*(param_decls or ('--password',)), **attrs)(f) + return decorator + + +def version_option(version=None, *param_decls, **attrs): + """Adds a ``--version`` option which immediately ends the program + printing out the version number. This is implemented as an eager + option that prints the version and exits the program in the callback. + + :param version: the version number to show. If not provided Click + attempts an auto discovery via setuptools. + :param prog_name: the name of the program (defaults to autodetection) + :param message: custom message to show instead of the default + (``'%(prog)s, version %(version)s'``) + :param others: everything else is forwarded to :func:`option`. + """ + if version is None: + module = sys._getframe(1).f_globals.get('__name__') + def decorator(f): + prog_name = attrs.pop('prog_name', None) + message = attrs.pop('message', '%(prog)s, version %(version)s') + + def callback(ctx, param, value): + if not value or ctx.resilient_parsing: + return + prog = prog_name + if prog is None: + prog = ctx.find_root().info_name + ver = version + if ver is None: + try: + import pkg_resources + except ImportError: + pass + else: + for dist in pkg_resources.working_set: + scripts = dist.get_entry_map().get('console_scripts') or {} + for script_name, entry_point in iteritems(scripts): + if entry_point.module_name == module: + ver = dist.version + break + if ver is None: + raise RuntimeError('Could not determine version') + echo(message % { + 'prog': prog, + 'version': ver, + }, color=ctx.color) + ctx.exit() + + attrs.setdefault('is_flag', True) + attrs.setdefault('expose_value', False) + attrs.setdefault('is_eager', True) + attrs.setdefault('help', 'Show the version and exit.') + attrs['callback'] = callback + return option(*(param_decls or ('--version',)), **attrs)(f) + return decorator + + +def help_option(*param_decls, **attrs): + """Adds a ``--help`` option which immediately ends the program + printing out the help page. This is usually unnecessary to add as + this is added by default to all commands unless suppressed. + + Like :func:`version_option`, this is implemented as eager option that + prints in the callback and exits. + + All arguments are forwarded to :func:`option`. + """ + def decorator(f): + def callback(ctx, param, value): + if value and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + attrs.setdefault('is_flag', True) + attrs.setdefault('expose_value', False) + attrs.setdefault('help', 'Show this message and exit.') + attrs.setdefault('is_eager', True) + attrs['callback'] = callback + return option(*(param_decls or ('--help',)), **attrs)(f) + return decorator + + +# Circular dependencies between core and decorators +from .core import Command, Group, Argument, Option diff --git a/venv/lib/python2.7/site-packages/click/exceptions.py b/venv/lib/python2.7/site-packages/click/exceptions.py new file mode 100644 index 0000000..74a4542 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/exceptions.py @@ -0,0 +1,201 @@ +from ._compat import PY2, filename_to_ui, get_text_stderr +from .utils import echo + + +class ClickException(Exception): + """An exception that Click can handle and show to the user.""" + + #: The exit code for this exception + exit_code = 1 + + def __init__(self, message): + if PY2: + if message is not None: + message = message.encode('utf-8') + Exception.__init__(self, message) + self.message = message + + def format_message(self): + return self.message + + def show(self, file=None): + if file is None: + file = get_text_stderr() + echo('Error: %s' % self.format_message(), file=file) + + +class UsageError(ClickException): + """An internal exception that signals a usage error. This typically + aborts any further handling. + + :param message: the error message to display. + :param ctx: optionally the context that caused this error. Click will + fill in the context automatically in some situations. + """ + exit_code = 2 + + def __init__(self, message, ctx=None): + ClickException.__init__(self, message) + self.ctx = ctx + + def show(self, file=None): + if file is None: + file = get_text_stderr() + color = None + if self.ctx is not None: + color = self.ctx.color + echo(self.ctx.get_usage() + '\n', file=file, color=color) + echo('Error: %s' % self.format_message(), file=file, color=color) + + +class BadParameter(UsageError): + """An exception that formats out a standardized error message for a + bad parameter. This is useful when thrown from a callback or type as + Click will attach contextual information to it (for instance, which + parameter it is). + + .. versionadded:: 2.0 + + :param param: the parameter object that caused this error. This can + be left out, and Click will attach this info itself + if possible. + :param param_hint: a string that shows up as parameter name. This + can be used as alternative to `param` in cases + where custom validation should happen. If it is + a string it's used as such, if it's a list then + each item is quoted and separated. + """ + + def __init__(self, message, ctx=None, param=None, + param_hint=None): + UsageError.__init__(self, message, ctx) + self.param = param + self.param_hint = param_hint + + def format_message(self): + if self.param_hint is not None: + param_hint = self.param_hint + elif self.param is not None: + param_hint = self.param.opts or [self.param.human_readable_name] + else: + return 'Invalid value: %s' % self.message + if isinstance(param_hint, (tuple, list)): + param_hint = ' / '.join('"%s"' % x for x in param_hint) + return 'Invalid value for %s: %s' % (param_hint, self.message) + + +class MissingParameter(BadParameter): + """Raised if click required an option or argument but it was not + provided when invoking the script. + + .. versionadded:: 4.0 + + :param param_type: a string that indicates the type of the parameter. + The default is to inherit the parameter type from + the given `param`. Valid values are ``'parameter'``, + ``'option'`` or ``'argument'``. + """ + + def __init__(self, message=None, ctx=None, param=None, + param_hint=None, param_type=None): + BadParameter.__init__(self, message, ctx, param, param_hint) + self.param_type = param_type + + def format_message(self): + if self.param_hint is not None: + param_hint = self.param_hint + elif self.param is not None: + param_hint = self.param.opts or [self.param.human_readable_name] + else: + param_hint = None + if isinstance(param_hint, (tuple, list)): + param_hint = ' / '.join('"%s"' % x for x in param_hint) + + param_type = self.param_type + if param_type is None and self.param is not None: + param_type = self.param.param_type_name + + msg = self.message + if self.param is not None: + msg_extra = self.param.type.get_missing_message(self.param) + if msg_extra: + if msg: + msg += '. ' + msg_extra + else: + msg = msg_extra + + return 'Missing %s%s%s%s' % ( + param_type, + param_hint and ' %s' % param_hint or '', + msg and '. ' or '.', + msg or '', + ) + + +class NoSuchOption(UsageError): + """Raised if click attempted to handle an option that does not + exist. + + .. versionadded:: 4.0 + """ + + def __init__(self, option_name, message=None, possibilities=None, + ctx=None): + if message is None: + message = 'no such option: %s' % option_name + UsageError.__init__(self, message, ctx) + self.option_name = option_name + self.possibilities = possibilities + + def format_message(self): + bits = [self.message] + if self.possibilities: + if len(self.possibilities) == 1: + bits.append('Did you mean %s?' % self.possibilities[0]) + else: + possibilities = sorted(self.possibilities) + bits.append('(Possible options: %s)' % ', '.join(possibilities)) + return ' '.join(bits) + + +class BadOptionUsage(UsageError): + """Raised if an option is generally supplied but the use of the option + was incorrect. This is for instance raised if the number of arguments + for an option is not correct. + + .. versionadded:: 4.0 + """ + + def __init__(self, message, ctx=None): + UsageError.__init__(self, message, ctx) + + +class BadArgumentUsage(UsageError): + """Raised if an argument is generally supplied but the use of the argument + was incorrect. This is for instance raised if the number of values + for an argument is not correct. + + .. versionadded:: 6.0 + """ + + def __init__(self, message, ctx=None): + UsageError.__init__(self, message, ctx) + + +class FileError(ClickException): + """Raised if a file cannot be opened.""" + + def __init__(self, filename, hint=None): + ui_filename = filename_to_ui(filename) + if hint is None: + hint = 'unknown error' + ClickException.__init__(self, hint) + self.ui_filename = ui_filename + self.filename = filename + + def format_message(self): + return 'Could not open file %s: %s' % (self.ui_filename, self.message) + + +class Abort(RuntimeError): + """An internal signalling exception that signals Click to abort.""" diff --git a/venv/lib/python2.7/site-packages/click/formatting.py b/venv/lib/python2.7/site-packages/click/formatting.py new file mode 100644 index 0000000..a3d6a4d --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/formatting.py @@ -0,0 +1,256 @@ +from contextlib import contextmanager +from .termui import get_terminal_size +from .parser import split_opt +from ._compat import term_len + + +# Can force a width. This is used by the test system +FORCED_WIDTH = None + + +def measure_table(rows): + widths = {} + for row in rows: + for idx, col in enumerate(row): + widths[idx] = max(widths.get(idx, 0), term_len(col)) + return tuple(y for x, y in sorted(widths.items())) + + +def iter_rows(rows, col_count): + for row in rows: + row = tuple(row) + yield row + ('',) * (col_count - len(row)) + + +def wrap_text(text, width=78, initial_indent='', subsequent_indent='', + preserve_paragraphs=False): + """A helper function that intelligently wraps text. By default, it + assumes that it operates on a single paragraph of text but if the + `preserve_paragraphs` parameter is provided it will intelligently + handle paragraphs (defined by two empty lines). + + If paragraphs are handled, a paragraph can be prefixed with an empty + line containing the ``\\b`` character (``\\x08``) to indicate that + no rewrapping should happen in that block. + + :param text: the text that should be rewrapped. + :param width: the maximum width for the text. + :param initial_indent: the initial indent that should be placed on the + first line as a string. + :param subsequent_indent: the indent string that should be placed on + each consecutive line. + :param preserve_paragraphs: if this flag is set then the wrapping will + intelligently handle paragraphs. + """ + from ._textwrap import TextWrapper + text = text.expandtabs() + wrapper = TextWrapper(width, initial_indent=initial_indent, + subsequent_indent=subsequent_indent, + replace_whitespace=False) + if not preserve_paragraphs: + return wrapper.fill(text) + + p = [] + buf = [] + indent = None + + def _flush_par(): + if not buf: + return + if buf[0].strip() == '\b': + p.append((indent or 0, True, '\n'.join(buf[1:]))) + else: + p.append((indent or 0, False, ' '.join(buf))) + del buf[:] + + for line in text.splitlines(): + if not line: + _flush_par() + indent = None + else: + if indent is None: + orig_len = term_len(line) + line = line.lstrip() + indent = orig_len - term_len(line) + buf.append(line) + _flush_par() + + rv = [] + for indent, raw, text in p: + with wrapper.extra_indent(' ' * indent): + if raw: + rv.append(wrapper.indent_only(text)) + else: + rv.append(wrapper.fill(text)) + + return '\n\n'.join(rv) + + +class HelpFormatter(object): + """This class helps with formatting text-based help pages. It's + usually just needed for very special internal cases, but it's also + exposed so that developers can write their own fancy outputs. + + At present, it always writes into memory. + + :param indent_increment: the additional increment for each level. + :param width: the width for the text. This defaults to the terminal + width clamped to a maximum of 78. + """ + + def __init__(self, indent_increment=2, width=None, max_width=None): + self.indent_increment = indent_increment + if max_width is None: + max_width = 80 + if width is None: + width = FORCED_WIDTH + if width is None: + width = max(min(get_terminal_size()[0], max_width) - 2, 50) + self.width = width + self.current_indent = 0 + self.buffer = [] + + def write(self, string): + """Writes a unicode string into the internal buffer.""" + self.buffer.append(string) + + def indent(self): + """Increases the indentation.""" + self.current_indent += self.indent_increment + + def dedent(self): + """Decreases the indentation.""" + self.current_indent -= self.indent_increment + + def write_usage(self, prog, args='', prefix='Usage: '): + """Writes a usage line into the buffer. + + :param prog: the program name. + :param args: whitespace separated list of arguments. + :param prefix: the prefix for the first line. + """ + usage_prefix = '%*s%s ' % (self.current_indent, prefix, prog) + text_width = self.width - self.current_indent + + if text_width >= (term_len(usage_prefix) + 20): + # The arguments will fit to the right of the prefix. + indent = ' ' * term_len(usage_prefix) + self.write(wrap_text(args, text_width, + initial_indent=usage_prefix, + subsequent_indent=indent)) + else: + # The prefix is too long, put the arguments on the next line. + self.write(usage_prefix) + self.write('\n') + indent = ' ' * (max(self.current_indent, term_len(prefix)) + 4) + self.write(wrap_text(args, text_width, + initial_indent=indent, + subsequent_indent=indent)) + + self.write('\n') + + def write_heading(self, heading): + """Writes a heading into the buffer.""" + self.write('%*s%s:\n' % (self.current_indent, '', heading)) + + def write_paragraph(self): + """Writes a paragraph into the buffer.""" + if self.buffer: + self.write('\n') + + def write_text(self, text): + """Writes re-indented text into the buffer. This rewraps and + preserves paragraphs. + """ + text_width = max(self.width - self.current_indent, 11) + indent = ' ' * self.current_indent + self.write(wrap_text(text, text_width, + initial_indent=indent, + subsequent_indent=indent, + preserve_paragraphs=True)) + self.write('\n') + + def write_dl(self, rows, col_max=30, col_spacing=2): + """Writes a definition list into the buffer. This is how options + and commands are usually formatted. + + :param rows: a list of two item tuples for the terms and values. + :param col_max: the maximum width of the first column. + :param col_spacing: the number of spaces between the first and + second column. + """ + rows = list(rows) + widths = measure_table(rows) + if len(widths) != 2: + raise TypeError('Expected two columns for definition list') + + first_col = min(widths[0], col_max) + col_spacing + + for first, second in iter_rows(rows, len(widths)): + self.write('%*s%s' % (self.current_indent, '', first)) + if not second: + self.write('\n') + continue + if term_len(first) <= first_col - col_spacing: + self.write(' ' * (first_col - term_len(first))) + else: + self.write('\n') + self.write(' ' * (first_col + self.current_indent)) + + text_width = max(self.width - first_col - 2, 10) + lines = iter(wrap_text(second, text_width).splitlines()) + if lines: + self.write(next(lines) + '\n') + for line in lines: + self.write('%*s%s\n' % ( + first_col + self.current_indent, '', line)) + else: + self.write('\n') + + @contextmanager + def section(self, name): + """Helpful context manager that writes a paragraph, a heading, + and the indents. + + :param name: the section name that is written as heading. + """ + self.write_paragraph() + self.write_heading(name) + self.indent() + try: + yield + finally: + self.dedent() + + @contextmanager + def indentation(self): + """A context manager that increases the indentation.""" + self.indent() + try: + yield + finally: + self.dedent() + + def getvalue(self): + """Returns the buffer contents.""" + return ''.join(self.buffer) + + +def join_options(options): + """Given a list of option strings this joins them in the most appropriate + way and returns them in the form ``(formatted_string, + any_prefix_is_slash)`` where the second item in the tuple is a flag that + indicates if any of the option prefixes was a slash. + """ + rv = [] + any_prefix_is_slash = False + for opt in options: + prefix = split_opt(opt)[0] + if prefix == '/': + any_prefix_is_slash = True + rv.append((len(prefix), opt)) + + rv.sort(key=lambda x: x[0]) + + rv = ', '.join(x[1] for x in rv) + return rv, any_prefix_is_slash diff --git a/venv/lib/python2.7/site-packages/click/globals.py b/venv/lib/python2.7/site-packages/click/globals.py new file mode 100644 index 0000000..14338e6 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/globals.py @@ -0,0 +1,48 @@ +from threading import local + + +_local = local() + + +def get_current_context(silent=False): + """Returns the current click context. This can be used as a way to + access the current context object from anywhere. This is a more implicit + alternative to the :func:`pass_context` decorator. This function is + primarily useful for helpers such as :func:`echo` which might be + interested in changing it's behavior based on the current context. + + To push the current context, :meth:`Context.scope` can be used. + + .. versionadded:: 5.0 + + :param silent: is set to `True` the return value is `None` if no context + is available. The default behavior is to raise a + :exc:`RuntimeError`. + """ + try: + return getattr(_local, 'stack')[-1] + except (AttributeError, IndexError): + if not silent: + raise RuntimeError('There is no active click context.') + + +def push_context(ctx): + """Pushes a new context to the current stack.""" + _local.__dict__.setdefault('stack', []).append(ctx) + + +def pop_context(): + """Removes the top level from the stack.""" + _local.stack.pop() + + +def resolve_color_default(color=None): + """"Internal helper to get the default value of the color flag. If a + value is passed it's returned unchanged, otherwise it's looked up from + the current context. + """ + if color is not None: + return color + ctx = get_current_context(silent=True) + if ctx is not None: + return ctx.color diff --git a/venv/lib/python2.7/site-packages/click/parser.py b/venv/lib/python2.7/site-packages/click/parser.py new file mode 100644 index 0000000..9775c9f --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/parser.py @@ -0,0 +1,426 @@ +# -*- coding: utf-8 -*- +""" + click.parser + ~~~~~~~~~~~~ + + This module started out as largely a copy paste from the stdlib's + optparse module with the features removed that we do not need from + optparse because we implement them in Click on a higher level (for + instance type handling, help formatting and a lot more). + + The plan is to remove more and more from here over time. + + The reason this is a different module and not optparse from the stdlib + is that there are differences in 2.x and 3.x about the error messages + generated and optparse in the stdlib uses gettext for no good reason + and might cause us issues. +""" +import re +from collections import deque +from .exceptions import UsageError, NoSuchOption, BadOptionUsage, \ + BadArgumentUsage + + +def _unpack_args(args, nargs_spec): + """Given an iterable of arguments and an iterable of nargs specifications, + it returns a tuple with all the unpacked arguments at the first index + and all remaining arguments as the second. + + The nargs specification is the number of arguments that should be consumed + or `-1` to indicate that this position should eat up all the remainders. + + Missing items are filled with `None`. + """ + args = deque(args) + nargs_spec = deque(nargs_spec) + rv = [] + spos = None + + def _fetch(c): + try: + if spos is None: + return c.popleft() + else: + return c.pop() + except IndexError: + return None + + while nargs_spec: + nargs = _fetch(nargs_spec) + if nargs == 1: + rv.append(_fetch(args)) + elif nargs > 1: + x = [_fetch(args) for _ in range(nargs)] + # If we're reversed, we're pulling in the arguments in reverse, + # so we need to turn them around. + if spos is not None: + x.reverse() + rv.append(tuple(x)) + elif nargs < 0: + if spos is not None: + raise TypeError('Cannot have two nargs < 0') + spos = len(rv) + rv.append(None) + + # spos is the position of the wildcard (star). If it's not `None`, + # we fill it with the remainder. + if spos is not None: + rv[spos] = tuple(args) + args = [] + rv[spos + 1:] = reversed(rv[spos + 1:]) + + return tuple(rv), list(args) + + +def _error_opt_args(nargs, opt): + if nargs == 1: + raise BadOptionUsage('%s option requires an argument' % opt) + raise BadOptionUsage('%s option requires %d arguments' % (opt, nargs)) + + +def split_opt(opt): + first = opt[:1] + if first.isalnum(): + return '', opt + if opt[1:2] == first: + return opt[:2], opt[2:] + return first, opt[1:] + + +def normalize_opt(opt, ctx): + if ctx is None or ctx.token_normalize_func is None: + return opt + prefix, opt = split_opt(opt) + return prefix + ctx.token_normalize_func(opt) + + +def split_arg_string(string): + """Given an argument string this attempts to split it into small parts.""" + rv = [] + for match in re.finditer(r"('([^'\\]*(?:\\.[^'\\]*)*)'" + r'|"([^"\\]*(?:\\.[^"\\]*)*)"' + r'|\S+)\s*', string, re.S): + arg = match.group().strip() + if arg[:1] == arg[-1:] and arg[:1] in '"\'': + arg = arg[1:-1].encode('ascii', 'backslashreplace') \ + .decode('unicode-escape') + try: + arg = type(string)(arg) + except UnicodeError: + pass + rv.append(arg) + return rv + + +class Option(object): + + def __init__(self, opts, dest, action=None, nargs=1, const=None, obj=None): + self._short_opts = [] + self._long_opts = [] + self.prefixes = set() + + for opt in opts: + prefix, value = split_opt(opt) + if not prefix: + raise ValueError('Invalid start character for option (%s)' + % opt) + self.prefixes.add(prefix[0]) + if len(prefix) == 1 and len(value) == 1: + self._short_opts.append(opt) + else: + self._long_opts.append(opt) + self.prefixes.add(prefix) + + if action is None: + action = 'store' + + self.dest = dest + self.action = action + self.nargs = nargs + self.const = const + self.obj = obj + + @property + def takes_value(self): + return self.action in ('store', 'append') + + def process(self, value, state): + if self.action == 'store': + state.opts[self.dest] = value + elif self.action == 'store_const': + state.opts[self.dest] = self.const + elif self.action == 'append': + state.opts.setdefault(self.dest, []).append(value) + elif self.action == 'append_const': + state.opts.setdefault(self.dest, []).append(self.const) + elif self.action == 'count': + state.opts[self.dest] = state.opts.get(self.dest, 0) + 1 + else: + raise ValueError('unknown action %r' % self.action) + state.order.append(self.obj) + + +class Argument(object): + + def __init__(self, dest, nargs=1, obj=None): + self.dest = dest + self.nargs = nargs + self.obj = obj + + def process(self, value, state): + if self.nargs > 1: + holes = sum(1 for x in value if x is None) + if holes == len(value): + value = None + elif holes != 0: + raise BadArgumentUsage('argument %s takes %d values' + % (self.dest, self.nargs)) + state.opts[self.dest] = value + state.order.append(self.obj) + + +class ParsingState(object): + + def __init__(self, rargs): + self.opts = {} + self.largs = [] + self.rargs = rargs + self.order = [] + + +class OptionParser(object): + """The option parser is an internal class that is ultimately used to + parse options and arguments. It's modelled after optparse and brings + a similar but vastly simplified API. It should generally not be used + directly as the high level Click classes wrap it for you. + + It's not nearly as extensible as optparse or argparse as it does not + implement features that are implemented on a higher level (such as + types or defaults). + + :param ctx: optionally the :class:`~click.Context` where this parser + should go with. + """ + + def __init__(self, ctx=None): + #: The :class:`~click.Context` for this parser. This might be + #: `None` for some advanced use cases. + self.ctx = ctx + #: This controls how the parser deals with interspersed arguments. + #: If this is set to `False`, the parser will stop on the first + #: non-option. Click uses this to implement nested subcommands + #: safely. + self.allow_interspersed_args = True + #: This tells the parser how to deal with unknown options. By + #: default it will error out (which is sensible), but there is a + #: second mode where it will ignore it and continue processing + #: after shifting all the unknown options into the resulting args. + self.ignore_unknown_options = False + if ctx is not None: + self.allow_interspersed_args = ctx.allow_interspersed_args + self.ignore_unknown_options = ctx.ignore_unknown_options + self._short_opt = {} + self._long_opt = {} + self._opt_prefixes = set(['-', '--']) + self._args = [] + + def add_option(self, opts, dest, action=None, nargs=1, const=None, + obj=None): + """Adds a new option named `dest` to the parser. The destination + is not inferred (unlike with optparse) and needs to be explicitly + provided. Action can be any of ``store``, ``store_const``, + ``append``, ``appnd_const`` or ``count``. + + The `obj` can be used to identify the option in the order list + that is returned from the parser. + """ + if obj is None: + obj = dest + opts = [normalize_opt(opt, self.ctx) for opt in opts] + option = Option(opts, dest, action=action, nargs=nargs, + const=const, obj=obj) + self._opt_prefixes.update(option.prefixes) + for opt in option._short_opts: + self._short_opt[opt] = option + for opt in option._long_opts: + self._long_opt[opt] = option + + def add_argument(self, dest, nargs=1, obj=None): + """Adds a positional argument named `dest` to the parser. + + The `obj` can be used to identify the option in the order list + that is returned from the parser. + """ + if obj is None: + obj = dest + self._args.append(Argument(dest=dest, nargs=nargs, obj=obj)) + + def parse_args(self, args): + """Parses positional arguments and returns ``(values, args, order)`` + for the parsed options and arguments as well as the leftover + arguments if there are any. The order is a list of objects as they + appear on the command line. If arguments appear multiple times they + will be memorized multiple times as well. + """ + state = ParsingState(args) + try: + self._process_args_for_options(state) + self._process_args_for_args(state) + except UsageError: + if self.ctx is None or not self.ctx.resilient_parsing: + raise + return state.opts, state.largs, state.order + + def _process_args_for_args(self, state): + pargs, args = _unpack_args(state.largs + state.rargs, + [x.nargs for x in self._args]) + + for idx, arg in enumerate(self._args): + arg.process(pargs[idx], state) + + state.largs = args + state.rargs = [] + + def _process_args_for_options(self, state): + while state.rargs: + arg = state.rargs.pop(0) + arglen = len(arg) + # Double dashes always handled explicitly regardless of what + # prefixes are valid. + if arg == '--': + return + elif arg[:1] in self._opt_prefixes and arglen > 1: + self._process_opts(arg, state) + elif self.allow_interspersed_args: + state.largs.append(arg) + else: + state.rargs.insert(0, arg) + return + + # Say this is the original argument list: + # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)] + # ^ + # (we are about to process arg(i)). + # + # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of + # [arg0, ..., arg(i-1)] (any options and their arguments will have + # been removed from largs). + # + # The while loop will usually consume 1 or more arguments per pass. + # If it consumes 1 (eg. arg is an option that takes no arguments), + # then after _process_arg() is done the situation is: + # + # largs = subset of [arg0, ..., arg(i)] + # rargs = [arg(i+1), ..., arg(N-1)] + # + # If allow_interspersed_args is false, largs will always be + # *empty* -- still a subset of [arg0, ..., arg(i-1)], but + # not a very interesting subset! + + def _match_long_opt(self, opt, explicit_value, state): + if opt not in self._long_opt: + possibilities = [word for word in self._long_opt + if word.startswith(opt)] + raise NoSuchOption(opt, possibilities=possibilities) + + option = self._long_opt[opt] + if option.takes_value: + # At this point it's safe to modify rargs by injecting the + # explicit value, because no exception is raised in this + # branch. This means that the inserted value will be fully + # consumed. + if explicit_value is not None: + state.rargs.insert(0, explicit_value) + + nargs = option.nargs + if len(state.rargs) < nargs: + _error_opt_args(nargs, opt) + elif nargs == 1: + value = state.rargs.pop(0) + else: + value = tuple(state.rargs[:nargs]) + del state.rargs[:nargs] + + elif explicit_value is not None: + raise BadOptionUsage('%s option does not take a value' % opt) + + else: + value = None + + option.process(value, state) + + def _match_short_opt(self, arg, state): + stop = False + i = 1 + prefix = arg[0] + unknown_options = [] + + for ch in arg[1:]: + opt = normalize_opt(prefix + ch, self.ctx) + option = self._short_opt.get(opt) + i += 1 + + if not option: + if self.ignore_unknown_options: + unknown_options.append(ch) + continue + raise NoSuchOption(opt) + if option.takes_value: + # Any characters left in arg? Pretend they're the + # next arg, and stop consuming characters of arg. + if i < len(arg): + state.rargs.insert(0, arg[i:]) + stop = True + + nargs = option.nargs + if len(state.rargs) < nargs: + _error_opt_args(nargs, opt) + elif nargs == 1: + value = state.rargs.pop(0) + else: + value = tuple(state.rargs[:nargs]) + del state.rargs[:nargs] + + else: + value = None + + option.process(value, state) + + if stop: + break + + # If we got any unknown options we re-combinate the string of the + # remaining options and re-attach the prefix, then report that + # to the state as new larg. This way there is basic combinatorics + # that can be achieved while still ignoring unknown arguments. + if self.ignore_unknown_options and unknown_options: + state.largs.append(prefix + ''.join(unknown_options)) + + def _process_opts(self, arg, state): + explicit_value = None + # Long option handling happens in two parts. The first part is + # supporting explicitly attached values. In any case, we will try + # to long match the option first. + if '=' in arg: + long_opt, explicit_value = arg.split('=', 1) + else: + long_opt = arg + norm_long_opt = normalize_opt(long_opt, self.ctx) + + # At this point we will match the (assumed) long option through + # the long option matching code. Note that this allows options + # like "-foo" to be matched as long options. + try: + self._match_long_opt(norm_long_opt, explicit_value, state) + except NoSuchOption: + # At this point the long option matching failed, and we need + # to try with short options. However there is a special rule + # which says, that if we have a two character options prefix + # (applies to "--foo" for instance), we do not dispatch to the + # short option code and will instead raise the no option + # error. + if arg[:2] not in self._opt_prefixes: + return self._match_short_opt(arg, state) + if not self.ignore_unknown_options: + raise + state.largs.append(arg) diff --git a/venv/lib/python2.7/site-packages/click/termui.py b/venv/lib/python2.7/site-packages/click/termui.py new file mode 100644 index 0000000..d9fba52 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/termui.py @@ -0,0 +1,539 @@ +import os +import sys +import struct + +from ._compat import raw_input, text_type, string_types, \ + isatty, strip_ansi, get_winterm_size, DEFAULT_COLUMNS, WIN +from .utils import echo +from .exceptions import Abort, UsageError +from .types import convert_type +from .globals import resolve_color_default + + +# The prompt functions to use. The doc tools currently override these +# functions to customize how they work. +visible_prompt_func = raw_input + +_ansi_colors = ('black', 'red', 'green', 'yellow', 'blue', 'magenta', + 'cyan', 'white', 'reset') +_ansi_reset_all = '\033[0m' + + +def hidden_prompt_func(prompt): + import getpass + return getpass.getpass(prompt) + + +def _build_prompt(text, suffix, show_default=False, default=None): + prompt = text + if default is not None and show_default: + prompt = '%s [%s]' % (prompt, default) + return prompt + suffix + + +def prompt(text, default=None, hide_input=False, + confirmation_prompt=False, type=None, + value_proc=None, prompt_suffix=': ', + show_default=True, err=False): + """Prompts a user for input. This is a convenience function that can + be used to prompt a user for input later. + + If the user aborts the input by sending a interrupt signal, this + function will catch it and raise a :exc:`Abort` exception. + + .. versionadded:: 6.0 + Added unicode support for cmd.exe on Windows. + + .. versionadded:: 4.0 + Added the `err` parameter. + + :param text: the text to show for the prompt. + :param default: the default value to use if no input happens. If this + is not given it will prompt until it's aborted. + :param hide_input: if this is set to true then the input value will + be hidden. + :param confirmation_prompt: asks for confirmation for the value. + :param type: the type to use to check the value against. + :param value_proc: if this parameter is provided it's a function that + is invoked instead of the type conversion to + convert a value. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + """ + result = None + + def prompt_func(text): + f = hide_input and hidden_prompt_func or visible_prompt_func + try: + # Write the prompt separately so that we get nice + # coloring through colorama on Windows + echo(text, nl=False, err=err) + return f('') + except (KeyboardInterrupt, EOFError): + # getpass doesn't print a newline if the user aborts input with ^C. + # Allegedly this behavior is inherited from getpass(3). + # A doc bug has been filed at https://bugs.python.org/issue24711 + if hide_input: + echo(None, err=err) + raise Abort() + + if value_proc is None: + value_proc = convert_type(type, default) + + prompt = _build_prompt(text, prompt_suffix, show_default, default) + + while 1: + while 1: + value = prompt_func(prompt) + if value: + break + # If a default is set and used, then the confirmation + # prompt is always skipped because that's the only thing + # that really makes sense. + elif default is not None: + return default + try: + result = value_proc(value) + except UsageError as e: + echo('Error: %s' % e.message, err=err) + continue + if not confirmation_prompt: + return result + while 1: + value2 = prompt_func('Repeat for confirmation: ') + if value2: + break + if value == value2: + return result + echo('Error: the two entered values do not match', err=err) + + +def confirm(text, default=False, abort=False, prompt_suffix=': ', + show_default=True, err=False): + """Prompts for confirmation (yes/no question). + + If the user aborts the input by sending a interrupt signal this + function will catch it and raise a :exc:`Abort` exception. + + .. versionadded:: 4.0 + Added the `err` parameter. + + :param text: the question to ask. + :param default: the default for the prompt. + :param abort: if this is set to `True` a negative answer aborts the + exception by raising :exc:`Abort`. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + """ + prompt = _build_prompt(text, prompt_suffix, show_default, + default and 'Y/n' or 'y/N') + while 1: + try: + # Write the prompt separately so that we get nice + # coloring through colorama on Windows + echo(prompt, nl=False, err=err) + value = visible_prompt_func('').lower().strip() + except (KeyboardInterrupt, EOFError): + raise Abort() + if value in ('y', 'yes'): + rv = True + elif value in ('n', 'no'): + rv = False + elif value == '': + rv = default + else: + echo('Error: invalid input', err=err) + continue + break + if abort and not rv: + raise Abort() + return rv + + +def get_terminal_size(): + """Returns the current size of the terminal as tuple in the form + ``(width, height)`` in columns and rows. + """ + # If shutil has get_terminal_size() (Python 3.3 and later) use that + if sys.version_info >= (3, 3): + import shutil + shutil_get_terminal_size = getattr(shutil, 'get_terminal_size', None) + if shutil_get_terminal_size: + sz = shutil_get_terminal_size() + return sz.columns, sz.lines + + if get_winterm_size is not None: + return get_winterm_size() + + def ioctl_gwinsz(fd): + try: + import fcntl + import termios + cr = struct.unpack( + 'hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234')) + except Exception: + return + return cr + + cr = ioctl_gwinsz(0) or ioctl_gwinsz(1) or ioctl_gwinsz(2) + if not cr: + try: + fd = os.open(os.ctermid(), os.O_RDONLY) + try: + cr = ioctl_gwinsz(fd) + finally: + os.close(fd) + except Exception: + pass + if not cr or not cr[0] or not cr[1]: + cr = (os.environ.get('LINES', 25), + os.environ.get('COLUMNS', DEFAULT_COLUMNS)) + return int(cr[1]), int(cr[0]) + + +def echo_via_pager(text, color=None): + """This function takes a text and shows it via an environment specific + pager on stdout. + + .. versionchanged:: 3.0 + Added the `color` flag. + + :param text: the text to page. + :param color: controls if the pager supports ANSI colors or not. The + default is autodetection. + """ + color = resolve_color_default(color) + if not isinstance(text, string_types): + text = text_type(text) + from ._termui_impl import pager + return pager(text + '\n', color) + + +def progressbar(iterable=None, length=None, label=None, show_eta=True, + show_percent=None, show_pos=False, + item_show_func=None, fill_char='#', empty_char='-', + bar_template='%(label)s [%(bar)s] %(info)s', + info_sep=' ', width=36, file=None, color=None): + """This function creates an iterable context manager that can be used + to iterate over something while showing a progress bar. It will + either iterate over the `iterable` or `length` items (that are counted + up). While iteration happens, this function will print a rendered + progress bar to the given `file` (defaults to stdout) and will attempt + to calculate remaining time and more. By default, this progress bar + will not be rendered if the file is not a terminal. + + The context manager creates the progress bar. When the context + manager is entered the progress bar is already displayed. With every + iteration over the progress bar, the iterable passed to the bar is + advanced and the bar is updated. When the context manager exits, + a newline is printed and the progress bar is finalized on screen. + + No printing must happen or the progress bar will be unintentionally + destroyed. + + Example usage:: + + with progressbar(items) as bar: + for item in bar: + do_something_with(item) + + Alternatively, if no iterable is specified, one can manually update the + progress bar through the `update()` method instead of directly + iterating over the progress bar. The update method accepts the number + of steps to increment the bar with:: + + with progressbar(length=chunks.total_bytes) as bar: + for chunk in chunks: + process_chunk(chunk) + bar.update(chunks.bytes) + + .. versionadded:: 2.0 + + .. versionadded:: 4.0 + Added the `color` parameter. Added a `update` method to the + progressbar object. + + :param iterable: an iterable to iterate over. If not provided the length + is required. + :param length: the number of items to iterate over. By default the + progressbar will attempt to ask the iterator about its + length, which might or might not work. If an iterable is + also provided this parameter can be used to override the + length. If an iterable is not provided the progress bar + will iterate over a range of that length. + :param label: the label to show next to the progress bar. + :param show_eta: enables or disables the estimated time display. This is + automatically disabled if the length cannot be + determined. + :param show_percent: enables or disables the percentage display. The + default is `True` if the iterable has a length or + `False` if not. + :param show_pos: enables or disables the absolute position display. The + default is `False`. + :param item_show_func: a function called with the current item which + can return a string to show the current item + next to the progress bar. Note that the current + item can be `None`! + :param fill_char: the character to use to show the filled part of the + progress bar. + :param empty_char: the character to use to show the non-filled part of + the progress bar. + :param bar_template: the format string to use as template for the bar. + The parameters in it are ``label`` for the label, + ``bar`` for the progress bar and ``info`` for the + info section. + :param info_sep: the separator between multiple info items (eta etc.) + :param width: the width of the progress bar in characters, 0 means full + terminal width + :param file: the file to write to. If this is not a terminal then + only the label is printed. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are included anywhere in the progress bar output + which is not the case by default. + """ + from ._termui_impl import ProgressBar + color = resolve_color_default(color) + return ProgressBar(iterable=iterable, length=length, show_eta=show_eta, + show_percent=show_percent, show_pos=show_pos, + item_show_func=item_show_func, fill_char=fill_char, + empty_char=empty_char, bar_template=bar_template, + info_sep=info_sep, file=file, label=label, + width=width, color=color) + + +def clear(): + """Clears the terminal screen. This will have the effect of clearing + the whole visible space of the terminal and moving the cursor to the + top left. This does not do anything if not connected to a terminal. + + .. versionadded:: 2.0 + """ + if not isatty(sys.stdout): + return + # If we're on Windows and we don't have colorama available, then we + # clear the screen by shelling out. Otherwise we can use an escape + # sequence. + if WIN: + os.system('cls') + else: + sys.stdout.write('\033[2J\033[1;1H') + + +def style(text, fg=None, bg=None, bold=None, dim=None, underline=None, + blink=None, reverse=None, reset=True): + """Styles a text with ANSI styles and returns the new string. By + default the styling is self contained which means that at the end + of the string a reset code is issued. This can be prevented by + passing ``reset=False``. + + Examples:: + + click.echo(click.style('Hello World!', fg='green')) + click.echo(click.style('ATTENTION!', blink=True)) + click.echo(click.style('Some things', reverse=True, fg='cyan')) + + Supported color names: + + * ``black`` (might be a gray) + * ``red`` + * ``green`` + * ``yellow`` (might be an orange) + * ``blue`` + * ``magenta`` + * ``cyan`` + * ``white`` (might be light gray) + * ``reset`` (reset the color code only) + + .. versionadded:: 2.0 + + :param text: the string to style with ansi codes. + :param fg: if provided this will become the foreground color. + :param bg: if provided this will become the background color. + :param bold: if provided this will enable or disable bold mode. + :param dim: if provided this will enable or disable dim mode. This is + badly supported. + :param underline: if provided this will enable or disable underline. + :param blink: if provided this will enable or disable blinking. + :param reverse: if provided this will enable or disable inverse + rendering (foreground becomes background and the + other way round). + :param reset: by default a reset-all code is added at the end of the + string which means that styles do not carry over. This + can be disabled to compose styles. + """ + bits = [] + if fg: + try: + bits.append('\033[%dm' % (_ansi_colors.index(fg) + 30)) + except ValueError: + raise TypeError('Unknown color %r' % fg) + if bg: + try: + bits.append('\033[%dm' % (_ansi_colors.index(bg) + 40)) + except ValueError: + raise TypeError('Unknown color %r' % bg) + if bold is not None: + bits.append('\033[%dm' % (1 if bold else 22)) + if dim is not None: + bits.append('\033[%dm' % (2 if dim else 22)) + if underline is not None: + bits.append('\033[%dm' % (4 if underline else 24)) + if blink is not None: + bits.append('\033[%dm' % (5 if blink else 25)) + if reverse is not None: + bits.append('\033[%dm' % (7 if reverse else 27)) + bits.append(text) + if reset: + bits.append(_ansi_reset_all) + return ''.join(bits) + + +def unstyle(text): + """Removes ANSI styling information from a string. Usually it's not + necessary to use this function as Click's echo function will + automatically remove styling if necessary. + + .. versionadded:: 2.0 + + :param text: the text to remove style information from. + """ + return strip_ansi(text) + + +def secho(text, file=None, nl=True, err=False, color=None, **styles): + """This function combines :func:`echo` and :func:`style` into one + call. As such the following two calls are the same:: + + click.secho('Hello World!', fg='green') + click.echo(click.style('Hello World!', fg='green')) + + All keyword arguments are forwarded to the underlying functions + depending on which one they go with. + + .. versionadded:: 2.0 + """ + return echo(style(text, **styles), file=file, nl=nl, err=err, color=color) + + +def edit(text=None, editor=None, env=None, require_save=True, + extension='.txt', filename=None): + r"""Edits the given text in the defined editor. If an editor is given + (should be the full path to the executable but the regular operating + system search path is used for finding the executable) it overrides + the detected editor. Optionally, some environment variables can be + used. If the editor is closed without changes, `None` is returned. In + case a file is edited directly the return value is always `None` and + `require_save` and `extension` are ignored. + + If the editor cannot be opened a :exc:`UsageError` is raised. + + Note for Windows: to simplify cross-platform usage, the newlines are + automatically converted from POSIX to Windows and vice versa. As such, + the message here will have ``\n`` as newline markers. + + :param text: the text to edit. + :param editor: optionally the editor to use. Defaults to automatic + detection. + :param env: environment variables to forward to the editor. + :param require_save: if this is true, then not saving in the editor + will make the return value become `None`. + :param extension: the extension to tell the editor about. This defaults + to `.txt` but changing this might change syntax + highlighting. + :param filename: if provided it will edit this file instead of the + provided text contents. It will not use a temporary + file as an indirection in that case. + """ + from ._termui_impl import Editor + editor = Editor(editor=editor, env=env, require_save=require_save, + extension=extension) + if filename is None: + return editor.edit(text) + editor.edit_file(filename) + + +def launch(url, wait=False, locate=False): + """This function launches the given URL (or filename) in the default + viewer application for this file type. If this is an executable, it + might launch the executable in a new session. The return value is + the exit code of the launched application. Usually, ``0`` indicates + success. + + Examples:: + + click.launch('http://click.pocoo.org/') + click.launch('/my/downloaded/file', locate=True) + + .. versionadded:: 2.0 + + :param url: URL or filename of the thing to launch. + :param wait: waits for the program to stop. + :param locate: if this is set to `True` then instead of launching the + application associated with the URL it will attempt to + launch a file manager with the file located. This + might have weird effects if the URL does not point to + the filesystem. + """ + from ._termui_impl import open_url + return open_url(url, wait=wait, locate=locate) + + +# If this is provided, getchar() calls into this instead. This is used +# for unittesting purposes. +_getchar = None + + +def getchar(echo=False): + """Fetches a single character from the terminal and returns it. This + will always return a unicode character and under certain rare + circumstances this might return more than one character. The + situations which more than one character is returned is when for + whatever reason multiple characters end up in the terminal buffer or + standard input was not actually a terminal. + + Note that this will always read from the terminal, even if something + is piped into the standard input. + + .. versionadded:: 2.0 + + :param echo: if set to `True`, the character read will also show up on + the terminal. The default is to not show it. + """ + f = _getchar + if f is None: + from ._termui_impl import getchar as f + return f(echo) + + +def pause(info='Press any key to continue ...', err=False): + """This command stops execution and waits for the user to press any + key to continue. This is similar to the Windows batch "pause" + command. If the program is not run through a terminal, this command + will instead do nothing. + + .. versionadded:: 2.0 + + .. versionadded:: 4.0 + Added the `err` parameter. + + :param info: the info string to print before pausing. + :param err: if set to message goes to ``stderr`` instead of + ``stdout``, the same as with echo. + """ + if not isatty(sys.stdin) or not isatty(sys.stdout): + return + try: + if info: + echo(info, nl=False, err=err) + try: + getchar() + except (KeyboardInterrupt, EOFError): + pass + finally: + if info: + echo(err=err) diff --git a/venv/lib/python2.7/site-packages/click/testing.py b/venv/lib/python2.7/site-packages/click/testing.py new file mode 100644 index 0000000..4416c77 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/testing.py @@ -0,0 +1,322 @@ +import os +import sys +import shutil +import tempfile +import contextlib + +from ._compat import iteritems, PY2 + + +# If someone wants to vendor click, we want to ensure the +# correct package is discovered. Ideally we could use a +# relative import here but unfortunately Python does not +# support that. +clickpkg = sys.modules[__name__.rsplit('.', 1)[0]] + + +if PY2: + from cStringIO import StringIO +else: + import io + from ._compat import _find_binary_reader + + +class EchoingStdin(object): + + def __init__(self, input, output): + self._input = input + self._output = output + + def __getattr__(self, x): + return getattr(self._input, x) + + def _echo(self, rv): + self._output.write(rv) + return rv + + def read(self, n=-1): + return self._echo(self._input.read(n)) + + def readline(self, n=-1): + return self._echo(self._input.readline(n)) + + def readlines(self): + return [self._echo(x) for x in self._input.readlines()] + + def __iter__(self): + return iter(self._echo(x) for x in self._input) + + def __repr__(self): + return repr(self._input) + + +def make_input_stream(input, charset): + # Is already an input stream. + if hasattr(input, 'read'): + if PY2: + return input + rv = _find_binary_reader(input) + if rv is not None: + return rv + raise TypeError('Could not find binary reader for input stream.') + + if input is None: + input = b'' + elif not isinstance(input, bytes): + input = input.encode(charset) + if PY2: + return StringIO(input) + return io.BytesIO(input) + + +class Result(object): + """Holds the captured result of an invoked CLI script.""" + + def __init__(self, runner, output_bytes, exit_code, exception, + exc_info=None): + #: The runner that created the result + self.runner = runner + #: The output as bytes. + self.output_bytes = output_bytes + #: The exit code as integer. + self.exit_code = exit_code + #: The exception that happend if one did. + self.exception = exception + #: The traceback + self.exc_info = exc_info + + @property + def output(self): + """The output as unicode string.""" + return self.output_bytes.decode(self.runner.charset, 'replace') \ + .replace('\r\n', '\n') + + def __repr__(self): + return '' % ( + self.exception and repr(self.exception) or 'okay', + ) + + +class CliRunner(object): + """The CLI runner provides functionality to invoke a Click command line + script for unittesting purposes in a isolated environment. This only + works in single-threaded systems without any concurrency as it changes the + global interpreter state. + + :param charset: the character set for the input and output data. This is + UTF-8 by default and should not be changed currently as + the reporting to Click only works in Python 2 properly. + :param env: a dictionary with environment variables for overriding. + :param echo_stdin: if this is set to `True`, then reading from stdin writes + to stdout. This is useful for showing examples in + some circumstances. Note that regular prompts + will automatically echo the input. + """ + + def __init__(self, charset=None, env=None, echo_stdin=False): + if charset is None: + charset = 'utf-8' + self.charset = charset + self.env = env or {} + self.echo_stdin = echo_stdin + + def get_default_prog_name(self, cli): + """Given a command object it will return the default program name + for it. The default is the `name` attribute or ``"root"`` if not + set. + """ + return cli.name or 'root' + + def make_env(self, overrides=None): + """Returns the environment overrides for invoking a script.""" + rv = dict(self.env) + if overrides: + rv.update(overrides) + return rv + + @contextlib.contextmanager + def isolation(self, input=None, env=None, color=False): + """A context manager that sets up the isolation for invoking of a + command line tool. This sets up stdin with the given input data + and `os.environ` with the overrides from the given dictionary. + This also rebinds some internals in Click to be mocked (like the + prompt functionality). + + This is automatically done in the :meth:`invoke` method. + + .. versionadded:: 4.0 + The ``color`` parameter was added. + + :param input: the input stream to put into sys.stdin. + :param env: the environment overrides as dictionary. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + """ + input = make_input_stream(input, self.charset) + + old_stdin = sys.stdin + old_stdout = sys.stdout + old_stderr = sys.stderr + old_forced_width = clickpkg.formatting.FORCED_WIDTH + clickpkg.formatting.FORCED_WIDTH = 80 + + env = self.make_env(env) + + if PY2: + sys.stdout = sys.stderr = bytes_output = StringIO() + if self.echo_stdin: + input = EchoingStdin(input, bytes_output) + else: + bytes_output = io.BytesIO() + if self.echo_stdin: + input = EchoingStdin(input, bytes_output) + input = io.TextIOWrapper(input, encoding=self.charset) + sys.stdout = sys.stderr = io.TextIOWrapper( + bytes_output, encoding=self.charset) + + sys.stdin = input + + def visible_input(prompt=None): + sys.stdout.write(prompt or '') + val = input.readline().rstrip('\r\n') + sys.stdout.write(val + '\n') + sys.stdout.flush() + return val + + def hidden_input(prompt=None): + sys.stdout.write((prompt or '') + '\n') + sys.stdout.flush() + return input.readline().rstrip('\r\n') + + def _getchar(echo): + char = sys.stdin.read(1) + if echo: + sys.stdout.write(char) + sys.stdout.flush() + return char + + default_color = color + def should_strip_ansi(stream=None, color=None): + if color is None: + return not default_color + return not color + + old_visible_prompt_func = clickpkg.termui.visible_prompt_func + old_hidden_prompt_func = clickpkg.termui.hidden_prompt_func + old__getchar_func = clickpkg.termui._getchar + old_should_strip_ansi = clickpkg.utils.should_strip_ansi + clickpkg.termui.visible_prompt_func = visible_input + clickpkg.termui.hidden_prompt_func = hidden_input + clickpkg.termui._getchar = _getchar + clickpkg.utils.should_strip_ansi = should_strip_ansi + + old_env = {} + try: + for key, value in iteritems(env): + old_env[key] = os.environ.get(key) + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + yield bytes_output + finally: + for key, value in iteritems(old_env): + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + sys.stdout = old_stdout + sys.stderr = old_stderr + sys.stdin = old_stdin + clickpkg.termui.visible_prompt_func = old_visible_prompt_func + clickpkg.termui.hidden_prompt_func = old_hidden_prompt_func + clickpkg.termui._getchar = old__getchar_func + clickpkg.utils.should_strip_ansi = old_should_strip_ansi + clickpkg.formatting.FORCED_WIDTH = old_forced_width + + def invoke(self, cli, args=None, input=None, env=None, + catch_exceptions=True, color=False, **extra): + """Invokes a command in an isolated environment. The arguments are + forwarded directly to the command line script, the `extra` keyword + arguments are passed to the :meth:`~clickpkg.Command.main` function of + the command. + + This returns a :class:`Result` object. + + .. versionadded:: 3.0 + The ``catch_exceptions`` parameter was added. + + .. versionchanged:: 3.0 + The result object now has an `exc_info` attribute with the + traceback if available. + + .. versionadded:: 4.0 + The ``color`` parameter was added. + + :param cli: the command to invoke + :param args: the arguments to invoke + :param input: the input data for `sys.stdin`. + :param env: the environment overrides. + :param catch_exceptions: Whether to catch any other exceptions than + ``SystemExit``. + :param extra: the keyword arguments to pass to :meth:`main`. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + """ + exc_info = None + with self.isolation(input=input, env=env, color=color) as out: + exception = None + exit_code = 0 + + try: + cli.main(args=args or (), + prog_name=self.get_default_prog_name(cli), **extra) + except SystemExit as e: + if e.code != 0: + exception = e + + exc_info = sys.exc_info() + + exit_code = e.code + if not isinstance(exit_code, int): + sys.stdout.write(str(exit_code)) + sys.stdout.write('\n') + exit_code = 1 + except Exception as e: + if not catch_exceptions: + raise + exception = e + exit_code = -1 + exc_info = sys.exc_info() + finally: + sys.stdout.flush() + output = out.getvalue() + + return Result(runner=self, + output_bytes=output, + exit_code=exit_code, + exception=exception, + exc_info=exc_info) + + @contextlib.contextmanager + def isolated_filesystem(self): + """A context manager that creates a temporary folder and changes + the current working directory to it for isolated filesystem tests. + """ + cwd = os.getcwd() + t = tempfile.mkdtemp() + os.chdir(t) + try: + yield t + finally: + os.chdir(cwd) + try: + shutil.rmtree(t) + except (OSError, IOError): + pass diff --git a/venv/lib/python2.7/site-packages/click/types.py b/venv/lib/python2.7/site-packages/click/types.py new file mode 100644 index 0000000..3639002 --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/types.py @@ -0,0 +1,550 @@ +import os +import stat + +from ._compat import open_stream, text_type, filename_to_ui, \ + get_filesystem_encoding, get_streerror, _get_argv_encoding, PY2 +from .exceptions import BadParameter +from .utils import safecall, LazyFile + + +class ParamType(object): + """Helper for converting values through types. The following is + necessary for a valid type: + + * it needs a name + * it needs to pass through None unchanged + * it needs to convert from a string + * it needs to convert its result type through unchanged + (eg: needs to be idempotent) + * it needs to be able to deal with param and context being `None`. + This can be the case when the object is used with prompt + inputs. + """ + is_composite = False + + #: the descriptive name of this type + name = None + + #: if a list of this type is expected and the value is pulled from a + #: string environment variable, this is what splits it up. `None` + #: means any whitespace. For all parameters the general rule is that + #: whitespace splits them up. The exception are paths and files which + #: are split by ``os.path.pathsep`` by default (":" on Unix and ";" on + #: Windows). + envvar_list_splitter = None + + def __call__(self, value, param=None, ctx=None): + if value is not None: + return self.convert(value, param, ctx) + + def get_metavar(self, param): + """Returns the metavar default for this param if it provides one.""" + + def get_missing_message(self, param): + """Optionally might return extra information about a missing + parameter. + + .. versionadded:: 2.0 + """ + + def convert(self, value, param, ctx): + """Converts the value. This is not invoked for values that are + `None` (the missing value). + """ + return value + + def split_envvar_value(self, rv): + """Given a value from an environment variable this splits it up + into small chunks depending on the defined envvar list splitter. + + If the splitter is set to `None`, which means that whitespace splits, + then leading and trailing whitespace is ignored. Otherwise, leading + and trailing splitters usually lead to empty items being included. + """ + return (rv or '').split(self.envvar_list_splitter) + + def fail(self, message, param=None, ctx=None): + """Helper method to fail with an invalid value message.""" + raise BadParameter(message, ctx=ctx, param=param) + + +class CompositeParamType(ParamType): + is_composite = True + + @property + def arity(self): + raise NotImplementedError() + + +class FuncParamType(ParamType): + + def __init__(self, func): + self.name = func.__name__ + self.func = func + + def convert(self, value, param, ctx): + try: + return self.func(value) + except ValueError: + try: + value = text_type(value) + except UnicodeError: + value = str(value).decode('utf-8', 'replace') + self.fail(value, param, ctx) + + +class UnprocessedParamType(ParamType): + name = 'text' + + def convert(self, value, param, ctx): + return value + + def __repr__(self): + return 'UNPROCESSED' + + +class StringParamType(ParamType): + name = 'text' + + def convert(self, value, param, ctx): + if isinstance(value, bytes): + enc = _get_argv_encoding() + try: + value = value.decode(enc) + except UnicodeError: + fs_enc = get_filesystem_encoding() + if fs_enc != enc: + try: + value = value.decode(fs_enc) + except UnicodeError: + value = value.decode('utf-8', 'replace') + return value + return value + + def __repr__(self): + return 'STRING' + + +class Choice(ParamType): + """The choice type allows a value to be checked against a fixed set of + supported values. All of these values have to be strings. + + See :ref:`choice-opts` for an example. + """ + name = 'choice' + + def __init__(self, choices): + self.choices = choices + + def get_metavar(self, param): + return '[%s]' % '|'.join(self.choices) + + def get_missing_message(self, param): + return 'Choose from %s.' % ', '.join(self.choices) + + def convert(self, value, param, ctx): + # Exact match + if value in self.choices: + return value + + # Match through normalization + if ctx is not None and \ + ctx.token_normalize_func is not None: + value = ctx.token_normalize_func(value) + for choice in self.choices: + if ctx.token_normalize_func(choice) == value: + return choice + + self.fail('invalid choice: %s. (choose from %s)' % + (value, ', '.join(self.choices)), param, ctx) + + def __repr__(self): + return 'Choice(%r)' % list(self.choices) + + +class IntParamType(ParamType): + name = 'integer' + + def convert(self, value, param, ctx): + try: + return int(value) + except (ValueError, UnicodeError): + self.fail('%s is not a valid integer' % value, param, ctx) + + def __repr__(self): + return 'INT' + + +class IntRange(IntParamType): + """A parameter that works similar to :data:`click.INT` but restricts + the value to fit into a range. The default behavior is to fail if the + value falls outside the range, but it can also be silently clamped + between the two edges. + + See :ref:`ranges` for an example. + """ + name = 'integer range' + + def __init__(self, min=None, max=None, clamp=False): + self.min = min + self.max = max + self.clamp = clamp + + def convert(self, value, param, ctx): + rv = IntParamType.convert(self, value, param, ctx) + if self.clamp: + if self.min is not None and rv < self.min: + return self.min + if self.max is not None and rv > self.max: + return self.max + if self.min is not None and rv < self.min or \ + self.max is not None and rv > self.max: + if self.min is None: + self.fail('%s is bigger than the maximum valid value ' + '%s.' % (rv, self.max), param, ctx) + elif self.max is None: + self.fail('%s is smaller than the minimum valid value ' + '%s.' % (rv, self.min), param, ctx) + else: + self.fail('%s is not in the valid range of %s to %s.' + % (rv, self.min, self.max), param, ctx) + return rv + + def __repr__(self): + return 'IntRange(%r, %r)' % (self.min, self.max) + + +class BoolParamType(ParamType): + name = 'boolean' + + def convert(self, value, param, ctx): + if isinstance(value, bool): + return bool(value) + value = value.lower() + if value in ('true', '1', 'yes', 'y'): + return True + elif value in ('false', '0', 'no', 'n'): + return False + self.fail('%s is not a valid boolean' % value, param, ctx) + + def __repr__(self): + return 'BOOL' + + +class FloatParamType(ParamType): + name = 'float' + + def convert(self, value, param, ctx): + try: + return float(value) + except (UnicodeError, ValueError): + self.fail('%s is not a valid floating point value' % + value, param, ctx) + + def __repr__(self): + return 'FLOAT' + + +class UUIDParameterType(ParamType): + name = 'uuid' + + def convert(self, value, param, ctx): + import uuid + try: + if PY2 and isinstance(value, text_type): + value = value.encode('ascii') + return uuid.UUID(value) + except (UnicodeError, ValueError): + self.fail('%s is not a valid UUID value' % value, param, ctx) + + def __repr__(self): + return 'UUID' + + +class File(ParamType): + """Declares a parameter to be a file for reading or writing. The file + is automatically closed once the context tears down (after the command + finished working). + + Files can be opened for reading or writing. The special value ``-`` + indicates stdin or stdout depending on the mode. + + By default, the file is opened for reading text data, but it can also be + opened in binary mode or for writing. The encoding parameter can be used + to force a specific encoding. + + The `lazy` flag controls if the file should be opened immediately or + upon first IO. The default is to be non lazy for standard input and + output streams as well as files opened for reading, lazy otherwise. + + Starting with Click 2.0, files can also be opened atomically in which + case all writes go into a separate file in the same folder and upon + completion the file will be moved over to the original location. This + is useful if a file regularly read by other users is modified. + + See :ref:`file-args` for more information. + """ + name = 'filename' + envvar_list_splitter = os.path.pathsep + + def __init__(self, mode='r', encoding=None, errors='strict', lazy=None, + atomic=False): + self.mode = mode + self.encoding = encoding + self.errors = errors + self.lazy = lazy + self.atomic = atomic + + def resolve_lazy_flag(self, value): + if self.lazy is not None: + return self.lazy + if value == '-': + return False + elif 'w' in self.mode: + return True + return False + + def convert(self, value, param, ctx): + try: + if hasattr(value, 'read') or hasattr(value, 'write'): + return value + + lazy = self.resolve_lazy_flag(value) + + if lazy: + f = LazyFile(value, self.mode, self.encoding, self.errors, + atomic=self.atomic) + if ctx is not None: + ctx.call_on_close(f.close_intelligently) + return f + + f, should_close = open_stream(value, self.mode, + self.encoding, self.errors, + atomic=self.atomic) + # If a context is provided, we automatically close the file + # at the end of the context execution (or flush out). If a + # context does not exist, it's the caller's responsibility to + # properly close the file. This for instance happens when the + # type is used with prompts. + if ctx is not None: + if should_close: + ctx.call_on_close(safecall(f.close)) + else: + ctx.call_on_close(safecall(f.flush)) + return f + except (IOError, OSError) as e: + self.fail('Could not open file: %s: %s' % ( + filename_to_ui(value), + get_streerror(e), + ), param, ctx) + + +class Path(ParamType): + """The path type is similar to the :class:`File` type but it performs + different checks. First of all, instead of returning an open file + handle it returns just the filename. Secondly, it can perform various + basic checks about what the file or directory should be. + + .. versionchanged:: 6.0 + `allow_dash` was added. + + :param exists: if set to true, the file or directory needs to exist for + this value to be valid. If this is not required and a + file does indeed not exist, then all further checks are + silently skipped. + :param file_okay: controls if a file is a possible value. + :param dir_okay: controls if a directory is a possible value. + :param writable: if true, a writable check is performed. + :param readable: if true, a readable check is performed. + :param resolve_path: if this is true, then the path is fully resolved + before the value is passed onwards. This means + that it's absolute and symlinks are resolved. + :param allow_dash: If this is set to `True`, a single dash to indicate + standard streams is permitted. + :param type: optionally a string type that should be used to + represent the path. The default is `None` which + means the return value will be either bytes or + unicode depending on what makes most sense given the + input data Click deals with. + """ + envvar_list_splitter = os.path.pathsep + + def __init__(self, exists=False, file_okay=True, dir_okay=True, + writable=False, readable=True, resolve_path=False, + allow_dash=False, path_type=None): + self.exists = exists + self.file_okay = file_okay + self.dir_okay = dir_okay + self.writable = writable + self.readable = readable + self.resolve_path = resolve_path + self.allow_dash = allow_dash + self.type = path_type + + if self.file_okay and not self.dir_okay: + self.name = 'file' + self.path_type = 'File' + if self.dir_okay and not self.file_okay: + self.name = 'directory' + self.path_type = 'Directory' + else: + self.name = 'path' + self.path_type = 'Path' + + def coerce_path_result(self, rv): + if self.type is not None and not isinstance(rv, self.type): + if self.type is text_type: + rv = rv.decode(get_filesystem_encoding()) + else: + rv = rv.encode(get_filesystem_encoding()) + return rv + + def convert(self, value, param, ctx): + rv = value + + is_dash = self.file_okay and self.allow_dash and rv in (b'-', '-') + + if not is_dash: + if self.resolve_path: + rv = os.path.realpath(rv) + + try: + st = os.stat(rv) + except OSError: + if not self.exists: + return self.coerce_path_result(rv) + self.fail('%s "%s" does not exist.' % ( + self.path_type, + filename_to_ui(value) + ), param, ctx) + + if not self.file_okay and stat.S_ISREG(st.st_mode): + self.fail('%s "%s" is a file.' % ( + self.path_type, + filename_to_ui(value) + ), param, ctx) + if not self.dir_okay and stat.S_ISDIR(st.st_mode): + self.fail('%s "%s" is a directory.' % ( + self.path_type, + filename_to_ui(value) + ), param, ctx) + if self.writable and not os.access(value, os.W_OK): + self.fail('%s "%s" is not writable.' % ( + self.path_type, + filename_to_ui(value) + ), param, ctx) + if self.readable and not os.access(value, os.R_OK): + self.fail('%s "%s" is not readable.' % ( + self.path_type, + filename_to_ui(value) + ), param, ctx) + + return self.coerce_path_result(rv) + + +class Tuple(CompositeParamType): + """The default behavior of Click is to apply a type on a value directly. + This works well in most cases, except for when `nargs` is set to a fixed + count and different types should be used for different items. In this + case the :class:`Tuple` type can be used. This type can only be used + if `nargs` is set to a fixed number. + + For more information see :ref:`tuple-type`. + + This can be selected by using a Python tuple literal as a type. + + :param types: a list of types that should be used for the tuple items. + """ + + def __init__(self, types): + self.types = [convert_type(ty) for ty in types] + + @property + def name(self): + return "<" + " ".join(ty.name for ty in self.types) + ">" + + @property + def arity(self): + return len(self.types) + + def convert(self, value, param, ctx): + if len(value) != len(self.types): + raise TypeError('It would appear that nargs is set to conflict ' + 'with the composite type arity.') + return tuple(ty(x, param, ctx) for ty, x in zip(self.types, value)) + + +def convert_type(ty, default=None): + """Converts a callable or python ty into the most appropriate param + ty. + """ + guessed_type = False + if ty is None and default is not None: + if isinstance(default, tuple): + ty = tuple(map(type, default)) + else: + ty = type(default) + guessed_type = True + + if isinstance(ty, tuple): + return Tuple(ty) + if isinstance(ty, ParamType): + return ty + if ty is text_type or ty is str or ty is None: + return STRING + if ty is int: + return INT + # Booleans are only okay if not guessed. This is done because for + # flags the default value is actually a bit of a lie in that it + # indicates which of the flags is the one we want. See get_default() + # for more information. + if ty is bool and not guessed_type: + return BOOL + if ty is float: + return FLOAT + if guessed_type: + return STRING + + # Catch a common mistake + if __debug__: + try: + if issubclass(ty, ParamType): + raise AssertionError('Attempted to use an uninstantiated ' + 'parameter type (%s).' % ty) + except TypeError: + pass + return FuncParamType(ty) + + +#: A dummy parameter type that just does nothing. From a user's +#: perspective this appears to just be the same as `STRING` but internally +#: no string conversion takes place. This is necessary to achieve the +#: same bytes/unicode behavior on Python 2/3 in situations where you want +#: to not convert argument types. This is usually useful when working +#: with file paths as they can appear in bytes and unicode. +#: +#: For path related uses the :class:`Path` type is a better choice but +#: there are situations where an unprocessed type is useful which is why +#: it is is provided. +#: +#: .. versionadded:: 4.0 +UNPROCESSED = UnprocessedParamType() + +#: A unicode string parameter type which is the implicit default. This +#: can also be selected by using ``str`` as type. +STRING = StringParamType() + +#: An integer parameter. This can also be selected by using ``int`` as +#: type. +INT = IntParamType() + +#: A floating point value parameter. This can also be selected by using +#: ``float`` as type. +FLOAT = FloatParamType() + +#: A boolean parameter. This is the default for boolean flags. This can +#: also be selected by using ``bool`` as a type. +BOOL = BoolParamType() + +#: A UUID parameter. +UUID = UUIDParameterType() diff --git a/venv/lib/python2.7/site-packages/click/utils.py b/venv/lib/python2.7/site-packages/click/utils.py new file mode 100644 index 0000000..eee626d --- /dev/null +++ b/venv/lib/python2.7/site-packages/click/utils.py @@ -0,0 +1,415 @@ +import os +import sys + +from .globals import resolve_color_default + +from ._compat import text_type, open_stream, get_filesystem_encoding, \ + get_streerror, string_types, PY2, binary_streams, text_streams, \ + filename_to_ui, auto_wrap_for_ansi, strip_ansi, should_strip_ansi, \ + _default_text_stdout, _default_text_stderr, is_bytes, WIN + +if not PY2: + from ._compat import _find_binary_writer +elif WIN: + from ._winconsole import _get_windows_argv, \ + _hash_py_argv, _initial_argv_hash + + +echo_native_types = string_types + (bytes, bytearray) + + +def _posixify(name): + return '-'.join(name.split()).lower() + + +def safecall(func): + """Wraps a function so that it swallows exceptions.""" + def wrapper(*args, **kwargs): + try: + return func(*args, **kwargs) + except Exception: + pass + return wrapper + + +def make_str(value): + """Converts a value into a valid string.""" + if isinstance(value, bytes): + try: + return value.decode(get_filesystem_encoding()) + except UnicodeError: + return value.decode('utf-8', 'replace') + return text_type(value) + + +def make_default_short_help(help, max_length=45): + words = help.split() + total_length = 0 + result = [] + done = False + + for word in words: + if word[-1:] == '.': + done = True + new_length = result and 1 + len(word) or len(word) + if total_length + new_length > max_length: + result.append('...') + done = True + else: + if result: + result.append(' ') + result.append(word) + if done: + break + total_length += new_length + + return ''.join(result) + + +class LazyFile(object): + """A lazy file works like a regular file but it does not fully open + the file but it does perform some basic checks early to see if the + filename parameter does make sense. This is useful for safely opening + files for writing. + """ + + def __init__(self, filename, mode='r', encoding=None, errors='strict', + atomic=False): + self.name = filename + self.mode = mode + self.encoding = encoding + self.errors = errors + self.atomic = atomic + + if filename == '-': + self._f, self.should_close = open_stream(filename, mode, + encoding, errors) + else: + if 'r' in mode: + # Open and close the file in case we're opening it for + # reading so that we can catch at least some errors in + # some cases early. + open(filename, mode).close() + self._f = None + self.should_close = True + + def __getattr__(self, name): + return getattr(self.open(), name) + + def __repr__(self): + if self._f is not None: + return repr(self._f) + return '' % (self.name, self.mode) + + def open(self): + """Opens the file if it's not yet open. This call might fail with + a :exc:`FileError`. Not handling this error will produce an error + that Click shows. + """ + if self._f is not None: + return self._f + try: + rv, self.should_close = open_stream(self.name, self.mode, + self.encoding, + self.errors, + atomic=self.atomic) + except (IOError, OSError) as e: + from .exceptions import FileError + raise FileError(self.name, hint=get_streerror(e)) + self._f = rv + return rv + + def close(self): + """Closes the underlying file, no matter what.""" + if self._f is not None: + self._f.close() + + def close_intelligently(self): + """This function only closes the file if it was opened by the lazy + file wrapper. For instance this will never close stdin. + """ + if self.should_close: + self.close() + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, tb): + self.close_intelligently() + + def __iter__(self): + self.open() + return iter(self._f) + + +class KeepOpenFile(object): + + def __init__(self, file): + self._file = file + + def __getattr__(self, name): + return getattr(self._file, name) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, tb): + pass + + def __repr__(self): + return repr(self._file) + + def __iter__(self): + return iter(self._file) + + +def echo(message=None, file=None, nl=True, err=False, color=None): + """Prints a message plus a newline to the given file or stdout. On + first sight, this looks like the print function, but it has improved + support for handling Unicode and binary data that does not fail no + matter how badly configured the system is. + + Primarily it means that you can print binary data as well as Unicode + data on both 2.x and 3.x to the given file in the most appropriate way + possible. This is a very carefree function as in that it will try its + best to not fail. As of Click 6.0 this includes support for unicode + output on the Windows console. + + In addition to that, if `colorama`_ is installed, the echo function will + also support clever handling of ANSI codes. Essentially it will then + do the following: + + - add transparent handling of ANSI color codes on Windows. + - hide ANSI codes automatically if the destination file is not a + terminal. + + .. _colorama: http://pypi.python.org/pypi/colorama + + .. versionchanged:: 6.0 + As of Click 6.0 the echo function will properly support unicode + output on the windows console. Not that click does not modify + the interpreter in any way which means that `sys.stdout` or the + print statement or function will still not provide unicode support. + + .. versionchanged:: 2.0 + Starting with version 2.0 of Click, the echo function will work + with colorama if it's installed. + + .. versionadded:: 3.0 + The `err` parameter was added. + + .. versionchanged:: 4.0 + Added the `color` flag. + + :param message: the message to print + :param file: the file to write to (defaults to ``stdout``) + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``. This is faster and easier than calling + :func:`get_text_stderr` yourself. + :param nl: if set to `True` (the default) a newline is printed afterwards. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. + """ + if file is None: + if err: + file = _default_text_stderr() + else: + file = _default_text_stdout() + + # Convert non bytes/text into the native string type. + if message is not None and not isinstance(message, echo_native_types): + message = text_type(message) + + if nl: + message = message or u'' + if isinstance(message, text_type): + message += u'\n' + else: + message += b'\n' + + # If there is a message, and we're in Python 3, and the value looks + # like bytes, we manually need to find the binary stream and write the + # message in there. This is done separately so that most stream + # types will work as you would expect. Eg: you can write to StringIO + # for other cases. + if message and not PY2 and is_bytes(message): + binary_file = _find_binary_writer(file) + if binary_file is not None: + file.flush() + binary_file.write(message) + binary_file.flush() + return + + # ANSI-style support. If there is no message or we are dealing with + # bytes nothing is happening. If we are connected to a file we want + # to strip colors. If we are on windows we either wrap the stream + # to strip the color or we use the colorama support to translate the + # ansi codes to API calls. + if message and not is_bytes(message): + color = resolve_color_default(color) + if should_strip_ansi(file, color): + message = strip_ansi(message) + elif WIN: + if auto_wrap_for_ansi is not None: + file = auto_wrap_for_ansi(file) + elif not color: + message = strip_ansi(message) + + if message: + file.write(message) + file.flush() + + +def get_binary_stream(name): + """Returns a system stream for byte processing. This essentially + returns the stream from the sys module with the given name but it + solves some compatibility issues between different Python versions. + Primarily this function is necessary for getting binary streams on + Python 3. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + """ + opener = binary_streams.get(name) + if opener is None: + raise TypeError('Unknown standard stream %r' % name) + return opener() + + +def get_text_stream(name, encoding=None, errors='strict'): + """Returns a system stream for text processing. This usually returns + a wrapped stream around a binary stream returned from + :func:`get_binary_stream` but it also can take shortcuts on Python 3 + for already correctly configured streams. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + :param encoding: overrides the detected default encoding. + :param errors: overrides the default error mode. + """ + opener = text_streams.get(name) + if opener is None: + raise TypeError('Unknown standard stream %r' % name) + return opener(encoding, errors) + + +def open_file(filename, mode='r', encoding=None, errors='strict', + lazy=False, atomic=False): + """This is similar to how the :class:`File` works but for manual + usage. Files are opened non lazy by default. This can open regular + files as well as stdin/stdout if ``'-'`` is passed. + + If stdin/stdout is returned the stream is wrapped so that the context + manager will not close the stream accidentally. This makes it possible + to always use the function like this without having to worry to + accidentally close a standard stream:: + + with open_file(filename) as f: + ... + + .. versionadded:: 3.0 + + :param filename: the name of the file to open (or ``'-'`` for stdin/stdout). + :param mode: the mode in which to open the file. + :param encoding: the encoding to use. + :param errors: the error handling for this file. + :param lazy: can be flipped to true to open the file lazily. + :param atomic: in atomic mode writes go into a temporary file and it's + moved on close. + """ + if lazy: + return LazyFile(filename, mode, encoding, errors, atomic=atomic) + f, should_close = open_stream(filename, mode, encoding, errors, + atomic=atomic) + if not should_close: + f = KeepOpenFile(f) + return f + + +def get_os_args(): + """This returns the argument part of sys.argv in the most appropriate + form for processing. What this means is that this return value is in + a format that works for Click to process but does not necessarily + correspond well to what's actually standard for the interpreter. + + On most environments the return value is ``sys.argv[:1]`` unchanged. + However if you are on Windows and running Python 2 the return value + will actually be a list of unicode strings instead because the + default behavior on that platform otherwise will not be able to + carry all possible values that sys.argv can have. + + .. versionadded:: 6.0 + """ + # We can only extract the unicode argv if sys.argv has not been + # changed since the startup of the application. + if PY2 and WIN and _initial_argv_hash == _hash_py_argv(): + return _get_windows_argv() + return sys.argv[1:] + + +def format_filename(filename, shorten=False): + """Formats a filename for user display. The main purpose of this + function is to ensure that the filename can be displayed at all. This + will decode the filename to unicode if necessary in a way that it will + not fail. Optionally, it can shorten the filename to not include the + full path to the filename. + + :param filename: formats a filename for UI display. This will also convert + the filename into unicode without failing. + :param shorten: this optionally shortens the filename to strip of the + path that leads up to it. + """ + if shorten: + filename = os.path.basename(filename) + return filename_to_ui(filename) + + +def get_app_dir(app_name, roaming=True, force_posix=False): + r"""Returns the config folder for the application. The default behavior + is to return whatever is most appropriate for the operating system. + + To give you an idea, for an app called ``"Foo Bar"``, something like + the following folders could be returned: + + Mac OS X: + ``~/Library/Application Support/Foo Bar`` + Mac OS X (POSIX): + ``~/.foo-bar`` + Unix: + ``~/.config/foo-bar`` + Unix (POSIX): + ``~/.foo-bar`` + Win XP (roaming): + ``C:\Documents and Settings\\Local Settings\Application Data\Foo Bar`` + Win XP (not roaming): + ``C:\Documents and Settings\\Application Data\Foo Bar`` + Win 7 (roaming): + ``C:\Users\\AppData\Roaming\Foo Bar`` + Win 7 (not roaming): + ``C:\Users\\AppData\Local\Foo Bar`` + + .. versionadded:: 2.0 + + :param app_name: the application name. This should be properly capitalized + and can contain whitespace. + :param roaming: controls if the folder should be roaming or not on Windows. + Has no affect otherwise. + :param force_posix: if this is set to `True` then on any POSIX system the + folder will be stored in the home folder with a leading + dot instead of the XDG config home or darwin's + application support folder. + """ + if WIN: + key = roaming and 'APPDATA' or 'LOCALAPPDATA' + folder = os.environ.get(key) + if folder is None: + folder = os.path.expanduser('~') + return os.path.join(folder, app_name) + if force_posix: + return os.path.join(os.path.expanduser('~/.' + _posixify(app_name))) + if sys.platform == 'darwin': + return os.path.join(os.path.expanduser( + '~/Library/Application Support'), app_name) + return os.path.join( + os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')), + _posixify(app_name)) diff --git a/venv/lib/python2.7/site-packages/cryptography-2.3.1.dist-info/INSTALLER b/venv/lib/python2.7/site-packages/cryptography-2.3.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography-2.3.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python2.7/site-packages/cryptography-2.3.1.dist-info/METADATA b/venv/lib/python2.7/site-packages/cryptography-2.3.1.dist-info/METADATA new file mode 100644 index 0000000..d2706bf --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography-2.3.1.dist-info/METADATA @@ -0,0 +1,134 @@ +Metadata-Version: 2.1 +Name: cryptography +Version: 2.3.1 +Summary: cryptography is a package which provides cryptographic recipes and primitives to Python developers. +Home-page: https://github.com/pyca/cryptography +Author: The cryptography developers +Author-email: cryptography-dev@python.org +License: BSD or Apache License, Version 2.0 +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Apache Software License +Classifier: License :: OSI Approved :: BSD License +Classifier: Natural Language :: English +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Operating System :: POSIX +Classifier: Operating System :: POSIX :: BSD +Classifier: Operating System :: POSIX :: Linux +Classifier: Operating System :: Microsoft :: Windows +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Security :: Cryptography +Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.* +Provides-Extra: test +Provides-Extra: docstest +Provides-Extra: docs +Provides-Extra: pep8test +Requires-Dist: idna (>=2.1) +Requires-Dist: asn1crypto (>=0.21.0) +Requires-Dist: six (>=1.4.1) +Requires-Dist: cffi (!=1.11.3,>=1.7) +Requires-Dist: enum34; python_version < '3' +Requires-Dist: ipaddress; python_version < '3' +Provides-Extra: docs +Requires-Dist: sphinx (>=1.6.5); extra == 'docs' +Requires-Dist: sphinx-rtd-theme; extra == 'docs' +Provides-Extra: docstest +Requires-Dist: doc8; extra == 'docstest' +Requires-Dist: pyenchant (>=1.6.11); extra == 'docstest' +Requires-Dist: readme-renderer (>=16.0); extra == 'docstest' +Requires-Dist: sphinxcontrib-spelling (>=4.0.1); extra == 'docstest' +Provides-Extra: pep8test +Requires-Dist: flake8; extra == 'pep8test' +Requires-Dist: flake8-import-order; extra == 'pep8test' +Requires-Dist: pep8-naming; extra == 'pep8test' +Provides-Extra: test +Requires-Dist: pytest (!=3.3.0,>=3.2.1); extra == 'test' +Requires-Dist: pretend; extra == 'test' +Requires-Dist: iso8601; extra == 'test' +Requires-Dist: pytz; extra == 'test' +Requires-Dist: hypothesis (>=1.11.4); extra == 'test' +Requires-Dist: cryptography-vectors (==2.3.1); extra == 'test' + +pyca/cryptography +================= + +.. image:: https://img.shields.io/pypi/v/cryptography.svg + :target: https://pypi.org/project/cryptography/ + :alt: Latest Version + +.. image:: https://readthedocs.org/projects/cryptography/badge/?version=latest + :target: https://cryptography.io + :alt: Latest Docs + +.. image:: https://travis-ci.org/pyca/cryptography.svg?branch=master + :target: https://travis-ci.org/pyca/cryptography + +.. image:: https://codecov.io/github/pyca/cryptography/coverage.svg?branch=master + :target: https://codecov.io/github/pyca/cryptography?branch=master + + +``cryptography`` is a package which provides cryptographic recipes and +primitives to Python developers. Our goal is for it to be your "cryptographic +standard library". It supports Python 2.7, Python 3.4+, and PyPy 5.3+. + +``cryptography`` includes both high level recipes and low level interfaces to +common cryptographic algorithms such as symmetric ciphers, message digests, and +key derivation functions. For example, to encrypt something with +``cryptography``'s high level symmetric encryption recipe: + +.. code-block:: pycon + + >>> from cryptography.fernet import Fernet + >>> # Put this somewhere safe! + >>> key = Fernet.generate_key() + >>> f = Fernet(key) + >>> token = f.encrypt(b"A really secret message. Not for prying eyes.") + >>> token + '...' + >>> f.decrypt(token) + 'A really secret message. Not for prying eyes.' + +You can find more information in the `documentation`_. + +You can install ``cryptography`` with: + +.. code-block:: console + + $ pip install cryptography + +For full details see `the installation documentation`_. + +Discussion +~~~~~~~~~~ + +If you run into bugs, you can file them in our `issue tracker`_. + +We maintain a `cryptography-dev`_ mailing list for development discussion. + +You can also join ``#cryptography-dev`` on Freenode to ask questions or get +involved. + +Security +~~~~~~~~ + +Need to report a security issue? Please consult our `security reporting`_ +documentation. + + +.. _`documentation`: https://cryptography.io/ +.. _`the installation documentation`: https://cryptography.io/en/latest/installation/ +.. _`issue tracker`: https://github.com/pyca/cryptography/issues +.. _`cryptography-dev`: https://mail.python.org/mailman/listinfo/cryptography-dev +.. _`security reporting`: https://cryptography.io/en/latest/security/ + + diff --git a/venv/lib/python2.7/site-packages/cryptography-2.3.1.dist-info/RECORD b/venv/lib/python2.7/site-packages/cryptography-2.3.1.dist-info/RECORD new file mode 100644 index 0000000..d995e63 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography-2.3.1.dist-info/RECORD @@ -0,0 +1,144 @@ +cryptography/exceptions.py,sha256=3DJSu6GT5l5yVqu8SHKODGZp_s66s_nZokxAgPyws-0,1234 +cryptography/__init__.py,sha256=M7mQrfCHYuk7TpEPpfYxkhc95comqxOt41xYjLa5wiA,527 +cryptography/__about__.py,sha256=of-yHeXokW_53yyuIGdspMit777nIbgeHE6AkA59y9Y,817 +cryptography/utils.py,sha256=UuySj9oOoTCM4NKUjSkeLCKt9pVyG8Cxi_ZgaUN5Hrk,4798 +cryptography/fernet.py,sha256=BmY5HBTeIQ24HmT9b10C0xY_-BZBMphFVx6S1QP6gyI,5290 +cryptography/x509/base.py,sha256=J44yZ15Hg2qAXMK9VAElvEsg05kZ2OZ0p3I3zLzGxY0,23698 +cryptography/x509/name.py,sha256=QSZUwfxGIkKqqKKgRmaHyLR_uB9M0kJ3jRaQWb6i-w8,5878 +cryptography/x509/__init__.py,sha256=KAMKCRdMXDohHKs9GoDtAQrOviOZXXwd_lt3TvcZiCQ,7179 +cryptography/x509/oid.py,sha256=cULjdRQSUW7vSTlHlPl1T5CnlVxrV8TGWKPB-C7b6lw,12050 +cryptography/x509/extensions.py,sha256=PaWUKwLelaOEoujg3qKiTodpPHFuks4F_kJ9wy7PaqQ,43668 +cryptography/x509/certificate_transparency.py,sha256=eJ9lrITdyMn4XsrcVdrTaFVI_RR7mX_VzMZyiaEpbps,1000 +cryptography/x509/general_name.py,sha256=uXAt7I-5ZR3Ut8EEl4CVVTPx9OjkOcYp3m6EY0-LNe4,9887 +cryptography/hazmat/__init__.py,sha256=hEPNQw8dgjIPIn42qaLwXNRLCyTGNZeSvkQb57DPhbs,483 +cryptography/hazmat/backends/interfaces.py,sha256=b8zZ92ehVJje6SbvsI4Mwn5OpUJujhIk4MFImmwMlr4,10789 +cryptography/hazmat/backends/__init__.py,sha256=92UZdmqTyQPOYA2ui17tksyjxBnTmj1XDsxDCChLvxE,496 +cryptography/hazmat/backends/openssl/backend.py,sha256=g4xIcy6Oh5aHO_UDYLI206Vo8rghNMsCAjFNWJKCqPY,75732 +cryptography/hazmat/backends/openssl/ciphers.py,sha256=wo1A55VCqS7PR7AqTI1Lz3hb210QoDosgibpgNRc1I8,8904 +cryptography/hazmat/backends/openssl/dsa.py,sha256=JGcNfoAByLPKhfQp0Q-eW2P4hOKRos8-MJ3nIDKxbWE,10278 +cryptography/hazmat/backends/openssl/hmac.py,sha256=-iWgdVdZ1Vs69oNvfbBAKYkvEHMUQChN484rRanhj3w,2958 +cryptography/hazmat/backends/openssl/x509.py,sha256=0E0rbzv60DXBbuEN7OP3sCoLJ_UMesrXfK5fIW7t-8g,18923 +cryptography/hazmat/backends/openssl/__init__.py,sha256=k4DMe228_hTuB2kY3Lwk62JdI3EmCd7VkV01zJm57ps,336 +cryptography/hazmat/backends/openssl/decode_asn1.py,sha256=2Vz1JePth-72JnV7os2VcjxrqX7cwNi7WFBzsqx_DM8,30975 +cryptography/hazmat/backends/openssl/hashes.py,sha256=37n2XyXCO-WK9Mvs8zkncJdBeHrRzTKsW8EMBCEbWo8,2532 +cryptography/hazmat/backends/openssl/x25519.py,sha256=XYQOG36AxW1y1iy5anFTxWiZnIjk4HjkAqw18IZM2us,3064 +cryptography/hazmat/backends/openssl/aead.py,sha256=NkmmYAgCjGdVMoRIzFLV2RkbhZ2WbVtNb5CqK1TlnKM,5581 +cryptography/hazmat/backends/openssl/cmac.py,sha256=AyKXShU3tMHEeGlHm_s_SAhyJwklcbWuFikj9IP-Z2k,2840 +cryptography/hazmat/backends/openssl/dh.py,sha256=kXH0LXLsgo7FLNan6V5BiidS30zVkWNwaWuVZ-n6Uog,10814 +cryptography/hazmat/backends/openssl/rsa.py,sha256=-tIGHoBGL0Vmxe7ZZ58G53oOAmnucdtIlUsBVdA1WwI,18099 +cryptography/hazmat/backends/openssl/encode_asn1.py,sha256=fcM5M9bkFLOUr-wgVjB82c5U8slXM5gb8C5E9q7ZZQA,22450 +cryptography/hazmat/backends/openssl/utils.py,sha256=WQl9SXQnyuigjhYsgPX4qQPlpAAVS5vOzIrDYX9E-EQ,1399 +cryptography/hazmat/backends/openssl/ec.py,sha256=j_DHfNTHBPT4JcnPpVjT1SHPMwFfcfwhesf79uQR1Z8,10286 +cryptography/hazmat/primitives/keywrap.py,sha256=LqjkVIs7ub5I5gwmYSb9Ia0VdXMqWWHmnKSdQ7HOGEA,5462 +cryptography/hazmat/primitives/hmac.py,sha256=88sNgH3-t6kKVAILsx1SvjHBlYuz6_i34hLf2Z5U84s,2339 +cryptography/hazmat/primitives/__init__.py,sha256=0wGw2OF9R7fHX7NWENCmrsYigbXHU2ojgn-N4Rkjs9U,246 +cryptography/hazmat/primitives/constant_time.py,sha256=2-OvdvG0rvaRT0Spt5vi5rmqBUJYz89VuK32cmS2GNA,1124 +cryptography/hazmat/primitives/hashes.py,sha256=NKhCtNpSbSMLYjo7mQjbQLTBRQF0wL3HTY-BqJSqQS8,4676 +cryptography/hazmat/primitives/cmac.py,sha256=jXv_7KmaCek2LNOAbXXp0bzA3Mts6ff_oWBFnFVXluo,2221 +cryptography/hazmat/primitives/padding.py,sha256=joCFMwVI8MnHT75GcUaInox1rYeLqjd4DtZLEBhYBlY,5736 +cryptography/hazmat/primitives/serialization.py,sha256=q0A61qepY1cCjArCmZHdEdetoGloR4SzzQ-IaadH8xA,5513 +cryptography/hazmat/primitives/mac.py,sha256=dgLoN6PdA_QqowwB_RzSeEqJjIPnAqTUTxio-8CFP-8,884 +cryptography/hazmat/primitives/kdf/kbkdf.py,sha256=SvuAqrv1ZZT-AG-pimTXZH4TtP42535tXaQbockFq_0,5025 +cryptography/hazmat/primitives/kdf/hkdf.py,sha256=SlAKFKFS6jowkfO8wMu27wa268RPekYVQpedq2b3iJk,3660 +cryptography/hazmat/primitives/kdf/__init__.py,sha256=nod5HjPswjZr8wFp6Tsu6en9blHYF3khgXI5R0zIcnM,771 +cryptography/hazmat/primitives/kdf/concatkdf.py,sha256=WTooWTAkHUCtaMAUouAluNbg71qXxPj_AHLyuRnPDR8,4109 +cryptography/hazmat/primitives/kdf/pbkdf2.py,sha256=YiFNDI4CbGRH0OQXDMXG8DfYap32vtjvA-Zo-n_oAE4,2185 +cryptography/hazmat/primitives/kdf/x963kdf.py,sha256=yOK2qAlWTHABVIvwT55jl_B6UR5ELyLFlcVtH16HxGc,2363 +cryptography/hazmat/primitives/kdf/scrypt.py,sha256=aZVkYFw9XqPCInjAadnzlYfPw3fi2COGDe7ubuYjReg,2252 +cryptography/hazmat/primitives/asymmetric/dsa.py,sha256=uzK7qpe0BtqHkgVLSrNGtska1w3JSUN_uZp6XAA5LMY,6891 +cryptography/hazmat/primitives/asymmetric/__init__.py,sha256=WhUn3tGxoLAxGAsZHElJ2aOILXSh55AZi04MBudYmQA,1020 +cryptography/hazmat/primitives/asymmetric/x25519.py,sha256=f4Tif1_sqmTRC9uByZ2eibijI5aHFZGUQ1jgQG5bqmo,1652 +cryptography/hazmat/primitives/asymmetric/padding.py,sha256=aCZatU5-q_WW5vazBWeKPF8ZZa0AI8hWzbJaVRN3RWI,2261 +cryptography/hazmat/primitives/asymmetric/dh.py,sha256=6Xl01bjTVHFCcdJr3Ph2cQ7hxkYYedqm-SekZpxnntY,5454 +cryptography/hazmat/primitives/asymmetric/rsa.py,sha256=V7MKK29BpNGF2f3uWEs3HPYbGuL3YtDFujvjFQrle0Q,10317 +cryptography/hazmat/primitives/asymmetric/utils.py,sha256=x7bcX3L_wLkZqdcOfUdDI70SdvUSrPolLv_6kRtFajk,1720 +cryptography/hazmat/primitives/asymmetric/ec.py,sha256=9d2lVsYinE_v7XPHofNl5Dd55uCgps4YOcgOE8_bbbM,10305 +cryptography/hazmat/primitives/ciphers/base.py,sha256=KOMTiI7-TPf9ENs_0IHuZ_kBkHz1wimdDG_xkfbdnAY,7148 +cryptography/hazmat/primitives/ciphers/__init__.py,sha256=QxaxejeFfz6CPhI1c4iNq_7DsiB41Y_Q-uLfzOx7fv8,626 +cryptography/hazmat/primitives/ciphers/modes.py,sha256=WipP7JtIogVaruguxxNj0FUi7GIjgV1crW_ybilsTF8,7027 +cryptography/hazmat/primitives/ciphers/aead.py,sha256=Ybu5PZd-44OgcyJVs61-zJ_zH9PUKRckEYAPcdUqX7w,6409 +cryptography/hazmat/primitives/ciphers/algorithms.py,sha256=akJFiPdwDT1OMIyhlMWbCVqs0ktaBzE5l4dT2iG-LJc,4233 +cryptography/hazmat/primitives/twofactor/hotp.py,sha256=6_EnKl-zRs0yCXuHxQhs2TEkHaprWxZnfJGrQjs5RIg,2589 +cryptography/hazmat/primitives/twofactor/totp.py,sha256=KL3A4bjpqaqynQYd9hfPVkvs5vYVqf1JVpucEX7_ddM,1594 +cryptography/hazmat/primitives/twofactor/__init__.py,sha256=BWrm3DKDoAa281E7U_nzz8v44OmAiXmlIycFcsehwfE,288 +cryptography/hazmat/primitives/twofactor/utils.py,sha256=71gX1bJeP9TQa-HbSPzeUUJwVY78ALYQNvuusknUO4U,954 +cryptography/hazmat/bindings/__init__.py,sha256=0wGw2OF9R7fHX7NWENCmrsYigbXHU2ojgn-N4Rkjs9U,246 +cryptography/hazmat/bindings/_constant_time.so,sha256=936IyDzOLQxyutPq_4xvxR131Og94H0qVKl6MrM4L04,26431 +cryptography/hazmat/bindings/_openssl.so,sha256=eVMIxlJMKYoUqZT5EeBXT2ZYZk1m4mmSL4uMV4BvUYU,5447928 +cryptography/hazmat/bindings/_padding.so,sha256=nuORmAJPTmqbdk-sSwLCbHf5we3VxtnQs4t0-aXMeng,28558 +cryptography/hazmat/bindings/openssl/binding.py,sha256=pgZNFDlx3gLHorz4ZHHUtA-LEQGi1dbYUG7WQ68tnp0,5496 +cryptography/hazmat/bindings/openssl/__init__.py,sha256=0wGw2OF9R7fHX7NWENCmrsYigbXHU2ojgn-N4Rkjs9U,246 +cryptography/hazmat/bindings/openssl/_conditional.py,sha256=o7cT8pGj-2rB7YN-EUGJNhs7DeFIr58AN3h9MK5uWo0,7692 +cryptography-2.3.1.dist-info/RECORD,, +cryptography-2.3.1.dist-info/METADATA,sha256=gcpoV8G9hZvJ8iRAZCfhx5-FffotP9OqHr1VSmmwudg,5002 +cryptography-2.3.1.dist-info/WHEEL,sha256=M5Ujap42zjfAFnpJOoFU72TFHuBKh-JF0Rqu5vZhkVE,110 +cryptography-2.3.1.dist-info/top_level.txt,sha256=QCkYQE4HJBpqIr-aBqbOZ70NlfbejKnDE6ODbNgUwwg,46 +cryptography-2.3.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +cryptography/hazmat/backends/__init__.pyc,, +cryptography/hazmat/primitives/kdf/kbkdf.pyc,, +cryptography/x509/general_name.pyc,, +cryptography/hazmat/primitives/padding.pyc,, +cryptography/hazmat/backends/interfaces.pyc,, +cryptography/x509/certificate_transparency.pyc,, +cryptography/hazmat/primitives/kdf/concatkdf.pyc,, +cryptography/__init__.pyc,, +cryptography/x509/oid.pyc,, +cryptography/hazmat/primitives/twofactor/__init__.pyc,, +cryptography/fernet.pyc,, +cryptography/hazmat/primitives/kdf/x963kdf.pyc,, +cryptography/hazmat/primitives/constant_time.pyc,, +cryptography/hazmat/backends/openssl/x25519.pyc,, +cryptography/hazmat/primitives/asymmetric/utils.pyc,, +cryptography/hazmat/primitives/twofactor/hotp.pyc,, +cryptography/hazmat/primitives/twofactor/utils.pyc,, +cryptography/hazmat/primitives/twofactor/totp.pyc,, +cryptography/x509/base.pyc,, +cryptography/exceptions.pyc,, +cryptography/hazmat/backends/openssl/hashes.pyc,, +cryptography/hazmat/primitives/serialization.pyc,, +cryptography/hazmat/bindings/openssl/binding.pyc,, +cryptography/hazmat/bindings/openssl/__init__.pyc,, +cryptography/hazmat/backends/openssl/hmac.pyc,, +cryptography/hazmat/bindings/openssl/_conditional.pyc,, +cryptography/hazmat/primitives/cmac.pyc,, +cryptography/hazmat/backends/openssl/backend.pyc,, +cryptography/hazmat/primitives/asymmetric/rsa.pyc,, +cryptography/hazmat/primitives/ciphers/aead.pyc,, +cryptography/hazmat/primitives/hmac.pyc,, +cryptography/hazmat/backends/openssl/__init__.pyc,, +cryptography/hazmat/primitives/hashes.pyc,, +cryptography/hazmat/backends/openssl/dh.pyc,, +cryptography/hazmat/primitives/kdf/hkdf.pyc,, +cryptography/hazmat/backends/openssl/ciphers.pyc,, +cryptography/hazmat/primitives/ciphers/__init__.pyc,, +cryptography/x509/name.pyc,, +cryptography/hazmat/primitives/kdf/__init__.pyc,, +cryptography/hazmat/backends/openssl/utils.pyc,, +cryptography/hazmat/backends/openssl/rsa.pyc,, +cryptography/x509/extensions.pyc,, +cryptography/hazmat/primitives/__init__.pyc,, +cryptography/hazmat/primitives/keywrap.pyc,, +cryptography/hazmat/primitives/asymmetric/dh.pyc,, +cryptography/hazmat/primitives/asymmetric/ec.pyc,, +cryptography/hazmat/backends/openssl/dsa.pyc,, +cryptography/hazmat/primitives/asymmetric/x25519.pyc,, +cryptography/hazmat/backends/openssl/encode_asn1.pyc,, +cryptography/hazmat/primitives/ciphers/modes.pyc,, +cryptography/hazmat/backends/openssl/x509.pyc,, +cryptography/hazmat/primitives/ciphers/base.pyc,, +cryptography/x509/__init__.pyc,, +cryptography/hazmat/__init__.pyc,, +cryptography/hazmat/backends/openssl/aead.pyc,, +cryptography/hazmat/backends/openssl/decode_asn1.pyc,, +cryptography/hazmat/primitives/mac.pyc,, +cryptography/__about__.pyc,, +cryptography/hazmat/primitives/asymmetric/padding.pyc,, +cryptography/hazmat/backends/openssl/cmac.pyc,, +cryptography/hazmat/backends/openssl/ec.pyc,, +cryptography/hazmat/primitives/asymmetric/dsa.pyc,, +cryptography/hazmat/primitives/kdf/pbkdf2.pyc,, +cryptography/hazmat/primitives/asymmetric/__init__.pyc,, +cryptography/hazmat/primitives/ciphers/algorithms.pyc,, +cryptography/utils.pyc,, +cryptography/hazmat/primitives/kdf/scrypt.pyc,, +cryptography/hazmat/bindings/__init__.pyc,, diff --git a/venv/lib/python2.7/site-packages/cryptography-2.3.1.dist-info/WHEEL b/venv/lib/python2.7/site-packages/cryptography-2.3.1.dist-info/WHEEL new file mode 100644 index 0000000..295a0ca --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography-2.3.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.31.1) +Root-Is-Purelib: false +Tag: cp27-cp27mu-manylinux1_x86_64 + diff --git a/venv/lib/python2.7/site-packages/cryptography-2.3.1.dist-info/top_level.txt b/venv/lib/python2.7/site-packages/cryptography-2.3.1.dist-info/top_level.txt new file mode 100644 index 0000000..e32461e --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography-2.3.1.dist-info/top_level.txt @@ -0,0 +1,4 @@ +_constant_time +_openssl +_padding +cryptography diff --git a/venv/lib/python2.7/site-packages/cryptography/__about__.py b/venv/lib/python2.7/site-packages/cryptography/__about__.py new file mode 100644 index 0000000..a99f58f --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/__about__.py @@ -0,0 +1,23 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +__all__ = [ + "__title__", "__summary__", "__uri__", "__version__", "__author__", + "__email__", "__license__", "__copyright__", +] + +__title__ = "cryptography" +__summary__ = ("cryptography is a package which provides cryptographic recipes" + " and primitives to Python developers.") +__uri__ = "https://github.com/pyca/cryptography" + +__version__ = "2.3.1" + +__author__ = "The cryptography developers" +__email__ = "cryptography-dev@python.org" + +__license__ = "BSD or Apache License, Version 2.0" +__copyright__ = "Copyright 2013-2017 {0}".format(__author__) diff --git a/venv/lib/python2.7/site-packages/cryptography/__init__.py b/venv/lib/python2.7/site-packages/cryptography/__init__.py new file mode 100644 index 0000000..6da0b38 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/__init__.py @@ -0,0 +1,16 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography.__about__ import ( + __author__, __copyright__, __email__, __license__, __summary__, __title__, + __uri__, __version__ +) + + +__all__ = [ + "__title__", "__summary__", "__uri__", "__version__", "__author__", + "__email__", "__license__", "__copyright__", +] diff --git a/venv/lib/python2.7/site-packages/cryptography/exceptions.py b/venv/lib/python2.7/site-packages/cryptography/exceptions.py new file mode 100644 index 0000000..648cf9d --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/exceptions.py @@ -0,0 +1,57 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from enum import Enum + + +class _Reasons(Enum): + BACKEND_MISSING_INTERFACE = 0 + UNSUPPORTED_HASH = 1 + UNSUPPORTED_CIPHER = 2 + UNSUPPORTED_PADDING = 3 + UNSUPPORTED_MGF = 4 + UNSUPPORTED_PUBLIC_KEY_ALGORITHM = 5 + UNSUPPORTED_ELLIPTIC_CURVE = 6 + UNSUPPORTED_SERIALIZATION = 7 + UNSUPPORTED_X509 = 8 + UNSUPPORTED_EXCHANGE_ALGORITHM = 9 + UNSUPPORTED_DIFFIE_HELLMAN = 10 + + +class UnsupportedAlgorithm(Exception): + def __init__(self, message, reason=None): + super(UnsupportedAlgorithm, self).__init__(message) + self._reason = reason + + +class AlreadyFinalized(Exception): + pass + + +class AlreadyUpdated(Exception): + pass + + +class NotYetFinalized(Exception): + pass + + +class InvalidTag(Exception): + pass + + +class InvalidSignature(Exception): + pass + + +class InternalError(Exception): + def __init__(self, msg, err_code): + super(InternalError, self).__init__(msg) + self.err_code = err_code + + +class InvalidKey(Exception): + pass diff --git a/venv/lib/python2.7/site-packages/cryptography/fernet.py b/venv/lib/python2.7/site-packages/cryptography/fernet.py new file mode 100644 index 0000000..ac2dd0b --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/fernet.py @@ -0,0 +1,173 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import base64 +import binascii +import os +import struct +import time + +import six + +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import hashes, padding +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from cryptography.hazmat.primitives.hmac import HMAC + + +class InvalidToken(Exception): + pass + + +_MAX_CLOCK_SKEW = 60 + + +class Fernet(object): + def __init__(self, key, backend=None): + if backend is None: + backend = default_backend() + + key = base64.urlsafe_b64decode(key) + if len(key) != 32: + raise ValueError( + "Fernet key must be 32 url-safe base64-encoded bytes." + ) + + self._signing_key = key[:16] + self._encryption_key = key[16:] + self._backend = backend + + @classmethod + def generate_key(cls): + return base64.urlsafe_b64encode(os.urandom(32)) + + def encrypt(self, data): + current_time = int(time.time()) + iv = os.urandom(16) + return self._encrypt_from_parts(data, current_time, iv) + + def _encrypt_from_parts(self, data, current_time, iv): + if not isinstance(data, bytes): + raise TypeError("data must be bytes.") + + padder = padding.PKCS7(algorithms.AES.block_size).padder() + padded_data = padder.update(data) + padder.finalize() + encryptor = Cipher( + algorithms.AES(self._encryption_key), modes.CBC(iv), self._backend + ).encryptor() + ciphertext = encryptor.update(padded_data) + encryptor.finalize() + + basic_parts = ( + b"\x80" + struct.pack(">Q", current_time) + iv + ciphertext + ) + + h = HMAC(self._signing_key, hashes.SHA256(), backend=self._backend) + h.update(basic_parts) + hmac = h.finalize() + return base64.urlsafe_b64encode(basic_parts + hmac) + + def decrypt(self, token, ttl=None): + timestamp, data = Fernet._get_unverified_token_data(token) + return self._decrypt_data(data, timestamp, ttl) + + def extract_timestamp(self, token): + timestamp, data = Fernet._get_unverified_token_data(token) + # Verify the token was not tampered with. + self._verify_signature(data) + return timestamp + + @staticmethod + def _get_unverified_token_data(token): + if not isinstance(token, bytes): + raise TypeError("token must be bytes.") + + try: + data = base64.urlsafe_b64decode(token) + except (TypeError, binascii.Error): + raise InvalidToken + + if not data or six.indexbytes(data, 0) != 0x80: + raise InvalidToken + + try: + timestamp, = struct.unpack(">Q", data[1:9]) + except struct.error: + raise InvalidToken + return timestamp, data + + def _verify_signature(self, data): + h = HMAC(self._signing_key, hashes.SHA256(), backend=self._backend) + h.update(data[:-32]) + try: + h.verify(data[-32:]) + except InvalidSignature: + raise InvalidToken + + def _decrypt_data(self, data, timestamp, ttl): + current_time = int(time.time()) + if ttl is not None: + if timestamp + ttl < current_time: + raise InvalidToken + + if current_time + _MAX_CLOCK_SKEW < timestamp: + raise InvalidToken + + self._verify_signature(data) + + iv = data[9:25] + ciphertext = data[25:-32] + decryptor = Cipher( + algorithms.AES(self._encryption_key), modes.CBC(iv), self._backend + ).decryptor() + plaintext_padded = decryptor.update(ciphertext) + try: + plaintext_padded += decryptor.finalize() + except ValueError: + raise InvalidToken + unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder() + + unpadded = unpadder.update(plaintext_padded) + try: + unpadded += unpadder.finalize() + except ValueError: + raise InvalidToken + return unpadded + + +class MultiFernet(object): + def __init__(self, fernets): + fernets = list(fernets) + if not fernets: + raise ValueError( + "MultiFernet requires at least one Fernet instance" + ) + self._fernets = fernets + + def encrypt(self, msg): + return self._fernets[0].encrypt(msg) + + def rotate(self, msg): + timestamp, data = Fernet._get_unverified_token_data(msg) + for f in self._fernets: + try: + p = f._decrypt_data(data, timestamp, None) + break + except InvalidToken: + pass + else: + raise InvalidToken + + iv = os.urandom(16) + return self._fernets[0]._encrypt_from_parts(p, timestamp, iv) + + def decrypt(self, msg, ttl=None): + for f in self._fernets: + try: + return f.decrypt(msg, ttl) + except InvalidToken: + pass + raise InvalidToken diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/__init__.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/__init__.py new file mode 100644 index 0000000..9f06a99 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/__init__.py @@ -0,0 +1,11 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +""" +Hazardous Materials + +This is a "Hazardous Materials" module. You should ONLY use it if you're +100% absolutely sure that you know what you're doing because this module +is full of land mines, dragons, and dinosaurs with laser guns. +""" +from __future__ import absolute_import, division, print_function diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/__init__.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/__init__.py new file mode 100644 index 0000000..565bde7 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/__init__.py @@ -0,0 +1,18 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + + +_default_backend = None + + +def default_backend(): + global _default_backend + + if _default_backend is None: + from cryptography.hazmat.backends.openssl.backend import backend + _default_backend = backend + + return _default_backend diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/interfaces.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/interfaces.py new file mode 100644 index 0000000..0a476b9 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/interfaces.py @@ -0,0 +1,395 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc + +import six + + +@six.add_metaclass(abc.ABCMeta) +class CipherBackend(object): + @abc.abstractmethod + def cipher_supported(self, cipher, mode): + """ + Return True if the given cipher and mode are supported. + """ + + @abc.abstractmethod + def create_symmetric_encryption_ctx(self, cipher, mode): + """ + Get a CipherContext that can be used for encryption. + """ + + @abc.abstractmethod + def create_symmetric_decryption_ctx(self, cipher, mode): + """ + Get a CipherContext that can be used for decryption. + """ + + +@six.add_metaclass(abc.ABCMeta) +class HashBackend(object): + @abc.abstractmethod + def hash_supported(self, algorithm): + """ + Return True if the hash algorithm is supported by this backend. + """ + + @abc.abstractmethod + def create_hash_ctx(self, algorithm): + """ + Create a HashContext for calculating a message digest. + """ + + +@six.add_metaclass(abc.ABCMeta) +class HMACBackend(object): + @abc.abstractmethod + def hmac_supported(self, algorithm): + """ + Return True if the hash algorithm is supported for HMAC by this + backend. + """ + + @abc.abstractmethod + def create_hmac_ctx(self, key, algorithm): + """ + Create a MACContext for calculating a message authentication code. + """ + + +@six.add_metaclass(abc.ABCMeta) +class CMACBackend(object): + @abc.abstractmethod + def cmac_algorithm_supported(self, algorithm): + """ + Returns True if the block cipher is supported for CMAC by this backend + """ + + @abc.abstractmethod + def create_cmac_ctx(self, algorithm): + """ + Create a MACContext for calculating a message authentication code. + """ + + +@six.add_metaclass(abc.ABCMeta) +class PBKDF2HMACBackend(object): + @abc.abstractmethod + def pbkdf2_hmac_supported(self, algorithm): + """ + Return True if the hash algorithm is supported for PBKDF2 by this + backend. + """ + + @abc.abstractmethod + def derive_pbkdf2_hmac(self, algorithm, length, salt, iterations, + key_material): + """ + Return length bytes derived from provided PBKDF2 parameters. + """ + + +@six.add_metaclass(abc.ABCMeta) +class RSABackend(object): + @abc.abstractmethod + def generate_rsa_private_key(self, public_exponent, key_size): + """ + Generate an RSAPrivateKey instance with public_exponent and a modulus + of key_size bits. + """ + + @abc.abstractmethod + def rsa_padding_supported(self, padding): + """ + Returns True if the backend supports the given padding options. + """ + + @abc.abstractmethod + def generate_rsa_parameters_supported(self, public_exponent, key_size): + """ + Returns True if the backend supports the given parameters for key + generation. + """ + + @abc.abstractmethod + def load_rsa_private_numbers(self, numbers): + """ + Returns an RSAPrivateKey provider. + """ + + @abc.abstractmethod + def load_rsa_public_numbers(self, numbers): + """ + Returns an RSAPublicKey provider. + """ + + +@six.add_metaclass(abc.ABCMeta) +class DSABackend(object): + @abc.abstractmethod + def generate_dsa_parameters(self, key_size): + """ + Generate a DSAParameters instance with a modulus of key_size bits. + """ + + @abc.abstractmethod + def generate_dsa_private_key(self, parameters): + """ + Generate a DSAPrivateKey instance with parameters as a DSAParameters + object. + """ + + @abc.abstractmethod + def generate_dsa_private_key_and_parameters(self, key_size): + """ + Generate a DSAPrivateKey instance using key size only. + """ + + @abc.abstractmethod + def dsa_hash_supported(self, algorithm): + """ + Return True if the hash algorithm is supported by the backend for DSA. + """ + + @abc.abstractmethod + def dsa_parameters_supported(self, p, q, g): + """ + Return True if the parameters are supported by the backend for DSA. + """ + + @abc.abstractmethod + def load_dsa_private_numbers(self, numbers): + """ + Returns a DSAPrivateKey provider. + """ + + @abc.abstractmethod + def load_dsa_public_numbers(self, numbers): + """ + Returns a DSAPublicKey provider. + """ + + @abc.abstractmethod + def load_dsa_parameter_numbers(self, numbers): + """ + Returns a DSAParameters provider. + """ + + +@six.add_metaclass(abc.ABCMeta) +class EllipticCurveBackend(object): + @abc.abstractmethod + def elliptic_curve_signature_algorithm_supported( + self, signature_algorithm, curve + ): + """ + Returns True if the backend supports the named elliptic curve with the + specified signature algorithm. + """ + + @abc.abstractmethod + def elliptic_curve_supported(self, curve): + """ + Returns True if the backend supports the named elliptic curve. + """ + + @abc.abstractmethod + def generate_elliptic_curve_private_key(self, curve): + """ + Return an object conforming to the EllipticCurvePrivateKey interface. + """ + + @abc.abstractmethod + def load_elliptic_curve_public_numbers(self, numbers): + """ + Return an EllipticCurvePublicKey provider using the given numbers. + """ + + @abc.abstractmethod + def load_elliptic_curve_private_numbers(self, numbers): + """ + Return an EllipticCurvePrivateKey provider using the given numbers. + """ + + @abc.abstractmethod + def elliptic_curve_exchange_algorithm_supported(self, algorithm, curve): + """ + Returns whether the exchange algorithm is supported by this backend. + """ + + @abc.abstractmethod + def derive_elliptic_curve_private_key(self, private_value, curve): + """ + Compute the private key given the private value and curve. + """ + + +@six.add_metaclass(abc.ABCMeta) +class PEMSerializationBackend(object): + @abc.abstractmethod + def load_pem_private_key(self, data, password): + """ + Loads a private key from PEM encoded data, using the provided password + if the data is encrypted. + """ + + @abc.abstractmethod + def load_pem_public_key(self, data): + """ + Loads a public key from PEM encoded data. + """ + + @abc.abstractmethod + def load_pem_parameters(self, data): + """ + Load encryption parameters from PEM encoded data. + """ + + +@six.add_metaclass(abc.ABCMeta) +class DERSerializationBackend(object): + @abc.abstractmethod + def load_der_private_key(self, data, password): + """ + Loads a private key from DER encoded data. Uses the provided password + if the data is encrypted. + """ + + @abc.abstractmethod + def load_der_public_key(self, data): + """ + Loads a public key from DER encoded data. + """ + + @abc.abstractmethod + def load_der_parameters(self, data): + """ + Load encryption parameters from DER encoded data. + """ + + +@six.add_metaclass(abc.ABCMeta) +class X509Backend(object): + @abc.abstractmethod + def load_pem_x509_certificate(self, data): + """ + Load an X.509 certificate from PEM encoded data. + """ + + @abc.abstractmethod + def load_der_x509_certificate(self, data): + """ + Load an X.509 certificate from DER encoded data. + """ + + @abc.abstractmethod + def load_der_x509_csr(self, data): + """ + Load an X.509 CSR from DER encoded data. + """ + + @abc.abstractmethod + def load_pem_x509_csr(self, data): + """ + Load an X.509 CSR from PEM encoded data. + """ + + @abc.abstractmethod + def create_x509_csr(self, builder, private_key, algorithm): + """ + Create and sign an X.509 CSR from a CSR builder object. + """ + + @abc.abstractmethod + def create_x509_certificate(self, builder, private_key, algorithm): + """ + Create and sign an X.509 certificate from a CertificateBuilder object. + """ + + @abc.abstractmethod + def create_x509_crl(self, builder, private_key, algorithm): + """ + Create and sign an X.509 CertificateRevocationList from a + CertificateRevocationListBuilder object. + """ + + @abc.abstractmethod + def create_x509_revoked_certificate(self, builder): + """ + Create a RevokedCertificate object from a RevokedCertificateBuilder + object. + """ + + @abc.abstractmethod + def x509_name_bytes(self, name): + """ + Compute the DER encoded bytes of an X509 Name object. + """ + + +@six.add_metaclass(abc.ABCMeta) +class DHBackend(object): + @abc.abstractmethod + def generate_dh_parameters(self, generator, key_size): + """ + Generate a DHParameters instance with a modulus of key_size bits. + Using the given generator. Often 2 or 5. + """ + + @abc.abstractmethod + def generate_dh_private_key(self, parameters): + """ + Generate a DHPrivateKey instance with parameters as a DHParameters + object. + """ + + @abc.abstractmethod + def generate_dh_private_key_and_parameters(self, generator, key_size): + """ + Generate a DHPrivateKey instance using key size only. + Using the given generator. Often 2 or 5. + """ + + @abc.abstractmethod + def load_dh_private_numbers(self, numbers): + """ + Load a DHPrivateKey from DHPrivateNumbers + """ + + @abc.abstractmethod + def load_dh_public_numbers(self, numbers): + """ + Load a DHPublicKey from DHPublicNumbers. + """ + + @abc.abstractmethod + def load_dh_parameter_numbers(self, numbers): + """ + Load DHParameters from DHParameterNumbers. + """ + + @abc.abstractmethod + def dh_parameters_supported(self, p, g, q=None): + """ + Returns whether the backend supports DH with these parameter values. + """ + + @abc.abstractmethod + def dh_x942_serialization_supported(self): + """ + Returns True if the backend supports the serialization of DH objects + with subgroup order (q). + """ + + +@six.add_metaclass(abc.ABCMeta) +class ScryptBackend(object): + @abc.abstractmethod + def derive_scrypt(self, key_material, salt, length, n, r, p): + """ + Return bytes derived from provided Scrypt parameters. + """ diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/__init__.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/__init__.py new file mode 100644 index 0000000..8eadeb6 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/__init__.py @@ -0,0 +1,10 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography.hazmat.backends.openssl.backend import backend + + +__all__ = ["backend"] diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/aead.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/aead.py new file mode 100644 index 0000000..9cec3e2 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/aead.py @@ -0,0 +1,159 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography.exceptions import InvalidTag + + +_ENCRYPT = 1 +_DECRYPT = 0 + + +def _aead_cipher_name(cipher): + from cryptography.hazmat.primitives.ciphers.aead import ( + AESCCM, AESGCM, ChaCha20Poly1305 + ) + if isinstance(cipher, ChaCha20Poly1305): + return b"chacha20-poly1305" + elif isinstance(cipher, AESCCM): + return "aes-{0}-ccm".format(len(cipher._key) * 8).encode("ascii") + else: + assert isinstance(cipher, AESGCM) + return "aes-{0}-gcm".format(len(cipher._key) * 8).encode("ascii") + + +def _aead_setup(backend, cipher_name, key, nonce, tag, tag_len, operation): + evp_cipher = backend._lib.EVP_get_cipherbyname(cipher_name) + backend.openssl_assert(evp_cipher != backend._ffi.NULL) + ctx = backend._lib.EVP_CIPHER_CTX_new() + ctx = backend._ffi.gc(ctx, backend._lib.EVP_CIPHER_CTX_free) + res = backend._lib.EVP_CipherInit_ex( + ctx, evp_cipher, + backend._ffi.NULL, + backend._ffi.NULL, + backend._ffi.NULL, + int(operation == _ENCRYPT) + ) + backend.openssl_assert(res != 0) + res = backend._lib.EVP_CIPHER_CTX_set_key_length(ctx, len(key)) + backend.openssl_assert(res != 0) + res = backend._lib.EVP_CIPHER_CTX_ctrl( + ctx, backend._lib.EVP_CTRL_AEAD_SET_IVLEN, len(nonce), + backend._ffi.NULL + ) + backend.openssl_assert(res != 0) + if operation == _DECRYPT: + res = backend._lib.EVP_CIPHER_CTX_ctrl( + ctx, backend._lib.EVP_CTRL_AEAD_SET_TAG, len(tag), tag + ) + backend.openssl_assert(res != 0) + else: + res = backend._lib.EVP_CIPHER_CTX_ctrl( + ctx, backend._lib.EVP_CTRL_AEAD_SET_TAG, tag_len, backend._ffi.NULL + ) + + res = backend._lib.EVP_CipherInit_ex( + ctx, + backend._ffi.NULL, + backend._ffi.NULL, + key, + nonce, + int(operation == _ENCRYPT) + ) + backend.openssl_assert(res != 0) + return ctx + + +def _set_length(backend, ctx, data_len): + intptr = backend._ffi.new("int *") + res = backend._lib.EVP_CipherUpdate( + ctx, + backend._ffi.NULL, + intptr, + backend._ffi.NULL, + data_len + ) + backend.openssl_assert(res != 0) + + +def _process_aad(backend, ctx, associated_data): + outlen = backend._ffi.new("int *") + res = backend._lib.EVP_CipherUpdate( + ctx, backend._ffi.NULL, outlen, associated_data, len(associated_data) + ) + backend.openssl_assert(res != 0) + + +def _process_data(backend, ctx, data): + outlen = backend._ffi.new("int *") + buf = backend._ffi.new("unsigned char[]", len(data)) + res = backend._lib.EVP_CipherUpdate(ctx, buf, outlen, data, len(data)) + backend.openssl_assert(res != 0) + return backend._ffi.buffer(buf, outlen[0])[:] + + +def _encrypt(backend, cipher, nonce, data, associated_data, tag_length): + from cryptography.hazmat.primitives.ciphers.aead import AESCCM + cipher_name = _aead_cipher_name(cipher) + ctx = _aead_setup( + backend, cipher_name, cipher._key, nonce, None, tag_length, _ENCRYPT + ) + # CCM requires us to pass the length of the data before processing anything + # However calling this with any other AEAD results in an error + if isinstance(cipher, AESCCM): + _set_length(backend, ctx, len(data)) + + _process_aad(backend, ctx, associated_data) + processed_data = _process_data(backend, ctx, data) + outlen = backend._ffi.new("int *") + res = backend._lib.EVP_CipherFinal_ex(ctx, backend._ffi.NULL, outlen) + backend.openssl_assert(res != 0) + backend.openssl_assert(outlen[0] == 0) + tag_buf = backend._ffi.new("unsigned char[]", tag_length) + res = backend._lib.EVP_CIPHER_CTX_ctrl( + ctx, backend._lib.EVP_CTRL_AEAD_GET_TAG, tag_length, tag_buf + ) + backend.openssl_assert(res != 0) + tag = backend._ffi.buffer(tag_buf)[:] + + return processed_data + tag + + +def _decrypt(backend, cipher, nonce, data, associated_data, tag_length): + from cryptography.hazmat.primitives.ciphers.aead import AESCCM + if len(data) < tag_length: + raise InvalidTag + tag = data[-tag_length:] + data = data[:-tag_length] + cipher_name = _aead_cipher_name(cipher) + ctx = _aead_setup( + backend, cipher_name, cipher._key, nonce, tag, tag_length, _DECRYPT + ) + # CCM requires us to pass the length of the data before processing anything + # However calling this with any other AEAD results in an error + if isinstance(cipher, AESCCM): + _set_length(backend, ctx, len(data)) + + _process_aad(backend, ctx, associated_data) + # CCM has a different error path if the tag doesn't match. Errors are + # raised in Update and Final is irrelevant. + if isinstance(cipher, AESCCM): + outlen = backend._ffi.new("int *") + buf = backend._ffi.new("unsigned char[]", len(data)) + res = backend._lib.EVP_CipherUpdate(ctx, buf, outlen, data, len(data)) + if res != 1: + backend._consume_errors() + raise InvalidTag + + processed_data = backend._ffi.buffer(buf, outlen[0])[:] + else: + processed_data = _process_data(backend, ctx, data) + outlen = backend._ffi.new("int *") + res = backend._lib.EVP_CipherFinal_ex(ctx, backend._ffi.NULL, outlen) + if res == 0: + backend._consume_errors() + raise InvalidTag + + return processed_data diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/backend.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/backend.py new file mode 100644 index 0000000..af14bfa --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/backend.py @@ -0,0 +1,1974 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import base64 +import calendar +import collections +import contextlib +import itertools +from contextlib import contextmanager + +import six + +from cryptography import utils, x509 +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.backends.interfaces import ( + CMACBackend, CipherBackend, DERSerializationBackend, DHBackend, DSABackend, + EllipticCurveBackend, HMACBackend, HashBackend, PBKDF2HMACBackend, + PEMSerializationBackend, RSABackend, ScryptBackend, X509Backend +) +from cryptography.hazmat.backends.openssl import aead +from cryptography.hazmat.backends.openssl.ciphers import _CipherContext +from cryptography.hazmat.backends.openssl.cmac import _CMACContext +from cryptography.hazmat.backends.openssl.decode_asn1 import _Integers +from cryptography.hazmat.backends.openssl.dh import ( + _DHParameters, _DHPrivateKey, _DHPublicKey, _dh_params_dup +) +from cryptography.hazmat.backends.openssl.dsa import ( + _DSAParameters, _DSAPrivateKey, _DSAPublicKey +) +from cryptography.hazmat.backends.openssl.ec import ( + _EllipticCurvePrivateKey, _EllipticCurvePublicKey +) +from cryptography.hazmat.backends.openssl.encode_asn1 import ( + _CRL_ENTRY_EXTENSION_ENCODE_HANDLERS, + _CRL_EXTENSION_ENCODE_HANDLERS, _EXTENSION_ENCODE_HANDLERS, + _encode_asn1_int_gc, _encode_asn1_str_gc, _encode_name_gc, _txt2obj_gc, +) +from cryptography.hazmat.backends.openssl.hashes import _HashContext +from cryptography.hazmat.backends.openssl.hmac import _HMACContext +from cryptography.hazmat.backends.openssl.rsa import ( + _RSAPrivateKey, _RSAPublicKey +) +from cryptography.hazmat.backends.openssl.x25519 import ( + _X25519PrivateKey, _X25519PublicKey +) +from cryptography.hazmat.backends.openssl.x509 import ( + _Certificate, _CertificateRevocationList, + _CertificateSigningRequest, _RevokedCertificate +) +from cryptography.hazmat.bindings.openssl import binding +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa +from cryptography.hazmat.primitives.asymmetric.padding import ( + MGF1, OAEP, PKCS1v15, PSS +) +from cryptography.hazmat.primitives.ciphers.algorithms import ( + AES, ARC4, Blowfish, CAST5, Camellia, ChaCha20, IDEA, SEED, TripleDES +) +from cryptography.hazmat.primitives.ciphers.modes import ( + CBC, CFB, CFB8, CTR, ECB, GCM, OFB, XTS +) +from cryptography.hazmat.primitives.kdf import scrypt + + +_MemoryBIO = collections.namedtuple("_MemoryBIO", ["bio", "char_ptr"]) + + +@utils.register_interface(CipherBackend) +@utils.register_interface(CMACBackend) +@utils.register_interface(DERSerializationBackend) +@utils.register_interface(DHBackend) +@utils.register_interface(DSABackend) +@utils.register_interface(EllipticCurveBackend) +@utils.register_interface(HashBackend) +@utils.register_interface(HMACBackend) +@utils.register_interface(PBKDF2HMACBackend) +@utils.register_interface(RSABackend) +@utils.register_interface(PEMSerializationBackend) +@utils.register_interface(X509Backend) +@utils.register_interface_if( + binding.Binding().lib.Cryptography_HAS_SCRYPT, ScryptBackend +) +class Backend(object): + """ + OpenSSL API binding interfaces. + """ + name = "openssl" + + def __init__(self): + self._binding = binding.Binding() + self._ffi = self._binding.ffi + self._lib = self._binding.lib + + self._cipher_registry = {} + self._register_default_ciphers() + self.activate_osrandom_engine() + self._dh_types = [self._lib.EVP_PKEY_DH] + if self._lib.Cryptography_HAS_EVP_PKEY_DHX: + self._dh_types.append(self._lib.EVP_PKEY_DHX) + + def openssl_assert(self, ok): + return binding._openssl_assert(self._lib, ok) + + def activate_builtin_random(self): + # Obtain a new structural reference. + e = self._lib.ENGINE_get_default_RAND() + if e != self._ffi.NULL: + self._lib.ENGINE_unregister_RAND(e) + # Reset the RNG to use the new engine. + self._lib.RAND_cleanup() + # decrement the structural reference from get_default_RAND + res = self._lib.ENGINE_finish(e) + self.openssl_assert(res == 1) + + @contextlib.contextmanager + def _get_osurandom_engine(self): + # Fetches an engine by id and returns it. This creates a structural + # reference. + e = self._lib.ENGINE_by_id(self._binding._osrandom_engine_id) + self.openssl_assert(e != self._ffi.NULL) + # Initialize the engine for use. This adds a functional reference. + res = self._lib.ENGINE_init(e) + self.openssl_assert(res == 1) + + try: + yield e + finally: + # Decrement the structural ref incremented by ENGINE_by_id. + res = self._lib.ENGINE_free(e) + self.openssl_assert(res == 1) + # Decrement the functional ref incremented by ENGINE_init. + res = self._lib.ENGINE_finish(e) + self.openssl_assert(res == 1) + + def activate_osrandom_engine(self): + # Unregister and free the current engine. + self.activate_builtin_random() + with self._get_osurandom_engine() as e: + # Set the engine as the default RAND provider. + res = self._lib.ENGINE_set_default_RAND(e) + self.openssl_assert(res == 1) + # Reset the RNG to use the new engine. + self._lib.RAND_cleanup() + + def osrandom_engine_implementation(self): + buf = self._ffi.new("char[]", 64) + with self._get_osurandom_engine() as e: + res = self._lib.ENGINE_ctrl_cmd(e, b"get_implementation", + len(buf), buf, + self._ffi.NULL, 0) + self.openssl_assert(res > 0) + return self._ffi.string(buf).decode('ascii') + + def openssl_version_text(self): + """ + Friendly string name of the loaded OpenSSL library. This is not + necessarily the same version as it was compiled against. + + Example: OpenSSL 1.0.1e 11 Feb 2013 + """ + return self._ffi.string( + self._lib.OpenSSL_version(self._lib.OPENSSL_VERSION) + ).decode("ascii") + + def openssl_version_number(self): + return self._lib.OpenSSL_version_num() + + def create_hmac_ctx(self, key, algorithm): + return _HMACContext(self, key, algorithm) + + def _build_openssl_digest_name(self, algorithm): + if algorithm.name == "blake2b" or algorithm.name == "blake2s": + alg = "{0}{1}".format( + algorithm.name, algorithm.digest_size * 8 + ).encode("ascii") + else: + alg = algorithm.name.encode("ascii") + + return alg + + def hash_supported(self, algorithm): + name = self._build_openssl_digest_name(algorithm) + digest = self._lib.EVP_get_digestbyname(name) + return digest != self._ffi.NULL + + def hmac_supported(self, algorithm): + return self.hash_supported(algorithm) + + def create_hash_ctx(self, algorithm): + return _HashContext(self, algorithm) + + def cipher_supported(self, cipher, mode): + try: + adapter = self._cipher_registry[type(cipher), type(mode)] + except KeyError: + return False + evp_cipher = adapter(self, cipher, mode) + return self._ffi.NULL != evp_cipher + + def register_cipher_adapter(self, cipher_cls, mode_cls, adapter): + if (cipher_cls, mode_cls) in self._cipher_registry: + raise ValueError("Duplicate registration for: {0} {1}.".format( + cipher_cls, mode_cls) + ) + self._cipher_registry[cipher_cls, mode_cls] = adapter + + def _register_default_ciphers(self): + for mode_cls in [CBC, CTR, ECB, OFB, CFB, CFB8, GCM]: + self.register_cipher_adapter( + AES, + mode_cls, + GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}") + ) + for mode_cls in [CBC, CTR, ECB, OFB, CFB]: + self.register_cipher_adapter( + Camellia, + mode_cls, + GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}") + ) + for mode_cls in [CBC, CFB, CFB8, OFB]: + self.register_cipher_adapter( + TripleDES, + mode_cls, + GetCipherByName("des-ede3-{mode.name}") + ) + self.register_cipher_adapter( + TripleDES, + ECB, + GetCipherByName("des-ede3") + ) + for mode_cls in [CBC, CFB, OFB, ECB]: + self.register_cipher_adapter( + Blowfish, + mode_cls, + GetCipherByName("bf-{mode.name}") + ) + for mode_cls in [CBC, CFB, OFB, ECB]: + self.register_cipher_adapter( + SEED, + mode_cls, + GetCipherByName("seed-{mode.name}") + ) + for cipher_cls, mode_cls in itertools.product( + [CAST5, IDEA], + [CBC, OFB, CFB, ECB], + ): + self.register_cipher_adapter( + cipher_cls, + mode_cls, + GetCipherByName("{cipher.name}-{mode.name}") + ) + self.register_cipher_adapter( + ARC4, + type(None), + GetCipherByName("rc4") + ) + self.register_cipher_adapter( + ChaCha20, + type(None), + GetCipherByName("chacha20") + ) + self.register_cipher_adapter(AES, XTS, _get_xts_cipher) + + def create_symmetric_encryption_ctx(self, cipher, mode): + return _CipherContext(self, cipher, mode, _CipherContext._ENCRYPT) + + def create_symmetric_decryption_ctx(self, cipher, mode): + return _CipherContext(self, cipher, mode, _CipherContext._DECRYPT) + + def pbkdf2_hmac_supported(self, algorithm): + return self.hmac_supported(algorithm) + + def derive_pbkdf2_hmac(self, algorithm, length, salt, iterations, + key_material): + buf = self._ffi.new("unsigned char[]", length) + evp_md = self._lib.EVP_get_digestbyname( + algorithm.name.encode("ascii")) + self.openssl_assert(evp_md != self._ffi.NULL) + res = self._lib.PKCS5_PBKDF2_HMAC( + key_material, + len(key_material), + salt, + len(salt), + iterations, + evp_md, + length, + buf + ) + self.openssl_assert(res == 1) + return self._ffi.buffer(buf)[:] + + def _consume_errors(self): + return binding._consume_errors(self._lib) + + def _bn_to_int(self, bn): + assert bn != self._ffi.NULL + + if not six.PY2: + # Python 3 has constant time from_bytes, so use that. + bn_num_bytes = self._lib.BN_num_bytes(bn) + bin_ptr = self._ffi.new("unsigned char[]", bn_num_bytes) + bin_len = self._lib.BN_bn2bin(bn, bin_ptr) + # A zero length means the BN has value 0 + self.openssl_assert(bin_len >= 0) + return int.from_bytes(self._ffi.buffer(bin_ptr)[:bin_len], "big") + else: + # Under Python 2 the best we can do is hex() + hex_cdata = self._lib.BN_bn2hex(bn) + self.openssl_assert(hex_cdata != self._ffi.NULL) + hex_str = self._ffi.string(hex_cdata) + self._lib.OPENSSL_free(hex_cdata) + return int(hex_str, 16) + + def _int_to_bn(self, num, bn=None): + """ + Converts a python integer to a BIGNUM. The returned BIGNUM will not + be garbage collected (to support adding them to structs that take + ownership of the object). Be sure to register it for GC if it will + be discarded after use. + """ + assert bn is None or bn != self._ffi.NULL + + if bn is None: + bn = self._ffi.NULL + + if not six.PY2: + # Python 3 has constant time to_bytes, so use that. + + binary = num.to_bytes(int(num.bit_length() / 8.0 + 1), "big") + bn_ptr = self._lib.BN_bin2bn(binary, len(binary), bn) + self.openssl_assert(bn_ptr != self._ffi.NULL) + return bn_ptr + + else: + # Under Python 2 the best we can do is hex(), [2:] removes the 0x + # prefix. + hex_num = hex(num).rstrip("L")[2:].encode("ascii") + bn_ptr = self._ffi.new("BIGNUM **") + bn_ptr[0] = bn + res = self._lib.BN_hex2bn(bn_ptr, hex_num) + self.openssl_assert(res != 0) + self.openssl_assert(bn_ptr[0] != self._ffi.NULL) + return bn_ptr[0] + + def generate_rsa_private_key(self, public_exponent, key_size): + rsa._verify_rsa_parameters(public_exponent, key_size) + + rsa_cdata = self._lib.RSA_new() + self.openssl_assert(rsa_cdata != self._ffi.NULL) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + + bn = self._int_to_bn(public_exponent) + bn = self._ffi.gc(bn, self._lib.BN_free) + + res = self._lib.RSA_generate_key_ex( + rsa_cdata, key_size, bn, self._ffi.NULL + ) + self.openssl_assert(res == 1) + evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) + + return _RSAPrivateKey(self, rsa_cdata, evp_pkey) + + def generate_rsa_parameters_supported(self, public_exponent, key_size): + return (public_exponent >= 3 and public_exponent & 1 != 0 and + key_size >= 512) + + def load_rsa_private_numbers(self, numbers): + rsa._check_private_key_components( + numbers.p, + numbers.q, + numbers.d, + numbers.dmp1, + numbers.dmq1, + numbers.iqmp, + numbers.public_numbers.e, + numbers.public_numbers.n + ) + rsa_cdata = self._lib.RSA_new() + self.openssl_assert(rsa_cdata != self._ffi.NULL) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + p = self._int_to_bn(numbers.p) + q = self._int_to_bn(numbers.q) + d = self._int_to_bn(numbers.d) + dmp1 = self._int_to_bn(numbers.dmp1) + dmq1 = self._int_to_bn(numbers.dmq1) + iqmp = self._int_to_bn(numbers.iqmp) + e = self._int_to_bn(numbers.public_numbers.e) + n = self._int_to_bn(numbers.public_numbers.n) + res = self._lib.RSA_set0_factors(rsa_cdata, p, q) + self.openssl_assert(res == 1) + res = self._lib.RSA_set0_key(rsa_cdata, n, e, d) + self.openssl_assert(res == 1) + res = self._lib.RSA_set0_crt_params(rsa_cdata, dmp1, dmq1, iqmp) + self.openssl_assert(res == 1) + res = self._lib.RSA_blinding_on(rsa_cdata, self._ffi.NULL) + self.openssl_assert(res == 1) + evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) + + return _RSAPrivateKey(self, rsa_cdata, evp_pkey) + + def load_rsa_public_numbers(self, numbers): + rsa._check_public_key_components(numbers.e, numbers.n) + rsa_cdata = self._lib.RSA_new() + self.openssl_assert(rsa_cdata != self._ffi.NULL) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + e = self._int_to_bn(numbers.e) + n = self._int_to_bn(numbers.n) + res = self._lib.RSA_set0_key(rsa_cdata, n, e, self._ffi.NULL) + self.openssl_assert(res == 1) + evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) + + return _RSAPublicKey(self, rsa_cdata, evp_pkey) + + def _create_evp_pkey_gc(self): + evp_pkey = self._lib.EVP_PKEY_new() + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + return evp_pkey + + def _rsa_cdata_to_evp_pkey(self, rsa_cdata): + evp_pkey = self._create_evp_pkey_gc() + res = self._lib.EVP_PKEY_set1_RSA(evp_pkey, rsa_cdata) + self.openssl_assert(res == 1) + return evp_pkey + + def _bytes_to_bio(self, data): + """ + Return a _MemoryBIO namedtuple of (BIO, char*). + + The char* is the storage for the BIO and it must stay alive until the + BIO is finished with. + """ + data_char_p = self._ffi.new("char[]", data) + bio = self._lib.BIO_new_mem_buf( + data_char_p, len(data) + ) + self.openssl_assert(bio != self._ffi.NULL) + + return _MemoryBIO(self._ffi.gc(bio, self._lib.BIO_free), data_char_p) + + def _create_mem_bio_gc(self): + """ + Creates an empty memory BIO. + """ + bio_method = self._lib.BIO_s_mem() + self.openssl_assert(bio_method != self._ffi.NULL) + bio = self._lib.BIO_new(bio_method) + self.openssl_assert(bio != self._ffi.NULL) + bio = self._ffi.gc(bio, self._lib.BIO_free) + return bio + + def _read_mem_bio(self, bio): + """ + Reads a memory BIO. This only works on memory BIOs. + """ + buf = self._ffi.new("char **") + buf_len = self._lib.BIO_get_mem_data(bio, buf) + self.openssl_assert(buf_len > 0) + self.openssl_assert(buf[0] != self._ffi.NULL) + bio_data = self._ffi.buffer(buf[0], buf_len)[:] + return bio_data + + def _evp_pkey_to_private_key(self, evp_pkey): + """ + Return the appropriate type of PrivateKey given an evp_pkey cdata + pointer. + """ + + key_type = self._lib.EVP_PKEY_id(evp_pkey) + + if key_type == self._lib.EVP_PKEY_RSA: + rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey) + self.openssl_assert(rsa_cdata != self._ffi.NULL) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + return _RSAPrivateKey(self, rsa_cdata, evp_pkey) + elif key_type == self._lib.EVP_PKEY_DSA: + dsa_cdata = self._lib.EVP_PKEY_get1_DSA(evp_pkey) + self.openssl_assert(dsa_cdata != self._ffi.NULL) + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + return _DSAPrivateKey(self, dsa_cdata, evp_pkey) + elif key_type == self._lib.EVP_PKEY_EC: + ec_cdata = self._lib.EVP_PKEY_get1_EC_KEY(evp_pkey) + self.openssl_assert(ec_cdata != self._ffi.NULL) + ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) + return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey) + elif key_type in self._dh_types: + dh_cdata = self._lib.EVP_PKEY_get1_DH(evp_pkey) + self.openssl_assert(dh_cdata != self._ffi.NULL) + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + return _DHPrivateKey(self, dh_cdata, evp_pkey) + else: + raise UnsupportedAlgorithm("Unsupported key type.") + + def _evp_pkey_to_public_key(self, evp_pkey): + """ + Return the appropriate type of PublicKey given an evp_pkey cdata + pointer. + """ + + key_type = self._lib.EVP_PKEY_id(evp_pkey) + + if key_type == self._lib.EVP_PKEY_RSA: + rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey) + self.openssl_assert(rsa_cdata != self._ffi.NULL) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + return _RSAPublicKey(self, rsa_cdata, evp_pkey) + elif key_type == self._lib.EVP_PKEY_DSA: + dsa_cdata = self._lib.EVP_PKEY_get1_DSA(evp_pkey) + self.openssl_assert(dsa_cdata != self._ffi.NULL) + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + return _DSAPublicKey(self, dsa_cdata, evp_pkey) + elif key_type == self._lib.EVP_PKEY_EC: + ec_cdata = self._lib.EVP_PKEY_get1_EC_KEY(evp_pkey) + self.openssl_assert(ec_cdata != self._ffi.NULL) + ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) + return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey) + elif key_type in self._dh_types: + dh_cdata = self._lib.EVP_PKEY_get1_DH(evp_pkey) + self.openssl_assert(dh_cdata != self._ffi.NULL) + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + return _DHPublicKey(self, dh_cdata, evp_pkey) + else: + raise UnsupportedAlgorithm("Unsupported key type.") + + def _oaep_hash_supported(self, algorithm): + if self._lib.Cryptography_HAS_RSA_OAEP_MD: + return isinstance( + algorithm, ( + hashes.SHA1, + hashes.SHA224, + hashes.SHA256, + hashes.SHA384, + hashes.SHA512, + ) + ) + else: + return isinstance(algorithm, hashes.SHA1) + + def rsa_padding_supported(self, padding): + if isinstance(padding, PKCS1v15): + return True + elif isinstance(padding, PSS) and isinstance(padding._mgf, MGF1): + return self.hash_supported(padding._mgf._algorithm) + elif isinstance(padding, OAEP) and isinstance(padding._mgf, MGF1): + return ( + self._oaep_hash_supported(padding._mgf._algorithm) and + self._oaep_hash_supported(padding._algorithm) and + ( + (padding._label is None or len(padding._label) == 0) or + self._lib.Cryptography_HAS_RSA_OAEP_LABEL == 1 + ) + ) + else: + return False + + def generate_dsa_parameters(self, key_size): + if key_size not in (1024, 2048, 3072): + raise ValueError("Key size must be 1024 or 2048 or 3072 bits.") + + ctx = self._lib.DSA_new() + self.openssl_assert(ctx != self._ffi.NULL) + ctx = self._ffi.gc(ctx, self._lib.DSA_free) + + res = self._lib.DSA_generate_parameters_ex( + ctx, key_size, self._ffi.NULL, 0, + self._ffi.NULL, self._ffi.NULL, self._ffi.NULL + ) + + self.openssl_assert(res == 1) + + return _DSAParameters(self, ctx) + + def generate_dsa_private_key(self, parameters): + ctx = self._lib.DSAparams_dup(parameters._dsa_cdata) + self.openssl_assert(ctx != self._ffi.NULL) + ctx = self._ffi.gc(ctx, self._lib.DSA_free) + self._lib.DSA_generate_key(ctx) + evp_pkey = self._dsa_cdata_to_evp_pkey(ctx) + + return _DSAPrivateKey(self, ctx, evp_pkey) + + def generate_dsa_private_key_and_parameters(self, key_size): + parameters = self.generate_dsa_parameters(key_size) + return self.generate_dsa_private_key(parameters) + + def _dsa_cdata_set_values(self, dsa_cdata, p, q, g, pub_key, priv_key): + res = self._lib.DSA_set0_pqg(dsa_cdata, p, q, g) + self.openssl_assert(res == 1) + res = self._lib.DSA_set0_key(dsa_cdata, pub_key, priv_key) + self.openssl_assert(res == 1) + + def load_dsa_private_numbers(self, numbers): + dsa._check_dsa_private_numbers(numbers) + parameter_numbers = numbers.public_numbers.parameter_numbers + + dsa_cdata = self._lib.DSA_new() + self.openssl_assert(dsa_cdata != self._ffi.NULL) + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + + p = self._int_to_bn(parameter_numbers.p) + q = self._int_to_bn(parameter_numbers.q) + g = self._int_to_bn(parameter_numbers.g) + pub_key = self._int_to_bn(numbers.public_numbers.y) + priv_key = self._int_to_bn(numbers.x) + self._dsa_cdata_set_values(dsa_cdata, p, q, g, pub_key, priv_key) + + evp_pkey = self._dsa_cdata_to_evp_pkey(dsa_cdata) + + return _DSAPrivateKey(self, dsa_cdata, evp_pkey) + + def load_dsa_public_numbers(self, numbers): + dsa._check_dsa_parameters(numbers.parameter_numbers) + dsa_cdata = self._lib.DSA_new() + self.openssl_assert(dsa_cdata != self._ffi.NULL) + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + + p = self._int_to_bn(numbers.parameter_numbers.p) + q = self._int_to_bn(numbers.parameter_numbers.q) + g = self._int_to_bn(numbers.parameter_numbers.g) + pub_key = self._int_to_bn(numbers.y) + priv_key = self._ffi.NULL + self._dsa_cdata_set_values(dsa_cdata, p, q, g, pub_key, priv_key) + + evp_pkey = self._dsa_cdata_to_evp_pkey(dsa_cdata) + + return _DSAPublicKey(self, dsa_cdata, evp_pkey) + + def load_dsa_parameter_numbers(self, numbers): + dsa._check_dsa_parameters(numbers) + dsa_cdata = self._lib.DSA_new() + self.openssl_assert(dsa_cdata != self._ffi.NULL) + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + + p = self._int_to_bn(numbers.p) + q = self._int_to_bn(numbers.q) + g = self._int_to_bn(numbers.g) + res = self._lib.DSA_set0_pqg(dsa_cdata, p, q, g) + self.openssl_assert(res == 1) + + return _DSAParameters(self, dsa_cdata) + + def _dsa_cdata_to_evp_pkey(self, dsa_cdata): + evp_pkey = self._create_evp_pkey_gc() + res = self._lib.EVP_PKEY_set1_DSA(evp_pkey, dsa_cdata) + self.openssl_assert(res == 1) + return evp_pkey + + def dsa_hash_supported(self, algorithm): + return self.hash_supported(algorithm) + + def dsa_parameters_supported(self, p, q, g): + return True + + def cmac_algorithm_supported(self, algorithm): + return self.cipher_supported( + algorithm, CBC(b"\x00" * algorithm.block_size) + ) + + def create_cmac_ctx(self, algorithm): + return _CMACContext(self, algorithm) + + def create_x509_csr(self, builder, private_key, algorithm): + if not isinstance(algorithm, hashes.HashAlgorithm): + raise TypeError('Algorithm must be a registered hash algorithm.') + + if ( + isinstance(algorithm, hashes.MD5) and not + isinstance(private_key, rsa.RSAPrivateKey) + ): + raise ValueError( + "MD5 is not a supported hash algorithm for EC/DSA CSRs" + ) + + # Resolve the signature algorithm. + evp_md = self._lib.EVP_get_digestbyname( + algorithm.name.encode('ascii') + ) + self.openssl_assert(evp_md != self._ffi.NULL) + + # Create an empty request. + x509_req = self._lib.X509_REQ_new() + self.openssl_assert(x509_req != self._ffi.NULL) + x509_req = self._ffi.gc(x509_req, self._lib.X509_REQ_free) + + # Set x509 version. + res = self._lib.X509_REQ_set_version(x509_req, x509.Version.v1.value) + self.openssl_assert(res == 1) + + # Set subject name. + res = self._lib.X509_REQ_set_subject_name( + x509_req, _encode_name_gc(self, builder._subject_name) + ) + self.openssl_assert(res == 1) + + # Set subject public key. + public_key = private_key.public_key() + res = self._lib.X509_REQ_set_pubkey( + x509_req, public_key._evp_pkey + ) + self.openssl_assert(res == 1) + + # Add extensions. + sk_extension = self._lib.sk_X509_EXTENSION_new_null() + self.openssl_assert(sk_extension != self._ffi.NULL) + sk_extension = self._ffi.gc( + sk_extension, self._lib.sk_X509_EXTENSION_free + ) + # gc is not necessary for CSRs, as sk_X509_EXTENSION_free + # will release all the X509_EXTENSIONs. + self._create_x509_extensions( + extensions=builder._extensions, + handlers=_EXTENSION_ENCODE_HANDLERS, + x509_obj=sk_extension, + add_func=self._lib.sk_X509_EXTENSION_insert, + gc=False + ) + res = self._lib.X509_REQ_add_extensions(x509_req, sk_extension) + self.openssl_assert(res == 1) + + # Sign the request using the requester's private key. + res = self._lib.X509_REQ_sign( + x509_req, private_key._evp_pkey, evp_md + ) + if res == 0: + errors = self._consume_errors() + self.openssl_assert( + errors[0]._lib_reason_match( + self._lib.ERR_LIB_RSA, + self._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY + ) + ) + + raise ValueError("Digest too big for RSA key") + + return _CertificateSigningRequest(self, x509_req) + + def create_x509_certificate(self, builder, private_key, algorithm): + if not isinstance(builder, x509.CertificateBuilder): + raise TypeError('Builder type mismatch.') + if not isinstance(algorithm, hashes.HashAlgorithm): + raise TypeError('Algorithm must be a registered hash algorithm.') + + if ( + isinstance(algorithm, hashes.MD5) and not + isinstance(private_key, rsa.RSAPrivateKey) + ): + raise ValueError( + "MD5 is not a supported hash algorithm for EC/DSA certificates" + ) + + # Resolve the signature algorithm. + evp_md = self._lib.EVP_get_digestbyname( + algorithm.name.encode('ascii') + ) + self.openssl_assert(evp_md != self._ffi.NULL) + + # Create an empty certificate. + x509_cert = self._lib.X509_new() + x509_cert = self._ffi.gc(x509_cert, backend._lib.X509_free) + + # Set the x509 version. + res = self._lib.X509_set_version(x509_cert, builder._version.value) + self.openssl_assert(res == 1) + + # Set the subject's name. + res = self._lib.X509_set_subject_name( + x509_cert, _encode_name_gc(self, builder._subject_name) + ) + self.openssl_assert(res == 1) + + # Set the subject's public key. + res = self._lib.X509_set_pubkey( + x509_cert, builder._public_key._evp_pkey + ) + self.openssl_assert(res == 1) + + # Set the certificate serial number. + serial_number = _encode_asn1_int_gc(self, builder._serial_number) + res = self._lib.X509_set_serialNumber(x509_cert, serial_number) + self.openssl_assert(res == 1) + + # Set the "not before" time. + res = self._lib.ASN1_TIME_set( + self._lib.X509_get_notBefore(x509_cert), + calendar.timegm(builder._not_valid_before.timetuple()) + ) + if res == self._ffi.NULL: + self._raise_time_set_error() + + # Set the "not after" time. + res = self._lib.ASN1_TIME_set( + self._lib.X509_get_notAfter(x509_cert), + calendar.timegm(builder._not_valid_after.timetuple()) + ) + if res == self._ffi.NULL: + self._raise_time_set_error() + + # Add extensions. + self._create_x509_extensions( + extensions=builder._extensions, + handlers=_EXTENSION_ENCODE_HANDLERS, + x509_obj=x509_cert, + add_func=self._lib.X509_add_ext, + gc=True + ) + + # Set the issuer name. + res = self._lib.X509_set_issuer_name( + x509_cert, _encode_name_gc(self, builder._issuer_name) + ) + self.openssl_assert(res == 1) + + # Sign the certificate with the issuer's private key. + res = self._lib.X509_sign( + x509_cert, private_key._evp_pkey, evp_md + ) + if res == 0: + errors = self._consume_errors() + self.openssl_assert( + errors[0]._lib_reason_match( + self._lib.ERR_LIB_RSA, + self._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY + ) + ) + raise ValueError("Digest too big for RSA key") + + return _Certificate(self, x509_cert) + + def _raise_time_set_error(self): + errors = self._consume_errors() + self.openssl_assert( + errors[0]._lib_reason_match( + self._lib.ERR_LIB_ASN1, + self._lib.ASN1_R_ERROR_GETTING_TIME + ) + ) + raise ValueError( + "Invalid time. This error can occur if you set a time too far in " + "the future on Windows." + ) + + def create_x509_crl(self, builder, private_key, algorithm): + if not isinstance(builder, x509.CertificateRevocationListBuilder): + raise TypeError('Builder type mismatch.') + if not isinstance(algorithm, hashes.HashAlgorithm): + raise TypeError('Algorithm must be a registered hash algorithm.') + + if ( + isinstance(algorithm, hashes.MD5) and not + isinstance(private_key, rsa.RSAPrivateKey) + ): + raise ValueError( + "MD5 is not a supported hash algorithm for EC/DSA CRLs" + ) + + evp_md = self._lib.EVP_get_digestbyname( + algorithm.name.encode('ascii') + ) + self.openssl_assert(evp_md != self._ffi.NULL) + + # Create an empty CRL. + x509_crl = self._lib.X509_CRL_new() + x509_crl = self._ffi.gc(x509_crl, backend._lib.X509_CRL_free) + + # Set the x509 CRL version. We only support v2 (integer value 1). + res = self._lib.X509_CRL_set_version(x509_crl, 1) + self.openssl_assert(res == 1) + + # Set the issuer name. + res = self._lib.X509_CRL_set_issuer_name( + x509_crl, _encode_name_gc(self, builder._issuer_name) + ) + self.openssl_assert(res == 1) + + # Set the last update time. + last_update = self._lib.ASN1_TIME_set( + self._ffi.NULL, calendar.timegm(builder._last_update.timetuple()) + ) + self.openssl_assert(last_update != self._ffi.NULL) + last_update = self._ffi.gc(last_update, self._lib.ASN1_TIME_free) + res = self._lib.X509_CRL_set_lastUpdate(x509_crl, last_update) + self.openssl_assert(res == 1) + + # Set the next update time. + next_update = self._lib.ASN1_TIME_set( + self._ffi.NULL, calendar.timegm(builder._next_update.timetuple()) + ) + self.openssl_assert(next_update != self._ffi.NULL) + next_update = self._ffi.gc(next_update, self._lib.ASN1_TIME_free) + res = self._lib.X509_CRL_set_nextUpdate(x509_crl, next_update) + self.openssl_assert(res == 1) + + # Add extensions. + self._create_x509_extensions( + extensions=builder._extensions, + handlers=_CRL_EXTENSION_ENCODE_HANDLERS, + x509_obj=x509_crl, + add_func=self._lib.X509_CRL_add_ext, + gc=True + ) + + # add revoked certificates + for revoked_cert in builder._revoked_certificates: + # Duplicating because the X509_CRL takes ownership and will free + # this memory when X509_CRL_free is called. + revoked = self._lib.Cryptography_X509_REVOKED_dup( + revoked_cert._x509_revoked + ) + self.openssl_assert(revoked != self._ffi.NULL) + res = self._lib.X509_CRL_add0_revoked(x509_crl, revoked) + self.openssl_assert(res == 1) + + res = self._lib.X509_CRL_sign( + x509_crl, private_key._evp_pkey, evp_md + ) + if res == 0: + errors = self._consume_errors() + self.openssl_assert( + errors[0]._lib_reason_match( + self._lib.ERR_LIB_RSA, + self._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY + ) + ) + raise ValueError("Digest too big for RSA key") + + return _CertificateRevocationList(self, x509_crl) + + def _create_x509_extensions(self, extensions, handlers, x509_obj, + add_func, gc): + for i, extension in enumerate(extensions): + x509_extension = self._create_x509_extension( + handlers, extension + ) + self.openssl_assert(x509_extension != self._ffi.NULL) + + if gc: + x509_extension = self._ffi.gc( + x509_extension, self._lib.X509_EXTENSION_free + ) + res = add_func(x509_obj, x509_extension, i) + self.openssl_assert(res >= 1) + + def _create_raw_x509_extension(self, extension, value): + obj = _txt2obj_gc(self, extension.oid.dotted_string) + return self._lib.X509_EXTENSION_create_by_OBJ( + self._ffi.NULL, obj, 1 if extension.critical else 0, value + ) + + def _create_x509_extension(self, handlers, extension): + if isinstance(extension.value, x509.UnrecognizedExtension): + value = _encode_asn1_str_gc( + self, extension.value.value, len(extension.value.value) + ) + return self._create_raw_x509_extension(extension, value) + elif isinstance(extension.value, x509.TLSFeature): + asn1 = _Integers([x.value for x in extension.value]).dump() + value = _encode_asn1_str_gc(self, asn1, len(asn1)) + return self._create_raw_x509_extension(extension, value) + else: + try: + encode = handlers[extension.oid] + except KeyError: + raise NotImplementedError( + 'Extension not supported: {0}'.format(extension.oid) + ) + + ext_struct = encode(self, extension.value) + nid = self._lib.OBJ_txt2nid( + extension.oid.dotted_string.encode("ascii") + ) + backend.openssl_assert(nid != self._lib.NID_undef) + return self._lib.X509V3_EXT_i2d( + nid, 1 if extension.critical else 0, ext_struct + ) + + def create_x509_revoked_certificate(self, builder): + if not isinstance(builder, x509.RevokedCertificateBuilder): + raise TypeError('Builder type mismatch.') + + x509_revoked = self._lib.X509_REVOKED_new() + self.openssl_assert(x509_revoked != self._ffi.NULL) + x509_revoked = self._ffi.gc(x509_revoked, self._lib.X509_REVOKED_free) + serial_number = _encode_asn1_int_gc(self, builder._serial_number) + res = self._lib.X509_REVOKED_set_serialNumber( + x509_revoked, serial_number + ) + self.openssl_assert(res == 1) + rev_date = self._lib.ASN1_TIME_set( + self._ffi.NULL, + calendar.timegm(builder._revocation_date.timetuple()) + ) + self.openssl_assert(rev_date != self._ffi.NULL) + rev_date = self._ffi.gc(rev_date, self._lib.ASN1_TIME_free) + res = self._lib.X509_REVOKED_set_revocationDate(x509_revoked, rev_date) + self.openssl_assert(res == 1) + # add CRL entry extensions + self._create_x509_extensions( + extensions=builder._extensions, + handlers=_CRL_ENTRY_EXTENSION_ENCODE_HANDLERS, + x509_obj=x509_revoked, + add_func=self._lib.X509_REVOKED_add_ext, + gc=True + ) + return _RevokedCertificate(self, None, x509_revoked) + + def load_pem_private_key(self, data, password): + return self._load_key( + self._lib.PEM_read_bio_PrivateKey, + self._evp_pkey_to_private_key, + data, + password, + ) + + def load_pem_public_key(self, data): + mem_bio = self._bytes_to_bio(data) + evp_pkey = self._lib.PEM_read_bio_PUBKEY( + mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL + ) + if evp_pkey != self._ffi.NULL: + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + return self._evp_pkey_to_public_key(evp_pkey) + else: + # It's not a (RSA/DSA/ECDSA) subjectPublicKeyInfo, but we still + # need to check to see if it is a pure PKCS1 RSA public key (not + # embedded in a subjectPublicKeyInfo) + self._consume_errors() + res = self._lib.BIO_reset(mem_bio.bio) + self.openssl_assert(res == 1) + rsa_cdata = self._lib.PEM_read_bio_RSAPublicKey( + mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL + ) + if rsa_cdata != self._ffi.NULL: + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) + return _RSAPublicKey(self, rsa_cdata, evp_pkey) + else: + self._handle_key_loading_error() + + def load_pem_parameters(self, data): + mem_bio = self._bytes_to_bio(data) + # only DH is supported currently + dh_cdata = self._lib.PEM_read_bio_DHparams( + mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL) + if dh_cdata != self._ffi.NULL: + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + return _DHParameters(self, dh_cdata) + else: + self._handle_key_loading_error() + + def load_der_private_key(self, data, password): + # OpenSSL has a function called d2i_AutoPrivateKey that in theory + # handles this automatically, however it doesn't handle encrypted + # private keys. Instead we try to load the key two different ways. + # First we'll try to load it as a traditional key. + bio_data = self._bytes_to_bio(data) + key = self._evp_pkey_from_der_traditional_key(bio_data, password) + if key: + return self._evp_pkey_to_private_key(key) + else: + # Finally we try to load it with the method that handles encrypted + # PKCS8 properly. + return self._load_key( + self._lib.d2i_PKCS8PrivateKey_bio, + self._evp_pkey_to_private_key, + data, + password, + ) + + def _evp_pkey_from_der_traditional_key(self, bio_data, password): + key = self._lib.d2i_PrivateKey_bio(bio_data.bio, self._ffi.NULL) + if key != self._ffi.NULL: + key = self._ffi.gc(key, self._lib.EVP_PKEY_free) + if password is not None: + raise TypeError( + "Password was given but private key is not encrypted." + ) + + return key + else: + self._consume_errors() + return None + + def load_der_public_key(self, data): + mem_bio = self._bytes_to_bio(data) + evp_pkey = self._lib.d2i_PUBKEY_bio(mem_bio.bio, self._ffi.NULL) + if evp_pkey != self._ffi.NULL: + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + return self._evp_pkey_to_public_key(evp_pkey) + else: + # It's not a (RSA/DSA/ECDSA) subjectPublicKeyInfo, but we still + # need to check to see if it is a pure PKCS1 RSA public key (not + # embedded in a subjectPublicKeyInfo) + self._consume_errors() + res = self._lib.BIO_reset(mem_bio.bio) + self.openssl_assert(res == 1) + rsa_cdata = self._lib.d2i_RSAPublicKey_bio( + mem_bio.bio, self._ffi.NULL + ) + if rsa_cdata != self._ffi.NULL: + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) + return _RSAPublicKey(self, rsa_cdata, evp_pkey) + else: + self._handle_key_loading_error() + + def load_der_parameters(self, data): + mem_bio = self._bytes_to_bio(data) + dh_cdata = self._lib.d2i_DHparams_bio( + mem_bio.bio, self._ffi.NULL + ) + if dh_cdata != self._ffi.NULL: + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + return _DHParameters(self, dh_cdata) + elif self._lib.Cryptography_HAS_EVP_PKEY_DHX: + # We check to see if the is dhx. + self._consume_errors() + res = self._lib.BIO_reset(mem_bio.bio) + self.openssl_assert(res == 1) + dh_cdata = self._lib.Cryptography_d2i_DHxparams_bio( + mem_bio.bio, self._ffi.NULL + ) + if dh_cdata != self._ffi.NULL: + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + return _DHParameters(self, dh_cdata) + + self._handle_key_loading_error() + + def load_pem_x509_certificate(self, data): + mem_bio = self._bytes_to_bio(data) + x509 = self._lib.PEM_read_bio_X509( + mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL + ) + if x509 == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to load certificate") + + x509 = self._ffi.gc(x509, self._lib.X509_free) + return _Certificate(self, x509) + + def load_der_x509_certificate(self, data): + mem_bio = self._bytes_to_bio(data) + x509 = self._lib.d2i_X509_bio(mem_bio.bio, self._ffi.NULL) + if x509 == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to load certificate") + + x509 = self._ffi.gc(x509, self._lib.X509_free) + return _Certificate(self, x509) + + def load_pem_x509_crl(self, data): + mem_bio = self._bytes_to_bio(data) + x509_crl = self._lib.PEM_read_bio_X509_CRL( + mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL + ) + if x509_crl == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to load CRL") + + x509_crl = self._ffi.gc(x509_crl, self._lib.X509_CRL_free) + return _CertificateRevocationList(self, x509_crl) + + def load_der_x509_crl(self, data): + mem_bio = self._bytes_to_bio(data) + x509_crl = self._lib.d2i_X509_CRL_bio(mem_bio.bio, self._ffi.NULL) + if x509_crl == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to load CRL") + + x509_crl = self._ffi.gc(x509_crl, self._lib.X509_CRL_free) + return _CertificateRevocationList(self, x509_crl) + + def load_pem_x509_csr(self, data): + mem_bio = self._bytes_to_bio(data) + x509_req = self._lib.PEM_read_bio_X509_REQ( + mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL + ) + if x509_req == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to load request") + + x509_req = self._ffi.gc(x509_req, self._lib.X509_REQ_free) + return _CertificateSigningRequest(self, x509_req) + + def load_der_x509_csr(self, data): + mem_bio = self._bytes_to_bio(data) + x509_req = self._lib.d2i_X509_REQ_bio(mem_bio.bio, self._ffi.NULL) + if x509_req == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to load request") + + x509_req = self._ffi.gc(x509_req, self._lib.X509_REQ_free) + return _CertificateSigningRequest(self, x509_req) + + def _load_key(self, openssl_read_func, convert_func, data, password): + mem_bio = self._bytes_to_bio(data) + + if password is not None and not isinstance(password, bytes): + raise TypeError("Password must be bytes") + + userdata = self._ffi.new("CRYPTOGRAPHY_PASSWORD_DATA *") + if password is not None: + password_buf = self._ffi.new("char []", password) + userdata.password = password_buf + userdata.length = len(password) + + evp_pkey = openssl_read_func( + mem_bio.bio, + self._ffi.NULL, + self._ffi.addressof( + self._lib._original_lib, "Cryptography_pem_password_cb" + ), + userdata, + ) + + if evp_pkey == self._ffi.NULL: + if userdata.error != 0: + errors = self._consume_errors() + self.openssl_assert(errors) + if userdata.error == -1: + raise TypeError( + "Password was not given but private key is encrypted" + ) + else: + assert userdata.error == -2 + raise ValueError( + "Passwords longer than {0} bytes are not supported " + "by this backend.".format(userdata.maxsize - 1) + ) + else: + self._handle_key_loading_error() + + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + + if password is not None and userdata.called == 0: + raise TypeError( + "Password was given but private key is not encrypted.") + + assert ( + (password is not None and userdata.called == 1) or + password is None + ) + + return convert_func(evp_pkey) + + def _handle_key_loading_error(self): + errors = self._consume_errors() + + if not errors: + raise ValueError("Could not deserialize key data.") + + elif ( + errors[0]._lib_reason_match( + self._lib.ERR_LIB_EVP, self._lib.EVP_R_BAD_DECRYPT + ) or errors[0]._lib_reason_match( + self._lib.ERR_LIB_PKCS12, + self._lib.PKCS12_R_PKCS12_CIPHERFINAL_ERROR + ) + ): + raise ValueError("Bad decrypt. Incorrect password?") + + elif ( + errors[0]._lib_reason_match( + self._lib.ERR_LIB_EVP, self._lib.EVP_R_UNKNOWN_PBE_ALGORITHM + ) or errors[0]._lib_reason_match( + self._lib.ERR_LIB_PEM, self._lib.PEM_R_UNSUPPORTED_ENCRYPTION + ) + ): + raise UnsupportedAlgorithm( + "PEM data is encrypted with an unsupported cipher", + _Reasons.UNSUPPORTED_CIPHER + ) + + elif any( + error._lib_reason_match( + self._lib.ERR_LIB_EVP, + self._lib.EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM + ) + for error in errors + ): + raise ValueError("Unsupported public key algorithm.") + + else: + assert errors[0].lib in ( + self._lib.ERR_LIB_EVP, + self._lib.ERR_LIB_PEM, + self._lib.ERR_LIB_ASN1, + ) + raise ValueError("Could not deserialize key data.") + + def elliptic_curve_supported(self, curve): + try: + curve_nid = self._elliptic_curve_to_nid(curve) + except UnsupportedAlgorithm: + curve_nid = self._lib.NID_undef + + group = self._lib.EC_GROUP_new_by_curve_name(curve_nid) + + if group == self._ffi.NULL: + errors = self._consume_errors() + self.openssl_assert( + curve_nid == self._lib.NID_undef or + errors[0]._lib_reason_match( + self._lib.ERR_LIB_EC, + self._lib.EC_R_UNKNOWN_GROUP + ) + ) + return False + else: + self.openssl_assert(curve_nid != self._lib.NID_undef) + self._lib.EC_GROUP_free(group) + return True + + def elliptic_curve_signature_algorithm_supported( + self, signature_algorithm, curve + ): + # We only support ECDSA right now. + if not isinstance(signature_algorithm, ec.ECDSA): + return False + + return self.elliptic_curve_supported(curve) + + def generate_elliptic_curve_private_key(self, curve): + """ + Generate a new private key on the named curve. + """ + + if self.elliptic_curve_supported(curve): + curve_nid = self._elliptic_curve_to_nid(curve) + + ec_cdata = self._lib.EC_KEY_new_by_curve_name(curve_nid) + self.openssl_assert(ec_cdata != self._ffi.NULL) + ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) + + res = self._lib.EC_KEY_generate_key(ec_cdata) + self.openssl_assert(res == 1) + + evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) + + return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey) + else: + raise UnsupportedAlgorithm( + "Backend object does not support {0}.".format(curve.name), + _Reasons.UNSUPPORTED_ELLIPTIC_CURVE + ) + + def load_elliptic_curve_private_numbers(self, numbers): + public = numbers.public_numbers + + curve_nid = self._elliptic_curve_to_nid(public.curve) + + ec_cdata = self._lib.EC_KEY_new_by_curve_name(curve_nid) + self.openssl_assert(ec_cdata != self._ffi.NULL) + ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) + + private_value = self._ffi.gc( + self._int_to_bn(numbers.private_value), self._lib.BN_clear_free + ) + res = self._lib.EC_KEY_set_private_key(ec_cdata, private_value) + self.openssl_assert(res == 1) + + ec_cdata = self._ec_key_set_public_key_affine_coordinates( + ec_cdata, public.x, public.y) + + evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) + + return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey) + + def load_elliptic_curve_public_numbers(self, numbers): + curve_nid = self._elliptic_curve_to_nid(numbers.curve) + + ec_cdata = self._lib.EC_KEY_new_by_curve_name(curve_nid) + self.openssl_assert(ec_cdata != self._ffi.NULL) + ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) + + ec_cdata = self._ec_key_set_public_key_affine_coordinates( + ec_cdata, numbers.x, numbers.y) + evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) + + return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey) + + def derive_elliptic_curve_private_key(self, private_value, curve): + curve_nid = self._elliptic_curve_to_nid(curve) + + ec_cdata = self._lib.EC_KEY_new_by_curve_name(curve_nid) + self.openssl_assert(ec_cdata != self._ffi.NULL) + ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) + + get_func, group = self._ec_key_determine_group_get_func(ec_cdata) + + point = self._lib.EC_POINT_new(group) + self.openssl_assert(point != self._ffi.NULL) + point = self._ffi.gc(point, self._lib.EC_POINT_free) + + value = self._int_to_bn(private_value) + value = self._ffi.gc(value, self._lib.BN_clear_free) + + with self._tmp_bn_ctx() as bn_ctx: + res = self._lib.EC_POINT_mul(group, point, value, self._ffi.NULL, + self._ffi.NULL, bn_ctx) + self.openssl_assert(res == 1) + + bn_x = self._lib.BN_CTX_get(bn_ctx) + bn_y = self._lib.BN_CTX_get(bn_ctx) + + res = get_func(group, point, bn_x, bn_y, bn_ctx) + self.openssl_assert(res == 1) + + res = self._lib.EC_KEY_set_public_key(ec_cdata, point) + self.openssl_assert(res == 1) + private = self._int_to_bn(private_value) + private = self._ffi.gc(private, self._lib.BN_clear_free) + res = self._lib.EC_KEY_set_private_key(ec_cdata, private) + self.openssl_assert(res == 1) + + evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) + + return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey) + + def elliptic_curve_exchange_algorithm_supported(self, algorithm, curve): + return ( + self.elliptic_curve_supported(curve) and + isinstance(algorithm, ec.ECDH) + ) + + def _ec_cdata_to_evp_pkey(self, ec_cdata): + evp_pkey = self._create_evp_pkey_gc() + res = self._lib.EVP_PKEY_set1_EC_KEY(evp_pkey, ec_cdata) + self.openssl_assert(res == 1) + return evp_pkey + + def _elliptic_curve_to_nid(self, curve): + """ + Get the NID for a curve name. + """ + + curve_aliases = { + "secp192r1": "prime192v1", + "secp256r1": "prime256v1" + } + + curve_name = curve_aliases.get(curve.name, curve.name) + + curve_nid = self._lib.OBJ_sn2nid(curve_name.encode()) + if curve_nid == self._lib.NID_undef: + raise UnsupportedAlgorithm( + "{0} is not a supported elliptic curve".format(curve.name), + _Reasons.UNSUPPORTED_ELLIPTIC_CURVE + ) + return curve_nid + + @contextmanager + def _tmp_bn_ctx(self): + bn_ctx = self._lib.BN_CTX_new() + self.openssl_assert(bn_ctx != self._ffi.NULL) + bn_ctx = self._ffi.gc(bn_ctx, self._lib.BN_CTX_free) + self._lib.BN_CTX_start(bn_ctx) + try: + yield bn_ctx + finally: + self._lib.BN_CTX_end(bn_ctx) + + def _ec_key_determine_group_get_func(self, ctx): + """ + Given an EC_KEY determine the group and what function is required to + get point coordinates. + """ + self.openssl_assert(ctx != self._ffi.NULL) + + nid_two_field = self._lib.OBJ_sn2nid(b"characteristic-two-field") + self.openssl_assert(nid_two_field != self._lib.NID_undef) + + group = self._lib.EC_KEY_get0_group(ctx) + self.openssl_assert(group != self._ffi.NULL) + + method = self._lib.EC_GROUP_method_of(group) + self.openssl_assert(method != self._ffi.NULL) + + nid = self._lib.EC_METHOD_get_field_type(method) + self.openssl_assert(nid != self._lib.NID_undef) + + if nid == nid_two_field and self._lib.Cryptography_HAS_EC2M: + get_func = self._lib.EC_POINT_get_affine_coordinates_GF2m + else: + get_func = self._lib.EC_POINT_get_affine_coordinates_GFp + + assert get_func + + return get_func, group + + def _ec_key_set_public_key_affine_coordinates(self, ctx, x, y): + """ + Sets the public key point in the EC_KEY context to the affine x and y + values. + """ + + if x < 0 or y < 0: + raise ValueError( + "Invalid EC key. Both x and y must be non-negative." + ) + + x = self._ffi.gc(self._int_to_bn(x), self._lib.BN_free) + y = self._ffi.gc(self._int_to_bn(y), self._lib.BN_free) + res = self._lib.EC_KEY_set_public_key_affine_coordinates(ctx, x, y) + if res != 1: + self._consume_errors() + raise ValueError("Invalid EC key.") + + return ctx + + def _private_key_bytes(self, encoding, format, encryption_algorithm, + evp_pkey, cdata): + if not isinstance(format, serialization.PrivateFormat): + raise TypeError( + "format must be an item from the PrivateFormat enum" + ) + + if not isinstance(encryption_algorithm, + serialization.KeySerializationEncryption): + raise TypeError( + "Encryption algorithm must be a KeySerializationEncryption " + "instance" + ) + + if isinstance(encryption_algorithm, serialization.NoEncryption): + password = b"" + passlen = 0 + evp_cipher = self._ffi.NULL + elif isinstance(encryption_algorithm, + serialization.BestAvailableEncryption): + # This is a curated value that we will update over time. + evp_cipher = self._lib.EVP_get_cipherbyname( + b"aes-256-cbc" + ) + password = encryption_algorithm.password + passlen = len(password) + if passlen > 1023: + raise ValueError( + "Passwords longer than 1023 bytes are not supported by " + "this backend" + ) + else: + raise ValueError("Unsupported encryption type") + + key_type = self._lib.EVP_PKEY_id(evp_pkey) + if encoding is serialization.Encoding.PEM: + if format is serialization.PrivateFormat.PKCS8: + write_bio = self._lib.PEM_write_bio_PKCS8PrivateKey + key = evp_pkey + else: + assert format is serialization.PrivateFormat.TraditionalOpenSSL + if key_type == self._lib.EVP_PKEY_RSA: + write_bio = self._lib.PEM_write_bio_RSAPrivateKey + elif key_type == self._lib.EVP_PKEY_DSA: + write_bio = self._lib.PEM_write_bio_DSAPrivateKey + else: + assert key_type == self._lib.EVP_PKEY_EC + write_bio = self._lib.PEM_write_bio_ECPrivateKey + + key = cdata + elif encoding is serialization.Encoding.DER: + if format is serialization.PrivateFormat.TraditionalOpenSSL: + if not isinstance( + encryption_algorithm, serialization.NoEncryption + ): + raise ValueError( + "Encryption is not supported for DER encoded " + "traditional OpenSSL keys" + ) + + return self._private_key_bytes_traditional_der(key_type, cdata) + else: + assert format is serialization.PrivateFormat.PKCS8 + write_bio = self._lib.i2d_PKCS8PrivateKey_bio + key = evp_pkey + else: + raise TypeError("encoding must be an item from the Encoding enum") + + bio = self._create_mem_bio_gc() + res = write_bio( + bio, + key, + evp_cipher, + password, + passlen, + self._ffi.NULL, + self._ffi.NULL + ) + self.openssl_assert(res == 1) + return self._read_mem_bio(bio) + + def _private_key_bytes_traditional_der(self, key_type, cdata): + if key_type == self._lib.EVP_PKEY_RSA: + write_bio = self._lib.i2d_RSAPrivateKey_bio + elif key_type == self._lib.EVP_PKEY_EC: + write_bio = self._lib.i2d_ECPrivateKey_bio + else: + self.openssl_assert(key_type == self._lib.EVP_PKEY_DSA) + write_bio = self._lib.i2d_DSAPrivateKey_bio + + bio = self._create_mem_bio_gc() + res = write_bio(bio, cdata) + self.openssl_assert(res == 1) + return self._read_mem_bio(bio) + + def _public_key_bytes(self, encoding, format, key, evp_pkey, cdata): + if not isinstance(encoding, serialization.Encoding): + raise TypeError("encoding must be an item from the Encoding enum") + + if ( + format is serialization.PublicFormat.OpenSSH or + encoding is serialization.Encoding.OpenSSH + ): + if ( + format is not serialization.PublicFormat.OpenSSH or + encoding is not serialization.Encoding.OpenSSH + ): + raise ValueError( + "OpenSSH format must be used with OpenSSH encoding" + ) + return self._openssh_public_key_bytes(key) + elif format is serialization.PublicFormat.SubjectPublicKeyInfo: + if encoding is serialization.Encoding.PEM: + write_bio = self._lib.PEM_write_bio_PUBKEY + else: + assert encoding is serialization.Encoding.DER + write_bio = self._lib.i2d_PUBKEY_bio + + key = evp_pkey + elif format is serialization.PublicFormat.PKCS1: + # Only RSA is supported here. + assert self._lib.EVP_PKEY_id(evp_pkey) == self._lib.EVP_PKEY_RSA + if encoding is serialization.Encoding.PEM: + write_bio = self._lib.PEM_write_bio_RSAPublicKey + else: + assert encoding is serialization.Encoding.DER + write_bio = self._lib.i2d_RSAPublicKey_bio + + key = cdata + else: + raise TypeError( + "format must be an item from the PublicFormat enum" + ) + + bio = self._create_mem_bio_gc() + res = write_bio(bio, key) + self.openssl_assert(res == 1) + return self._read_mem_bio(bio) + + def _openssh_public_key_bytes(self, key): + if isinstance(key, rsa.RSAPublicKey): + public_numbers = key.public_numbers() + return b"ssh-rsa " + base64.b64encode( + serialization._ssh_write_string(b"ssh-rsa") + + serialization._ssh_write_mpint(public_numbers.e) + + serialization._ssh_write_mpint(public_numbers.n) + ) + elif isinstance(key, dsa.DSAPublicKey): + public_numbers = key.public_numbers() + parameter_numbers = public_numbers.parameter_numbers + return b"ssh-dss " + base64.b64encode( + serialization._ssh_write_string(b"ssh-dss") + + serialization._ssh_write_mpint(parameter_numbers.p) + + serialization._ssh_write_mpint(parameter_numbers.q) + + serialization._ssh_write_mpint(parameter_numbers.g) + + serialization._ssh_write_mpint(public_numbers.y) + ) + else: + assert isinstance(key, ec.EllipticCurvePublicKey) + public_numbers = key.public_numbers() + try: + curve_name = { + ec.SECP256R1: b"nistp256", + ec.SECP384R1: b"nistp384", + ec.SECP521R1: b"nistp521", + }[type(public_numbers.curve)] + except KeyError: + raise ValueError( + "Only SECP256R1, SECP384R1, and SECP521R1 curves are " + "supported by the SSH public key format" + ) + return b"ecdsa-sha2-" + curve_name + b" " + base64.b64encode( + serialization._ssh_write_string(b"ecdsa-sha2-" + curve_name) + + serialization._ssh_write_string(curve_name) + + serialization._ssh_write_string(public_numbers.encode_point()) + ) + + def _parameter_bytes(self, encoding, format, cdata): + if encoding is serialization.Encoding.OpenSSH: + raise TypeError( + "OpenSSH encoding is not supported" + ) + + # Only DH is supported here currently. + q = self._ffi.new("BIGNUM **") + self._lib.DH_get0_pqg(cdata, + self._ffi.NULL, + q, + self._ffi.NULL) + if encoding is serialization.Encoding.PEM: + if q[0] != self._ffi.NULL: + write_bio = self._lib.PEM_write_bio_DHxparams + else: + write_bio = self._lib.PEM_write_bio_DHparams + elif encoding is serialization.Encoding.DER: + if q[0] != self._ffi.NULL: + write_bio = self._lib.Cryptography_i2d_DHxparams_bio + else: + write_bio = self._lib.i2d_DHparams_bio + else: + raise TypeError("encoding must be an item from the Encoding enum") + + bio = self._create_mem_bio_gc() + res = write_bio(bio, cdata) + self.openssl_assert(res == 1) + return self._read_mem_bio(bio) + + def generate_dh_parameters(self, generator, key_size): + if key_size < 512: + raise ValueError("DH key_size must be at least 512 bits") + + if generator not in (2, 5): + raise ValueError("DH generator must be 2 or 5") + + dh_param_cdata = self._lib.DH_new() + self.openssl_assert(dh_param_cdata != self._ffi.NULL) + dh_param_cdata = self._ffi.gc(dh_param_cdata, self._lib.DH_free) + + res = self._lib.DH_generate_parameters_ex( + dh_param_cdata, + key_size, + generator, + self._ffi.NULL + ) + self.openssl_assert(res == 1) + + return _DHParameters(self, dh_param_cdata) + + def _dh_cdata_to_evp_pkey(self, dh_cdata): + evp_pkey = self._create_evp_pkey_gc() + res = self._lib.EVP_PKEY_set1_DH(evp_pkey, dh_cdata) + self.openssl_assert(res == 1) + return evp_pkey + + def generate_dh_private_key(self, parameters): + dh_key_cdata = _dh_params_dup(parameters._dh_cdata, self) + + res = self._lib.DH_generate_key(dh_key_cdata) + self.openssl_assert(res == 1) + + evp_pkey = self._dh_cdata_to_evp_pkey(dh_key_cdata) + + return _DHPrivateKey(self, dh_key_cdata, evp_pkey) + + def generate_dh_private_key_and_parameters(self, generator, key_size): + return self.generate_dh_private_key( + self.generate_dh_parameters(generator, key_size)) + + def load_dh_private_numbers(self, numbers): + parameter_numbers = numbers.public_numbers.parameter_numbers + + dh_cdata = self._lib.DH_new() + self.openssl_assert(dh_cdata != self._ffi.NULL) + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + + p = self._int_to_bn(parameter_numbers.p) + g = self._int_to_bn(parameter_numbers.g) + + if parameter_numbers.q is not None: + q = self._int_to_bn(parameter_numbers.q) + else: + q = self._ffi.NULL + + pub_key = self._int_to_bn(numbers.public_numbers.y) + priv_key = self._int_to_bn(numbers.x) + + res = self._lib.DH_set0_pqg(dh_cdata, p, q, g) + self.openssl_assert(res == 1) + + res = self._lib.DH_set0_key(dh_cdata, pub_key, priv_key) + self.openssl_assert(res == 1) + + codes = self._ffi.new("int[]", 1) + res = self._lib.Cryptography_DH_check(dh_cdata, codes) + self.openssl_assert(res == 1) + + # DH_check will return DH_NOT_SUITABLE_GENERATOR if p % 24 does not + # equal 11 when the generator is 2 (a quadratic nonresidue). + # We want to ignore that error because p % 24 == 23 is also fine. + # Specifically, g is then a quadratic residue. Within the context of + # Diffie-Hellman this means it can only generate half the possible + # values. That sounds bad, but quadratic nonresidues leak a bit of + # the key to the attacker in exchange for having the full key space + # available. See: https://crypto.stackexchange.com/questions/12961 + if codes[0] != 0 and not ( + parameter_numbers.g == 2 and + codes[0] ^ self._lib.DH_NOT_SUITABLE_GENERATOR == 0 + ): + raise ValueError( + "DH private numbers did not pass safety checks." + ) + + evp_pkey = self._dh_cdata_to_evp_pkey(dh_cdata) + + return _DHPrivateKey(self, dh_cdata, evp_pkey) + + def load_dh_public_numbers(self, numbers): + dh_cdata = self._lib.DH_new() + self.openssl_assert(dh_cdata != self._ffi.NULL) + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + + parameter_numbers = numbers.parameter_numbers + + p = self._int_to_bn(parameter_numbers.p) + g = self._int_to_bn(parameter_numbers.g) + + if parameter_numbers.q is not None: + q = self._int_to_bn(parameter_numbers.q) + else: + q = self._ffi.NULL + + pub_key = self._int_to_bn(numbers.y) + + res = self._lib.DH_set0_pqg(dh_cdata, p, q, g) + self.openssl_assert(res == 1) + + res = self._lib.DH_set0_key(dh_cdata, pub_key, self._ffi.NULL) + self.openssl_assert(res == 1) + + evp_pkey = self._dh_cdata_to_evp_pkey(dh_cdata) + + return _DHPublicKey(self, dh_cdata, evp_pkey) + + def load_dh_parameter_numbers(self, numbers): + dh_cdata = self._lib.DH_new() + self.openssl_assert(dh_cdata != self._ffi.NULL) + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + + p = self._int_to_bn(numbers.p) + g = self._int_to_bn(numbers.g) + + if numbers.q is not None: + q = self._int_to_bn(numbers.q) + else: + q = self._ffi.NULL + + res = self._lib.DH_set0_pqg(dh_cdata, p, q, g) + self.openssl_assert(res == 1) + + return _DHParameters(self, dh_cdata) + + def dh_parameters_supported(self, p, g, q=None): + dh_cdata = self._lib.DH_new() + self.openssl_assert(dh_cdata != self._ffi.NULL) + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + + p = self._int_to_bn(p) + g = self._int_to_bn(g) + + if q is not None: + q = self._int_to_bn(q) + else: + q = self._ffi.NULL + + res = self._lib.DH_set0_pqg(dh_cdata, p, q, g) + self.openssl_assert(res == 1) + + codes = self._ffi.new("int[]", 1) + res = self._lib.Cryptography_DH_check(dh_cdata, codes) + self.openssl_assert(res == 1) + + return codes[0] == 0 + + def dh_x942_serialization_supported(self): + return self._lib.Cryptography_HAS_EVP_PKEY_DHX == 1 + + def x509_name_bytes(self, name): + x509_name = _encode_name_gc(self, name) + pp = self._ffi.new("unsigned char **") + res = self._lib.i2d_X509_NAME(x509_name, pp) + self.openssl_assert(pp[0] != self._ffi.NULL) + pp = self._ffi.gc( + pp, lambda pointer: self._lib.OPENSSL_free(pointer[0]) + ) + self.openssl_assert(res > 0) + return self._ffi.buffer(pp[0], res)[:] + + def x25519_load_public_bytes(self, data): + evp_pkey = self._create_evp_pkey_gc() + res = self._lib.EVP_PKEY_set_type(evp_pkey, self._lib.NID_X25519) + backend.openssl_assert(res == 1) + res = self._lib.EVP_PKEY_set1_tls_encodedpoint( + evp_pkey, data, len(data) + ) + backend.openssl_assert(res == 1) + return _X25519PublicKey(self, evp_pkey) + + def x25519_load_private_bytes(self, data): + # OpenSSL only has facilities for loading PKCS8 formatted private + # keys using the algorithm identifiers specified in + # https://tools.ietf.org/html/draft-ietf-curdle-pkix-09. + # This is the standard PKCS8 prefix for a 32 byte X25519 key. + # The form is: + # 0:d=0 hl=2 l= 46 cons: SEQUENCE + # 2:d=1 hl=2 l= 1 prim: INTEGER :00 + # 5:d=1 hl=2 l= 5 cons: SEQUENCE + # 7:d=2 hl=2 l= 3 prim: OBJECT :1.3.101.110 + # 12:d=1 hl=2 l= 34 prim: OCTET STRING (the key) + # Of course there's a bit more complexity. In reality OCTET STRING + # contains an OCTET STRING of length 32! So the last two bytes here + # are \x04\x20, which is an OCTET STRING of length 32. + pkcs8_prefix = b'0.\x02\x01\x000\x05\x06\x03+en\x04"\x04 ' + bio = self._bytes_to_bio(pkcs8_prefix + data) + evp_pkey = backend._lib.d2i_PrivateKey_bio(bio.bio, self._ffi.NULL) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + self.openssl_assert( + self._lib.EVP_PKEY_id(evp_pkey) == self._lib.EVP_PKEY_X25519 + ) + return _X25519PrivateKey(self, evp_pkey) + + def x25519_generate_key(self): + evp_pkey_ctx = self._lib.EVP_PKEY_CTX_new_id( + self._lib.NID_X25519, self._ffi.NULL + ) + self.openssl_assert(evp_pkey_ctx != self._ffi.NULL) + evp_pkey_ctx = self._ffi.gc( + evp_pkey_ctx, self._lib.EVP_PKEY_CTX_free + ) + res = self._lib.EVP_PKEY_keygen_init(evp_pkey_ctx) + self.openssl_assert(res == 1) + evp_ppkey = self._ffi.new("EVP_PKEY **") + res = self._lib.EVP_PKEY_keygen(evp_pkey_ctx, evp_ppkey) + self.openssl_assert(res == 1) + self.openssl_assert(evp_ppkey[0] != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_ppkey[0], self._lib.EVP_PKEY_free) + return _X25519PrivateKey(self, evp_pkey) + + def x25519_supported(self): + return self._lib.CRYPTOGRAPHY_OPENSSL_110_OR_GREATER + + def derive_scrypt(self, key_material, salt, length, n, r, p): + buf = self._ffi.new("unsigned char[]", length) + res = self._lib.EVP_PBE_scrypt( + key_material, len(key_material), salt, len(salt), n, r, p, + scrypt._MEM_LIMIT, buf, length + ) + self.openssl_assert(res == 1) + return self._ffi.buffer(buf)[:] + + def aead_cipher_supported(self, cipher): + cipher_name = aead._aead_cipher_name(cipher) + return ( + self._lib.EVP_get_cipherbyname(cipher_name) != self._ffi.NULL + ) + + +class GetCipherByName(object): + def __init__(self, fmt): + self._fmt = fmt + + def __call__(self, backend, cipher, mode): + cipher_name = self._fmt.format(cipher=cipher, mode=mode).lower() + return backend._lib.EVP_get_cipherbyname(cipher_name.encode("ascii")) + + +def _get_xts_cipher(backend, cipher, mode): + cipher_name = "aes-{0}-xts".format(cipher.key_size // 2) + return backend._lib.EVP_get_cipherbyname(cipher_name.encode("ascii")) + + +backend = Backend() diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/ciphers.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/ciphers.py new file mode 100644 index 0000000..e0ee06e --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/ciphers.py @@ -0,0 +1,222 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import utils +from cryptography.exceptions import InvalidTag, UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.primitives import ciphers +from cryptography.hazmat.primitives.ciphers import modes + + +@utils.register_interface(ciphers.CipherContext) +@utils.register_interface(ciphers.AEADCipherContext) +@utils.register_interface(ciphers.AEADEncryptionContext) +@utils.register_interface(ciphers.AEADDecryptionContext) +class _CipherContext(object): + _ENCRYPT = 1 + _DECRYPT = 0 + + def __init__(self, backend, cipher, mode, operation): + self._backend = backend + self._cipher = cipher + self._mode = mode + self._operation = operation + self._tag = None + + if isinstance(self._cipher, ciphers.BlockCipherAlgorithm): + self._block_size_bytes = self._cipher.block_size // 8 + else: + self._block_size_bytes = 1 + + ctx = self._backend._lib.EVP_CIPHER_CTX_new() + ctx = self._backend._ffi.gc( + ctx, self._backend._lib.EVP_CIPHER_CTX_free + ) + + registry = self._backend._cipher_registry + try: + adapter = registry[type(cipher), type(mode)] + except KeyError: + raise UnsupportedAlgorithm( + "cipher {0} in {1} mode is not supported " + "by this backend.".format( + cipher.name, mode.name if mode else mode), + _Reasons.UNSUPPORTED_CIPHER + ) + + evp_cipher = adapter(self._backend, cipher, mode) + if evp_cipher == self._backend._ffi.NULL: + raise UnsupportedAlgorithm( + "cipher {0} in {1} mode is not supported " + "by this backend.".format( + cipher.name, mode.name if mode else mode), + _Reasons.UNSUPPORTED_CIPHER + ) + + if isinstance(mode, modes.ModeWithInitializationVector): + iv_nonce = mode.initialization_vector + elif isinstance(mode, modes.ModeWithTweak): + iv_nonce = mode.tweak + elif isinstance(mode, modes.ModeWithNonce): + iv_nonce = mode.nonce + elif isinstance(cipher, modes.ModeWithNonce): + iv_nonce = cipher.nonce + else: + iv_nonce = self._backend._ffi.NULL + # begin init with cipher and operation type + res = self._backend._lib.EVP_CipherInit_ex(ctx, evp_cipher, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + operation) + self._backend.openssl_assert(res != 0) + # set the key length to handle variable key ciphers + res = self._backend._lib.EVP_CIPHER_CTX_set_key_length( + ctx, len(cipher.key) + ) + self._backend.openssl_assert(res != 0) + if isinstance(mode, modes.GCM): + res = self._backend._lib.EVP_CIPHER_CTX_ctrl( + ctx, self._backend._lib.EVP_CTRL_AEAD_SET_IVLEN, + len(iv_nonce), self._backend._ffi.NULL + ) + self._backend.openssl_assert(res != 0) + if mode.tag is not None: + res = self._backend._lib.EVP_CIPHER_CTX_ctrl( + ctx, self._backend._lib.EVP_CTRL_AEAD_SET_TAG, + len(mode.tag), mode.tag + ) + self._backend.openssl_assert(res != 0) + self._tag = mode.tag + elif ( + self._operation == self._DECRYPT and + self._backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 and + not self._backend._lib.CRYPTOGRAPHY_IS_LIBRESSL + ): + raise NotImplementedError( + "delayed passing of GCM tag requires OpenSSL >= 1.0.2." + " To use this feature please update OpenSSL" + ) + + # pass key/iv + res = self._backend._lib.EVP_CipherInit_ex( + ctx, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + cipher.key, + iv_nonce, + operation + ) + self._backend.openssl_assert(res != 0) + # We purposely disable padding here as it's handled higher up in the + # API. + self._backend._lib.EVP_CIPHER_CTX_set_padding(ctx, 0) + self._ctx = ctx + + def update(self, data): + buf = bytearray(len(data) + self._block_size_bytes - 1) + n = self.update_into(data, buf) + return bytes(buf[:n]) + + def update_into(self, data, buf): + if len(buf) < (len(data) + self._block_size_bytes - 1): + raise ValueError( + "buffer must be at least {0} bytes for this " + "payload".format(len(data) + self._block_size_bytes - 1) + ) + + buf = self._backend._ffi.cast( + "unsigned char *", self._backend._ffi.from_buffer(buf) + ) + outlen = self._backend._ffi.new("int *") + res = self._backend._lib.EVP_CipherUpdate(self._ctx, buf, outlen, + data, len(data)) + self._backend.openssl_assert(res != 0) + return outlen[0] + + def finalize(self): + # OpenSSL 1.0.1 on Ubuntu 12.04 (and possibly other distributions) + # appears to have a bug where you must make at least one call to update + # even if you are only using authenticate_additional_data or the + # GCM tag will be wrong. An (empty) call to update resolves this + # and is harmless for all other versions of OpenSSL. + if isinstance(self._mode, modes.GCM): + self.update(b"") + + if ( + self._operation == self._DECRYPT and + isinstance(self._mode, modes.ModeWithAuthenticationTag) and + self.tag is None + ): + raise ValueError( + "Authentication tag must be provided when decrypting." + ) + + buf = self._backend._ffi.new("unsigned char[]", self._block_size_bytes) + outlen = self._backend._ffi.new("int *") + res = self._backend._lib.EVP_CipherFinal_ex(self._ctx, buf, outlen) + if res == 0: + errors = self._backend._consume_errors() + + if not errors and isinstance(self._mode, modes.GCM): + raise InvalidTag + + self._backend.openssl_assert( + errors[0]._lib_reason_match( + self._backend._lib.ERR_LIB_EVP, + self._backend._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH + ) + ) + raise ValueError( + "The length of the provided data is not a multiple of " + "the block length." + ) + + if (isinstance(self._mode, modes.GCM) and + self._operation == self._ENCRYPT): + tag_buf = self._backend._ffi.new( + "unsigned char[]", self._block_size_bytes + ) + res = self._backend._lib.EVP_CIPHER_CTX_ctrl( + self._ctx, self._backend._lib.EVP_CTRL_AEAD_GET_TAG, + self._block_size_bytes, tag_buf + ) + self._backend.openssl_assert(res != 0) + self._tag = self._backend._ffi.buffer(tag_buf)[:] + + res = self._backend._lib.EVP_CIPHER_CTX_cleanup(self._ctx) + self._backend.openssl_assert(res == 1) + return self._backend._ffi.buffer(buf)[:outlen[0]] + + def finalize_with_tag(self, tag): + if ( + self._backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 and + not self._backend._lib.CRYPTOGRAPHY_IS_LIBRESSL + ): + raise NotImplementedError( + "finalize_with_tag requires OpenSSL >= 1.0.2. To use this " + "method please update OpenSSL" + ) + if len(tag) < self._mode._min_tag_length: + raise ValueError( + "Authentication tag must be {0} bytes or longer.".format( + self._mode._min_tag_length) + ) + res = self._backend._lib.EVP_CIPHER_CTX_ctrl( + self._ctx, self._backend._lib.EVP_CTRL_AEAD_SET_TAG, + len(tag), tag + ) + self._backend.openssl_assert(res != 0) + self._tag = tag + return self.finalize() + + def authenticate_additional_data(self, data): + outlen = self._backend._ffi.new("int *") + res = self._backend._lib.EVP_CipherUpdate( + self._ctx, self._backend._ffi.NULL, outlen, data, len(data) + ) + self._backend.openssl_assert(res != 0) + + tag = utils.read_only_property("_tag") diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/cmac.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/cmac.py new file mode 100644 index 0000000..e20f66d --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/cmac.py @@ -0,0 +1,81 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + + +from cryptography import utils +from cryptography.exceptions import ( + InvalidSignature, UnsupportedAlgorithm, _Reasons +) +from cryptography.hazmat.primitives import constant_time, mac +from cryptography.hazmat.primitives.ciphers.modes import CBC + + +@utils.register_interface(mac.MACContext) +class _CMACContext(object): + def __init__(self, backend, algorithm, ctx=None): + if not backend.cmac_algorithm_supported(algorithm): + raise UnsupportedAlgorithm("This backend does not support CMAC.", + _Reasons.UNSUPPORTED_CIPHER) + + self._backend = backend + self._key = algorithm.key + self._algorithm = algorithm + self._output_length = algorithm.block_size // 8 + + if ctx is None: + registry = self._backend._cipher_registry + adapter = registry[type(algorithm), CBC] + + evp_cipher = adapter(self._backend, algorithm, CBC) + + ctx = self._backend._lib.CMAC_CTX_new() + + self._backend.openssl_assert(ctx != self._backend._ffi.NULL) + ctx = self._backend._ffi.gc(ctx, self._backend._lib.CMAC_CTX_free) + + res = self._backend._lib.CMAC_Init( + ctx, self._key, len(self._key), + evp_cipher, self._backend._ffi.NULL + ) + self._backend.openssl_assert(res == 1) + + self._ctx = ctx + + algorithm = utils.read_only_property("_algorithm") + + def update(self, data): + res = self._backend._lib.CMAC_Update(self._ctx, data, len(data)) + self._backend.openssl_assert(res == 1) + + def finalize(self): + buf = self._backend._ffi.new("unsigned char[]", self._output_length) + length = self._backend._ffi.new("size_t *", self._output_length) + res = self._backend._lib.CMAC_Final( + self._ctx, buf, length + ) + self._backend.openssl_assert(res == 1) + + self._ctx = None + + return self._backend._ffi.buffer(buf)[:] + + def copy(self): + copied_ctx = self._backend._lib.CMAC_CTX_new() + copied_ctx = self._backend._ffi.gc( + copied_ctx, self._backend._lib.CMAC_CTX_free + ) + res = self._backend._lib.CMAC_CTX_copy( + copied_ctx, self._ctx + ) + self._backend.openssl_assert(res == 1) + return _CMACContext( + self._backend, self._algorithm, ctx=copied_ctx + ) + + def verify(self, signature): + digest = self.finalize() + if not constant_time.bytes_eq(digest, signature): + raise InvalidSignature("Signature did not match digest.") diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/decode_asn1.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/decode_asn1.py new file mode 100644 index 0000000..31fb8cf --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -0,0 +1,826 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import datetime +import ipaddress + +from asn1crypto.core import Integer, SequenceOf + +from cryptography import x509 +from cryptography.x509.extensions import _TLS_FEATURE_TYPE_TO_ENUM +from cryptography.x509.name import _ASN1_TYPE_TO_ENUM +from cryptography.x509.oid import ( + CRLEntryExtensionOID, CertificatePoliciesOID, ExtensionOID +) + + +class _Integers(SequenceOf): + _child_spec = Integer + + +def _obj2txt(backend, obj): + # Set to 80 on the recommendation of + # https://www.openssl.org/docs/crypto/OBJ_nid2ln.html#return_values + # + # But OIDs longer than this occur in real life (e.g. Active + # Directory makes some very long OIDs). So we need to detect + # and properly handle the case where the default buffer is not + # big enough. + # + buf_len = 80 + buf = backend._ffi.new("char[]", buf_len) + + # 'res' is the number of bytes that *would* be written if the + # buffer is large enough. If 'res' > buf_len - 1, we need to + # alloc a big-enough buffer and go again. + res = backend._lib.OBJ_obj2txt(buf, buf_len, obj, 1) + if res > buf_len - 1: # account for terminating null byte + buf_len = res + 1 + buf = backend._ffi.new("char[]", buf_len) + res = backend._lib.OBJ_obj2txt(buf, buf_len, obj, 1) + backend.openssl_assert(res > 0) + return backend._ffi.buffer(buf, res)[:].decode() + + +def _decode_x509_name_entry(backend, x509_name_entry): + obj = backend._lib.X509_NAME_ENTRY_get_object(x509_name_entry) + backend.openssl_assert(obj != backend._ffi.NULL) + data = backend._lib.X509_NAME_ENTRY_get_data(x509_name_entry) + backend.openssl_assert(data != backend._ffi.NULL) + value = _asn1_string_to_utf8(backend, data) + oid = _obj2txt(backend, obj) + type = _ASN1_TYPE_TO_ENUM[data.type] + + return x509.NameAttribute(x509.ObjectIdentifier(oid), value, type) + + +def _decode_x509_name(backend, x509_name): + count = backend._lib.X509_NAME_entry_count(x509_name) + attributes = [] + prev_set_id = -1 + for x in range(count): + entry = backend._lib.X509_NAME_get_entry(x509_name, x) + attribute = _decode_x509_name_entry(backend, entry) + set_id = backend._lib.Cryptography_X509_NAME_ENTRY_set(entry) + if set_id != prev_set_id: + attributes.append(set([attribute])) + else: + # is in the same RDN a previous entry + attributes[-1].add(attribute) + prev_set_id = set_id + + return x509.Name(x509.RelativeDistinguishedName(rdn) for rdn in attributes) + + +def _decode_general_names(backend, gns): + num = backend._lib.sk_GENERAL_NAME_num(gns) + names = [] + for i in range(num): + gn = backend._lib.sk_GENERAL_NAME_value(gns, i) + backend.openssl_assert(gn != backend._ffi.NULL) + names.append(_decode_general_name(backend, gn)) + + return names + + +def _decode_general_name(backend, gn): + if gn.type == backend._lib.GEN_DNS: + # Convert to bytes and then decode to utf8. We don't use + # asn1_string_to_utf8 here because it doesn't properly convert + # utf8 from ia5strings. + data = _asn1_string_to_bytes(backend, gn.d.dNSName).decode("utf8") + # We don't use the constructor for DNSName so we can bypass validation + # This allows us to create DNSName objects that have unicode chars + # when a certificate (against the RFC) contains them. + return x509.DNSName._init_without_validation(data) + elif gn.type == backend._lib.GEN_URI: + # Convert to bytes and then decode to utf8. We don't use + # asn1_string_to_utf8 here because it doesn't properly convert + # utf8 from ia5strings. + data = _asn1_string_to_bytes( + backend, gn.d.uniformResourceIdentifier + ).decode("utf8") + # We don't use the constructor for URI so we can bypass validation + # This allows us to create URI objects that have unicode chars + # when a certificate (against the RFC) contains them. + return x509.UniformResourceIdentifier._init_without_validation(data) + elif gn.type == backend._lib.GEN_RID: + oid = _obj2txt(backend, gn.d.registeredID) + return x509.RegisteredID(x509.ObjectIdentifier(oid)) + elif gn.type == backend._lib.GEN_IPADD: + data = _asn1_string_to_bytes(backend, gn.d.iPAddress) + data_len = len(data) + if data_len == 8 or data_len == 32: + # This is an IPv4 or IPv6 Network and not a single IP. This + # type of data appears in Name Constraints. Unfortunately, + # ipaddress doesn't support packed bytes + netmask. Additionally, + # IPv6Network can only handle CIDR rather than the full 16 byte + # netmask. To handle this we convert the netmask to integer, then + # find the first 0 bit, which will be the prefix. If another 1 + # bit is present after that the netmask is invalid. + base = ipaddress.ip_address(data[:data_len // 2]) + netmask = ipaddress.ip_address(data[data_len // 2:]) + bits = bin(int(netmask))[2:] + prefix = bits.find('0') + # If no 0 bits are found it is a /32 or /128 + if prefix == -1: + prefix = len(bits) + + if "1" in bits[prefix:]: + raise ValueError("Invalid netmask") + + ip = ipaddress.ip_network(base.exploded + u"/{0}".format(prefix)) + else: + ip = ipaddress.ip_address(data) + + return x509.IPAddress(ip) + elif gn.type == backend._lib.GEN_DIRNAME: + return x509.DirectoryName( + _decode_x509_name(backend, gn.d.directoryName) + ) + elif gn.type == backend._lib.GEN_EMAIL: + # Convert to bytes and then decode to utf8. We don't use + # asn1_string_to_utf8 here because it doesn't properly convert + # utf8 from ia5strings. + data = _asn1_string_to_bytes(backend, gn.d.rfc822Name).decode("utf8") + # We don't use the constructor for RFC822Name so we can bypass + # validation. This allows us to create RFC822Name objects that have + # unicode chars when a certificate (against the RFC) contains them. + return x509.RFC822Name._init_without_validation(data) + elif gn.type == backend._lib.GEN_OTHERNAME: + type_id = _obj2txt(backend, gn.d.otherName.type_id) + value = _asn1_to_der(backend, gn.d.otherName.value) + return x509.OtherName(x509.ObjectIdentifier(type_id), value) + else: + # x400Address or ediPartyName + raise x509.UnsupportedGeneralNameType( + "{0} is not a supported type".format( + x509._GENERAL_NAMES.get(gn.type, gn.type) + ), + gn.type + ) + + +def _decode_ocsp_no_check(backend, ext): + return x509.OCSPNoCheck() + + +def _decode_crl_number(backend, ext): + asn1_int = backend._ffi.cast("ASN1_INTEGER *", ext) + asn1_int = backend._ffi.gc(asn1_int, backend._lib.ASN1_INTEGER_free) + return x509.CRLNumber(_asn1_integer_to_int(backend, asn1_int)) + + +def _decode_delta_crl_indicator(backend, ext): + asn1_int = backend._ffi.cast("ASN1_INTEGER *", ext) + asn1_int = backend._ffi.gc(asn1_int, backend._lib.ASN1_INTEGER_free) + return x509.DeltaCRLIndicator(_asn1_integer_to_int(backend, asn1_int)) + + +class _X509ExtensionParser(object): + def __init__(self, ext_count, get_ext, handlers): + self.ext_count = ext_count + self.get_ext = get_ext + self.handlers = handlers + + def parse(self, backend, x509_obj): + extensions = [] + seen_oids = set() + for i in range(self.ext_count(backend, x509_obj)): + ext = self.get_ext(backend, x509_obj, i) + backend.openssl_assert(ext != backend._ffi.NULL) + crit = backend._lib.X509_EXTENSION_get_critical(ext) + critical = crit == 1 + oid = x509.ObjectIdentifier( + _obj2txt(backend, backend._lib.X509_EXTENSION_get_object(ext)) + ) + if oid in seen_oids: + raise x509.DuplicateExtension( + "Duplicate {0} extension found".format(oid), oid + ) + + # This OID is only supported in OpenSSL 1.1.0+ but we want + # to support it in all versions of OpenSSL so we decode it + # ourselves. + if oid == ExtensionOID.TLS_FEATURE: + data = backend._lib.X509_EXTENSION_get_data(ext) + parsed = _Integers.load(_asn1_string_to_bytes(backend, data)) + value = x509.TLSFeature( + [_TLS_FEATURE_TYPE_TO_ENUM[x.native] for x in parsed] + ) + extensions.append(x509.Extension(oid, critical, value)) + seen_oids.add(oid) + continue + + try: + handler = self.handlers[oid] + except KeyError: + # Dump the DER payload into an UnrecognizedExtension object + data = backend._lib.X509_EXTENSION_get_data(ext) + backend.openssl_assert(data != backend._ffi.NULL) + der = backend._ffi.buffer(data.data, data.length)[:] + unrecognized = x509.UnrecognizedExtension(oid, der) + extensions.append( + x509.Extension(oid, critical, unrecognized) + ) + else: + ext_data = backend._lib.X509V3_EXT_d2i(ext) + if ext_data == backend._ffi.NULL: + backend._consume_errors() + raise ValueError( + "The {0} extension is invalid and can't be " + "parsed".format(oid) + ) + + value = handler(backend, ext_data) + extensions.append(x509.Extension(oid, critical, value)) + + seen_oids.add(oid) + + return x509.Extensions(extensions) + + +def _decode_certificate_policies(backend, cp): + cp = backend._ffi.cast("Cryptography_STACK_OF_POLICYINFO *", cp) + cp = backend._ffi.gc(cp, backend._lib.CERTIFICATEPOLICIES_free) + + num = backend._lib.sk_POLICYINFO_num(cp) + certificate_policies = [] + for i in range(num): + qualifiers = None + pi = backend._lib.sk_POLICYINFO_value(cp, i) + oid = x509.ObjectIdentifier(_obj2txt(backend, pi.policyid)) + if pi.qualifiers != backend._ffi.NULL: + qnum = backend._lib.sk_POLICYQUALINFO_num(pi.qualifiers) + qualifiers = [] + for j in range(qnum): + pqi = backend._lib.sk_POLICYQUALINFO_value( + pi.qualifiers, j + ) + pqualid = x509.ObjectIdentifier( + _obj2txt(backend, pqi.pqualid) + ) + if pqualid == CertificatePoliciesOID.CPS_QUALIFIER: + cpsuri = backend._ffi.buffer( + pqi.d.cpsuri.data, pqi.d.cpsuri.length + )[:].decode('ascii') + qualifiers.append(cpsuri) + else: + assert pqualid == CertificatePoliciesOID.CPS_USER_NOTICE + user_notice = _decode_user_notice( + backend, pqi.d.usernotice + ) + qualifiers.append(user_notice) + + certificate_policies.append( + x509.PolicyInformation(oid, qualifiers) + ) + + return x509.CertificatePolicies(certificate_policies) + + +def _decode_user_notice(backend, un): + explicit_text = None + notice_reference = None + + if un.exptext != backend._ffi.NULL: + explicit_text = _asn1_string_to_utf8(backend, un.exptext) + + if un.noticeref != backend._ffi.NULL: + organization = _asn1_string_to_utf8( + backend, un.noticeref.organization + ) + + num = backend._lib.sk_ASN1_INTEGER_num( + un.noticeref.noticenos + ) + notice_numbers = [] + for i in range(num): + asn1_int = backend._lib.sk_ASN1_INTEGER_value( + un.noticeref.noticenos, i + ) + notice_num = _asn1_integer_to_int(backend, asn1_int) + notice_numbers.append(notice_num) + + notice_reference = x509.NoticeReference( + organization, notice_numbers + ) + + return x509.UserNotice(notice_reference, explicit_text) + + +def _decode_basic_constraints(backend, bc_st): + basic_constraints = backend._ffi.cast("BASIC_CONSTRAINTS *", bc_st) + basic_constraints = backend._ffi.gc( + basic_constraints, backend._lib.BASIC_CONSTRAINTS_free + ) + # The byte representation of an ASN.1 boolean true is \xff. OpenSSL + # chooses to just map this to its ordinal value, so true is 255 and + # false is 0. + ca = basic_constraints.ca == 255 + path_length = _asn1_integer_to_int_or_none( + backend, basic_constraints.pathlen + ) + + return x509.BasicConstraints(ca, path_length) + + +def _decode_subject_key_identifier(backend, asn1_string): + asn1_string = backend._ffi.cast("ASN1_OCTET_STRING *", asn1_string) + asn1_string = backend._ffi.gc( + asn1_string, backend._lib.ASN1_OCTET_STRING_free + ) + return x509.SubjectKeyIdentifier( + backend._ffi.buffer(asn1_string.data, asn1_string.length)[:] + ) + + +def _decode_authority_key_identifier(backend, akid): + akid = backend._ffi.cast("AUTHORITY_KEYID *", akid) + akid = backend._ffi.gc(akid, backend._lib.AUTHORITY_KEYID_free) + key_identifier = None + authority_cert_issuer = None + + if akid.keyid != backend._ffi.NULL: + key_identifier = backend._ffi.buffer( + akid.keyid.data, akid.keyid.length + )[:] + + if akid.issuer != backend._ffi.NULL: + authority_cert_issuer = _decode_general_names( + backend, akid.issuer + ) + + authority_cert_serial_number = _asn1_integer_to_int_or_none( + backend, akid.serial + ) + + return x509.AuthorityKeyIdentifier( + key_identifier, authority_cert_issuer, authority_cert_serial_number + ) + + +def _decode_authority_information_access(backend, aia): + aia = backend._ffi.cast("Cryptography_STACK_OF_ACCESS_DESCRIPTION *", aia) + aia = backend._ffi.gc(aia, backend._lib.sk_ACCESS_DESCRIPTION_free) + num = backend._lib.sk_ACCESS_DESCRIPTION_num(aia) + access_descriptions = [] + for i in range(num): + ad = backend._lib.sk_ACCESS_DESCRIPTION_value(aia, i) + backend.openssl_assert(ad.method != backend._ffi.NULL) + oid = x509.ObjectIdentifier(_obj2txt(backend, ad.method)) + backend.openssl_assert(ad.location != backend._ffi.NULL) + gn = _decode_general_name(backend, ad.location) + access_descriptions.append(x509.AccessDescription(oid, gn)) + + return x509.AuthorityInformationAccess(access_descriptions) + + +def _decode_key_usage(backend, bit_string): + bit_string = backend._ffi.cast("ASN1_BIT_STRING *", bit_string) + bit_string = backend._ffi.gc(bit_string, backend._lib.ASN1_BIT_STRING_free) + get_bit = backend._lib.ASN1_BIT_STRING_get_bit + digital_signature = get_bit(bit_string, 0) == 1 + content_commitment = get_bit(bit_string, 1) == 1 + key_encipherment = get_bit(bit_string, 2) == 1 + data_encipherment = get_bit(bit_string, 3) == 1 + key_agreement = get_bit(bit_string, 4) == 1 + key_cert_sign = get_bit(bit_string, 5) == 1 + crl_sign = get_bit(bit_string, 6) == 1 + encipher_only = get_bit(bit_string, 7) == 1 + decipher_only = get_bit(bit_string, 8) == 1 + return x509.KeyUsage( + digital_signature, + content_commitment, + key_encipherment, + data_encipherment, + key_agreement, + key_cert_sign, + crl_sign, + encipher_only, + decipher_only + ) + + +def _decode_general_names_extension(backend, gns): + gns = backend._ffi.cast("GENERAL_NAMES *", gns) + gns = backend._ffi.gc(gns, backend._lib.GENERAL_NAMES_free) + general_names = _decode_general_names(backend, gns) + return general_names + + +def _decode_subject_alt_name(backend, ext): + return x509.SubjectAlternativeName( + _decode_general_names_extension(backend, ext) + ) + + +def _decode_issuer_alt_name(backend, ext): + return x509.IssuerAlternativeName( + _decode_general_names_extension(backend, ext) + ) + + +def _decode_name_constraints(backend, nc): + nc = backend._ffi.cast("NAME_CONSTRAINTS *", nc) + nc = backend._ffi.gc(nc, backend._lib.NAME_CONSTRAINTS_free) + permitted = _decode_general_subtrees(backend, nc.permittedSubtrees) + excluded = _decode_general_subtrees(backend, nc.excludedSubtrees) + return x509.NameConstraints( + permitted_subtrees=permitted, excluded_subtrees=excluded + ) + + +def _decode_general_subtrees(backend, stack_subtrees): + if stack_subtrees == backend._ffi.NULL: + return None + + num = backend._lib.sk_GENERAL_SUBTREE_num(stack_subtrees) + subtrees = [] + + for i in range(num): + obj = backend._lib.sk_GENERAL_SUBTREE_value(stack_subtrees, i) + backend.openssl_assert(obj != backend._ffi.NULL) + name = _decode_general_name(backend, obj.base) + subtrees.append(name) + + return subtrees + + +def _decode_policy_constraints(backend, pc): + pc = backend._ffi.cast("POLICY_CONSTRAINTS *", pc) + pc = backend._ffi.gc(pc, backend._lib.POLICY_CONSTRAINTS_free) + + require_explicit_policy = _asn1_integer_to_int_or_none( + backend, pc.requireExplicitPolicy + ) + inhibit_policy_mapping = _asn1_integer_to_int_or_none( + backend, pc.inhibitPolicyMapping + ) + + return x509.PolicyConstraints( + require_explicit_policy, inhibit_policy_mapping + ) + + +def _decode_extended_key_usage(backend, sk): + sk = backend._ffi.cast("Cryptography_STACK_OF_ASN1_OBJECT *", sk) + sk = backend._ffi.gc(sk, backend._lib.sk_ASN1_OBJECT_free) + num = backend._lib.sk_ASN1_OBJECT_num(sk) + ekus = [] + + for i in range(num): + obj = backend._lib.sk_ASN1_OBJECT_value(sk, i) + backend.openssl_assert(obj != backend._ffi.NULL) + oid = x509.ObjectIdentifier(_obj2txt(backend, obj)) + ekus.append(oid) + + return x509.ExtendedKeyUsage(ekus) + + +_DISTPOINT_TYPE_FULLNAME = 0 +_DISTPOINT_TYPE_RELATIVENAME = 1 + + +def _decode_dist_points(backend, cdps): + cdps = backend._ffi.cast("Cryptography_STACK_OF_DIST_POINT *", cdps) + cdps = backend._ffi.gc(cdps, backend._lib.CRL_DIST_POINTS_free) + + num = backend._lib.sk_DIST_POINT_num(cdps) + dist_points = [] + for i in range(num): + full_name = None + relative_name = None + crl_issuer = None + reasons = None + cdp = backend._lib.sk_DIST_POINT_value(cdps, i) + if cdp.reasons != backend._ffi.NULL: + # We will check each bit from RFC 5280 + # ReasonFlags ::= BIT STRING { + # unused (0), + # keyCompromise (1), + # cACompromise (2), + # affiliationChanged (3), + # superseded (4), + # cessationOfOperation (5), + # certificateHold (6), + # privilegeWithdrawn (7), + # aACompromise (8) } + reasons = [] + get_bit = backend._lib.ASN1_BIT_STRING_get_bit + if get_bit(cdp.reasons, 1): + reasons.append(x509.ReasonFlags.key_compromise) + + if get_bit(cdp.reasons, 2): + reasons.append(x509.ReasonFlags.ca_compromise) + + if get_bit(cdp.reasons, 3): + reasons.append(x509.ReasonFlags.affiliation_changed) + + if get_bit(cdp.reasons, 4): + reasons.append(x509.ReasonFlags.superseded) + + if get_bit(cdp.reasons, 5): + reasons.append(x509.ReasonFlags.cessation_of_operation) + + if get_bit(cdp.reasons, 6): + reasons.append(x509.ReasonFlags.certificate_hold) + + if get_bit(cdp.reasons, 7): + reasons.append(x509.ReasonFlags.privilege_withdrawn) + + if get_bit(cdp.reasons, 8): + reasons.append(x509.ReasonFlags.aa_compromise) + + reasons = frozenset(reasons) + + if cdp.CRLissuer != backend._ffi.NULL: + crl_issuer = _decode_general_names(backend, cdp.CRLissuer) + + # Certificates may have a crl_issuer/reasons and no distribution + # point so make sure it's not null. + if cdp.distpoint != backend._ffi.NULL: + # Type 0 is fullName, there is no #define for it in the code. + if cdp.distpoint.type == _DISTPOINT_TYPE_FULLNAME: + full_name = _decode_general_names( + backend, cdp.distpoint.name.fullname + ) + # OpenSSL code doesn't test for a specific type for + # relativename, everything that isn't fullname is considered + # relativename. Per RFC 5280: + # + # DistributionPointName ::= CHOICE { + # fullName [0] GeneralNames, + # nameRelativeToCRLIssuer [1] RelativeDistinguishedName } + else: + rns = cdp.distpoint.name.relativename + rnum = backend._lib.sk_X509_NAME_ENTRY_num(rns) + attributes = set() + for i in range(rnum): + rn = backend._lib.sk_X509_NAME_ENTRY_value( + rns, i + ) + backend.openssl_assert(rn != backend._ffi.NULL) + attributes.add( + _decode_x509_name_entry(backend, rn) + ) + + relative_name = x509.RelativeDistinguishedName(attributes) + + dist_points.append( + x509.DistributionPoint( + full_name, relative_name, reasons, crl_issuer + ) + ) + + return dist_points + + +def _decode_crl_distribution_points(backend, cdps): + dist_points = _decode_dist_points(backend, cdps) + return x509.CRLDistributionPoints(dist_points) + + +def _decode_freshest_crl(backend, cdps): + dist_points = _decode_dist_points(backend, cdps) + return x509.FreshestCRL(dist_points) + + +def _decode_inhibit_any_policy(backend, asn1_int): + asn1_int = backend._ffi.cast("ASN1_INTEGER *", asn1_int) + asn1_int = backend._ffi.gc(asn1_int, backend._lib.ASN1_INTEGER_free) + skip_certs = _asn1_integer_to_int(backend, asn1_int) + return x509.InhibitAnyPolicy(skip_certs) + + +def _decode_precert_signed_certificate_timestamps(backend, asn1_scts): + from cryptography.hazmat.backends.openssl.x509 import ( + _SignedCertificateTimestamp + ) + asn1_scts = backend._ffi.cast("Cryptography_STACK_OF_SCT *", asn1_scts) + asn1_scts = backend._ffi.gc(asn1_scts, backend._lib.SCT_LIST_free) + + scts = [] + for i in range(backend._lib.sk_SCT_num(asn1_scts)): + sct = backend._lib.sk_SCT_value(asn1_scts, i) + + scts.append(_SignedCertificateTimestamp(backend, asn1_scts, sct)) + return x509.PrecertificateSignedCertificateTimestamps(scts) + + +# CRLReason ::= ENUMERATED { +# unspecified (0), +# keyCompromise (1), +# cACompromise (2), +# affiliationChanged (3), +# superseded (4), +# cessationOfOperation (5), +# certificateHold (6), +# -- value 7 is not used +# removeFromCRL (8), +# privilegeWithdrawn (9), +# aACompromise (10) } +_CRL_ENTRY_REASON_CODE_TO_ENUM = { + 0: x509.ReasonFlags.unspecified, + 1: x509.ReasonFlags.key_compromise, + 2: x509.ReasonFlags.ca_compromise, + 3: x509.ReasonFlags.affiliation_changed, + 4: x509.ReasonFlags.superseded, + 5: x509.ReasonFlags.cessation_of_operation, + 6: x509.ReasonFlags.certificate_hold, + 8: x509.ReasonFlags.remove_from_crl, + 9: x509.ReasonFlags.privilege_withdrawn, + 10: x509.ReasonFlags.aa_compromise, +} + + +_CRL_ENTRY_REASON_ENUM_TO_CODE = { + x509.ReasonFlags.unspecified: 0, + x509.ReasonFlags.key_compromise: 1, + x509.ReasonFlags.ca_compromise: 2, + x509.ReasonFlags.affiliation_changed: 3, + x509.ReasonFlags.superseded: 4, + x509.ReasonFlags.cessation_of_operation: 5, + x509.ReasonFlags.certificate_hold: 6, + x509.ReasonFlags.remove_from_crl: 8, + x509.ReasonFlags.privilege_withdrawn: 9, + x509.ReasonFlags.aa_compromise: 10 +} + + +def _decode_crl_reason(backend, enum): + enum = backend._ffi.cast("ASN1_ENUMERATED *", enum) + enum = backend._ffi.gc(enum, backend._lib.ASN1_ENUMERATED_free) + code = backend._lib.ASN1_ENUMERATED_get(enum) + + try: + return x509.CRLReason(_CRL_ENTRY_REASON_CODE_TO_ENUM[code]) + except KeyError: + raise ValueError("Unsupported reason code: {0}".format(code)) + + +def _decode_invalidity_date(backend, inv_date): + generalized_time = backend._ffi.cast( + "ASN1_GENERALIZEDTIME *", inv_date + ) + generalized_time = backend._ffi.gc( + generalized_time, backend._lib.ASN1_GENERALIZEDTIME_free + ) + return x509.InvalidityDate( + _parse_asn1_generalized_time(backend, generalized_time) + ) + + +def _decode_cert_issuer(backend, gns): + gns = backend._ffi.cast("GENERAL_NAMES *", gns) + gns = backend._ffi.gc(gns, backend._lib.GENERAL_NAMES_free) + general_names = _decode_general_names(backend, gns) + return x509.CertificateIssuer(general_names) + + +def _asn1_to_der(backend, asn1_type): + buf = backend._ffi.new("unsigned char **") + res = backend._lib.i2d_ASN1_TYPE(asn1_type, buf) + backend.openssl_assert(res >= 0) + backend.openssl_assert(buf[0] != backend._ffi.NULL) + buf = backend._ffi.gc( + buf, lambda buffer: backend._lib.OPENSSL_free(buffer[0]) + ) + return backend._ffi.buffer(buf[0], res)[:] + + +def _asn1_integer_to_int(backend, asn1_int): + bn = backend._lib.ASN1_INTEGER_to_BN(asn1_int, backend._ffi.NULL) + backend.openssl_assert(bn != backend._ffi.NULL) + bn = backend._ffi.gc(bn, backend._lib.BN_free) + return backend._bn_to_int(bn) + + +def _asn1_integer_to_int_or_none(backend, asn1_int): + if asn1_int == backend._ffi.NULL: + return None + else: + return _asn1_integer_to_int(backend, asn1_int) + + +def _asn1_string_to_bytes(backend, asn1_string): + return backend._ffi.buffer(asn1_string.data, asn1_string.length)[:] + + +def _asn1_string_to_ascii(backend, asn1_string): + return _asn1_string_to_bytes(backend, asn1_string).decode("ascii") + + +def _asn1_string_to_utf8(backend, asn1_string): + buf = backend._ffi.new("unsigned char **") + res = backend._lib.ASN1_STRING_to_UTF8(buf, asn1_string) + if res == -1: + raise ValueError( + "Unsupported ASN1 string type. Type: {0}".format(asn1_string.type) + ) + + backend.openssl_assert(buf[0] != backend._ffi.NULL) + buf = backend._ffi.gc( + buf, lambda buffer: backend._lib.OPENSSL_free(buffer[0]) + ) + return backend._ffi.buffer(buf[0], res)[:].decode('utf8') + + +def _parse_asn1_time(backend, asn1_time): + backend.openssl_assert(asn1_time != backend._ffi.NULL) + generalized_time = backend._lib.ASN1_TIME_to_generalizedtime( + asn1_time, backend._ffi.NULL + ) + if generalized_time == backend._ffi.NULL: + raise ValueError( + "Couldn't parse ASN.1 time as generalizedtime {!r}".format( + _asn1_string_to_bytes(backend, asn1_time) + ) + ) + + generalized_time = backend._ffi.gc( + generalized_time, backend._lib.ASN1_GENERALIZEDTIME_free + ) + return _parse_asn1_generalized_time(backend, generalized_time) + + +def _parse_asn1_generalized_time(backend, generalized_time): + time = _asn1_string_to_ascii( + backend, backend._ffi.cast("ASN1_STRING *", generalized_time) + ) + return datetime.datetime.strptime(time, "%Y%m%d%H%M%SZ") + + +_EXTENSION_HANDLERS_NO_SCT = { + ExtensionOID.BASIC_CONSTRAINTS: _decode_basic_constraints, + ExtensionOID.SUBJECT_KEY_IDENTIFIER: _decode_subject_key_identifier, + ExtensionOID.KEY_USAGE: _decode_key_usage, + ExtensionOID.SUBJECT_ALTERNATIVE_NAME: _decode_subject_alt_name, + ExtensionOID.EXTENDED_KEY_USAGE: _decode_extended_key_usage, + ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _decode_authority_key_identifier, + ExtensionOID.AUTHORITY_INFORMATION_ACCESS: ( + _decode_authority_information_access + ), + ExtensionOID.CERTIFICATE_POLICIES: _decode_certificate_policies, + ExtensionOID.CRL_DISTRIBUTION_POINTS: _decode_crl_distribution_points, + ExtensionOID.FRESHEST_CRL: _decode_freshest_crl, + ExtensionOID.OCSP_NO_CHECK: _decode_ocsp_no_check, + ExtensionOID.INHIBIT_ANY_POLICY: _decode_inhibit_any_policy, + ExtensionOID.ISSUER_ALTERNATIVE_NAME: _decode_issuer_alt_name, + ExtensionOID.NAME_CONSTRAINTS: _decode_name_constraints, + ExtensionOID.POLICY_CONSTRAINTS: _decode_policy_constraints, +} +_EXTENSION_HANDLERS = _EXTENSION_HANDLERS_NO_SCT.copy() +_EXTENSION_HANDLERS[ + ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS +] = _decode_precert_signed_certificate_timestamps + + +_REVOKED_EXTENSION_HANDLERS = { + CRLEntryExtensionOID.CRL_REASON: _decode_crl_reason, + CRLEntryExtensionOID.INVALIDITY_DATE: _decode_invalidity_date, + CRLEntryExtensionOID.CERTIFICATE_ISSUER: _decode_cert_issuer, +} + +_CRL_EXTENSION_HANDLERS = { + ExtensionOID.CRL_NUMBER: _decode_crl_number, + ExtensionOID.DELTA_CRL_INDICATOR: _decode_delta_crl_indicator, + ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _decode_authority_key_identifier, + ExtensionOID.ISSUER_ALTERNATIVE_NAME: _decode_issuer_alt_name, + ExtensionOID.AUTHORITY_INFORMATION_ACCESS: ( + _decode_authority_information_access + ), +} + +_CERTIFICATE_EXTENSION_PARSER_NO_SCT = _X509ExtensionParser( + ext_count=lambda backend, x: backend._lib.X509_get_ext_count(x), + get_ext=lambda backend, x, i: backend._lib.X509_get_ext(x, i), + handlers=_EXTENSION_HANDLERS_NO_SCT +) + +_CERTIFICATE_EXTENSION_PARSER = _X509ExtensionParser( + ext_count=lambda backend, x: backend._lib.X509_get_ext_count(x), + get_ext=lambda backend, x, i: backend._lib.X509_get_ext(x, i), + handlers=_EXTENSION_HANDLERS +) + +_CSR_EXTENSION_PARSER = _X509ExtensionParser( + ext_count=lambda backend, x: backend._lib.sk_X509_EXTENSION_num(x), + get_ext=lambda backend, x, i: backend._lib.sk_X509_EXTENSION_value(x, i), + handlers=_EXTENSION_HANDLERS +) + +_REVOKED_CERTIFICATE_EXTENSION_PARSER = _X509ExtensionParser( + ext_count=lambda backend, x: backend._lib.X509_REVOKED_get_ext_count(x), + get_ext=lambda backend, x, i: backend._lib.X509_REVOKED_get_ext(x, i), + handlers=_REVOKED_EXTENSION_HANDLERS, +) + +_CRL_EXTENSION_PARSER = _X509ExtensionParser( + ext_count=lambda backend, x: backend._lib.X509_CRL_get_ext_count(x), + get_ext=lambda backend, x, i: backend._lib.X509_CRL_get_ext(x, i), + handlers=_CRL_EXTENSION_HANDLERS, +) diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/dh.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/dh.py new file mode 100644 index 0000000..095f062 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/dh.py @@ -0,0 +1,280 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import utils +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import dh + + +def _dh_params_dup(dh_cdata, backend): + lib = backend._lib + ffi = backend._ffi + + param_cdata = lib.DHparams_dup(dh_cdata) + backend.openssl_assert(param_cdata != ffi.NULL) + param_cdata = ffi.gc(param_cdata, lib.DH_free) + if lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102: + # In OpenSSL versions < 1.0.2 or libressl DHparams_dup don't copy q + q = ffi.new("BIGNUM **") + lib.DH_get0_pqg(dh_cdata, ffi.NULL, q, ffi.NULL) + q_dup = lib.BN_dup(q[0]) + res = lib.DH_set0_pqg(param_cdata, ffi.NULL, q_dup, ffi.NULL) + backend.openssl_assert(res == 1) + + return param_cdata + + +def _dh_cdata_to_parameters(dh_cdata, backend): + param_cdata = _dh_params_dup(dh_cdata, backend) + return _DHParameters(backend, param_cdata) + + +@utils.register_interface(dh.DHParametersWithSerialization) +class _DHParameters(object): + def __init__(self, backend, dh_cdata): + self._backend = backend + self._dh_cdata = dh_cdata + + def parameter_numbers(self): + p = self._backend._ffi.new("BIGNUM **") + g = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) + if q[0] == self._backend._ffi.NULL: + q_val = None + else: + q_val = self._backend._bn_to_int(q[0]) + return dh.DHParameterNumbers( + p=self._backend._bn_to_int(p[0]), + g=self._backend._bn_to_int(g[0]), + q=q_val + ) + + def generate_private_key(self): + return self._backend.generate_dh_private_key(self) + + def parameter_bytes(self, encoding, format): + if format is not serialization.ParameterFormat.PKCS3: + raise ValueError( + "Only PKCS3 serialization is supported" + ) + if not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX: + q = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_pqg(self._dh_cdata, + self._backend._ffi.NULL, + q, + self._backend._ffi.NULL) + if q[0] != self._backend._ffi.NULL: + raise UnsupportedAlgorithm( + "DH X9.42 serialization is not supported", + _Reasons.UNSUPPORTED_SERIALIZATION) + + return self._backend._parameter_bytes( + encoding, + format, + self._dh_cdata + ) + + +def _handle_dh_compute_key_error(errors, backend): + lib = backend._lib + + backend.openssl_assert( + errors[0]._lib_reason_match( + lib.ERR_LIB_DH, lib.DH_R_INVALID_PUBKEY + ) + ) + + raise ValueError("Public key value is invalid for this exchange.") + + +def _get_dh_num_bits(backend, dh_cdata): + p = backend._ffi.new("BIGNUM **") + backend._lib.DH_get0_pqg(dh_cdata, p, + backend._ffi.NULL, + backend._ffi.NULL) + backend.openssl_assert(p[0] != backend._ffi.NULL) + return backend._lib.BN_num_bits(p[0]) + + +@utils.register_interface(dh.DHPrivateKeyWithSerialization) +class _DHPrivateKey(object): + def __init__(self, backend, dh_cdata, evp_pkey): + self._backend = backend + self._dh_cdata = dh_cdata + self._evp_pkey = evp_pkey + self._key_size_bytes = self._backend._lib.DH_size(dh_cdata) + + @property + def key_size(self): + return _get_dh_num_bits(self._backend, self._dh_cdata) + + def private_numbers(self): + p = self._backend._ffi.new("BIGNUM **") + g = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) + if q[0] == self._backend._ffi.NULL: + q_val = None + else: + q_val = self._backend._bn_to_int(q[0]) + pub_key = self._backend._ffi.new("BIGNUM **") + priv_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_key(self._dh_cdata, pub_key, priv_key) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(priv_key[0] != self._backend._ffi.NULL) + return dh.DHPrivateNumbers( + public_numbers=dh.DHPublicNumbers( + parameter_numbers=dh.DHParameterNumbers( + p=self._backend._bn_to_int(p[0]), + g=self._backend._bn_to_int(g[0]), + q=q_val + ), + y=self._backend._bn_to_int(pub_key[0]) + ), + x=self._backend._bn_to_int(priv_key[0]) + ) + + def exchange(self, peer_public_key): + + buf = self._backend._ffi.new("unsigned char[]", self._key_size_bytes) + pub_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_key(peer_public_key._dh_cdata, pub_key, + self._backend._ffi.NULL) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + res = self._backend._lib.DH_compute_key( + buf, + pub_key[0], + self._dh_cdata + ) + + if res == -1: + errors = self._backend._consume_errors() + return _handle_dh_compute_key_error(errors, self._backend) + else: + self._backend.openssl_assert(res >= 1) + + key = self._backend._ffi.buffer(buf)[:res] + pad = self._key_size_bytes - len(key) + + if pad > 0: + key = (b"\x00" * pad) + key + + return key + + def public_key(self): + dh_cdata = _dh_params_dup(self._dh_cdata, self._backend) + pub_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_key(self._dh_cdata, + pub_key, self._backend._ffi.NULL) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + pub_key_dup = self._backend._lib.BN_dup(pub_key[0]) + self._backend.openssl_assert(pub_key_dup != self._backend._ffi.NULL) + + res = self._backend._lib.DH_set0_key(dh_cdata, + pub_key_dup, + self._backend._ffi.NULL) + self._backend.openssl_assert(res == 1) + evp_pkey = self._backend._dh_cdata_to_evp_pkey(dh_cdata) + return _DHPublicKey(self._backend, dh_cdata, evp_pkey) + + def parameters(self): + return _dh_cdata_to_parameters(self._dh_cdata, self._backend) + + def private_bytes(self, encoding, format, encryption_algorithm): + if format is not serialization.PrivateFormat.PKCS8: + raise ValueError( + "DH private keys support only PKCS8 serialization" + ) + if not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX: + q = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_pqg(self._dh_cdata, + self._backend._ffi.NULL, + q, + self._backend._ffi.NULL) + if q[0] != self._backend._ffi.NULL: + raise UnsupportedAlgorithm( + "DH X9.42 serialization is not supported", + _Reasons.UNSUPPORTED_SERIALIZATION) + + return self._backend._private_key_bytes( + encoding, + format, + encryption_algorithm, + self._evp_pkey, + self._dh_cdata + ) + + +@utils.register_interface(dh.DHPublicKeyWithSerialization) +class _DHPublicKey(object): + def __init__(self, backend, dh_cdata, evp_pkey): + self._backend = backend + self._dh_cdata = dh_cdata + self._evp_pkey = evp_pkey + self._key_size_bits = _get_dh_num_bits(self._backend, self._dh_cdata) + + @property + def key_size(self): + return self._key_size_bits + + def public_numbers(self): + p = self._backend._ffi.new("BIGNUM **") + g = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) + if q[0] == self._backend._ffi.NULL: + q_val = None + else: + q_val = self._backend._bn_to_int(q[0]) + pub_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_key(self._dh_cdata, + pub_key, self._backend._ffi.NULL) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + return dh.DHPublicNumbers( + parameter_numbers=dh.DHParameterNumbers( + p=self._backend._bn_to_int(p[0]), + g=self._backend._bn_to_int(g[0]), + q=q_val + ), + y=self._backend._bn_to_int(pub_key[0]) + ) + + def parameters(self): + return _dh_cdata_to_parameters(self._dh_cdata, self._backend) + + def public_bytes(self, encoding, format): + if format is not serialization.PublicFormat.SubjectPublicKeyInfo: + raise ValueError( + "DH public keys support only " + "SubjectPublicKeyInfo serialization" + ) + + if not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX: + q = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_pqg(self._dh_cdata, + self._backend._ffi.NULL, + q, + self._backend._ffi.NULL) + if q[0] != self._backend._ffi.NULL: + raise UnsupportedAlgorithm( + "DH X9.42 serialization is not supported", + _Reasons.UNSUPPORTED_SERIALIZATION) + + return self._backend._public_key_bytes( + encoding, + format, + self, + self._evp_pkey, + None + ) diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/dsa.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/dsa.py new file mode 100644 index 0000000..48886e4 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/dsa.py @@ -0,0 +1,269 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import utils +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.backends.openssl.utils import ( + _calculate_digest_and_algorithm, _check_not_prehashed, + _warn_sign_verify_deprecated +) +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import ( + AsymmetricSignatureContext, AsymmetricVerificationContext, dsa +) + + +def _dsa_sig_sign(backend, private_key, data): + sig_buf_len = backend._lib.DSA_size(private_key._dsa_cdata) + sig_buf = backend._ffi.new("unsigned char[]", sig_buf_len) + buflen = backend._ffi.new("unsigned int *") + + # The first parameter passed to DSA_sign is unused by OpenSSL but + # must be an integer. + res = backend._lib.DSA_sign( + 0, data, len(data), sig_buf, buflen, private_key._dsa_cdata + ) + backend.openssl_assert(res == 1) + backend.openssl_assert(buflen[0]) + + return backend._ffi.buffer(sig_buf)[:buflen[0]] + + +def _dsa_sig_verify(backend, public_key, signature, data): + # The first parameter passed to DSA_verify is unused by OpenSSL but + # must be an integer. + res = backend._lib.DSA_verify( + 0, data, len(data), signature, len(signature), public_key._dsa_cdata + ) + + if res != 1: + backend._consume_errors() + raise InvalidSignature + + +@utils.register_interface(AsymmetricVerificationContext) +class _DSAVerificationContext(object): + def __init__(self, backend, public_key, signature, algorithm): + self._backend = backend + self._public_key = public_key + self._signature = signature + self._algorithm = algorithm + + self._hash_ctx = hashes.Hash(self._algorithm, self._backend) + + def update(self, data): + self._hash_ctx.update(data) + + def verify(self): + data_to_verify = self._hash_ctx.finalize() + + _dsa_sig_verify( + self._backend, self._public_key, self._signature, data_to_verify + ) + + +@utils.register_interface(AsymmetricSignatureContext) +class _DSASignatureContext(object): + def __init__(self, backend, private_key, algorithm): + self._backend = backend + self._private_key = private_key + self._algorithm = algorithm + self._hash_ctx = hashes.Hash(self._algorithm, self._backend) + + def update(self, data): + self._hash_ctx.update(data) + + def finalize(self): + data_to_sign = self._hash_ctx.finalize() + return _dsa_sig_sign(self._backend, self._private_key, data_to_sign) + + +@utils.register_interface(dsa.DSAParametersWithNumbers) +class _DSAParameters(object): + def __init__(self, backend, dsa_cdata): + self._backend = backend + self._dsa_cdata = dsa_cdata + + def parameter_numbers(self): + p = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + g = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DSA_get0_pqg(self._dsa_cdata, p, q, g) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(q[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) + return dsa.DSAParameterNumbers( + p=self._backend._bn_to_int(p[0]), + q=self._backend._bn_to_int(q[0]), + g=self._backend._bn_to_int(g[0]) + ) + + def generate_private_key(self): + return self._backend.generate_dsa_private_key(self) + + +@utils.register_interface(dsa.DSAPrivateKeyWithSerialization) +class _DSAPrivateKey(object): + def __init__(self, backend, dsa_cdata, evp_pkey): + self._backend = backend + self._dsa_cdata = dsa_cdata + self._evp_pkey = evp_pkey + + p = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DSA_get0_pqg( + dsa_cdata, p, self._backend._ffi.NULL, self._backend._ffi.NULL + ) + self._backend.openssl_assert(p[0] != backend._ffi.NULL) + self._key_size = self._backend._lib.BN_num_bits(p[0]) + + key_size = utils.read_only_property("_key_size") + + def signer(self, signature_algorithm): + _warn_sign_verify_deprecated() + _check_not_prehashed(signature_algorithm) + return _DSASignatureContext(self._backend, self, signature_algorithm) + + def private_numbers(self): + p = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + g = self._backend._ffi.new("BIGNUM **") + pub_key = self._backend._ffi.new("BIGNUM **") + priv_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DSA_get0_pqg(self._dsa_cdata, p, q, g) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(q[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) + self._backend._lib.DSA_get0_key(self._dsa_cdata, pub_key, priv_key) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(priv_key[0] != self._backend._ffi.NULL) + return dsa.DSAPrivateNumbers( + public_numbers=dsa.DSAPublicNumbers( + parameter_numbers=dsa.DSAParameterNumbers( + p=self._backend._bn_to_int(p[0]), + q=self._backend._bn_to_int(q[0]), + g=self._backend._bn_to_int(g[0]) + ), + y=self._backend._bn_to_int(pub_key[0]) + ), + x=self._backend._bn_to_int(priv_key[0]) + ) + + def public_key(self): + dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata) + self._backend.openssl_assert(dsa_cdata != self._backend._ffi.NULL) + dsa_cdata = self._backend._ffi.gc( + dsa_cdata, self._backend._lib.DSA_free + ) + pub_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DSA_get0_key( + self._dsa_cdata, pub_key, self._backend._ffi.NULL + ) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + pub_key_dup = self._backend._lib.BN_dup(pub_key[0]) + res = self._backend._lib.DSA_set0_key( + dsa_cdata, pub_key_dup, self._backend._ffi.NULL + ) + self._backend.openssl_assert(res == 1) + evp_pkey = self._backend._dsa_cdata_to_evp_pkey(dsa_cdata) + return _DSAPublicKey(self._backend, dsa_cdata, evp_pkey) + + def parameters(self): + dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata) + self._backend.openssl_assert(dsa_cdata != self._backend._ffi.NULL) + dsa_cdata = self._backend._ffi.gc( + dsa_cdata, self._backend._lib.DSA_free + ) + return _DSAParameters(self._backend, dsa_cdata) + + def private_bytes(self, encoding, format, encryption_algorithm): + return self._backend._private_key_bytes( + encoding, + format, + encryption_algorithm, + self._evp_pkey, + self._dsa_cdata + ) + + def sign(self, data, algorithm): + data, algorithm = _calculate_digest_and_algorithm( + self._backend, data, algorithm + ) + return _dsa_sig_sign(self._backend, self, data) + + +@utils.register_interface(dsa.DSAPublicKeyWithSerialization) +class _DSAPublicKey(object): + def __init__(self, backend, dsa_cdata, evp_pkey): + self._backend = backend + self._dsa_cdata = dsa_cdata + self._evp_pkey = evp_pkey + p = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DSA_get0_pqg( + dsa_cdata, p, self._backend._ffi.NULL, self._backend._ffi.NULL + ) + self._backend.openssl_assert(p[0] != backend._ffi.NULL) + self._key_size = self._backend._lib.BN_num_bits(p[0]) + + key_size = utils.read_only_property("_key_size") + + def verifier(self, signature, signature_algorithm): + _warn_sign_verify_deprecated() + if not isinstance(signature, bytes): + raise TypeError("signature must be bytes.") + + _check_not_prehashed(signature_algorithm) + return _DSAVerificationContext( + self._backend, self, signature, signature_algorithm + ) + + def public_numbers(self): + p = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + g = self._backend._ffi.new("BIGNUM **") + pub_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DSA_get0_pqg(self._dsa_cdata, p, q, g) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(q[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) + self._backend._lib.DSA_get0_key( + self._dsa_cdata, pub_key, self._backend._ffi.NULL + ) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + return dsa.DSAPublicNumbers( + parameter_numbers=dsa.DSAParameterNumbers( + p=self._backend._bn_to_int(p[0]), + q=self._backend._bn_to_int(q[0]), + g=self._backend._bn_to_int(g[0]) + ), + y=self._backend._bn_to_int(pub_key[0]) + ) + + def parameters(self): + dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata) + dsa_cdata = self._backend._ffi.gc( + dsa_cdata, self._backend._lib.DSA_free + ) + return _DSAParameters(self._backend, dsa_cdata) + + def public_bytes(self, encoding, format): + if format is serialization.PublicFormat.PKCS1: + raise ValueError( + "DSA public keys do not support PKCS1 serialization" + ) + + return self._backend._public_key_bytes( + encoding, + format, + self, + self._evp_pkey, + None + ) + + def verify(self, signature, data, algorithm): + data, algorithm = _calculate_digest_and_algorithm( + self._backend, data, algorithm + ) + return _dsa_sig_verify(self._backend, self, signature, data) diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/ec.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/ec.py new file mode 100644 index 0000000..69da234 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/ec.py @@ -0,0 +1,298 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import utils +from cryptography.exceptions import ( + InvalidSignature, UnsupportedAlgorithm, _Reasons +) +from cryptography.hazmat.backends.openssl.utils import ( + _calculate_digest_and_algorithm, _check_not_prehashed, + _warn_sign_verify_deprecated +) +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import ( + AsymmetricSignatureContext, AsymmetricVerificationContext, ec +) + + +def _check_signature_algorithm(signature_algorithm): + if not isinstance(signature_algorithm, ec.ECDSA): + raise UnsupportedAlgorithm( + "Unsupported elliptic curve signature algorithm.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) + + +def _ec_key_curve_sn(backend, ec_key): + group = backend._lib.EC_KEY_get0_group(ec_key) + backend.openssl_assert(group != backend._ffi.NULL) + + nid = backend._lib.EC_GROUP_get_curve_name(group) + # The following check is to find EC keys with unnamed curves and raise + # an error for now. + if nid == backend._lib.NID_undef: + raise NotImplementedError( + "ECDSA certificates with unnamed curves are unsupported " + "at this time" + ) + + curve_name = backend._lib.OBJ_nid2sn(nid) + backend.openssl_assert(curve_name != backend._ffi.NULL) + + sn = backend._ffi.string(curve_name).decode('ascii') + return sn + + +def _mark_asn1_named_ec_curve(backend, ec_cdata): + """ + Set the named curve flag on the EC_KEY. This causes OpenSSL to + serialize EC keys along with their curve OID which makes + deserialization easier. + """ + + backend._lib.EC_KEY_set_asn1_flag( + ec_cdata, backend._lib.OPENSSL_EC_NAMED_CURVE + ) + + +def _sn_to_elliptic_curve(backend, sn): + try: + return ec._CURVE_TYPES[sn]() + except KeyError: + raise UnsupportedAlgorithm( + "{0} is not a supported elliptic curve".format(sn), + _Reasons.UNSUPPORTED_ELLIPTIC_CURVE + ) + + +def _ecdsa_sig_sign(backend, private_key, data): + max_size = backend._lib.ECDSA_size(private_key._ec_key) + backend.openssl_assert(max_size > 0) + + sigbuf = backend._ffi.new("unsigned char[]", max_size) + siglen_ptr = backend._ffi.new("unsigned int[]", 1) + res = backend._lib.ECDSA_sign( + 0, data, len(data), sigbuf, siglen_ptr, private_key._ec_key + ) + backend.openssl_assert(res == 1) + return backend._ffi.buffer(sigbuf)[:siglen_ptr[0]] + + +def _ecdsa_sig_verify(backend, public_key, signature, data): + res = backend._lib.ECDSA_verify( + 0, data, len(data), signature, len(signature), public_key._ec_key + ) + if res != 1: + backend._consume_errors() + raise InvalidSignature + + +@utils.register_interface(AsymmetricSignatureContext) +class _ECDSASignatureContext(object): + def __init__(self, backend, private_key, algorithm): + self._backend = backend + self._private_key = private_key + self._digest = hashes.Hash(algorithm, backend) + + def update(self, data): + self._digest.update(data) + + def finalize(self): + digest = self._digest.finalize() + + return _ecdsa_sig_sign(self._backend, self._private_key, digest) + + +@utils.register_interface(AsymmetricVerificationContext) +class _ECDSAVerificationContext(object): + def __init__(self, backend, public_key, signature, algorithm): + self._backend = backend + self._public_key = public_key + self._signature = signature + self._digest = hashes.Hash(algorithm, backend) + + def update(self, data): + self._digest.update(data) + + def verify(self): + digest = self._digest.finalize() + _ecdsa_sig_verify( + self._backend, self._public_key, self._signature, digest + ) + + +@utils.register_interface(ec.EllipticCurvePrivateKeyWithSerialization) +class _EllipticCurvePrivateKey(object): + def __init__(self, backend, ec_key_cdata, evp_pkey): + self._backend = backend + _mark_asn1_named_ec_curve(backend, ec_key_cdata) + self._ec_key = ec_key_cdata + self._evp_pkey = evp_pkey + + sn = _ec_key_curve_sn(backend, ec_key_cdata) + self._curve = _sn_to_elliptic_curve(backend, sn) + + curve = utils.read_only_property("_curve") + + @property + def key_size(self): + return self.curve.key_size + + def signer(self, signature_algorithm): + _warn_sign_verify_deprecated() + _check_signature_algorithm(signature_algorithm) + _check_not_prehashed(signature_algorithm.algorithm) + return _ECDSASignatureContext( + self._backend, self, signature_algorithm.algorithm + ) + + def exchange(self, algorithm, peer_public_key): + if not ( + self._backend.elliptic_curve_exchange_algorithm_supported( + algorithm, self.curve + ) + ): + raise UnsupportedAlgorithm( + "This backend does not support the ECDH algorithm.", + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM + ) + + if peer_public_key.curve.name != self.curve.name: + raise ValueError( + "peer_public_key and self are not on the same curve" + ) + + group = self._backend._lib.EC_KEY_get0_group(self._ec_key) + z_len = (self._backend._lib.EC_GROUP_get_degree(group) + 7) // 8 + self._backend.openssl_assert(z_len > 0) + z_buf = self._backend._ffi.new("uint8_t[]", z_len) + peer_key = self._backend._lib.EC_KEY_get0_public_key( + peer_public_key._ec_key + ) + + r = self._backend._lib.ECDH_compute_key( + z_buf, z_len, peer_key, self._ec_key, self._backend._ffi.NULL + ) + self._backend.openssl_assert(r > 0) + return self._backend._ffi.buffer(z_buf)[:z_len] + + def public_key(self): + group = self._backend._lib.EC_KEY_get0_group(self._ec_key) + self._backend.openssl_assert(group != self._backend._ffi.NULL) + + curve_nid = self._backend._lib.EC_GROUP_get_curve_name(group) + + public_ec_key = self._backend._lib.EC_KEY_new_by_curve_name(curve_nid) + self._backend.openssl_assert(public_ec_key != self._backend._ffi.NULL) + public_ec_key = self._backend._ffi.gc( + public_ec_key, self._backend._lib.EC_KEY_free + ) + + point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key) + self._backend.openssl_assert(point != self._backend._ffi.NULL) + + res = self._backend._lib.EC_KEY_set_public_key(public_ec_key, point) + self._backend.openssl_assert(res == 1) + + evp_pkey = self._backend._ec_cdata_to_evp_pkey(public_ec_key) + + return _EllipticCurvePublicKey(self._backend, public_ec_key, evp_pkey) + + def private_numbers(self): + bn = self._backend._lib.EC_KEY_get0_private_key(self._ec_key) + private_value = self._backend._bn_to_int(bn) + return ec.EllipticCurvePrivateNumbers( + private_value=private_value, + public_numbers=self.public_key().public_numbers() + ) + + def private_bytes(self, encoding, format, encryption_algorithm): + return self._backend._private_key_bytes( + encoding, + format, + encryption_algorithm, + self._evp_pkey, + self._ec_key + ) + + def sign(self, data, signature_algorithm): + _check_signature_algorithm(signature_algorithm) + data, algorithm = _calculate_digest_and_algorithm( + self._backend, data, signature_algorithm._algorithm + ) + return _ecdsa_sig_sign(self._backend, self, data) + + +@utils.register_interface(ec.EllipticCurvePublicKeyWithSerialization) +class _EllipticCurvePublicKey(object): + def __init__(self, backend, ec_key_cdata, evp_pkey): + self._backend = backend + _mark_asn1_named_ec_curve(backend, ec_key_cdata) + self._ec_key = ec_key_cdata + self._evp_pkey = evp_pkey + + sn = _ec_key_curve_sn(backend, ec_key_cdata) + self._curve = _sn_to_elliptic_curve(backend, sn) + + curve = utils.read_only_property("_curve") + + @property + def key_size(self): + return self.curve.key_size + + def verifier(self, signature, signature_algorithm): + _warn_sign_verify_deprecated() + if not isinstance(signature, bytes): + raise TypeError("signature must be bytes.") + + _check_signature_algorithm(signature_algorithm) + _check_not_prehashed(signature_algorithm.algorithm) + return _ECDSAVerificationContext( + self._backend, self, signature, signature_algorithm.algorithm + ) + + def public_numbers(self): + get_func, group = ( + self._backend._ec_key_determine_group_get_func(self._ec_key) + ) + point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key) + self._backend.openssl_assert(point != self._backend._ffi.NULL) + + with self._backend._tmp_bn_ctx() as bn_ctx: + bn_x = self._backend._lib.BN_CTX_get(bn_ctx) + bn_y = self._backend._lib.BN_CTX_get(bn_ctx) + + res = get_func(group, point, bn_x, bn_y, bn_ctx) + self._backend.openssl_assert(res == 1) + + x = self._backend._bn_to_int(bn_x) + y = self._backend._bn_to_int(bn_y) + + return ec.EllipticCurvePublicNumbers( + x=x, + y=y, + curve=self._curve + ) + + def public_bytes(self, encoding, format): + if format is serialization.PublicFormat.PKCS1: + raise ValueError( + "EC public keys do not support PKCS1 serialization" + ) + + return self._backend._public_key_bytes( + encoding, + format, + self, + self._evp_pkey, + None + ) + + def verify(self, signature, data, signature_algorithm): + _check_signature_algorithm(signature_algorithm) + data, algorithm = _calculate_digest_and_algorithm( + self._backend, data, signature_algorithm._algorithm + ) + _ecdsa_sig_verify(self._backend, self, signature, data) diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py new file mode 100644 index 0000000..a2c7ed7 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py @@ -0,0 +1,611 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import calendar +import ipaddress + +import six + +from cryptography import utils, x509 +from cryptography.hazmat.backends.openssl.decode_asn1 import ( + _CRL_ENTRY_REASON_ENUM_TO_CODE, _DISTPOINT_TYPE_FULLNAME, + _DISTPOINT_TYPE_RELATIVENAME +) +from cryptography.x509.name import _ASN1Type +from cryptography.x509.oid import CRLEntryExtensionOID, ExtensionOID + + +def _encode_asn1_int(backend, x): + """ + Converts a python integer to an ASN1_INTEGER. The returned ASN1_INTEGER + will not be garbage collected (to support adding them to structs that take + ownership of the object). Be sure to register it for GC if it will be + discarded after use. + + """ + # Convert Python integer to OpenSSL "bignum" in case value exceeds + # machine's native integer limits (note: `int_to_bn` doesn't automatically + # GC). + i = backend._int_to_bn(x) + i = backend._ffi.gc(i, backend._lib.BN_free) + + # Wrap in an ASN.1 integer. Don't GC -- as documented. + i = backend._lib.BN_to_ASN1_INTEGER(i, backend._ffi.NULL) + backend.openssl_assert(i != backend._ffi.NULL) + return i + + +def _encode_asn1_int_gc(backend, x): + i = _encode_asn1_int(backend, x) + i = backend._ffi.gc(i, backend._lib.ASN1_INTEGER_free) + return i + + +def _encode_asn1_str(backend, data, length): + """ + Create an ASN1_OCTET_STRING from a Python byte string. + """ + s = backend._lib.ASN1_OCTET_STRING_new() + res = backend._lib.ASN1_OCTET_STRING_set(s, data, length) + backend.openssl_assert(res == 1) + return s + + +def _encode_asn1_utf8_str(backend, string): + """ + Create an ASN1_UTF8STRING from a Python unicode string. + This object will be an ASN1_STRING with UTF8 type in OpenSSL and + can be decoded with ASN1_STRING_to_UTF8. + """ + s = backend._lib.ASN1_UTF8STRING_new() + res = backend._lib.ASN1_STRING_set( + s, string.encode("utf8"), len(string.encode("utf8")) + ) + backend.openssl_assert(res == 1) + return s + + +def _encode_asn1_str_gc(backend, data, length): + s = _encode_asn1_str(backend, data, length) + s = backend._ffi.gc(s, backend._lib.ASN1_OCTET_STRING_free) + return s + + +def _encode_inhibit_any_policy(backend, inhibit_any_policy): + return _encode_asn1_int_gc(backend, inhibit_any_policy.skip_certs) + + +def _encode_name(backend, name): + """ + The X509_NAME created will not be gc'd. Use _encode_name_gc if needed. + """ + subject = backend._lib.X509_NAME_new() + for rdn in name.rdns: + set_flag = 0 # indicate whether to add to last RDN or create new RDN + for attribute in rdn: + name_entry = _encode_name_entry(backend, attribute) + # X509_NAME_add_entry dups the object so we need to gc this copy + name_entry = backend._ffi.gc( + name_entry, backend._lib.X509_NAME_ENTRY_free + ) + res = backend._lib.X509_NAME_add_entry( + subject, name_entry, -1, set_flag) + backend.openssl_assert(res == 1) + set_flag = -1 + return subject + + +def _encode_name_gc(backend, attributes): + subject = _encode_name(backend, attributes) + subject = backend._ffi.gc(subject, backend._lib.X509_NAME_free) + return subject + + +def _encode_sk_name_entry(backend, attributes): + """ + The sk_X509_NAME_ENTRY created will not be gc'd. + """ + stack = backend._lib.sk_X509_NAME_ENTRY_new_null() + for attribute in attributes: + name_entry = _encode_name_entry(backend, attribute) + res = backend._lib.sk_X509_NAME_ENTRY_push(stack, name_entry) + backend.openssl_assert(res == 1) + return stack + + +def _encode_name_entry(backend, attribute): + if attribute._type is _ASN1Type.BMPString: + value = attribute.value.encode('utf_16_be') + else: + value = attribute.value.encode('utf8') + + obj = _txt2obj_gc(backend, attribute.oid.dotted_string) + + name_entry = backend._lib.X509_NAME_ENTRY_create_by_OBJ( + backend._ffi.NULL, obj, attribute._type.value, value, len(value) + ) + return name_entry + + +def _encode_crl_number_delta_crl_indicator(backend, ext): + return _encode_asn1_int_gc(backend, ext.crl_number) + + +def _encode_crl_reason(backend, crl_reason): + asn1enum = backend._lib.ASN1_ENUMERATED_new() + backend.openssl_assert(asn1enum != backend._ffi.NULL) + asn1enum = backend._ffi.gc(asn1enum, backend._lib.ASN1_ENUMERATED_free) + res = backend._lib.ASN1_ENUMERATED_set( + asn1enum, _CRL_ENTRY_REASON_ENUM_TO_CODE[crl_reason.reason] + ) + backend.openssl_assert(res == 1) + + return asn1enum + + +def _encode_invalidity_date(backend, invalidity_date): + time = backend._lib.ASN1_GENERALIZEDTIME_set( + backend._ffi.NULL, calendar.timegm( + invalidity_date.invalidity_date.timetuple() + ) + ) + backend.openssl_assert(time != backend._ffi.NULL) + time = backend._ffi.gc(time, backend._lib.ASN1_GENERALIZEDTIME_free) + + return time + + +def _encode_certificate_policies(backend, certificate_policies): + cp = backend._lib.sk_POLICYINFO_new_null() + backend.openssl_assert(cp != backend._ffi.NULL) + cp = backend._ffi.gc(cp, backend._lib.sk_POLICYINFO_free) + for policy_info in certificate_policies: + pi = backend._lib.POLICYINFO_new() + backend.openssl_assert(pi != backend._ffi.NULL) + res = backend._lib.sk_POLICYINFO_push(cp, pi) + backend.openssl_assert(res >= 1) + oid = _txt2obj(backend, policy_info.policy_identifier.dotted_string) + pi.policyid = oid + if policy_info.policy_qualifiers: + pqis = backend._lib.sk_POLICYQUALINFO_new_null() + backend.openssl_assert(pqis != backend._ffi.NULL) + for qualifier in policy_info.policy_qualifiers: + pqi = backend._lib.POLICYQUALINFO_new() + backend.openssl_assert(pqi != backend._ffi.NULL) + res = backend._lib.sk_POLICYQUALINFO_push(pqis, pqi) + backend.openssl_assert(res >= 1) + if isinstance(qualifier, six.text_type): + pqi.pqualid = _txt2obj( + backend, x509.OID_CPS_QUALIFIER.dotted_string + ) + pqi.d.cpsuri = _encode_asn1_str( + backend, + qualifier.encode("ascii"), + len(qualifier.encode("ascii")) + ) + else: + assert isinstance(qualifier, x509.UserNotice) + pqi.pqualid = _txt2obj( + backend, x509.OID_CPS_USER_NOTICE.dotted_string + ) + un = backend._lib.USERNOTICE_new() + backend.openssl_assert(un != backend._ffi.NULL) + pqi.d.usernotice = un + if qualifier.explicit_text: + un.exptext = _encode_asn1_utf8_str( + backend, qualifier.explicit_text + ) + + un.noticeref = _encode_notice_reference( + backend, qualifier.notice_reference + ) + + pi.qualifiers = pqis + + return cp + + +def _encode_notice_reference(backend, notice): + if notice is None: + return backend._ffi.NULL + else: + nr = backend._lib.NOTICEREF_new() + backend.openssl_assert(nr != backend._ffi.NULL) + # organization is a required field + nr.organization = _encode_asn1_utf8_str(backend, notice.organization) + + notice_stack = backend._lib.sk_ASN1_INTEGER_new_null() + nr.noticenos = notice_stack + for number in notice.notice_numbers: + num = _encode_asn1_int(backend, number) + res = backend._lib.sk_ASN1_INTEGER_push(notice_stack, num) + backend.openssl_assert(res >= 1) + + return nr + + +def _txt2obj(backend, name): + """ + Converts a Python string with an ASN.1 object ID in dotted form to a + ASN1_OBJECT. + """ + name = name.encode('ascii') + obj = backend._lib.OBJ_txt2obj(name, 1) + backend.openssl_assert(obj != backend._ffi.NULL) + return obj + + +def _txt2obj_gc(backend, name): + obj = _txt2obj(backend, name) + obj = backend._ffi.gc(obj, backend._lib.ASN1_OBJECT_free) + return obj + + +def _encode_ocsp_nocheck(backend, ext): + """ + The OCSP No Check extension is defined as a null ASN.1 value embedded in + an ASN.1 string. + """ + return _encode_asn1_str_gc(backend, b"\x05\x00", 2) + + +def _encode_key_usage(backend, key_usage): + set_bit = backend._lib.ASN1_BIT_STRING_set_bit + ku = backend._lib.ASN1_BIT_STRING_new() + ku = backend._ffi.gc(ku, backend._lib.ASN1_BIT_STRING_free) + res = set_bit(ku, 0, key_usage.digital_signature) + backend.openssl_assert(res == 1) + res = set_bit(ku, 1, key_usage.content_commitment) + backend.openssl_assert(res == 1) + res = set_bit(ku, 2, key_usage.key_encipherment) + backend.openssl_assert(res == 1) + res = set_bit(ku, 3, key_usage.data_encipherment) + backend.openssl_assert(res == 1) + res = set_bit(ku, 4, key_usage.key_agreement) + backend.openssl_assert(res == 1) + res = set_bit(ku, 5, key_usage.key_cert_sign) + backend.openssl_assert(res == 1) + res = set_bit(ku, 6, key_usage.crl_sign) + backend.openssl_assert(res == 1) + if key_usage.key_agreement: + res = set_bit(ku, 7, key_usage.encipher_only) + backend.openssl_assert(res == 1) + res = set_bit(ku, 8, key_usage.decipher_only) + backend.openssl_assert(res == 1) + else: + res = set_bit(ku, 7, 0) + backend.openssl_assert(res == 1) + res = set_bit(ku, 8, 0) + backend.openssl_assert(res == 1) + + return ku + + +def _encode_authority_key_identifier(backend, authority_keyid): + akid = backend._lib.AUTHORITY_KEYID_new() + backend.openssl_assert(akid != backend._ffi.NULL) + akid = backend._ffi.gc(akid, backend._lib.AUTHORITY_KEYID_free) + if authority_keyid.key_identifier is not None: + akid.keyid = _encode_asn1_str( + backend, + authority_keyid.key_identifier, + len(authority_keyid.key_identifier) + ) + + if authority_keyid.authority_cert_issuer is not None: + akid.issuer = _encode_general_names( + backend, authority_keyid.authority_cert_issuer + ) + + if authority_keyid.authority_cert_serial_number is not None: + akid.serial = _encode_asn1_int( + backend, authority_keyid.authority_cert_serial_number + ) + + return akid + + +def _encode_basic_constraints(backend, basic_constraints): + constraints = backend._lib.BASIC_CONSTRAINTS_new() + constraints = backend._ffi.gc( + constraints, backend._lib.BASIC_CONSTRAINTS_free + ) + constraints.ca = 255 if basic_constraints.ca else 0 + if basic_constraints.ca and basic_constraints.path_length is not None: + constraints.pathlen = _encode_asn1_int( + backend, basic_constraints.path_length + ) + + return constraints + + +def _encode_authority_information_access(backend, authority_info_access): + aia = backend._lib.sk_ACCESS_DESCRIPTION_new_null() + backend.openssl_assert(aia != backend._ffi.NULL) + aia = backend._ffi.gc( + aia, backend._lib.sk_ACCESS_DESCRIPTION_free + ) + for access_description in authority_info_access: + ad = backend._lib.ACCESS_DESCRIPTION_new() + method = _txt2obj( + backend, access_description.access_method.dotted_string + ) + gn = _encode_general_name(backend, access_description.access_location) + ad.method = method + ad.location = gn + res = backend._lib.sk_ACCESS_DESCRIPTION_push(aia, ad) + backend.openssl_assert(res >= 1) + + return aia + + +def _encode_general_names(backend, names): + general_names = backend._lib.GENERAL_NAMES_new() + backend.openssl_assert(general_names != backend._ffi.NULL) + for name in names: + gn = _encode_general_name(backend, name) + res = backend._lib.sk_GENERAL_NAME_push(general_names, gn) + backend.openssl_assert(res != 0) + + return general_names + + +def _encode_alt_name(backend, san): + general_names = _encode_general_names(backend, san) + general_names = backend._ffi.gc( + general_names, backend._lib.GENERAL_NAMES_free + ) + return general_names + + +def _encode_subject_key_identifier(backend, ski): + return _encode_asn1_str_gc(backend, ski.digest, len(ski.digest)) + + +def _encode_general_name(backend, name): + if isinstance(name, x509.DNSName): + gn = backend._lib.GENERAL_NAME_new() + backend.openssl_assert(gn != backend._ffi.NULL) + gn.type = backend._lib.GEN_DNS + + ia5 = backend._lib.ASN1_IA5STRING_new() + backend.openssl_assert(ia5 != backend._ffi.NULL) + # ia5strings are supposed to be ITU T.50 but to allow round-tripping + # of broken certs that encode utf8 we'll encode utf8 here too. + value = name.value.encode("utf8") + + res = backend._lib.ASN1_STRING_set(ia5, value, len(value)) + backend.openssl_assert(res == 1) + gn.d.dNSName = ia5 + elif isinstance(name, x509.RegisteredID): + gn = backend._lib.GENERAL_NAME_new() + backend.openssl_assert(gn != backend._ffi.NULL) + gn.type = backend._lib.GEN_RID + obj = backend._lib.OBJ_txt2obj( + name.value.dotted_string.encode('ascii'), 1 + ) + backend.openssl_assert(obj != backend._ffi.NULL) + gn.d.registeredID = obj + elif isinstance(name, x509.DirectoryName): + gn = backend._lib.GENERAL_NAME_new() + backend.openssl_assert(gn != backend._ffi.NULL) + dir_name = _encode_name(backend, name.value) + gn.type = backend._lib.GEN_DIRNAME + gn.d.directoryName = dir_name + elif isinstance(name, x509.IPAddress): + gn = backend._lib.GENERAL_NAME_new() + backend.openssl_assert(gn != backend._ffi.NULL) + if isinstance(name.value, ipaddress.IPv4Network): + packed = ( + name.value.network_address.packed + + utils.int_to_bytes(((1 << 32) - name.value.num_addresses), 4) + ) + elif isinstance(name.value, ipaddress.IPv6Network): + packed = ( + name.value.network_address.packed + + utils.int_to_bytes((1 << 128) - name.value.num_addresses, 16) + ) + else: + packed = name.value.packed + ipaddr = _encode_asn1_str(backend, packed, len(packed)) + gn.type = backend._lib.GEN_IPADD + gn.d.iPAddress = ipaddr + elif isinstance(name, x509.OtherName): + gn = backend._lib.GENERAL_NAME_new() + backend.openssl_assert(gn != backend._ffi.NULL) + other_name = backend._lib.OTHERNAME_new() + backend.openssl_assert(other_name != backend._ffi.NULL) + + type_id = backend._lib.OBJ_txt2obj( + name.type_id.dotted_string.encode('ascii'), 1 + ) + backend.openssl_assert(type_id != backend._ffi.NULL) + data = backend._ffi.new("unsigned char[]", name.value) + data_ptr_ptr = backend._ffi.new("unsigned char **") + data_ptr_ptr[0] = data + value = backend._lib.d2i_ASN1_TYPE( + backend._ffi.NULL, data_ptr_ptr, len(name.value) + ) + if value == backend._ffi.NULL: + backend._consume_errors() + raise ValueError("Invalid ASN.1 data") + other_name.type_id = type_id + other_name.value = value + gn.type = backend._lib.GEN_OTHERNAME + gn.d.otherName = other_name + elif isinstance(name, x509.RFC822Name): + gn = backend._lib.GENERAL_NAME_new() + backend.openssl_assert(gn != backend._ffi.NULL) + # ia5strings are supposed to be ITU T.50 but to allow round-tripping + # of broken certs that encode utf8 we'll encode utf8 here too. + data = name.value.encode("utf8") + asn1_str = _encode_asn1_str(backend, data, len(data)) + gn.type = backend._lib.GEN_EMAIL + gn.d.rfc822Name = asn1_str + elif isinstance(name, x509.UniformResourceIdentifier): + gn = backend._lib.GENERAL_NAME_new() + backend.openssl_assert(gn != backend._ffi.NULL) + # ia5strings are supposed to be ITU T.50 but to allow round-tripping + # of broken certs that encode utf8 we'll encode utf8 here too. + data = name.value.encode("utf8") + asn1_str = _encode_asn1_str(backend, data, len(data)) + gn.type = backend._lib.GEN_URI + gn.d.uniformResourceIdentifier = asn1_str + else: + raise ValueError( + "{0} is an unknown GeneralName type".format(name) + ) + + return gn + + +def _encode_extended_key_usage(backend, extended_key_usage): + eku = backend._lib.sk_ASN1_OBJECT_new_null() + eku = backend._ffi.gc(eku, backend._lib.sk_ASN1_OBJECT_free) + for oid in extended_key_usage: + obj = _txt2obj(backend, oid.dotted_string) + res = backend._lib.sk_ASN1_OBJECT_push(eku, obj) + backend.openssl_assert(res >= 1) + + return eku + + +_CRLREASONFLAGS = { + x509.ReasonFlags.key_compromise: 1, + x509.ReasonFlags.ca_compromise: 2, + x509.ReasonFlags.affiliation_changed: 3, + x509.ReasonFlags.superseded: 4, + x509.ReasonFlags.cessation_of_operation: 5, + x509.ReasonFlags.certificate_hold: 6, + x509.ReasonFlags.privilege_withdrawn: 7, + x509.ReasonFlags.aa_compromise: 8, +} + + +def _encode_cdps_freshest_crl(backend, cdps): + cdp = backend._lib.sk_DIST_POINT_new_null() + cdp = backend._ffi.gc(cdp, backend._lib.sk_DIST_POINT_free) + for point in cdps: + dp = backend._lib.DIST_POINT_new() + backend.openssl_assert(dp != backend._ffi.NULL) + + if point.reasons: + bitmask = backend._lib.ASN1_BIT_STRING_new() + backend.openssl_assert(bitmask != backend._ffi.NULL) + dp.reasons = bitmask + for reason in point.reasons: + res = backend._lib.ASN1_BIT_STRING_set_bit( + bitmask, _CRLREASONFLAGS[reason], 1 + ) + backend.openssl_assert(res == 1) + + if point.full_name: + dpn = backend._lib.DIST_POINT_NAME_new() + backend.openssl_assert(dpn != backend._ffi.NULL) + dpn.type = _DISTPOINT_TYPE_FULLNAME + dpn.name.fullname = _encode_general_names(backend, point.full_name) + dp.distpoint = dpn + + if point.relative_name: + dpn = backend._lib.DIST_POINT_NAME_new() + backend.openssl_assert(dpn != backend._ffi.NULL) + dpn.type = _DISTPOINT_TYPE_RELATIVENAME + relativename = _encode_sk_name_entry(backend, point.relative_name) + backend.openssl_assert(relativename != backend._ffi.NULL) + dpn.name.relativename = relativename + dp.distpoint = dpn + + if point.crl_issuer: + dp.CRLissuer = _encode_general_names(backend, point.crl_issuer) + + res = backend._lib.sk_DIST_POINT_push(cdp, dp) + backend.openssl_assert(res >= 1) + + return cdp + + +def _encode_name_constraints(backend, name_constraints): + nc = backend._lib.NAME_CONSTRAINTS_new() + backend.openssl_assert(nc != backend._ffi.NULL) + nc = backend._ffi.gc(nc, backend._lib.NAME_CONSTRAINTS_free) + permitted = _encode_general_subtree( + backend, name_constraints.permitted_subtrees + ) + nc.permittedSubtrees = permitted + excluded = _encode_general_subtree( + backend, name_constraints.excluded_subtrees + ) + nc.excludedSubtrees = excluded + + return nc + + +def _encode_policy_constraints(backend, policy_constraints): + pc = backend._lib.POLICY_CONSTRAINTS_new() + backend.openssl_assert(pc != backend._ffi.NULL) + pc = backend._ffi.gc(pc, backend._lib.POLICY_CONSTRAINTS_free) + if policy_constraints.require_explicit_policy is not None: + pc.requireExplicitPolicy = _encode_asn1_int( + backend, policy_constraints.require_explicit_policy + ) + + if policy_constraints.inhibit_policy_mapping is not None: + pc.inhibitPolicyMapping = _encode_asn1_int( + backend, policy_constraints.inhibit_policy_mapping + ) + + return pc + + +def _encode_general_subtree(backend, subtrees): + if subtrees is None: + return backend._ffi.NULL + else: + general_subtrees = backend._lib.sk_GENERAL_SUBTREE_new_null() + for name in subtrees: + gs = backend._lib.GENERAL_SUBTREE_new() + gs.base = _encode_general_name(backend, name) + res = backend._lib.sk_GENERAL_SUBTREE_push(general_subtrees, gs) + assert res >= 1 + + return general_subtrees + + +_EXTENSION_ENCODE_HANDLERS = { + ExtensionOID.BASIC_CONSTRAINTS: _encode_basic_constraints, + ExtensionOID.SUBJECT_KEY_IDENTIFIER: _encode_subject_key_identifier, + ExtensionOID.KEY_USAGE: _encode_key_usage, + ExtensionOID.SUBJECT_ALTERNATIVE_NAME: _encode_alt_name, + ExtensionOID.ISSUER_ALTERNATIVE_NAME: _encode_alt_name, + ExtensionOID.EXTENDED_KEY_USAGE: _encode_extended_key_usage, + ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _encode_authority_key_identifier, + ExtensionOID.CERTIFICATE_POLICIES: _encode_certificate_policies, + ExtensionOID.AUTHORITY_INFORMATION_ACCESS: ( + _encode_authority_information_access + ), + ExtensionOID.CRL_DISTRIBUTION_POINTS: _encode_cdps_freshest_crl, + ExtensionOID.FRESHEST_CRL: _encode_cdps_freshest_crl, + ExtensionOID.INHIBIT_ANY_POLICY: _encode_inhibit_any_policy, + ExtensionOID.OCSP_NO_CHECK: _encode_ocsp_nocheck, + ExtensionOID.NAME_CONSTRAINTS: _encode_name_constraints, + ExtensionOID.POLICY_CONSTRAINTS: _encode_policy_constraints, +} + +_CRL_EXTENSION_ENCODE_HANDLERS = { + ExtensionOID.ISSUER_ALTERNATIVE_NAME: _encode_alt_name, + ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _encode_authority_key_identifier, + ExtensionOID.AUTHORITY_INFORMATION_ACCESS: ( + _encode_authority_information_access + ), + ExtensionOID.CRL_NUMBER: _encode_crl_number_delta_crl_indicator, + ExtensionOID.DELTA_CRL_INDICATOR: _encode_crl_number_delta_crl_indicator, +} + +_CRL_ENTRY_EXTENSION_ENCODE_HANDLERS = { + CRLEntryExtensionOID.CERTIFICATE_ISSUER: _encode_alt_name, + CRLEntryExtensionOID.CRL_REASON: _encode_crl_reason, + CRLEntryExtensionOID.INVALIDITY_DATE: _encode_invalidity_date, +} diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/hashes.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/hashes.py new file mode 100644 index 0000000..92ea53b --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/hashes.py @@ -0,0 +1,61 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + + +from cryptography import utils +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.primitives import hashes + + +@utils.register_interface(hashes.HashContext) +class _HashContext(object): + def __init__(self, backend, algorithm, ctx=None): + self._algorithm = algorithm + + self._backend = backend + + if ctx is None: + ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new() + ctx = self._backend._ffi.gc( + ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free + ) + name = self._backend._build_openssl_digest_name(algorithm) + evp_md = self._backend._lib.EVP_get_digestbyname(name) + if evp_md == self._backend._ffi.NULL: + raise UnsupportedAlgorithm( + "{0} is not a supported hash on this backend.".format( + name), + _Reasons.UNSUPPORTED_HASH + ) + res = self._backend._lib.EVP_DigestInit_ex(ctx, evp_md, + self._backend._ffi.NULL) + self._backend.openssl_assert(res != 0) + + self._ctx = ctx + + algorithm = utils.read_only_property("_algorithm") + + def copy(self): + copied_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new() + copied_ctx = self._backend._ffi.gc( + copied_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_MD_CTX_copy_ex(copied_ctx, self._ctx) + self._backend.openssl_assert(res != 0) + return _HashContext(self._backend, self.algorithm, ctx=copied_ctx) + + def update(self, data): + res = self._backend._lib.EVP_DigestUpdate(self._ctx, data, len(data)) + self._backend.openssl_assert(res != 0) + + def finalize(self): + buf = self._backend._ffi.new("unsigned char[]", + self._backend._lib.EVP_MAX_MD_SIZE) + outlen = self._backend._ffi.new("unsigned int *") + res = self._backend._lib.EVP_DigestFinal_ex(self._ctx, buf, outlen) + self._backend.openssl_assert(res != 0) + self._backend.openssl_assert(outlen[0] == self.algorithm.digest_size) + return self._backend._ffi.buffer(buf)[:outlen[0]] diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/hmac.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/hmac.py new file mode 100644 index 0000000..3577f47 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/hmac.py @@ -0,0 +1,73 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + + +from cryptography import utils +from cryptography.exceptions import ( + InvalidSignature, UnsupportedAlgorithm, _Reasons +) +from cryptography.hazmat.primitives import constant_time, hashes, mac + + +@utils.register_interface(mac.MACContext) +@utils.register_interface(hashes.HashContext) +class _HMACContext(object): + def __init__(self, backend, key, algorithm, ctx=None): + self._algorithm = algorithm + self._backend = backend + + if ctx is None: + ctx = self._backend._lib.Cryptography_HMAC_CTX_new() + self._backend.openssl_assert(ctx != self._backend._ffi.NULL) + ctx = self._backend._ffi.gc( + ctx, self._backend._lib.Cryptography_HMAC_CTX_free + ) + name = self._backend._build_openssl_digest_name(algorithm) + evp_md = self._backend._lib.EVP_get_digestbyname(name) + if evp_md == self._backend._ffi.NULL: + raise UnsupportedAlgorithm( + "{0} is not a supported hash on this backend".format(name), + _Reasons.UNSUPPORTED_HASH + ) + res = self._backend._lib.HMAC_Init_ex( + ctx, key, len(key), evp_md, self._backend._ffi.NULL + ) + self._backend.openssl_assert(res != 0) + + self._ctx = ctx + self._key = key + + algorithm = utils.read_only_property("_algorithm") + + def copy(self): + copied_ctx = self._backend._lib.Cryptography_HMAC_CTX_new() + self._backend.openssl_assert(copied_ctx != self._backend._ffi.NULL) + copied_ctx = self._backend._ffi.gc( + copied_ctx, self._backend._lib.Cryptography_HMAC_CTX_free + ) + res = self._backend._lib.HMAC_CTX_copy(copied_ctx, self._ctx) + self._backend.openssl_assert(res != 0) + return _HMACContext( + self._backend, self._key, self.algorithm, ctx=copied_ctx + ) + + def update(self, data): + res = self._backend._lib.HMAC_Update(self._ctx, data, len(data)) + self._backend.openssl_assert(res != 0) + + def finalize(self): + buf = self._backend._ffi.new("unsigned char[]", + self._backend._lib.EVP_MAX_MD_SIZE) + outlen = self._backend._ffi.new("unsigned int *") + res = self._backend._lib.HMAC_Final(self._ctx, buf, outlen) + self._backend.openssl_assert(res != 0) + self._backend.openssl_assert(outlen[0] == self.algorithm.digest_size) + return self._backend._ffi.buffer(buf)[:outlen[0]] + + def verify(self, signature): + digest = self.finalize() + if not constant_time.bytes_eq(digest, signature): + raise InvalidSignature("Signature did not match digest.") diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/rsa.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/rsa.py new file mode 100644 index 0000000..9a7bfaa --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/rsa.py @@ -0,0 +1,475 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import math + +from cryptography import utils +from cryptography.exceptions import ( + InvalidSignature, UnsupportedAlgorithm, _Reasons +) +from cryptography.hazmat.backends.openssl.utils import ( + _calculate_digest_and_algorithm, _check_not_prehashed, + _warn_sign_verify_deprecated +) +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric import ( + AsymmetricSignatureContext, AsymmetricVerificationContext, rsa +) +from cryptography.hazmat.primitives.asymmetric.padding import ( + AsymmetricPadding, MGF1, OAEP, PKCS1v15, PSS, calculate_max_pss_salt_length +) +from cryptography.hazmat.primitives.asymmetric.rsa import ( + RSAPrivateKeyWithSerialization, RSAPublicKeyWithSerialization +) + + +def _get_rsa_pss_salt_length(pss, key, hash_algorithm): + salt = pss._salt_length + + if salt is MGF1.MAX_LENGTH or salt is PSS.MAX_LENGTH: + return calculate_max_pss_salt_length(key, hash_algorithm) + else: + return salt + + +def _enc_dec_rsa(backend, key, data, padding): + if not isinstance(padding, AsymmetricPadding): + raise TypeError("Padding must be an instance of AsymmetricPadding.") + + if isinstance(padding, PKCS1v15): + padding_enum = backend._lib.RSA_PKCS1_PADDING + elif isinstance(padding, OAEP): + padding_enum = backend._lib.RSA_PKCS1_OAEP_PADDING + + if not isinstance(padding._mgf, MGF1): + raise UnsupportedAlgorithm( + "Only MGF1 is supported by this backend.", + _Reasons.UNSUPPORTED_MGF + ) + + if not backend.rsa_padding_supported(padding): + raise UnsupportedAlgorithm( + "This combination of padding and hash algorithm is not " + "supported by this backend.", + _Reasons.UNSUPPORTED_PADDING + ) + + else: + raise UnsupportedAlgorithm( + "{0} is not supported by this backend.".format( + padding.name + ), + _Reasons.UNSUPPORTED_PADDING + ) + + return _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum, padding) + + +def _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum, padding): + if isinstance(key, _RSAPublicKey): + init = backend._lib.EVP_PKEY_encrypt_init + crypt = backend._lib.EVP_PKEY_encrypt + else: + init = backend._lib.EVP_PKEY_decrypt_init + crypt = backend._lib.EVP_PKEY_decrypt + + pkey_ctx = backend._lib.EVP_PKEY_CTX_new( + key._evp_pkey, backend._ffi.NULL + ) + backend.openssl_assert(pkey_ctx != backend._ffi.NULL) + pkey_ctx = backend._ffi.gc(pkey_ctx, backend._lib.EVP_PKEY_CTX_free) + res = init(pkey_ctx) + backend.openssl_assert(res == 1) + res = backend._lib.EVP_PKEY_CTX_set_rsa_padding( + pkey_ctx, padding_enum) + backend.openssl_assert(res > 0) + buf_size = backend._lib.EVP_PKEY_size(key._evp_pkey) + backend.openssl_assert(buf_size > 0) + if ( + isinstance(padding, OAEP) and + backend._lib.Cryptography_HAS_RSA_OAEP_MD + ): + mgf1_md = backend._lib.EVP_get_digestbyname( + padding._mgf._algorithm.name.encode("ascii")) + backend.openssl_assert(mgf1_md != backend._ffi.NULL) + res = backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1_md) + backend.openssl_assert(res > 0) + oaep_md = backend._lib.EVP_get_digestbyname( + padding._algorithm.name.encode("ascii")) + backend.openssl_assert(oaep_md != backend._ffi.NULL) + res = backend._lib.EVP_PKEY_CTX_set_rsa_oaep_md(pkey_ctx, oaep_md) + backend.openssl_assert(res > 0) + + if ( + isinstance(padding, OAEP) and + padding._label is not None and + len(padding._label) > 0 + ): + # set0_rsa_oaep_label takes ownership of the char * so we need to + # copy it into some new memory + labelptr = backend._lib.OPENSSL_malloc(len(padding._label)) + backend.openssl_assert(labelptr != backend._ffi.NULL) + backend._ffi.memmove(labelptr, padding._label, len(padding._label)) + res = backend._lib.EVP_PKEY_CTX_set0_rsa_oaep_label( + pkey_ctx, labelptr, len(padding._label) + ) + backend.openssl_assert(res == 1) + + outlen = backend._ffi.new("size_t *", buf_size) + buf = backend._ffi.new("unsigned char[]", buf_size) + res = crypt(pkey_ctx, buf, outlen, data, len(data)) + if res <= 0: + _handle_rsa_enc_dec_error(backend, key) + + return backend._ffi.buffer(buf)[:outlen[0]] + + +def _handle_rsa_enc_dec_error(backend, key): + errors = backend._consume_errors() + backend.openssl_assert(errors) + assert errors[0].lib == backend._lib.ERR_LIB_RSA + if isinstance(key, _RSAPublicKey): + assert (errors[0].reason == + backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE) + raise ValueError( + "Data too long for key size. Encrypt less data or use a " + "larger key size." + ) + else: + decoding_errors = [ + backend._lib.RSA_R_BLOCK_TYPE_IS_NOT_01, + backend._lib.RSA_R_BLOCK_TYPE_IS_NOT_02, + backend._lib.RSA_R_OAEP_DECODING_ERROR, + # Though this error looks similar to the + # RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE, this occurs on decrypts, + # rather than on encrypts + backend._lib.RSA_R_DATA_TOO_LARGE_FOR_MODULUS, + ] + if backend._lib.Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR: + decoding_errors.append(backend._lib.RSA_R_PKCS_DECODING_ERROR) + + assert errors[0].reason in decoding_errors + raise ValueError("Decryption failed.") + + +def _rsa_sig_determine_padding(backend, key, padding, algorithm): + if not isinstance(padding, AsymmetricPadding): + raise TypeError("Expected provider of AsymmetricPadding.") + + pkey_size = backend._lib.EVP_PKEY_size(key._evp_pkey) + backend.openssl_assert(pkey_size > 0) + + if isinstance(padding, PKCS1v15): + padding_enum = backend._lib.RSA_PKCS1_PADDING + elif isinstance(padding, PSS): + if not isinstance(padding._mgf, MGF1): + raise UnsupportedAlgorithm( + "Only MGF1 is supported by this backend.", + _Reasons.UNSUPPORTED_MGF + ) + + # Size of key in bytes - 2 is the maximum + # PSS signature length (salt length is checked later) + if pkey_size - algorithm.digest_size - 2 < 0: + raise ValueError("Digest too large for key size. Use a larger " + "key or different digest.") + + padding_enum = backend._lib.RSA_PKCS1_PSS_PADDING + else: + raise UnsupportedAlgorithm( + "{0} is not supported by this backend.".format(padding.name), + _Reasons.UNSUPPORTED_PADDING + ) + + return padding_enum + + +def _rsa_sig_setup(backend, padding, algorithm, key, data, init_func): + padding_enum = _rsa_sig_determine_padding(backend, key, padding, algorithm) + evp_md = backend._lib.EVP_get_digestbyname(algorithm.name.encode("ascii")) + backend.openssl_assert(evp_md != backend._ffi.NULL) + pkey_ctx = backend._lib.EVP_PKEY_CTX_new(key._evp_pkey, backend._ffi.NULL) + backend.openssl_assert(pkey_ctx != backend._ffi.NULL) + pkey_ctx = backend._ffi.gc(pkey_ctx, backend._lib.EVP_PKEY_CTX_free) + res = init_func(pkey_ctx) + backend.openssl_assert(res == 1) + res = backend._lib.EVP_PKEY_CTX_set_signature_md(pkey_ctx, evp_md) + backend.openssl_assert(res > 0) + res = backend._lib.EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, padding_enum) + backend.openssl_assert(res > 0) + if isinstance(padding, PSS): + res = backend._lib.EVP_PKEY_CTX_set_rsa_pss_saltlen( + pkey_ctx, _get_rsa_pss_salt_length(padding, key, algorithm) + ) + backend.openssl_assert(res > 0) + + mgf1_md = backend._lib.EVP_get_digestbyname( + padding._mgf._algorithm.name.encode("ascii") + ) + backend.openssl_assert(mgf1_md != backend._ffi.NULL) + res = backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1_md) + backend.openssl_assert(res > 0) + + return pkey_ctx + + +def _rsa_sig_sign(backend, padding, algorithm, private_key, data): + pkey_ctx = _rsa_sig_setup( + backend, padding, algorithm, private_key, data, + backend._lib.EVP_PKEY_sign_init + ) + buflen = backend._ffi.new("size_t *") + res = backend._lib.EVP_PKEY_sign( + pkey_ctx, + backend._ffi.NULL, + buflen, + data, + len(data) + ) + backend.openssl_assert(res == 1) + buf = backend._ffi.new("unsigned char[]", buflen[0]) + res = backend._lib.EVP_PKEY_sign( + pkey_ctx, buf, buflen, data, len(data)) + if res != 1: + errors = backend._consume_errors() + assert errors[0].lib == backend._lib.ERR_LIB_RSA + reason = None + if (errors[0].reason == + backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE): + reason = ("Salt length too long for key size. Try using " + "MAX_LENGTH instead.") + else: + assert (errors[0].reason == + backend._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY) + reason = "Digest too large for key size. Use a larger key." + assert reason is not None + raise ValueError(reason) + + return backend._ffi.buffer(buf)[:] + + +def _rsa_sig_verify(backend, padding, algorithm, public_key, signature, data): + pkey_ctx = _rsa_sig_setup( + backend, padding, algorithm, public_key, data, + backend._lib.EVP_PKEY_verify_init + ) + res = backend._lib.EVP_PKEY_verify( + pkey_ctx, signature, len(signature), data, len(data) + ) + # The previous call can return negative numbers in the event of an + # error. This is not a signature failure but we need to fail if it + # occurs. + backend.openssl_assert(res >= 0) + if res == 0: + backend._consume_errors() + raise InvalidSignature + + +@utils.register_interface(AsymmetricSignatureContext) +class _RSASignatureContext(object): + def __init__(self, backend, private_key, padding, algorithm): + self._backend = backend + self._private_key = private_key + + # We now call _rsa_sig_determine_padding in _rsa_sig_setup. However + # we need to make a pointless call to it here so we maintain the + # API of erroring on init with this context if the values are invalid. + _rsa_sig_determine_padding(backend, private_key, padding, algorithm) + self._padding = padding + self._algorithm = algorithm + self._hash_ctx = hashes.Hash(self._algorithm, self._backend) + + def update(self, data): + self._hash_ctx.update(data) + + def finalize(self): + return _rsa_sig_sign( + self._backend, + self._padding, + self._algorithm, + self._private_key, + self._hash_ctx.finalize() + ) + + +@utils.register_interface(AsymmetricVerificationContext) +class _RSAVerificationContext(object): + def __init__(self, backend, public_key, signature, padding, algorithm): + self._backend = backend + self._public_key = public_key + self._signature = signature + self._padding = padding + # We now call _rsa_sig_determine_padding in _rsa_sig_setup. However + # we need to make a pointless call to it here so we maintain the + # API of erroring on init with this context if the values are invalid. + _rsa_sig_determine_padding(backend, public_key, padding, algorithm) + + padding = padding + self._algorithm = algorithm + self._hash_ctx = hashes.Hash(self._algorithm, self._backend) + + def update(self, data): + self._hash_ctx.update(data) + + def verify(self): + return _rsa_sig_verify( + self._backend, + self._padding, + self._algorithm, + self._public_key, + self._signature, + self._hash_ctx.finalize() + ) + + +@utils.register_interface(RSAPrivateKeyWithSerialization) +class _RSAPrivateKey(object): + def __init__(self, backend, rsa_cdata, evp_pkey): + self._backend = backend + self._rsa_cdata = rsa_cdata + self._evp_pkey = evp_pkey + + n = self._backend._ffi.new("BIGNUM **") + self._backend._lib.RSA_get0_key( + self._rsa_cdata, n, self._backend._ffi.NULL, + self._backend._ffi.NULL + ) + self._backend.openssl_assert(n[0] != self._backend._ffi.NULL) + self._key_size = self._backend._lib.BN_num_bits(n[0]) + + key_size = utils.read_only_property("_key_size") + + def signer(self, padding, algorithm): + _warn_sign_verify_deprecated() + _check_not_prehashed(algorithm) + return _RSASignatureContext(self._backend, self, padding, algorithm) + + def decrypt(self, ciphertext, padding): + key_size_bytes = int(math.ceil(self.key_size / 8.0)) + if key_size_bytes != len(ciphertext): + raise ValueError("Ciphertext length must be equal to key size.") + + return _enc_dec_rsa(self._backend, self, ciphertext, padding) + + def public_key(self): + ctx = self._backend._lib.RSAPublicKey_dup(self._rsa_cdata) + self._backend.openssl_assert(ctx != self._backend._ffi.NULL) + ctx = self._backend._ffi.gc(ctx, self._backend._lib.RSA_free) + res = self._backend._lib.RSA_blinding_on(ctx, self._backend._ffi.NULL) + self._backend.openssl_assert(res == 1) + evp_pkey = self._backend._rsa_cdata_to_evp_pkey(ctx) + return _RSAPublicKey(self._backend, ctx, evp_pkey) + + def private_numbers(self): + n = self._backend._ffi.new("BIGNUM **") + e = self._backend._ffi.new("BIGNUM **") + d = self._backend._ffi.new("BIGNUM **") + p = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + dmp1 = self._backend._ffi.new("BIGNUM **") + dmq1 = self._backend._ffi.new("BIGNUM **") + iqmp = self._backend._ffi.new("BIGNUM **") + self._backend._lib.RSA_get0_key(self._rsa_cdata, n, e, d) + self._backend.openssl_assert(n[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(e[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(d[0] != self._backend._ffi.NULL) + self._backend._lib.RSA_get0_factors(self._rsa_cdata, p, q) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(q[0] != self._backend._ffi.NULL) + self._backend._lib.RSA_get0_crt_params( + self._rsa_cdata, dmp1, dmq1, iqmp + ) + self._backend.openssl_assert(dmp1[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(dmq1[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(iqmp[0] != self._backend._ffi.NULL) + return rsa.RSAPrivateNumbers( + p=self._backend._bn_to_int(p[0]), + q=self._backend._bn_to_int(q[0]), + d=self._backend._bn_to_int(d[0]), + dmp1=self._backend._bn_to_int(dmp1[0]), + dmq1=self._backend._bn_to_int(dmq1[0]), + iqmp=self._backend._bn_to_int(iqmp[0]), + public_numbers=rsa.RSAPublicNumbers( + e=self._backend._bn_to_int(e[0]), + n=self._backend._bn_to_int(n[0]), + ) + ) + + def private_bytes(self, encoding, format, encryption_algorithm): + return self._backend._private_key_bytes( + encoding, + format, + encryption_algorithm, + self._evp_pkey, + self._rsa_cdata + ) + + def sign(self, data, padding, algorithm): + data, algorithm = _calculate_digest_and_algorithm( + self._backend, data, algorithm + ) + return _rsa_sig_sign(self._backend, padding, algorithm, self, data) + + +@utils.register_interface(RSAPublicKeyWithSerialization) +class _RSAPublicKey(object): + def __init__(self, backend, rsa_cdata, evp_pkey): + self._backend = backend + self._rsa_cdata = rsa_cdata + self._evp_pkey = evp_pkey + + n = self._backend._ffi.new("BIGNUM **") + self._backend._lib.RSA_get0_key( + self._rsa_cdata, n, self._backend._ffi.NULL, + self._backend._ffi.NULL + ) + self._backend.openssl_assert(n[0] != self._backend._ffi.NULL) + self._key_size = self._backend._lib.BN_num_bits(n[0]) + + key_size = utils.read_only_property("_key_size") + + def verifier(self, signature, padding, algorithm): + _warn_sign_verify_deprecated() + if not isinstance(signature, bytes): + raise TypeError("signature must be bytes.") + + _check_not_prehashed(algorithm) + return _RSAVerificationContext( + self._backend, self, signature, padding, algorithm + ) + + def encrypt(self, plaintext, padding): + return _enc_dec_rsa(self._backend, self, plaintext, padding) + + def public_numbers(self): + n = self._backend._ffi.new("BIGNUM **") + e = self._backend._ffi.new("BIGNUM **") + self._backend._lib.RSA_get0_key( + self._rsa_cdata, n, e, self._backend._ffi.NULL + ) + self._backend.openssl_assert(n[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(e[0] != self._backend._ffi.NULL) + return rsa.RSAPublicNumbers( + e=self._backend._bn_to_int(e[0]), + n=self._backend._bn_to_int(n[0]), + ) + + def public_bytes(self, encoding, format): + return self._backend._public_key_bytes( + encoding, + format, + self, + self._evp_pkey, + self._rsa_cdata + ) + + def verify(self, signature, data, padding, algorithm): + data, algorithm = _calculate_digest_and_algorithm( + self._backend, data, algorithm + ) + return _rsa_sig_verify( + self._backend, padding, algorithm, self, signature, data + ) diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/utils.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/utils.py new file mode 100644 index 0000000..05d0fe5 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/utils.py @@ -0,0 +1,45 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import warnings + +from cryptography import utils +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric.utils import Prehashed + + +def _calculate_digest_and_algorithm(backend, data, algorithm): + if not isinstance(algorithm, Prehashed): + hash_ctx = hashes.Hash(algorithm, backend) + hash_ctx.update(data) + data = hash_ctx.finalize() + else: + algorithm = algorithm._algorithm + + if len(data) != algorithm.digest_size: + raise ValueError( + "The provided data must be the same length as the hash " + "algorithm's digest size." + ) + + return (data, algorithm) + + +def _check_not_prehashed(signature_algorithm): + if isinstance(signature_algorithm, Prehashed): + raise TypeError( + "Prehashed is only supported in the sign and verify methods. " + "It cannot be used with signer or verifier." + ) + + +def _warn_sign_verify_deprecated(): + warnings.warn( + "signer and verifier have been deprecated. Please use sign " + "and verify instead.", + utils.PersistentlyDeprecated, + stacklevel=3 + ) diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/x25519.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/x25519.py new file mode 100644 index 0000000..983ece6 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/x25519.py @@ -0,0 +1,79 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import utils +from cryptography.hazmat.primitives.asymmetric.x25519 import ( + X25519PrivateKey, X25519PublicKey +) + + +@utils.register_interface(X25519PublicKey) +class _X25519PublicKey(object): + def __init__(self, backend, evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_bytes(self): + ucharpp = self._backend._ffi.new("unsigned char **") + res = self._backend._lib.EVP_PKEY_get1_tls_encodedpoint( + self._evp_pkey, ucharpp + ) + self._backend.openssl_assert(res == 32) + self._backend.openssl_assert(ucharpp[0] != self._backend._ffi.NULL) + data = self._backend._ffi.gc( + ucharpp[0], self._backend._lib.OPENSSL_free + ) + return self._backend._ffi.buffer(data, res)[:] + + +@utils.register_interface(X25519PrivateKey) +class _X25519PrivateKey(object): + def __init__(self, backend, evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_key(self): + bio = self._backend._create_mem_bio_gc() + res = self._backend._lib.i2d_PUBKEY_bio(bio, self._evp_pkey) + self._backend.openssl_assert(res == 1) + evp_pkey = self._backend._lib.d2i_PUBKEY_bio( + bio, self._backend._ffi.NULL + ) + self._backend.openssl_assert(evp_pkey != self._backend._ffi.NULL) + evp_pkey = self._backend._ffi.gc( + evp_pkey, self._backend._lib.EVP_PKEY_free + ) + return _X25519PublicKey(self._backend, evp_pkey) + + def exchange(self, peer_public_key): + if not isinstance(peer_public_key, X25519PublicKey): + raise TypeError("peer_public_key must be X25519PublicKey.") + + ctx = self._backend._lib.EVP_PKEY_CTX_new( + self._evp_pkey, self._backend._ffi.NULL + ) + self._backend.openssl_assert(ctx != self._backend._ffi.NULL) + ctx = self._backend._ffi.gc(ctx, self._backend._lib.EVP_PKEY_CTX_free) + res = self._backend._lib.EVP_PKEY_derive_init(ctx) + self._backend.openssl_assert(res == 1) + res = self._backend._lib.EVP_PKEY_derive_set_peer( + ctx, peer_public_key._evp_pkey + ) + self._backend.openssl_assert(res == 1) + keylen = self._backend._ffi.new("size_t *") + res = self._backend._lib.EVP_PKEY_derive( + ctx, self._backend._ffi.NULL, keylen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(keylen[0] > 0) + buf = self._backend._ffi.new("unsigned char[]", keylen[0]) + res = self._backend._lib.EVP_PKEY_derive(ctx, buf, keylen) + if res != 1: + raise ValueError( + "Null shared key derived from public/private pair." + ) + + return self._backend._ffi.buffer(buf, keylen[0])[:] diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/x509.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/x509.py new file mode 100644 index 0000000..b870eeb --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/x509.py @@ -0,0 +1,518 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import datetime +import operator +import warnings + +from cryptography import utils, x509 +from cryptography.exceptions import UnsupportedAlgorithm +from cryptography.hazmat.backends.openssl.decode_asn1 import ( + _CERTIFICATE_EXTENSION_PARSER, _CERTIFICATE_EXTENSION_PARSER_NO_SCT, + _CRL_EXTENSION_PARSER, _CSR_EXTENSION_PARSER, + _REVOKED_CERTIFICATE_EXTENSION_PARSER, _asn1_integer_to_int, + _asn1_string_to_bytes, _decode_x509_name, _obj2txt, _parse_asn1_time +) +from cryptography.hazmat.backends.openssl.encode_asn1 import ( + _encode_asn1_int_gc +) +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa + + +@utils.register_interface(x509.Certificate) +class _Certificate(object): + def __init__(self, backend, x509): + self._backend = backend + self._x509 = x509 + + def __repr__(self): + return "".format(self.subject) + + def __eq__(self, other): + if not isinstance(other, x509.Certificate): + return NotImplemented + + res = self._backend._lib.X509_cmp(self._x509, other._x509) + return res == 0 + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(self.public_bytes(serialization.Encoding.DER)) + + def fingerprint(self, algorithm): + h = hashes.Hash(algorithm, self._backend) + h.update(self.public_bytes(serialization.Encoding.DER)) + return h.finalize() + + @property + def version(self): + version = self._backend._lib.X509_get_version(self._x509) + if version == 0: + return x509.Version.v1 + elif version == 2: + return x509.Version.v3 + else: + raise x509.InvalidVersion( + "{0} is not a valid X509 version".format(version), version + ) + + @property + def serial(self): + warnings.warn( + "Certificate serial is deprecated, use serial_number instead.", + utils.PersistentlyDeprecated, + stacklevel=2 + ) + return self.serial_number + + @property + def serial_number(self): + asn1_int = self._backend._lib.X509_get_serialNumber(self._x509) + self._backend.openssl_assert(asn1_int != self._backend._ffi.NULL) + return _asn1_integer_to_int(self._backend, asn1_int) + + def public_key(self): + pkey = self._backend._lib.X509_get_pubkey(self._x509) + if pkey == self._backend._ffi.NULL: + # Remove errors from the stack. + self._backend._consume_errors() + raise ValueError("Certificate public key is of an unknown type") + + pkey = self._backend._ffi.gc(pkey, self._backend._lib.EVP_PKEY_free) + + return self._backend._evp_pkey_to_public_key(pkey) + + @property + def not_valid_before(self): + asn1_time = self._backend._lib.X509_get_notBefore(self._x509) + return _parse_asn1_time(self._backend, asn1_time) + + @property + def not_valid_after(self): + asn1_time = self._backend._lib.X509_get_notAfter(self._x509) + return _parse_asn1_time(self._backend, asn1_time) + + @property + def issuer(self): + issuer = self._backend._lib.X509_get_issuer_name(self._x509) + self._backend.openssl_assert(issuer != self._backend._ffi.NULL) + return _decode_x509_name(self._backend, issuer) + + @property + def subject(self): + subject = self._backend._lib.X509_get_subject_name(self._x509) + self._backend.openssl_assert(subject != self._backend._ffi.NULL) + return _decode_x509_name(self._backend, subject) + + @property + def signature_hash_algorithm(self): + oid = self.signature_algorithm_oid + try: + return x509._SIG_OIDS_TO_HASH[oid] + except KeyError: + raise UnsupportedAlgorithm( + "Signature algorithm OID:{0} not recognized".format(oid) + ) + + @property + def signature_algorithm_oid(self): + alg = self._backend._ffi.new("X509_ALGOR **") + self._backend._lib.X509_get0_signature( + self._backend._ffi.NULL, alg, self._x509 + ) + self._backend.openssl_assert(alg[0] != self._backend._ffi.NULL) + oid = _obj2txt(self._backend, alg[0].algorithm) + return x509.ObjectIdentifier(oid) + + @utils.cached_property + def extensions(self): + if self._backend._lib.CRYPTOGRAPHY_OPENSSL_110_OR_GREATER: + return _CERTIFICATE_EXTENSION_PARSER.parse( + self._backend, self._x509 + ) + else: + return _CERTIFICATE_EXTENSION_PARSER_NO_SCT.parse( + self._backend, self._x509 + ) + + @property + def signature(self): + sig = self._backend._ffi.new("ASN1_BIT_STRING **") + self._backend._lib.X509_get0_signature( + sig, self._backend._ffi.NULL, self._x509 + ) + self._backend.openssl_assert(sig[0] != self._backend._ffi.NULL) + return _asn1_string_to_bytes(self._backend, sig[0]) + + @property + def tbs_certificate_bytes(self): + pp = self._backend._ffi.new("unsigned char **") + res = self._backend._lib.i2d_re_X509_tbs(self._x509, pp) + self._backend.openssl_assert(res > 0) + pp = self._backend._ffi.gc( + pp, lambda pointer: self._backend._lib.OPENSSL_free(pointer[0]) + ) + return self._backend._ffi.buffer(pp[0], res)[:] + + def public_bytes(self, encoding): + bio = self._backend._create_mem_bio_gc() + if encoding is serialization.Encoding.PEM: + res = self._backend._lib.PEM_write_bio_X509(bio, self._x509) + elif encoding is serialization.Encoding.DER: + res = self._backend._lib.i2d_X509_bio(bio, self._x509) + else: + raise TypeError("encoding must be an item from the Encoding enum") + + self._backend.openssl_assert(res == 1) + return self._backend._read_mem_bio(bio) + + +@utils.register_interface(x509.RevokedCertificate) +class _RevokedCertificate(object): + def __init__(self, backend, crl, x509_revoked): + self._backend = backend + # The X509_REVOKED_value is a X509_REVOKED * that has + # no reference counting. This means when X509_CRL_free is + # called then the CRL and all X509_REVOKED * are freed. Since + # you can retain a reference to a single revoked certificate + # and let the CRL fall out of scope we need to retain a + # private reference to the CRL inside the RevokedCertificate + # object to prevent the gc from being called inappropriately. + self._crl = crl + self._x509_revoked = x509_revoked + + @property + def serial_number(self): + asn1_int = self._backend._lib.X509_REVOKED_get0_serialNumber( + self._x509_revoked + ) + self._backend.openssl_assert(asn1_int != self._backend._ffi.NULL) + return _asn1_integer_to_int(self._backend, asn1_int) + + @property + def revocation_date(self): + return _parse_asn1_time( + self._backend, + self._backend._lib.X509_REVOKED_get0_revocationDate( + self._x509_revoked + ) + ) + + @utils.cached_property + def extensions(self): + return _REVOKED_CERTIFICATE_EXTENSION_PARSER.parse( + self._backend, self._x509_revoked + ) + + +@utils.register_interface(x509.CertificateRevocationList) +class _CertificateRevocationList(object): + def __init__(self, backend, x509_crl): + self._backend = backend + self._x509_crl = x509_crl + + def __eq__(self, other): + if not isinstance(other, x509.CertificateRevocationList): + return NotImplemented + + res = self._backend._lib.X509_CRL_cmp(self._x509_crl, other._x509_crl) + return res == 0 + + def __ne__(self, other): + return not self == other + + def fingerprint(self, algorithm): + h = hashes.Hash(algorithm, self._backend) + bio = self._backend._create_mem_bio_gc() + res = self._backend._lib.i2d_X509_CRL_bio( + bio, self._x509_crl + ) + self._backend.openssl_assert(res == 1) + der = self._backend._read_mem_bio(bio) + h.update(der) + return h.finalize() + + def get_revoked_certificate_by_serial_number(self, serial_number): + revoked = self._backend._ffi.new("X509_REVOKED **") + asn1_int = _encode_asn1_int_gc(self._backend, serial_number) + res = self._backend._lib.X509_CRL_get0_by_serial( + self._x509_crl, revoked, asn1_int + ) + if res == 0: + return None + else: + self._backend.openssl_assert( + revoked[0] != self._backend._ffi.NULL + ) + return _RevokedCertificate( + self._backend, self._x509_crl, revoked[0] + ) + + @property + def signature_hash_algorithm(self): + oid = self.signature_algorithm_oid + try: + return x509._SIG_OIDS_TO_HASH[oid] + except KeyError: + raise UnsupportedAlgorithm( + "Signature algorithm OID:{0} not recognized".format(oid) + ) + + @property + def signature_algorithm_oid(self): + alg = self._backend._ffi.new("X509_ALGOR **") + self._backend._lib.X509_CRL_get0_signature( + self._x509_crl, self._backend._ffi.NULL, alg + ) + self._backend.openssl_assert(alg[0] != self._backend._ffi.NULL) + oid = _obj2txt(self._backend, alg[0].algorithm) + return x509.ObjectIdentifier(oid) + + @property + def issuer(self): + issuer = self._backend._lib.X509_CRL_get_issuer(self._x509_crl) + self._backend.openssl_assert(issuer != self._backend._ffi.NULL) + return _decode_x509_name(self._backend, issuer) + + @property + def next_update(self): + nu = self._backend._lib.X509_CRL_get_nextUpdate(self._x509_crl) + self._backend.openssl_assert(nu != self._backend._ffi.NULL) + return _parse_asn1_time(self._backend, nu) + + @property + def last_update(self): + lu = self._backend._lib.X509_CRL_get_lastUpdate(self._x509_crl) + self._backend.openssl_assert(lu != self._backend._ffi.NULL) + return _parse_asn1_time(self._backend, lu) + + @property + def signature(self): + sig = self._backend._ffi.new("ASN1_BIT_STRING **") + self._backend._lib.X509_CRL_get0_signature( + self._x509_crl, sig, self._backend._ffi.NULL + ) + self._backend.openssl_assert(sig[0] != self._backend._ffi.NULL) + return _asn1_string_to_bytes(self._backend, sig[0]) + + @property + def tbs_certlist_bytes(self): + pp = self._backend._ffi.new("unsigned char **") + res = self._backend._lib.i2d_re_X509_CRL_tbs(self._x509_crl, pp) + self._backend.openssl_assert(res > 0) + pp = self._backend._ffi.gc( + pp, lambda pointer: self._backend._lib.OPENSSL_free(pointer[0]) + ) + return self._backend._ffi.buffer(pp[0], res)[:] + + def public_bytes(self, encoding): + bio = self._backend._create_mem_bio_gc() + if encoding is serialization.Encoding.PEM: + res = self._backend._lib.PEM_write_bio_X509_CRL( + bio, self._x509_crl + ) + elif encoding is serialization.Encoding.DER: + res = self._backend._lib.i2d_X509_CRL_bio(bio, self._x509_crl) + else: + raise TypeError("encoding must be an item from the Encoding enum") + + self._backend.openssl_assert(res == 1) + return self._backend._read_mem_bio(bio) + + def _revoked_cert(self, idx): + revoked = self._backend._lib.X509_CRL_get_REVOKED(self._x509_crl) + r = self._backend._lib.sk_X509_REVOKED_value(revoked, idx) + self._backend.openssl_assert(r != self._backend._ffi.NULL) + return _RevokedCertificate(self._backend, self, r) + + def __iter__(self): + for i in range(len(self)): + yield self._revoked_cert(i) + + def __getitem__(self, idx): + if isinstance(idx, slice): + start, stop, step = idx.indices(len(self)) + return [self._revoked_cert(i) for i in range(start, stop, step)] + else: + idx = operator.index(idx) + if idx < 0: + idx += len(self) + if not 0 <= idx < len(self): + raise IndexError + return self._revoked_cert(idx) + + def __len__(self): + revoked = self._backend._lib.X509_CRL_get_REVOKED(self._x509_crl) + if revoked == self._backend._ffi.NULL: + return 0 + else: + return self._backend._lib.sk_X509_REVOKED_num(revoked) + + @utils.cached_property + def extensions(self): + return _CRL_EXTENSION_PARSER.parse(self._backend, self._x509_crl) + + def is_signature_valid(self, public_key): + if not isinstance(public_key, (dsa.DSAPublicKey, rsa.RSAPublicKey, + ec.EllipticCurvePublicKey)): + raise TypeError('Expecting one of DSAPublicKey, RSAPublicKey,' + ' or EllipticCurvePublicKey.') + res = self._backend._lib.X509_CRL_verify( + self._x509_crl, public_key._evp_pkey + ) + + if res != 1: + self._backend._consume_errors() + return False + + return True + + +@utils.register_interface(x509.CertificateSigningRequest) +class _CertificateSigningRequest(object): + def __init__(self, backend, x509_req): + self._backend = backend + self._x509_req = x509_req + + def __eq__(self, other): + if not isinstance(other, _CertificateSigningRequest): + return NotImplemented + + self_bytes = self.public_bytes(serialization.Encoding.DER) + other_bytes = other.public_bytes(serialization.Encoding.DER) + return self_bytes == other_bytes + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(self.public_bytes(serialization.Encoding.DER)) + + def public_key(self): + pkey = self._backend._lib.X509_REQ_get_pubkey(self._x509_req) + self._backend.openssl_assert(pkey != self._backend._ffi.NULL) + pkey = self._backend._ffi.gc(pkey, self._backend._lib.EVP_PKEY_free) + return self._backend._evp_pkey_to_public_key(pkey) + + @property + def subject(self): + subject = self._backend._lib.X509_REQ_get_subject_name(self._x509_req) + self._backend.openssl_assert(subject != self._backend._ffi.NULL) + return _decode_x509_name(self._backend, subject) + + @property + def signature_hash_algorithm(self): + oid = self.signature_algorithm_oid + try: + return x509._SIG_OIDS_TO_HASH[oid] + except KeyError: + raise UnsupportedAlgorithm( + "Signature algorithm OID:{0} not recognized".format(oid) + ) + + @property + def signature_algorithm_oid(self): + alg = self._backend._ffi.new("X509_ALGOR **") + self._backend._lib.X509_REQ_get0_signature( + self._x509_req, self._backend._ffi.NULL, alg + ) + self._backend.openssl_assert(alg[0] != self._backend._ffi.NULL) + oid = _obj2txt(self._backend, alg[0].algorithm) + return x509.ObjectIdentifier(oid) + + @utils.cached_property + def extensions(self): + x509_exts = self._backend._lib.X509_REQ_get_extensions(self._x509_req) + return _CSR_EXTENSION_PARSER.parse(self._backend, x509_exts) + + def public_bytes(self, encoding): + bio = self._backend._create_mem_bio_gc() + if encoding is serialization.Encoding.PEM: + res = self._backend._lib.PEM_write_bio_X509_REQ( + bio, self._x509_req + ) + elif encoding is serialization.Encoding.DER: + res = self._backend._lib.i2d_X509_REQ_bio(bio, self._x509_req) + else: + raise TypeError("encoding must be an item from the Encoding enum") + + self._backend.openssl_assert(res == 1) + return self._backend._read_mem_bio(bio) + + @property + def tbs_certrequest_bytes(self): + pp = self._backend._ffi.new("unsigned char **") + res = self._backend._lib.i2d_re_X509_REQ_tbs(self._x509_req, pp) + self._backend.openssl_assert(res > 0) + pp = self._backend._ffi.gc( + pp, lambda pointer: self._backend._lib.OPENSSL_free(pointer[0]) + ) + return self._backend._ffi.buffer(pp[0], res)[:] + + @property + def signature(self): + sig = self._backend._ffi.new("ASN1_BIT_STRING **") + self._backend._lib.X509_REQ_get0_signature( + self._x509_req, sig, self._backend._ffi.NULL + ) + self._backend.openssl_assert(sig[0] != self._backend._ffi.NULL) + return _asn1_string_to_bytes(self._backend, sig[0]) + + @property + def is_signature_valid(self): + pkey = self._backend._lib.X509_REQ_get_pubkey(self._x509_req) + self._backend.openssl_assert(pkey != self._backend._ffi.NULL) + pkey = self._backend._ffi.gc(pkey, self._backend._lib.EVP_PKEY_free) + res = self._backend._lib.X509_REQ_verify(self._x509_req, pkey) + + if res != 1: + self._backend._consume_errors() + return False + + return True + + +@utils.register_interface( + x509.certificate_transparency.SignedCertificateTimestamp +) +class _SignedCertificateTimestamp(object): + def __init__(self, backend, sct_list, sct): + self._backend = backend + # Keep the SCT_LIST that this SCT came from alive. + self._sct_list = sct_list + self._sct = sct + + @property + def version(self): + version = self._backend._lib.SCT_get_version(self._sct) + assert version == self._backend._lib.SCT_VERSION_V1 + return x509.certificate_transparency.Version.v1 + + @property + def log_id(self): + out = self._backend._ffi.new("unsigned char **") + log_id_length = self._backend._lib.SCT_get0_log_id(self._sct, out) + assert log_id_length >= 0 + return self._backend._ffi.buffer(out[0], log_id_length)[:] + + @property + def timestamp(self): + timestamp = self._backend._lib.SCT_get_timestamp(self._sct) + milliseconds = timestamp % 1000 + return datetime.datetime.utcfromtimestamp( + timestamp // 1000 + ).replace(microsecond=milliseconds * 1000) + + @property + def entry_type(self): + entry_type = self._backend._lib.SCT_get_log_entry_type(self._sct) + # We currently only support loading SCTs from the X.509 extension, so + # we only have precerts. + assert entry_type == self._backend._lib.CT_LOG_ENTRY_TYPE_PRECERT + return x509.certificate_transparency.LogEntryType.PRE_CERTIFICATE diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/bindings/__init__.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/bindings/__init__.py new file mode 100644 index 0000000..4b54088 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/bindings/__init__.py @@ -0,0 +1,5 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/bindings/_constant_time.so b/venv/lib/python2.7/site-packages/cryptography/hazmat/bindings/_constant_time.so new file mode 100755 index 0000000..b5c59c9 Binary files /dev/null and b/venv/lib/python2.7/site-packages/cryptography/hazmat/bindings/_constant_time.so differ diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/bindings/_openssl.so b/venv/lib/python2.7/site-packages/cryptography/hazmat/bindings/_openssl.so new file mode 100755 index 0000000..686062d Binary files /dev/null and b/venv/lib/python2.7/site-packages/cryptography/hazmat/bindings/_openssl.so differ diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/bindings/_padding.so b/venv/lib/python2.7/site-packages/cryptography/hazmat/bindings/_padding.so new file mode 100755 index 0000000..aa3a254 Binary files /dev/null and b/venv/lib/python2.7/site-packages/cryptography/hazmat/bindings/_padding.so differ diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/bindings/openssl/__init__.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/bindings/openssl/__init__.py new file mode 100644 index 0000000..4b54088 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/bindings/openssl/__init__.py @@ -0,0 +1,5 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/bindings/openssl/_conditional.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/bindings/openssl/_conditional.py new file mode 100644 index 0000000..b3e4e8b --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/bindings/openssl/_conditional.py @@ -0,0 +1,302 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + + +def cryptography_has_ec2m(): + return [ + "EC_POINT_set_affine_coordinates_GF2m", + "EC_POINT_get_affine_coordinates_GF2m", + "EC_POINT_set_compressed_coordinates_GF2m", + ] + + +def cryptography_has_ec_1_0_2(): + return [ + "EC_curve_nid2nist", + ] + + +def cryptography_has_set_ecdh_auto(): + return [ + "SSL_CTX_set_ecdh_auto", + ] + + +def cryptography_has_rsa_r_pkcs_decoding_error(): + return [ + "RSA_R_PKCS_DECODING_ERROR" + ] + + +def cryptography_has_rsa_oaep_md(): + return [ + "EVP_PKEY_CTX_set_rsa_oaep_md", + ] + + +def cryptography_has_rsa_oaep_label(): + return [ + "EVP_PKEY_CTX_set0_rsa_oaep_label", + ] + + +def cryptography_has_ssl3_method(): + return [ + "SSLv3_method", + "SSLv3_client_method", + "SSLv3_server_method", + ] + + +def cryptography_has_alpn(): + return [ + "SSL_CTX_set_alpn_protos", + "SSL_set_alpn_protos", + "SSL_CTX_set_alpn_select_cb", + "SSL_get0_alpn_selected", + ] + + +def cryptography_has_compression(): + return [ + "SSL_get_current_compression", + "SSL_get_current_expansion", + "SSL_COMP_get_name", + ] + + +def cryptography_has_get_server_tmp_key(): + return [ + "SSL_get_server_tmp_key", + ] + + +def cryptography_has_102_verification_error_codes(): + return [ + 'X509_V_ERR_SUITE_B_INVALID_VERSION', + 'X509_V_ERR_SUITE_B_INVALID_ALGORITHM', + 'X509_V_ERR_SUITE_B_INVALID_CURVE', + 'X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM', + 'X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED', + 'X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256', + 'X509_V_ERR_HOSTNAME_MISMATCH', + 'X509_V_ERR_EMAIL_MISMATCH', + 'X509_V_ERR_IP_ADDRESS_MISMATCH' + ] + + +def cryptography_has_102_verification_params(): + return [ + "X509_V_FLAG_SUITEB_128_LOS_ONLY", + "X509_V_FLAG_SUITEB_192_LOS", + "X509_V_FLAG_SUITEB_128_LOS", + "X509_VERIFY_PARAM_set1_host", + "X509_VERIFY_PARAM_set1_email", + "X509_VERIFY_PARAM_set1_ip", + "X509_VERIFY_PARAM_set1_ip_asc", + "X509_VERIFY_PARAM_set_hostflags", + ] + + +def cryptography_has_x509_v_flag_trusted_first(): + return [ + "X509_V_FLAG_TRUSTED_FIRST", + ] + + +def cryptography_has_x509_v_flag_partial_chain(): + return [ + "X509_V_FLAG_PARTIAL_CHAIN", + ] + + +def cryptography_has_set_cert_cb(): + return [ + "SSL_CTX_set_cert_cb", + "SSL_set_cert_cb", + ] + + +def cryptography_has_ssl_st(): + return [ + "SSL_ST_BEFORE", + "SSL_ST_OK", + "SSL_ST_INIT", + "SSL_ST_RENEGOTIATE", + ] + + +def cryptography_has_tls_st(): + return [ + "TLS_ST_BEFORE", + "TLS_ST_OK", + ] + + +def cryptography_has_locking_callbacks(): + return [ + "CRYPTO_LOCK", + "CRYPTO_UNLOCK", + "CRYPTO_READ", + "CRYPTO_LOCK_SSL", + "CRYPTO_lock", + ] + + +def cryptography_has_scrypt(): + return [ + "EVP_PBE_scrypt", + ] + + +def cryptography_has_generic_dtls_method(): + return [ + "DTLS_method", + "DTLS_server_method", + "DTLS_client_method", + "SSL_OP_NO_DTLSv1", + "SSL_OP_NO_DTLSv1_2", + "DTLS_set_link_mtu", + "DTLS_get_link_min_mtu", + ] + + +def cryptography_has_evp_pkey_dhx(): + return [ + "EVP_PKEY_DHX", + ] + + +def cryptography_has_mem_functions(): + return [ + "Cryptography_CRYPTO_set_mem_functions", + ] + + +def cryptography_has_sct(): + return [ + "SCT_get_version", + "SCT_get_log_entry_type", + "SCT_get0_log_id", + "SCT_get_timestamp", + "SCT_set_source", + "sk_SCT_num", + "sk_SCT_value", + "SCT_LIST_free", + ] + + +def cryptography_has_x509_store_ctx_get_issuer(): + return [ + "X509_STORE_get_get_issuer", + "X509_STORE_set_get_issuer", + ] + + +def cryptography_has_x25519(): + return [ + "EVP_PKEY_X25519", + "NID_X25519", + ] + + +def cryptography_has_evp_pkey_get_set_tls_encodedpoint(): + return [ + "EVP_PKEY_get1_tls_encodedpoint", + "EVP_PKEY_set1_tls_encodedpoint", + ] + + +def cryptography_has_fips(): + return [ + "FIPS_set_mode", + "FIPS_mode", + ] + + +def cryptography_has_ssl_sigalgs(): + return [ + "SSL_CTX_set1_sigalgs_list", + "SSL_get_sigalgs", + ] + + +def cryptography_has_psk(): + return [ + "SSL_CTX_use_psk_identity_hint", + "SSL_CTX_set_psk_server_callback", + "SSL_CTX_set_psk_client_callback", + ] + + +def cryptography_has_custom_ext(): + return [ + "SSL_CTX_add_client_custom_ext", + "SSL_CTX_add_server_custom_ext", + "SSL_extension_supported", + ] + + +def cryptography_has_openssl_cleanup(): + return [ + "OPENSSL_cleanup", + ] + + +# This is a mapping of +# {condition: function-returning-names-dependent-on-that-condition} so we can +# loop over them and delete unsupported names at runtime. It will be removed +# when cffi supports #if in cdef. We use functions instead of just a dict of +# lists so we can use coverage to measure which are used. +CONDITIONAL_NAMES = { + "Cryptography_HAS_EC2M": cryptography_has_ec2m, + "Cryptography_HAS_EC_1_0_2": cryptography_has_ec_1_0_2, + "Cryptography_HAS_SET_ECDH_AUTO": cryptography_has_set_ecdh_auto, + "Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR": ( + cryptography_has_rsa_r_pkcs_decoding_error + ), + "Cryptography_HAS_RSA_OAEP_MD": cryptography_has_rsa_oaep_md, + "Cryptography_HAS_RSA_OAEP_LABEL": cryptography_has_rsa_oaep_label, + "Cryptography_HAS_SSL3_METHOD": cryptography_has_ssl3_method, + "Cryptography_HAS_ALPN": cryptography_has_alpn, + "Cryptography_HAS_COMPRESSION": cryptography_has_compression, + "Cryptography_HAS_GET_SERVER_TMP_KEY": cryptography_has_get_server_tmp_key, + "Cryptography_HAS_102_VERIFICATION_ERROR_CODES": ( + cryptography_has_102_verification_error_codes + ), + "Cryptography_HAS_102_VERIFICATION_PARAMS": ( + cryptography_has_102_verification_params + ), + "Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST": ( + cryptography_has_x509_v_flag_trusted_first + ), + "Cryptography_HAS_X509_V_FLAG_PARTIAL_CHAIN": ( + cryptography_has_x509_v_flag_partial_chain + ), + "Cryptography_HAS_SET_CERT_CB": cryptography_has_set_cert_cb, + "Cryptography_HAS_SSL_ST": cryptography_has_ssl_st, + "Cryptography_HAS_TLS_ST": cryptography_has_tls_st, + "Cryptography_HAS_LOCKING_CALLBACKS": cryptography_has_locking_callbacks, + "Cryptography_HAS_SCRYPT": cryptography_has_scrypt, + "Cryptography_HAS_GENERIC_DTLS_METHOD": ( + cryptography_has_generic_dtls_method + ), + "Cryptography_HAS_EVP_PKEY_DHX": cryptography_has_evp_pkey_dhx, + "Cryptography_HAS_MEM_FUNCTIONS": cryptography_has_mem_functions, + "Cryptography_HAS_SCT": cryptography_has_sct, + "Cryptography_HAS_X509_STORE_CTX_GET_ISSUER": ( + cryptography_has_x509_store_ctx_get_issuer + ), + "Cryptography_HAS_X25519": cryptography_has_x25519, + "Cryptography_HAS_EVP_PKEY_get_set_tls_encodedpoint": ( + cryptography_has_evp_pkey_get_set_tls_encodedpoint + ), + "Cryptography_HAS_FIPS": cryptography_has_fips, + "Cryptography_HAS_SIGALGS": cryptography_has_ssl_sigalgs, + "Cryptography_HAS_PSK": cryptography_has_psk, + "Cryptography_HAS_CUSTOM_EXT": cryptography_has_custom_ext, + "Cryptography_HAS_OPENSSL_CLEANUP": cryptography_has_openssl_cleanup, +} diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/bindings/openssl/binding.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/bindings/openssl/binding.py new file mode 100644 index 0000000..81cf547 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/bindings/openssl/binding.py @@ -0,0 +1,157 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import collections +import threading +import types + +from cryptography import utils +from cryptography.exceptions import InternalError +from cryptography.hazmat.bindings._openssl import ffi, lib +from cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES + +_OpenSSLErrorWithText = collections.namedtuple( + "_OpenSSLErrorWithText", ["code", "lib", "func", "reason", "reason_text"] +) + + +class _OpenSSLError(object): + def __init__(self, code, lib, func, reason): + self._code = code + self._lib = lib + self._func = func + self._reason = reason + + def _lib_reason_match(self, lib, reason): + return lib == self.lib and reason == self.reason + + code = utils.read_only_property("_code") + lib = utils.read_only_property("_lib") + func = utils.read_only_property("_func") + reason = utils.read_only_property("_reason") + + +def _consume_errors(lib): + errors = [] + while True: + code = lib.ERR_get_error() + if code == 0: + break + + err_lib = lib.ERR_GET_LIB(code) + err_func = lib.ERR_GET_FUNC(code) + err_reason = lib.ERR_GET_REASON(code) + + errors.append(_OpenSSLError(code, err_lib, err_func, err_reason)) + + return errors + + +def _openssl_assert(lib, ok): + if not ok: + errors = _consume_errors(lib) + errors_with_text = [] + for err in errors: + buf = ffi.new("char[]", 256) + lib.ERR_error_string_n(err.code, buf, len(buf)) + err_text_reason = ffi.string(buf) + + errors_with_text.append( + _OpenSSLErrorWithText( + err.code, err.lib, err.func, err.reason, err_text_reason + ) + ) + + raise InternalError( + "Unknown OpenSSL error. This error is commonly encountered when " + "another library is not cleaning up the OpenSSL error stack. If " + "you are using cryptography with another library that uses " + "OpenSSL try disabling it before reporting a bug. Otherwise " + "please file an issue at https://github.com/pyca/cryptography/" + "issues with information on how to reproduce " + "this. ({0!r})".format(errors_with_text), + errors_with_text + ) + + +def build_conditional_library(lib, conditional_names): + conditional_lib = types.ModuleType("lib") + conditional_lib._original_lib = lib + excluded_names = set() + for condition, names_cb in conditional_names.items(): + if not getattr(lib, condition): + excluded_names.update(names_cb()) + + for attr in dir(lib): + if attr not in excluded_names: + setattr(conditional_lib, attr, getattr(lib, attr)) + + return conditional_lib + + +class Binding(object): + """ + OpenSSL API wrapper. + """ + lib = None + ffi = ffi + _lib_loaded = False + _init_lock = threading.Lock() + _lock_init_lock = threading.Lock() + + def __init__(self): + self._ensure_ffi_initialized() + + @classmethod + def _register_osrandom_engine(cls): + # Clear any errors extant in the queue before we start. In many + # scenarios other things may be interacting with OpenSSL in the same + # process space and it has proven untenable to assume that they will + # reliably clear the error queue. Once we clear it here we will + # error on any subsequent unexpected item in the stack. + cls.lib.ERR_clear_error() + cls._osrandom_engine_id = cls.lib.Cryptography_osrandom_engine_id + cls._osrandom_engine_name = cls.lib.Cryptography_osrandom_engine_name + result = cls.lib.Cryptography_add_osrandom_engine() + _openssl_assert(cls.lib, result in (1, 2)) + + @classmethod + def _ensure_ffi_initialized(cls): + with cls._init_lock: + if not cls._lib_loaded: + cls.lib = build_conditional_library(lib, CONDITIONAL_NAMES) + cls._lib_loaded = True + # initialize the SSL library + cls.lib.SSL_library_init() + # adds all ciphers/digests for EVP + cls.lib.OpenSSL_add_all_algorithms() + # loads error strings for libcrypto and libssl functions + cls.lib.SSL_load_error_strings() + cls._register_osrandom_engine() + + @classmethod + def init_static_locks(cls): + with cls._lock_init_lock: + cls._ensure_ffi_initialized() + # Use Python's implementation if available, importing _ssl triggers + # the setup for this. + __import__("_ssl") + + if cls.lib.CRYPTO_get_locking_callback() != cls.ffi.NULL: + return + + # If nothing else has setup a locking callback already, we set up + # our own + res = lib.Cryptography_setup_ssl_threads() + _openssl_assert(cls.lib, res == 1) + + +# OpenSSL is not thread safe until the locks are initialized. We call this +# method in module scope so that it executes with the import lock. On +# Pythons < 3.4 this import lock is a global lock, which can prevent a race +# condition registering the OpenSSL locks. On Python 3.4+ the import lock +# is per module so this approach will not work. +Binding.init_static_locks() diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/__init__.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/__init__.py new file mode 100644 index 0000000..4b54088 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/__init__.py @@ -0,0 +1,5 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/asymmetric/__init__.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/asymmetric/__init__.py new file mode 100644 index 0000000..494a7a1 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/asymmetric/__init__.py @@ -0,0 +1,40 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc + +import six + + +@six.add_metaclass(abc.ABCMeta) +class AsymmetricSignatureContext(object): + @abc.abstractmethod + def update(self, data): + """ + Processes the provided bytes and returns nothing. + """ + + @abc.abstractmethod + def finalize(self): + """ + Returns the signature as bytes. + """ + + +@six.add_metaclass(abc.ABCMeta) +class AsymmetricVerificationContext(object): + @abc.abstractmethod + def update(self, data): + """ + Processes the provided bytes and returns nothing. + """ + + @abc.abstractmethod + def verify(self): + """ + Raises an exception if the bytes provided to update do not match the + signature or the signature does not match the public key. + """ diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/asymmetric/dh.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/asymmetric/dh.py new file mode 100644 index 0000000..4fc9952 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/asymmetric/dh.py @@ -0,0 +1,212 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc + +import six + +from cryptography import utils + + +def generate_parameters(generator, key_size, backend): + return backend.generate_dh_parameters(generator, key_size) + + +class DHPrivateNumbers(object): + def __init__(self, x, public_numbers): + if not isinstance(x, six.integer_types): + raise TypeError("x must be an integer.") + + if not isinstance(public_numbers, DHPublicNumbers): + raise TypeError("public_numbers must be an instance of " + "DHPublicNumbers.") + + self._x = x + self._public_numbers = public_numbers + + def __eq__(self, other): + if not isinstance(other, DHPrivateNumbers): + return NotImplemented + + return ( + self._x == other._x and + self._public_numbers == other._public_numbers + ) + + def __ne__(self, other): + return not self == other + + def private_key(self, backend): + return backend.load_dh_private_numbers(self) + + public_numbers = utils.read_only_property("_public_numbers") + x = utils.read_only_property("_x") + + +class DHPublicNumbers(object): + def __init__(self, y, parameter_numbers): + if not isinstance(y, six.integer_types): + raise TypeError("y must be an integer.") + + if not isinstance(parameter_numbers, DHParameterNumbers): + raise TypeError( + "parameters must be an instance of DHParameterNumbers.") + + self._y = y + self._parameter_numbers = parameter_numbers + + def __eq__(self, other): + if not isinstance(other, DHPublicNumbers): + return NotImplemented + + return ( + self._y == other._y and + self._parameter_numbers == other._parameter_numbers + ) + + def __ne__(self, other): + return not self == other + + def public_key(self, backend): + return backend.load_dh_public_numbers(self) + + y = utils.read_only_property("_y") + parameter_numbers = utils.read_only_property("_parameter_numbers") + + +class DHParameterNumbers(object): + def __init__(self, p, g, q=None): + if ( + not isinstance(p, six.integer_types) or + not isinstance(g, six.integer_types) + ): + raise TypeError("p and g must be integers") + if q is not None and not isinstance(q, six.integer_types): + raise TypeError("q must be integer or None") + + if g < 2: + raise ValueError("DH generator must be 2 or greater") + + self._p = p + self._g = g + self._q = q + + def __eq__(self, other): + if not isinstance(other, DHParameterNumbers): + return NotImplemented + + return ( + self._p == other._p and + self._g == other._g and + self._q == other._q + ) + + def __ne__(self, other): + return not self == other + + def parameters(self, backend): + return backend.load_dh_parameter_numbers(self) + + p = utils.read_only_property("_p") + g = utils.read_only_property("_g") + q = utils.read_only_property("_q") + + +@six.add_metaclass(abc.ABCMeta) +class DHParameters(object): + @abc.abstractmethod + def generate_private_key(self): + """ + Generates and returns a DHPrivateKey. + """ + + @abc.abstractmethod + def parameter_bytes(self, encoding, format): + """ + Returns the parameters serialized as bytes. + """ + + @abc.abstractmethod + def parameter_numbers(self): + """ + Returns a DHParameterNumbers. + """ + + +DHParametersWithSerialization = DHParameters + + +@six.add_metaclass(abc.ABCMeta) +class DHPrivateKey(object): + @abc.abstractproperty + def key_size(self): + """ + The bit length of the prime modulus. + """ + + @abc.abstractmethod + def public_key(self): + """ + The DHPublicKey associated with this private key. + """ + + @abc.abstractmethod + def parameters(self): + """ + The DHParameters object associated with this private key. + """ + + @abc.abstractmethod + def exchange(self, peer_public_key): + """ + Given peer's DHPublicKey, carry out the key exchange and + return shared key as bytes. + """ + + +@six.add_metaclass(abc.ABCMeta) +class DHPrivateKeyWithSerialization(DHPrivateKey): + @abc.abstractmethod + def private_numbers(self): + """ + Returns a DHPrivateNumbers. + """ + + @abc.abstractmethod + def private_bytes(self, encoding, format, encryption_algorithm): + """ + Returns the key serialized as bytes. + """ + + +@six.add_metaclass(abc.ABCMeta) +class DHPublicKey(object): + @abc.abstractproperty + def key_size(self): + """ + The bit length of the prime modulus. + """ + + @abc.abstractmethod + def parameters(self): + """ + The DHParameters object associated with this public key. + """ + + @abc.abstractmethod + def public_numbers(self): + """ + Returns a DHPublicNumbers. + """ + + @abc.abstractmethod + def public_bytes(self, encoding, format): + """ + Returns the key serialized as bytes. + """ + + +DHPublicKeyWithSerialization = DHPublicKey diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py new file mode 100644 index 0000000..e380a44 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py @@ -0,0 +1,254 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc + +import six + +from cryptography import utils + + +@six.add_metaclass(abc.ABCMeta) +class DSAParameters(object): + @abc.abstractmethod + def generate_private_key(self): + """ + Generates and returns a DSAPrivateKey. + """ + + +@six.add_metaclass(abc.ABCMeta) +class DSAParametersWithNumbers(DSAParameters): + @abc.abstractmethod + def parameter_numbers(self): + """ + Returns a DSAParameterNumbers. + """ + + +@six.add_metaclass(abc.ABCMeta) +class DSAPrivateKey(object): + @abc.abstractproperty + def key_size(self): + """ + The bit length of the prime modulus. + """ + + @abc.abstractmethod + def public_key(self): + """ + The DSAPublicKey associated with this private key. + """ + + @abc.abstractmethod + def parameters(self): + """ + The DSAParameters object associated with this private key. + """ + + @abc.abstractmethod + def signer(self, signature_algorithm): + """ + Returns an AsymmetricSignatureContext used for signing data. + """ + + @abc.abstractmethod + def sign(self, data, algorithm): + """ + Signs the data + """ + + +@six.add_metaclass(abc.ABCMeta) +class DSAPrivateKeyWithSerialization(DSAPrivateKey): + @abc.abstractmethod + def private_numbers(self): + """ + Returns a DSAPrivateNumbers. + """ + + @abc.abstractmethod + def private_bytes(self, encoding, format, encryption_algorithm): + """ + Returns the key serialized as bytes. + """ + + +@six.add_metaclass(abc.ABCMeta) +class DSAPublicKey(object): + @abc.abstractproperty + def key_size(self): + """ + The bit length of the prime modulus. + """ + + @abc.abstractmethod + def parameters(self): + """ + The DSAParameters object associated with this public key. + """ + + @abc.abstractmethod + def verifier(self, signature, signature_algorithm): + """ + Returns an AsymmetricVerificationContext used for signing data. + """ + + @abc.abstractmethod + def public_numbers(self): + """ + Returns a DSAPublicNumbers. + """ + + @abc.abstractmethod + def public_bytes(self, encoding, format): + """ + Returns the key serialized as bytes. + """ + + @abc.abstractmethod + def verify(self, signature, data, algorithm): + """ + Verifies the signature of the data. + """ + + +DSAPublicKeyWithSerialization = DSAPublicKey + + +def generate_parameters(key_size, backend): + return backend.generate_dsa_parameters(key_size) + + +def generate_private_key(key_size, backend): + return backend.generate_dsa_private_key_and_parameters(key_size) + + +def _check_dsa_parameters(parameters): + if parameters.p.bit_length() not in [1024, 2048, 3072]: + raise ValueError("p must be exactly 1024, 2048, or 3072 bits long") + if parameters.q.bit_length() not in [160, 224, 256]: + raise ValueError("q must be exactly 160, 224, or 256 bits long") + + if not (1 < parameters.g < parameters.p): + raise ValueError("g, p don't satisfy 1 < g < p.") + + +def _check_dsa_private_numbers(numbers): + parameters = numbers.public_numbers.parameter_numbers + _check_dsa_parameters(parameters) + if numbers.x <= 0 or numbers.x >= parameters.q: + raise ValueError("x must be > 0 and < q.") + + if numbers.public_numbers.y != pow(parameters.g, numbers.x, parameters.p): + raise ValueError("y must be equal to (g ** x % p).") + + +class DSAParameterNumbers(object): + def __init__(self, p, q, g): + if ( + not isinstance(p, six.integer_types) or + not isinstance(q, six.integer_types) or + not isinstance(g, six.integer_types) + ): + raise TypeError( + "DSAParameterNumbers p, q, and g arguments must be integers." + ) + + self._p = p + self._q = q + self._g = g + + p = utils.read_only_property("_p") + q = utils.read_only_property("_q") + g = utils.read_only_property("_g") + + def parameters(self, backend): + return backend.load_dsa_parameter_numbers(self) + + def __eq__(self, other): + if not isinstance(other, DSAParameterNumbers): + return NotImplemented + + return self.p == other.p and self.q == other.q and self.g == other.g + + def __ne__(self, other): + return not self == other + + def __repr__(self): + return ( + "".format( + self=self + ) + ) + + +class DSAPublicNumbers(object): + def __init__(self, y, parameter_numbers): + if not isinstance(y, six.integer_types): + raise TypeError("DSAPublicNumbers y argument must be an integer.") + + if not isinstance(parameter_numbers, DSAParameterNumbers): + raise TypeError( + "parameter_numbers must be a DSAParameterNumbers instance." + ) + + self._y = y + self._parameter_numbers = parameter_numbers + + y = utils.read_only_property("_y") + parameter_numbers = utils.read_only_property("_parameter_numbers") + + def public_key(self, backend): + return backend.load_dsa_public_numbers(self) + + def __eq__(self, other): + if not isinstance(other, DSAPublicNumbers): + return NotImplemented + + return ( + self.y == other.y and + self.parameter_numbers == other.parameter_numbers + ) + + def __ne__(self, other): + return not self == other + + def __repr__(self): + return ( + "".format(self=self) + ) + + +class DSAPrivateNumbers(object): + def __init__(self, x, public_numbers): + if not isinstance(x, six.integer_types): + raise TypeError("DSAPrivateNumbers x argument must be an integer.") + + if not isinstance(public_numbers, DSAPublicNumbers): + raise TypeError( + "public_numbers must be a DSAPublicNumbers instance." + ) + self._public_numbers = public_numbers + self._x = x + + x = utils.read_only_property("_x") + public_numbers = utils.read_only_property("_public_numbers") + + def private_key(self, backend): + return backend.load_dsa_private_numbers(self) + + def __eq__(self, other): + if not isinstance(other, DSAPrivateNumbers): + return NotImplemented + + return ( + self.x == other.x and self.public_numbers == other.public_numbers + ) + + def __ne__(self, other): + return not self == other diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/asymmetric/ec.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/asymmetric/ec.py new file mode 100644 index 0000000..6cbfcab --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/asymmetric/ec.py @@ -0,0 +1,411 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc + +import six + +from cryptography import utils + + +@six.add_metaclass(abc.ABCMeta) +class EllipticCurve(object): + @abc.abstractproperty + def name(self): + """ + The name of the curve. e.g. secp256r1. + """ + + @abc.abstractproperty + def key_size(self): + """ + Bit size of a secret scalar for the curve. + """ + + +@six.add_metaclass(abc.ABCMeta) +class EllipticCurveSignatureAlgorithm(object): + @abc.abstractproperty + def algorithm(self): + """ + The digest algorithm used with this signature. + """ + + +@six.add_metaclass(abc.ABCMeta) +class EllipticCurvePrivateKey(object): + @abc.abstractmethod + def signer(self, signature_algorithm): + """ + Returns an AsymmetricSignatureContext used for signing data. + """ + + @abc.abstractmethod + def exchange(self, algorithm, peer_public_key): + """ + Performs a key exchange operation using the provided algorithm with the + provided peer's public key. + """ + + @abc.abstractmethod + def public_key(self): + """ + The EllipticCurvePublicKey for this private key. + """ + + @abc.abstractproperty + def curve(self): + """ + The EllipticCurve that this key is on. + """ + + @abc.abstractproperty + def key_size(self): + """ + Bit size of a secret scalar for the curve. + """ + + @abc.abstractproperty + def sign(self, data, signature_algorithm): + """ + Signs the data + """ + + +@six.add_metaclass(abc.ABCMeta) +class EllipticCurvePrivateKeyWithSerialization(EllipticCurvePrivateKey): + @abc.abstractmethod + def private_numbers(self): + """ + Returns an EllipticCurvePrivateNumbers. + """ + + @abc.abstractmethod + def private_bytes(self, encoding, format, encryption_algorithm): + """ + Returns the key serialized as bytes. + """ + + +@six.add_metaclass(abc.ABCMeta) +class EllipticCurvePublicKey(object): + @abc.abstractmethod + def verifier(self, signature, signature_algorithm): + """ + Returns an AsymmetricVerificationContext used for signing data. + """ + + @abc.abstractproperty + def curve(self): + """ + The EllipticCurve that this key is on. + """ + + @abc.abstractproperty + def key_size(self): + """ + Bit size of a secret scalar for the curve. + """ + + @abc.abstractmethod + def public_numbers(self): + """ + Returns an EllipticCurvePublicNumbers. + """ + + @abc.abstractmethod + def public_bytes(self, encoding, format): + """ + Returns the key serialized as bytes. + """ + + @abc.abstractmethod + def verify(self, signature, data, signature_algorithm): + """ + Verifies the signature of the data. + """ + + +EllipticCurvePublicKeyWithSerialization = EllipticCurvePublicKey + + +@utils.register_interface(EllipticCurve) +class SECT571R1(object): + name = "sect571r1" + key_size = 570 + + +@utils.register_interface(EllipticCurve) +class SECT409R1(object): + name = "sect409r1" + key_size = 409 + + +@utils.register_interface(EllipticCurve) +class SECT283R1(object): + name = "sect283r1" + key_size = 283 + + +@utils.register_interface(EllipticCurve) +class SECT233R1(object): + name = "sect233r1" + key_size = 233 + + +@utils.register_interface(EllipticCurve) +class SECT163R2(object): + name = "sect163r2" + key_size = 163 + + +@utils.register_interface(EllipticCurve) +class SECT571K1(object): + name = "sect571k1" + key_size = 571 + + +@utils.register_interface(EllipticCurve) +class SECT409K1(object): + name = "sect409k1" + key_size = 409 + + +@utils.register_interface(EllipticCurve) +class SECT283K1(object): + name = "sect283k1" + key_size = 283 + + +@utils.register_interface(EllipticCurve) +class SECT233K1(object): + name = "sect233k1" + key_size = 233 + + +@utils.register_interface(EllipticCurve) +class SECT163K1(object): + name = "sect163k1" + key_size = 163 + + +@utils.register_interface(EllipticCurve) +class SECP521R1(object): + name = "secp521r1" + key_size = 521 + + +@utils.register_interface(EllipticCurve) +class SECP384R1(object): + name = "secp384r1" + key_size = 384 + + +@utils.register_interface(EllipticCurve) +class SECP256R1(object): + name = "secp256r1" + key_size = 256 + + +@utils.register_interface(EllipticCurve) +class SECP256K1(object): + name = "secp256k1" + key_size = 256 + + +@utils.register_interface(EllipticCurve) +class SECP224R1(object): + name = "secp224r1" + key_size = 224 + + +@utils.register_interface(EllipticCurve) +class SECP192R1(object): + name = "secp192r1" + key_size = 192 + + +@utils.register_interface(EllipticCurve) +class BrainpoolP256R1(object): + name = "brainpoolP256r1" + key_size = 256 + + +@utils.register_interface(EllipticCurve) +class BrainpoolP384R1(object): + name = "brainpoolP384r1" + key_size = 384 + + +@utils.register_interface(EllipticCurve) +class BrainpoolP512R1(object): + name = "brainpoolP512r1" + key_size = 512 + + +_CURVE_TYPES = { + "prime192v1": SECP192R1, + "prime256v1": SECP256R1, + + "secp192r1": SECP192R1, + "secp224r1": SECP224R1, + "secp256r1": SECP256R1, + "secp384r1": SECP384R1, + "secp521r1": SECP521R1, + "secp256k1": SECP256K1, + + "sect163k1": SECT163K1, + "sect233k1": SECT233K1, + "sect283k1": SECT283K1, + "sect409k1": SECT409K1, + "sect571k1": SECT571K1, + + "sect163r2": SECT163R2, + "sect233r1": SECT233R1, + "sect283r1": SECT283R1, + "sect409r1": SECT409R1, + "sect571r1": SECT571R1, + + "brainpoolP256r1": BrainpoolP256R1, + "brainpoolP384r1": BrainpoolP384R1, + "brainpoolP512r1": BrainpoolP512R1, +} + + +@utils.register_interface(EllipticCurveSignatureAlgorithm) +class ECDSA(object): + def __init__(self, algorithm): + self._algorithm = algorithm + + algorithm = utils.read_only_property("_algorithm") + + +def generate_private_key(curve, backend): + return backend.generate_elliptic_curve_private_key(curve) + + +def derive_private_key(private_value, curve, backend): + if not isinstance(private_value, six.integer_types): + raise TypeError("private_value must be an integer type.") + + if private_value <= 0: + raise ValueError("private_value must be a positive integer.") + + if not isinstance(curve, EllipticCurve): + raise TypeError("curve must provide the EllipticCurve interface.") + + return backend.derive_elliptic_curve_private_key(private_value, curve) + + +class EllipticCurvePublicNumbers(object): + def __init__(self, x, y, curve): + if ( + not isinstance(x, six.integer_types) or + not isinstance(y, six.integer_types) + ): + raise TypeError("x and y must be integers.") + + if not isinstance(curve, EllipticCurve): + raise TypeError("curve must provide the EllipticCurve interface.") + + self._y = y + self._x = x + self._curve = curve + + def public_key(self, backend): + return backend.load_elliptic_curve_public_numbers(self) + + def encode_point(self): + # key_size is in bits. Convert to bytes and round up + byte_length = (self.curve.key_size + 7) // 8 + return ( + b'\x04' + utils.int_to_bytes(self.x, byte_length) + + utils.int_to_bytes(self.y, byte_length) + ) + + @classmethod + def from_encoded_point(cls, curve, data): + if not isinstance(curve, EllipticCurve): + raise TypeError("curve must be an EllipticCurve instance") + + if data.startswith(b'\x04'): + # key_size is in bits. Convert to bytes and round up + byte_length = (curve.key_size + 7) // 8 + if len(data) == 2 * byte_length + 1: + x = utils.int_from_bytes(data[1:byte_length + 1], 'big') + y = utils.int_from_bytes(data[byte_length + 1:], 'big') + return cls(x, y, curve) + else: + raise ValueError('Invalid elliptic curve point data length') + else: + raise ValueError('Unsupported elliptic curve point type') + + curve = utils.read_only_property("_curve") + x = utils.read_only_property("_x") + y = utils.read_only_property("_y") + + def __eq__(self, other): + if not isinstance(other, EllipticCurvePublicNumbers): + return NotImplemented + + return ( + self.x == other.x and + self.y == other.y and + self.curve.name == other.curve.name and + self.curve.key_size == other.curve.key_size + ) + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash((self.x, self.y, self.curve.name, self.curve.key_size)) + + def __repr__(self): + return ( + "".format(self) + ) + + +class EllipticCurvePrivateNumbers(object): + def __init__(self, private_value, public_numbers): + if not isinstance(private_value, six.integer_types): + raise TypeError("private_value must be an integer.") + + if not isinstance(public_numbers, EllipticCurvePublicNumbers): + raise TypeError( + "public_numbers must be an EllipticCurvePublicNumbers " + "instance." + ) + + self._private_value = private_value + self._public_numbers = public_numbers + + def private_key(self, backend): + return backend.load_elliptic_curve_private_numbers(self) + + private_value = utils.read_only_property("_private_value") + public_numbers = utils.read_only_property("_public_numbers") + + def __eq__(self, other): + if not isinstance(other, EllipticCurvePrivateNumbers): + return NotImplemented + + return ( + self.private_value == other.private_value and + self.public_numbers == other.public_numbers + ) + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash((self.private_value, self.public_numbers)) + + +class ECDH(object): + pass diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/asymmetric/padding.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/asymmetric/padding.py new file mode 100644 index 0000000..a37c3f9 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/asymmetric/padding.py @@ -0,0 +1,79 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc +import math + +import six + +from cryptography import utils +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric import rsa + + +@six.add_metaclass(abc.ABCMeta) +class AsymmetricPadding(object): + @abc.abstractproperty + def name(self): + """ + A string naming this padding (e.g. "PSS", "PKCS1"). + """ + + +@utils.register_interface(AsymmetricPadding) +class PKCS1v15(object): + name = "EMSA-PKCS1-v1_5" + + +@utils.register_interface(AsymmetricPadding) +class PSS(object): + MAX_LENGTH = object() + name = "EMSA-PSS" + + def __init__(self, mgf, salt_length): + self._mgf = mgf + + if (not isinstance(salt_length, six.integer_types) and + salt_length is not self.MAX_LENGTH): + raise TypeError("salt_length must be an integer.") + + if salt_length is not self.MAX_LENGTH and salt_length < 0: + raise ValueError("salt_length must be zero or greater.") + + self._salt_length = salt_length + + +@utils.register_interface(AsymmetricPadding) +class OAEP(object): + name = "EME-OAEP" + + def __init__(self, mgf, algorithm, label): + if not isinstance(algorithm, hashes.HashAlgorithm): + raise TypeError("Expected instance of hashes.HashAlgorithm.") + + self._mgf = mgf + self._algorithm = algorithm + self._label = label + + +class MGF1(object): + MAX_LENGTH = object() + + def __init__(self, algorithm): + if not isinstance(algorithm, hashes.HashAlgorithm): + raise TypeError("Expected instance of hashes.HashAlgorithm.") + + self._algorithm = algorithm + + +def calculate_max_pss_salt_length(key, hash_algorithm): + if not isinstance(key, (rsa.RSAPrivateKey, rsa.RSAPublicKey)): + raise TypeError("key must be an RSA public or private key") + # bit length - 1 per RFC 3447 + emlen = int(math.ceil((key.key_size - 1) / 8.0)) + salt_length = emlen - hash_algorithm.digest_size - 2 + assert salt_length >= 0 + return salt_length diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py new file mode 100644 index 0000000..27db671 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py @@ -0,0 +1,368 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc +try: + # Only available in math in 3.5+ + from math import gcd +except ImportError: + from fractions import gcd + +import six + +from cryptography import utils +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.backends.interfaces import RSABackend + + +@six.add_metaclass(abc.ABCMeta) +class RSAPrivateKey(object): + @abc.abstractmethod + def signer(self, padding, algorithm): + """ + Returns an AsymmetricSignatureContext used for signing data. + """ + + @abc.abstractmethod + def decrypt(self, ciphertext, padding): + """ + Decrypts the provided ciphertext. + """ + + @abc.abstractproperty + def key_size(self): + """ + The bit length of the public modulus. + """ + + @abc.abstractmethod + def public_key(self): + """ + The RSAPublicKey associated with this private key. + """ + + @abc.abstractmethod + def sign(self, data, padding, algorithm): + """ + Signs the data. + """ + + +@six.add_metaclass(abc.ABCMeta) +class RSAPrivateKeyWithSerialization(RSAPrivateKey): + @abc.abstractmethod + def private_numbers(self): + """ + Returns an RSAPrivateNumbers. + """ + + @abc.abstractmethod + def private_bytes(self, encoding, format, encryption_algorithm): + """ + Returns the key serialized as bytes. + """ + + +@six.add_metaclass(abc.ABCMeta) +class RSAPublicKey(object): + @abc.abstractmethod + def verifier(self, signature, padding, algorithm): + """ + Returns an AsymmetricVerificationContext used for verifying signatures. + """ + + @abc.abstractmethod + def encrypt(self, plaintext, padding): + """ + Encrypts the given plaintext. + """ + + @abc.abstractproperty + def key_size(self): + """ + The bit length of the public modulus. + """ + + @abc.abstractmethod + def public_numbers(self): + """ + Returns an RSAPublicNumbers + """ + + @abc.abstractmethod + def public_bytes(self, encoding, format): + """ + Returns the key serialized as bytes. + """ + + @abc.abstractmethod + def verify(self, signature, data, padding, algorithm): + """ + Verifies the signature of the data. + """ + + +RSAPublicKeyWithSerialization = RSAPublicKey + + +def generate_private_key(public_exponent, key_size, backend): + if not isinstance(backend, RSABackend): + raise UnsupportedAlgorithm( + "Backend object does not implement RSABackend.", + _Reasons.BACKEND_MISSING_INTERFACE + ) + + _verify_rsa_parameters(public_exponent, key_size) + return backend.generate_rsa_private_key(public_exponent, key_size) + + +def _verify_rsa_parameters(public_exponent, key_size): + if public_exponent < 3: + raise ValueError("public_exponent must be >= 3.") + + if public_exponent & 1 == 0: + raise ValueError("public_exponent must be odd.") + + if key_size < 512: + raise ValueError("key_size must be at least 512-bits.") + + +def _check_private_key_components(p, q, private_exponent, dmp1, dmq1, iqmp, + public_exponent, modulus): + if modulus < 3: + raise ValueError("modulus must be >= 3.") + + if p >= modulus: + raise ValueError("p must be < modulus.") + + if q >= modulus: + raise ValueError("q must be < modulus.") + + if dmp1 >= modulus: + raise ValueError("dmp1 must be < modulus.") + + if dmq1 >= modulus: + raise ValueError("dmq1 must be < modulus.") + + if iqmp >= modulus: + raise ValueError("iqmp must be < modulus.") + + if private_exponent >= modulus: + raise ValueError("private_exponent must be < modulus.") + + if public_exponent < 3 or public_exponent >= modulus: + raise ValueError("public_exponent must be >= 3 and < modulus.") + + if public_exponent & 1 == 0: + raise ValueError("public_exponent must be odd.") + + if dmp1 & 1 == 0: + raise ValueError("dmp1 must be odd.") + + if dmq1 & 1 == 0: + raise ValueError("dmq1 must be odd.") + + if p * q != modulus: + raise ValueError("p*q must equal modulus.") + + +def _check_public_key_components(e, n): + if n < 3: + raise ValueError("n must be >= 3.") + + if e < 3 or e >= n: + raise ValueError("e must be >= 3 and < n.") + + if e & 1 == 0: + raise ValueError("e must be odd.") + + +def _modinv(e, m): + """ + Modular Multiplicative Inverse. Returns x such that: (x*e) mod m == 1 + """ + x1, y1, x2, y2 = 1, 0, 0, 1 + a, b = e, m + while b > 0: + q, r = divmod(a, b) + xn, yn = x1 - q * x2, y1 - q * y2 + a, b, x1, y1, x2, y2 = b, r, x2, y2, xn, yn + return x1 % m + + +def rsa_crt_iqmp(p, q): + """ + Compute the CRT (q ** -1) % p value from RSA primes p and q. + """ + return _modinv(q, p) + + +def rsa_crt_dmp1(private_exponent, p): + """ + Compute the CRT private_exponent % (p - 1) value from the RSA + private_exponent (d) and p. + """ + return private_exponent % (p - 1) + + +def rsa_crt_dmq1(private_exponent, q): + """ + Compute the CRT private_exponent % (q - 1) value from the RSA + private_exponent (d) and q. + """ + return private_exponent % (q - 1) + + +# Controls the number of iterations rsa_recover_prime_factors will perform +# to obtain the prime factors. Each iteration increments by 2 so the actual +# maximum attempts is half this number. +_MAX_RECOVERY_ATTEMPTS = 1000 + + +def rsa_recover_prime_factors(n, e, d): + """ + Compute factors p and q from the private exponent d. We assume that n has + no more than two factors. This function is adapted from code in PyCrypto. + """ + # See 8.2.2(i) in Handbook of Applied Cryptography. + ktot = d * e - 1 + # The quantity d*e-1 is a multiple of phi(n), even, + # and can be represented as t*2^s. + t = ktot + while t % 2 == 0: + t = t // 2 + # Cycle through all multiplicative inverses in Zn. + # The algorithm is non-deterministic, but there is a 50% chance + # any candidate a leads to successful factoring. + # See "Digitalized Signatures and Public Key Functions as Intractable + # as Factorization", M. Rabin, 1979 + spotted = False + a = 2 + while not spotted and a < _MAX_RECOVERY_ATTEMPTS: + k = t + # Cycle through all values a^{t*2^i}=a^k + while k < ktot: + cand = pow(a, k, n) + # Check if a^k is a non-trivial root of unity (mod n) + if cand != 1 and cand != (n - 1) and pow(cand, 2, n) == 1: + # We have found a number such that (cand-1)(cand+1)=0 (mod n). + # Either of the terms divides n. + p = gcd(cand + 1, n) + spotted = True + break + k *= 2 + # This value was not any good... let's try another! + a += 2 + if not spotted: + raise ValueError("Unable to compute factors p and q from exponent d.") + # Found ! + q, r = divmod(n, p) + assert r == 0 + p, q = sorted((p, q), reverse=True) + return (p, q) + + +class RSAPrivateNumbers(object): + def __init__(self, p, q, d, dmp1, dmq1, iqmp, + public_numbers): + if ( + not isinstance(p, six.integer_types) or + not isinstance(q, six.integer_types) or + not isinstance(d, six.integer_types) or + not isinstance(dmp1, six.integer_types) or + not isinstance(dmq1, six.integer_types) or + not isinstance(iqmp, six.integer_types) + ): + raise TypeError( + "RSAPrivateNumbers p, q, d, dmp1, dmq1, iqmp arguments must" + " all be an integers." + ) + + if not isinstance(public_numbers, RSAPublicNumbers): + raise TypeError( + "RSAPrivateNumbers public_numbers must be an RSAPublicNumbers" + " instance." + ) + + self._p = p + self._q = q + self._d = d + self._dmp1 = dmp1 + self._dmq1 = dmq1 + self._iqmp = iqmp + self._public_numbers = public_numbers + + p = utils.read_only_property("_p") + q = utils.read_only_property("_q") + d = utils.read_only_property("_d") + dmp1 = utils.read_only_property("_dmp1") + dmq1 = utils.read_only_property("_dmq1") + iqmp = utils.read_only_property("_iqmp") + public_numbers = utils.read_only_property("_public_numbers") + + def private_key(self, backend): + return backend.load_rsa_private_numbers(self) + + def __eq__(self, other): + if not isinstance(other, RSAPrivateNumbers): + return NotImplemented + + return ( + self.p == other.p and + self.q == other.q and + self.d == other.d and + self.dmp1 == other.dmp1 and + self.dmq1 == other.dmq1 and + self.iqmp == other.iqmp and + self.public_numbers == other.public_numbers + ) + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(( + self.p, + self.q, + self.d, + self.dmp1, + self.dmq1, + self.iqmp, + self.public_numbers, + )) + + +class RSAPublicNumbers(object): + def __init__(self, e, n): + if ( + not isinstance(e, six.integer_types) or + not isinstance(n, six.integer_types) + ): + raise TypeError("RSAPublicNumbers arguments must be integers.") + + self._e = e + self._n = n + + e = utils.read_only_property("_e") + n = utils.read_only_property("_n") + + def public_key(self, backend): + return backend.load_rsa_public_numbers(self) + + def __repr__(self): + return "".format(self) + + def __eq__(self, other): + if not isinstance(other, RSAPublicNumbers): + return NotImplemented + + return self.e == other.e and self.n == other.n + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash((self.e, self.n)) diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/asymmetric/utils.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/asymmetric/utils.py new file mode 100644 index 0000000..ef1e7eb --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/asymmetric/utils.py @@ -0,0 +1,60 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import warnings + +from asn1crypto.algos import DSASignature + +import six + +from cryptography import utils +from cryptography.hazmat.primitives import hashes + + +def decode_rfc6979_signature(signature): + warnings.warn( + "decode_rfc6979_signature is deprecated and will " + "be removed in a future version, use decode_dss_signature instead.", + utils.PersistentlyDeprecated, + stacklevel=2 + ) + return decode_dss_signature(signature) + + +def decode_dss_signature(signature): + data = DSASignature.load(signature, strict=True).native + return data['r'], data['s'] + + +def encode_rfc6979_signature(r, s): + warnings.warn( + "encode_rfc6979_signature is deprecated and will " + "be removed in a future version, use encode_dss_signature instead.", + utils.PersistentlyDeprecated, + stacklevel=2 + ) + return encode_dss_signature(r, s) + + +def encode_dss_signature(r, s): + if ( + not isinstance(r, six.integer_types) or + not isinstance(s, six.integer_types) + ): + raise ValueError("Both r and s must be integers") + + return DSASignature({'r': r, 's': s}).dump() + + +class Prehashed(object): + def __init__(self, algorithm): + if not isinstance(algorithm, hashes.HashAlgorithm): + raise TypeError("Expected instance of HashAlgorithm.") + + self._algorithm = algorithm + self._digest_size = algorithm.digest_size + + digest_size = utils.read_only_property("_digest_size") diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/asymmetric/x25519.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/asymmetric/x25519.py new file mode 100644 index 0000000..5c4652a --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/asymmetric/x25519.py @@ -0,0 +1,54 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc + +import six + +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons + + +@six.add_metaclass(abc.ABCMeta) +class X25519PublicKey(object): + @classmethod + def from_public_bytes(cls, data): + from cryptography.hazmat.backends.openssl.backend import backend + if not backend.x25519_supported(): + raise UnsupportedAlgorithm( + "X25519 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM + ) + return backend.x25519_load_public_bytes(data) + + @abc.abstractmethod + def public_bytes(self): + pass + + +@six.add_metaclass(abc.ABCMeta) +class X25519PrivateKey(object): + @classmethod + def generate(cls): + from cryptography.hazmat.backends.openssl.backend import backend + if not backend.x25519_supported(): + raise UnsupportedAlgorithm( + "X25519 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM + ) + return backend.x25519_generate_key() + + @classmethod + def _from_private_bytes(cls, data): + from cryptography.hazmat.backends.openssl.backend import backend + return backend.x25519_load_private_bytes(data) + + @abc.abstractmethod + def public_key(self): + pass + + @abc.abstractmethod + def exchange(self, peer_public_key): + pass diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/ciphers/__init__.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/ciphers/__init__.py new file mode 100644 index 0000000..171b1c6 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/ciphers/__init__.py @@ -0,0 +1,21 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography.hazmat.primitives.ciphers.base import ( + AEADCipherContext, AEADDecryptionContext, AEADEncryptionContext, + BlockCipherAlgorithm, Cipher, CipherAlgorithm, CipherContext +) + + +__all__ = [ + "Cipher", + "CipherAlgorithm", + "BlockCipherAlgorithm", + "CipherContext", + "AEADCipherContext", + "AEADDecryptionContext", + "AEADEncryptionContext", +] diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/ciphers/aead.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/ciphers/aead.py new file mode 100644 index 0000000..e519765 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/ciphers/aead.py @@ -0,0 +1,188 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import os + +from cryptography import exceptions, utils +from cryptography.hazmat.backends.openssl import aead +from cryptography.hazmat.backends.openssl.backend import backend + + +class ChaCha20Poly1305(object): + _MAX_SIZE = 2 ** 32 + + def __init__(self, key): + if not backend.aead_cipher_supported(self): + raise exceptions.UnsupportedAlgorithm( + "ChaCha20Poly1305 is not supported by this version of OpenSSL", + exceptions._Reasons.UNSUPPORTED_CIPHER + ) + utils._check_bytes("key", key) + + if len(key) != 32: + raise ValueError("ChaCha20Poly1305 key must be 32 bytes.") + + self._key = key + + @classmethod + def generate_key(cls): + return os.urandom(32) + + def encrypt(self, nonce, data, associated_data): + if associated_data is None: + associated_data = b"" + + if len(data) > self._MAX_SIZE or len(associated_data) > self._MAX_SIZE: + # This is OverflowError to match what cffi would raise + raise OverflowError( + "Data or associated data too long. Max 2**32 bytes" + ) + + self._check_params(nonce, data, associated_data) + return aead._encrypt( + backend, self, nonce, data, associated_data, 16 + ) + + def decrypt(self, nonce, data, associated_data): + if associated_data is None: + associated_data = b"" + + self._check_params(nonce, data, associated_data) + return aead._decrypt( + backend, self, nonce, data, associated_data, 16 + ) + + def _check_params(self, nonce, data, associated_data): + utils._check_bytes("nonce", nonce) + utils._check_bytes("data", data) + utils._check_bytes("associated_data", associated_data) + if len(nonce) != 12: + raise ValueError("Nonce must be 12 bytes") + + +class AESCCM(object): + _MAX_SIZE = 2 ** 32 + + def __init__(self, key, tag_length=16): + utils._check_bytes("key", key) + if len(key) not in (16, 24, 32): + raise ValueError("AESCCM key must be 128, 192, or 256 bits.") + + self._key = key + if not isinstance(tag_length, int): + raise TypeError("tag_length must be an integer") + + if tag_length not in (4, 6, 8, 12, 14, 16): + raise ValueError("Invalid tag_length") + + self._tag_length = tag_length + + if not backend.aead_cipher_supported(self): + raise exceptions.UnsupportedAlgorithm( + "AESCCM is not supported by this version of OpenSSL", + exceptions._Reasons.UNSUPPORTED_CIPHER + ) + + @classmethod + def generate_key(cls, bit_length): + if not isinstance(bit_length, int): + raise TypeError("bit_length must be an integer") + + if bit_length not in (128, 192, 256): + raise ValueError("bit_length must be 128, 192, or 256") + + return os.urandom(bit_length // 8) + + def encrypt(self, nonce, data, associated_data): + if associated_data is None: + associated_data = b"" + + if len(data) > self._MAX_SIZE or len(associated_data) > self._MAX_SIZE: + # This is OverflowError to match what cffi would raise + raise OverflowError( + "Data or associated data too long. Max 2**32 bytes" + ) + + self._check_params(nonce, data, associated_data) + self._validate_lengths(nonce, len(data)) + return aead._encrypt( + backend, self, nonce, data, associated_data, self._tag_length + ) + + def decrypt(self, nonce, data, associated_data): + if associated_data is None: + associated_data = b"" + + self._check_params(nonce, data, associated_data) + return aead._decrypt( + backend, self, nonce, data, associated_data, self._tag_length + ) + + def _validate_lengths(self, nonce, data_len): + # For information about computing this, see + # https://tools.ietf.org/html/rfc3610#section-2.1 + l_val = 15 - len(nonce) + if 2 ** (8 * l_val) < data_len: + raise ValueError("Nonce too long for data") + + def _check_params(self, nonce, data, associated_data): + utils._check_bytes("nonce", nonce) + utils._check_bytes("data", data) + utils._check_bytes("associated_data", associated_data) + if not 7 <= len(nonce) <= 13: + raise ValueError("Nonce must be between 7 and 13 bytes") + + +class AESGCM(object): + _MAX_SIZE = 2 ** 32 + + def __init__(self, key): + utils._check_bytes("key", key) + if len(key) not in (16, 24, 32): + raise ValueError("AESGCM key must be 128, 192, or 256 bits.") + + self._key = key + + @classmethod + def generate_key(cls, bit_length): + if not isinstance(bit_length, int): + raise TypeError("bit_length must be an integer") + + if bit_length not in (128, 192, 256): + raise ValueError("bit_length must be 128, 192, or 256") + + return os.urandom(bit_length // 8) + + def encrypt(self, nonce, data, associated_data): + if associated_data is None: + associated_data = b"" + + if len(data) > self._MAX_SIZE or len(associated_data) > self._MAX_SIZE: + # This is OverflowError to match what cffi would raise + raise OverflowError( + "Data or associated data too long. Max 2**32 bytes" + ) + + self._check_params(nonce, data, associated_data) + return aead._encrypt( + backend, self, nonce, data, associated_data, 16 + ) + + def decrypt(self, nonce, data, associated_data): + if associated_data is None: + associated_data = b"" + + self._check_params(nonce, data, associated_data) + return aead._decrypt( + backend, self, nonce, data, associated_data, 16 + ) + + def _check_params(self, nonce, data, associated_data): + utils._check_bytes("nonce", nonce) + utils._check_bytes("data", data) + utils._check_bytes("associated_data", associated_data) + if len(nonce) == 0: + raise ValueError("Nonce must be at least 1 byte") diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/ciphers/algorithms.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/ciphers/algorithms.py new file mode 100644 index 0000000..68a9e33 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/ciphers/algorithms.py @@ -0,0 +1,168 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import utils +from cryptography.hazmat.primitives.ciphers import ( + BlockCipherAlgorithm, CipherAlgorithm +) +from cryptography.hazmat.primitives.ciphers.modes import ModeWithNonce + + +def _verify_key_size(algorithm, key): + # Verify that the key is instance of bytes + utils._check_bytes("key", key) + + # Verify that the key size matches the expected key size + if len(key) * 8 not in algorithm.key_sizes: + raise ValueError("Invalid key size ({0}) for {1}.".format( + len(key) * 8, algorithm.name + )) + return key + + +@utils.register_interface(BlockCipherAlgorithm) +@utils.register_interface(CipherAlgorithm) +class AES(object): + name = "AES" + block_size = 128 + # 512 added to support AES-256-XTS, which uses 512-bit keys + key_sizes = frozenset([128, 192, 256, 512]) + + def __init__(self, key): + self.key = _verify_key_size(self, key) + + @property + def key_size(self): + return len(self.key) * 8 + + +@utils.register_interface(BlockCipherAlgorithm) +@utils.register_interface(CipherAlgorithm) +class Camellia(object): + name = "camellia" + block_size = 128 + key_sizes = frozenset([128, 192, 256]) + + def __init__(self, key): + self.key = _verify_key_size(self, key) + + @property + def key_size(self): + return len(self.key) * 8 + + +@utils.register_interface(BlockCipherAlgorithm) +@utils.register_interface(CipherAlgorithm) +class TripleDES(object): + name = "3DES" + block_size = 64 + key_sizes = frozenset([64, 128, 192]) + + def __init__(self, key): + if len(key) == 8: + key += key + key + elif len(key) == 16: + key += key[:8] + self.key = _verify_key_size(self, key) + + @property + def key_size(self): + return len(self.key) * 8 + + +@utils.register_interface(BlockCipherAlgorithm) +@utils.register_interface(CipherAlgorithm) +class Blowfish(object): + name = "Blowfish" + block_size = 64 + key_sizes = frozenset(range(32, 449, 8)) + + def __init__(self, key): + self.key = _verify_key_size(self, key) + + @property + def key_size(self): + return len(self.key) * 8 + + +@utils.register_interface(BlockCipherAlgorithm) +@utils.register_interface(CipherAlgorithm) +class CAST5(object): + name = "CAST5" + block_size = 64 + key_sizes = frozenset(range(40, 129, 8)) + + def __init__(self, key): + self.key = _verify_key_size(self, key) + + @property + def key_size(self): + return len(self.key) * 8 + + +@utils.register_interface(CipherAlgorithm) +class ARC4(object): + name = "RC4" + key_sizes = frozenset([40, 56, 64, 80, 128, 160, 192, 256]) + + def __init__(self, key): + self.key = _verify_key_size(self, key) + + @property + def key_size(self): + return len(self.key) * 8 + + +@utils.register_interface(CipherAlgorithm) +class IDEA(object): + name = "IDEA" + block_size = 64 + key_sizes = frozenset([128]) + + def __init__(self, key): + self.key = _verify_key_size(self, key) + + @property + def key_size(self): + return len(self.key) * 8 + + +@utils.register_interface(BlockCipherAlgorithm) +@utils.register_interface(CipherAlgorithm) +class SEED(object): + name = "SEED" + block_size = 128 + key_sizes = frozenset([128]) + + def __init__(self, key): + self.key = _verify_key_size(self, key) + + @property + def key_size(self): + return len(self.key) * 8 + + +@utils.register_interface(CipherAlgorithm) +@utils.register_interface(ModeWithNonce) +class ChaCha20(object): + name = "ChaCha20" + key_sizes = frozenset([256]) + + def __init__(self, key, nonce): + self.key = _verify_key_size(self, key) + if not isinstance(nonce, bytes): + raise TypeError("nonce must be bytes") + + if len(nonce) != 16: + raise ValueError("nonce must be 128-bits (16 bytes)") + + self._nonce = nonce + + nonce = utils.read_only_property("_nonce") + + @property + def key_size(self): + return len(self.key) * 8 diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/ciphers/base.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/ciphers/base.py new file mode 100644 index 0000000..f857041 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/ciphers/base.py @@ -0,0 +1,235 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc + +import six + +from cryptography import utils +from cryptography.exceptions import ( + AlreadyFinalized, AlreadyUpdated, NotYetFinalized, UnsupportedAlgorithm, + _Reasons +) +from cryptography.hazmat.backends.interfaces import CipherBackend +from cryptography.hazmat.primitives.ciphers import modes + + +@six.add_metaclass(abc.ABCMeta) +class CipherAlgorithm(object): + @abc.abstractproperty + def name(self): + """ + A string naming this mode (e.g. "AES", "Camellia"). + """ + + @abc.abstractproperty + def key_size(self): + """ + The size of the key being used as an integer in bits (e.g. 128, 256). + """ + + +@six.add_metaclass(abc.ABCMeta) +class BlockCipherAlgorithm(object): + @abc.abstractproperty + def block_size(self): + """ + The size of a block as an integer in bits (e.g. 64, 128). + """ + + +@six.add_metaclass(abc.ABCMeta) +class CipherContext(object): + @abc.abstractmethod + def update(self, data): + """ + Processes the provided bytes through the cipher and returns the results + as bytes. + """ + + @abc.abstractmethod + def update_into(self, data, buf): + """ + Processes the provided bytes and writes the resulting data into the + provided buffer. Returns the number of bytes written. + """ + + @abc.abstractmethod + def finalize(self): + """ + Returns the results of processing the final block as bytes. + """ + + +@six.add_metaclass(abc.ABCMeta) +class AEADCipherContext(object): + @abc.abstractmethod + def authenticate_additional_data(self, data): + """ + Authenticates the provided bytes. + """ + + +@six.add_metaclass(abc.ABCMeta) +class AEADDecryptionContext(object): + @abc.abstractmethod + def finalize_with_tag(self, tag): + """ + Returns the results of processing the final block as bytes and allows + delayed passing of the authentication tag. + """ + + +@six.add_metaclass(abc.ABCMeta) +class AEADEncryptionContext(object): + @abc.abstractproperty + def tag(self): + """ + Returns tag bytes. This is only available after encryption is + finalized. + """ + + +class Cipher(object): + def __init__(self, algorithm, mode, backend): + if not isinstance(backend, CipherBackend): + raise UnsupportedAlgorithm( + "Backend object does not implement CipherBackend.", + _Reasons.BACKEND_MISSING_INTERFACE + ) + + if not isinstance(algorithm, CipherAlgorithm): + raise TypeError("Expected interface of CipherAlgorithm.") + + if mode is not None: + mode.validate_for_algorithm(algorithm) + + self.algorithm = algorithm + self.mode = mode + self._backend = backend + + def encryptor(self): + if isinstance(self.mode, modes.ModeWithAuthenticationTag): + if self.mode.tag is not None: + raise ValueError( + "Authentication tag must be None when encrypting." + ) + ctx = self._backend.create_symmetric_encryption_ctx( + self.algorithm, self.mode + ) + return self._wrap_ctx(ctx, encrypt=True) + + def decryptor(self): + ctx = self._backend.create_symmetric_decryption_ctx( + self.algorithm, self.mode + ) + return self._wrap_ctx(ctx, encrypt=False) + + def _wrap_ctx(self, ctx, encrypt): + if isinstance(self.mode, modes.ModeWithAuthenticationTag): + if encrypt: + return _AEADEncryptionContext(ctx) + else: + return _AEADCipherContext(ctx) + else: + return _CipherContext(ctx) + + +@utils.register_interface(CipherContext) +class _CipherContext(object): + def __init__(self, ctx): + self._ctx = ctx + + def update(self, data): + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + return self._ctx.update(data) + + def update_into(self, data, buf): + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + return self._ctx.update_into(data, buf) + + def finalize(self): + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + data = self._ctx.finalize() + self._ctx = None + return data + + +@utils.register_interface(AEADCipherContext) +@utils.register_interface(CipherContext) +@utils.register_interface(AEADDecryptionContext) +class _AEADCipherContext(object): + def __init__(self, ctx): + self._ctx = ctx + self._bytes_processed = 0 + self._aad_bytes_processed = 0 + self._tag = None + self._updated = False + + def _check_limit(self, data_size): + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + self._updated = True + self._bytes_processed += data_size + if self._bytes_processed > self._ctx._mode._MAX_ENCRYPTED_BYTES: + raise ValueError( + "{0} has a maximum encrypted byte limit of {1}".format( + self._ctx._mode.name, self._ctx._mode._MAX_ENCRYPTED_BYTES + ) + ) + + def update(self, data): + self._check_limit(len(data)) + return self._ctx.update(data) + + def update_into(self, data, buf): + self._check_limit(len(data)) + return self._ctx.update_into(data, buf) + + def finalize(self): + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + data = self._ctx.finalize() + self._tag = self._ctx.tag + self._ctx = None + return data + + def finalize_with_tag(self, tag): + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + data = self._ctx.finalize_with_tag(tag) + self._tag = self._ctx.tag + self._ctx = None + return data + + def authenticate_additional_data(self, data): + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + if self._updated: + raise AlreadyUpdated("Update has been called on this context.") + + self._aad_bytes_processed += len(data) + if self._aad_bytes_processed > self._ctx._mode._MAX_AAD_BYTES: + raise ValueError( + "{0} has a maximum AAD byte limit of {1}".format( + self._ctx._mode.name, self._ctx._mode._MAX_AAD_BYTES + ) + ) + + self._ctx.authenticate_additional_data(data) + + +@utils.register_interface(AEADEncryptionContext) +class _AEADEncryptionContext(_AEADCipherContext): + @property + def tag(self): + if self._ctx is not None: + raise NotYetFinalized("You must finalize encryption before " + "getting the tag.") + return self._tag diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/ciphers/modes.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/ciphers/modes.py new file mode 100644 index 0000000..e82c1a8 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/ciphers/modes.py @@ -0,0 +1,231 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc + +import six + +from cryptography import utils + + +@six.add_metaclass(abc.ABCMeta) +class Mode(object): + @abc.abstractproperty + def name(self): + """ + A string naming this mode (e.g. "ECB", "CBC"). + """ + + @abc.abstractmethod + def validate_for_algorithm(self, algorithm): + """ + Checks that all the necessary invariants of this (mode, algorithm) + combination are met. + """ + + +@six.add_metaclass(abc.ABCMeta) +class ModeWithInitializationVector(object): + @abc.abstractproperty + def initialization_vector(self): + """ + The value of the initialization vector for this mode as bytes. + """ + + +@six.add_metaclass(abc.ABCMeta) +class ModeWithTweak(object): + @abc.abstractproperty + def tweak(self): + """ + The value of the tweak for this mode as bytes. + """ + + +@six.add_metaclass(abc.ABCMeta) +class ModeWithNonce(object): + @abc.abstractproperty + def nonce(self): + """ + The value of the nonce for this mode as bytes. + """ + + +@six.add_metaclass(abc.ABCMeta) +class ModeWithAuthenticationTag(object): + @abc.abstractproperty + def tag(self): + """ + The value of the tag supplied to the constructor of this mode. + """ + + +def _check_aes_key_length(self, algorithm): + if algorithm.key_size > 256 and algorithm.name == "AES": + raise ValueError( + "Only 128, 192, and 256 bit keys are allowed for this AES mode" + ) + + +def _check_iv_length(self, algorithm): + if len(self.initialization_vector) * 8 != algorithm.block_size: + raise ValueError("Invalid IV size ({0}) for {1}.".format( + len(self.initialization_vector), self.name + )) + + +def _check_iv_and_key_length(self, algorithm): + _check_aes_key_length(self, algorithm) + _check_iv_length(self, algorithm) + + +@utils.register_interface(Mode) +@utils.register_interface(ModeWithInitializationVector) +class CBC(object): + name = "CBC" + + def __init__(self, initialization_vector): + if not isinstance(initialization_vector, bytes): + raise TypeError("initialization_vector must be bytes") + + self._initialization_vector = initialization_vector + + initialization_vector = utils.read_only_property("_initialization_vector") + validate_for_algorithm = _check_iv_and_key_length + + +@utils.register_interface(Mode) +@utils.register_interface(ModeWithTweak) +class XTS(object): + name = "XTS" + + def __init__(self, tweak): + if not isinstance(tweak, bytes): + raise TypeError("tweak must be bytes") + + if len(tweak) != 16: + raise ValueError("tweak must be 128-bits (16 bytes)") + + self._tweak = tweak + + tweak = utils.read_only_property("_tweak") + + def validate_for_algorithm(self, algorithm): + if algorithm.key_size not in (256, 512): + raise ValueError( + "The XTS specification requires a 256-bit key for AES-128-XTS" + " and 512-bit key for AES-256-XTS" + ) + + +@utils.register_interface(Mode) +class ECB(object): + name = "ECB" + + validate_for_algorithm = _check_aes_key_length + + +@utils.register_interface(Mode) +@utils.register_interface(ModeWithInitializationVector) +class OFB(object): + name = "OFB" + + def __init__(self, initialization_vector): + if not isinstance(initialization_vector, bytes): + raise TypeError("initialization_vector must be bytes") + + self._initialization_vector = initialization_vector + + initialization_vector = utils.read_only_property("_initialization_vector") + validate_for_algorithm = _check_iv_and_key_length + + +@utils.register_interface(Mode) +@utils.register_interface(ModeWithInitializationVector) +class CFB(object): + name = "CFB" + + def __init__(self, initialization_vector): + if not isinstance(initialization_vector, bytes): + raise TypeError("initialization_vector must be bytes") + + self._initialization_vector = initialization_vector + + initialization_vector = utils.read_only_property("_initialization_vector") + validate_for_algorithm = _check_iv_and_key_length + + +@utils.register_interface(Mode) +@utils.register_interface(ModeWithInitializationVector) +class CFB8(object): + name = "CFB8" + + def __init__(self, initialization_vector): + if not isinstance(initialization_vector, bytes): + raise TypeError("initialization_vector must be bytes") + + self._initialization_vector = initialization_vector + + initialization_vector = utils.read_only_property("_initialization_vector") + validate_for_algorithm = _check_iv_and_key_length + + +@utils.register_interface(Mode) +@utils.register_interface(ModeWithNonce) +class CTR(object): + name = "CTR" + + def __init__(self, nonce): + if not isinstance(nonce, bytes): + raise TypeError("nonce must be bytes") + + self._nonce = nonce + + nonce = utils.read_only_property("_nonce") + + def validate_for_algorithm(self, algorithm): + _check_aes_key_length(self, algorithm) + if len(self.nonce) * 8 != algorithm.block_size: + raise ValueError("Invalid nonce size ({0}) for {1}.".format( + len(self.nonce), self.name + )) + + +@utils.register_interface(Mode) +@utils.register_interface(ModeWithInitializationVector) +@utils.register_interface(ModeWithAuthenticationTag) +class GCM(object): + name = "GCM" + _MAX_ENCRYPTED_BYTES = (2 ** 39 - 256) // 8 + _MAX_AAD_BYTES = (2 ** 64) // 8 + + def __init__(self, initialization_vector, tag=None, min_tag_length=16): + # len(initialization_vector) must in [1, 2 ** 64), but it's impossible + # to actually construct a bytes object that large, so we don't check + # for it + if not isinstance(initialization_vector, bytes): + raise TypeError("initialization_vector must be bytes") + if len(initialization_vector) == 0: + raise ValueError("initialization_vector must be at least 1 byte") + self._initialization_vector = initialization_vector + if tag is not None: + if not isinstance(tag, bytes): + raise TypeError("tag must be bytes or None") + if min_tag_length < 4: + raise ValueError("min_tag_length must be >= 4") + if len(tag) < min_tag_length: + raise ValueError( + "Authentication tag must be {0} bytes or longer.".format( + min_tag_length) + ) + self._tag = tag + self._min_tag_length = min_tag_length + + tag = utils.read_only_property("_tag") + initialization_vector = utils.read_only_property("_initialization_vector") + + def validate_for_algorithm(self, algorithm): + _check_aes_key_length(self, algorithm) diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/cmac.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/cmac.py new file mode 100644 index 0000000..77537f0 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/cmac.py @@ -0,0 +1,66 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import utils +from cryptography.exceptions import ( + AlreadyFinalized, UnsupportedAlgorithm, _Reasons +) +from cryptography.hazmat.backends.interfaces import CMACBackend +from cryptography.hazmat.primitives import ciphers, mac + + +@utils.register_interface(mac.MACContext) +class CMAC(object): + def __init__(self, algorithm, backend, ctx=None): + if not isinstance(backend, CMACBackend): + raise UnsupportedAlgorithm( + "Backend object does not implement CMACBackend.", + _Reasons.BACKEND_MISSING_INTERFACE + ) + + if not isinstance(algorithm, ciphers.BlockCipherAlgorithm): + raise TypeError( + "Expected instance of BlockCipherAlgorithm." + ) + self._algorithm = algorithm + + self._backend = backend + if ctx is None: + self._ctx = self._backend.create_cmac_ctx(self._algorithm) + else: + self._ctx = ctx + + def update(self, data): + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + if not isinstance(data, bytes): + raise TypeError("data must be bytes.") + self._ctx.update(data) + + def finalize(self): + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + digest = self._ctx.finalize() + self._ctx = None + return digest + + def verify(self, signature): + if not isinstance(signature, bytes): + raise TypeError("signature must be bytes.") + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + + ctx, self._ctx = self._ctx, None + ctx.verify(signature) + + def copy(self): + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + return CMAC( + self._algorithm, + backend=self._backend, + ctx=self._ctx.copy() + ) diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/constant_time.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/constant_time.py new file mode 100644 index 0000000..0e987ea --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/constant_time.py @@ -0,0 +1,35 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import hmac +import warnings + +from cryptography import utils +from cryptography.hazmat.bindings._constant_time import lib + + +if hasattr(hmac, "compare_digest"): + def bytes_eq(a, b): + if not isinstance(a, bytes) or not isinstance(b, bytes): + raise TypeError("a and b must be bytes.") + + return hmac.compare_digest(a, b) + +else: + warnings.warn( + "Support for your Python version is deprecated. The next version of " + "cryptography will remove support. Please upgrade to a 2.7.x " + "release that supports hmac.compare_digest as soon as possible.", + utils.DeprecatedIn23, + ) + + def bytes_eq(a, b): + if not isinstance(a, bytes) or not isinstance(b, bytes): + raise TypeError("a and b must be bytes.") + + return lib.Cryptography_constant_time_bytes_eq( + a, len(a), b, len(b) + ) == 1 diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/hashes.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/hashes.py new file mode 100644 index 0000000..3f3aadd --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/hashes.py @@ -0,0 +1,185 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc + +import six + +from cryptography import utils +from cryptography.exceptions import ( + AlreadyFinalized, UnsupportedAlgorithm, _Reasons +) +from cryptography.hazmat.backends.interfaces import HashBackend + + +@six.add_metaclass(abc.ABCMeta) +class HashAlgorithm(object): + @abc.abstractproperty + def name(self): + """ + A string naming this algorithm (e.g. "sha256", "md5"). + """ + + @abc.abstractproperty + def digest_size(self): + """ + The size of the resulting digest in bytes. + """ + + +@six.add_metaclass(abc.ABCMeta) +class HashContext(object): + @abc.abstractproperty + def algorithm(self): + """ + A HashAlgorithm that will be used by this context. + """ + + @abc.abstractmethod + def update(self, data): + """ + Processes the provided bytes through the hash. + """ + + @abc.abstractmethod + def finalize(self): + """ + Finalizes the hash context and returns the hash digest as bytes. + """ + + @abc.abstractmethod + def copy(self): + """ + Return a HashContext that is a copy of the current context. + """ + + +@utils.register_interface(HashContext) +class Hash(object): + def __init__(self, algorithm, backend, ctx=None): + if not isinstance(backend, HashBackend): + raise UnsupportedAlgorithm( + "Backend object does not implement HashBackend.", + _Reasons.BACKEND_MISSING_INTERFACE + ) + + if not isinstance(algorithm, HashAlgorithm): + raise TypeError("Expected instance of hashes.HashAlgorithm.") + self._algorithm = algorithm + + self._backend = backend + + if ctx is None: + self._ctx = self._backend.create_hash_ctx(self.algorithm) + else: + self._ctx = ctx + + algorithm = utils.read_only_property("_algorithm") + + def update(self, data): + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + if not isinstance(data, bytes): + raise TypeError("data must be bytes.") + self._ctx.update(data) + + def copy(self): + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + return Hash( + self.algorithm, backend=self._backend, ctx=self._ctx.copy() + ) + + def finalize(self): + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + digest = self._ctx.finalize() + self._ctx = None + return digest + + +@utils.register_interface(HashAlgorithm) +class SHA1(object): + name = "sha1" + digest_size = 20 + block_size = 64 + + +@utils.register_interface(HashAlgorithm) +class SHA224(object): + name = "sha224" + digest_size = 28 + block_size = 64 + + +@utils.register_interface(HashAlgorithm) +class SHA256(object): + name = "sha256" + digest_size = 32 + block_size = 64 + + +@utils.register_interface(HashAlgorithm) +class SHA384(object): + name = "sha384" + digest_size = 48 + block_size = 128 + + +@utils.register_interface(HashAlgorithm) +class SHA512(object): + name = "sha512" + digest_size = 64 + block_size = 128 + + +@utils.register_interface(HashAlgorithm) +class MD5(object): + name = "md5" + digest_size = 16 + block_size = 64 + + +@utils.register_interface(HashAlgorithm) +class BLAKE2b(object): + name = "blake2b" + _max_digest_size = 64 + _min_digest_size = 1 + block_size = 128 + + def __init__(self, digest_size): + if ( + digest_size > self._max_digest_size or + digest_size < self._min_digest_size + ): + raise ValueError("Digest size must be {0}-{1}".format( + self._min_digest_size, self._max_digest_size) + ) + + self._digest_size = digest_size + + digest_size = utils.read_only_property("_digest_size") + + +@utils.register_interface(HashAlgorithm) +class BLAKE2s(object): + name = "blake2s" + block_size = 64 + _max_digest_size = 32 + _min_digest_size = 1 + + def __init__(self, digest_size): + if ( + digest_size > self._max_digest_size or + digest_size < self._min_digest_size + ): + raise ValueError("Digest size must be {0}-{1}".format( + self._min_digest_size, self._max_digest_size) + ) + + self._digest_size = digest_size + + digest_size = utils.read_only_property("_digest_size") diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/hmac.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/hmac.py new file mode 100644 index 0000000..2e9a4e2 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/hmac.py @@ -0,0 +1,69 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import utils +from cryptography.exceptions import ( + AlreadyFinalized, UnsupportedAlgorithm, _Reasons +) +from cryptography.hazmat.backends.interfaces import HMACBackend +from cryptography.hazmat.primitives import hashes, mac + + +@utils.register_interface(mac.MACContext) +@utils.register_interface(hashes.HashContext) +class HMAC(object): + def __init__(self, key, algorithm, backend, ctx=None): + if not isinstance(backend, HMACBackend): + raise UnsupportedAlgorithm( + "Backend object does not implement HMACBackend.", + _Reasons.BACKEND_MISSING_INTERFACE + ) + + if not isinstance(algorithm, hashes.HashAlgorithm): + raise TypeError("Expected instance of hashes.HashAlgorithm.") + self._algorithm = algorithm + + self._backend = backend + self._key = key + if ctx is None: + self._ctx = self._backend.create_hmac_ctx(key, self.algorithm) + else: + self._ctx = ctx + + algorithm = utils.read_only_property("_algorithm") + + def update(self, data): + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + if not isinstance(data, bytes): + raise TypeError("data must be bytes.") + self._ctx.update(data) + + def copy(self): + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + return HMAC( + self._key, + self.algorithm, + backend=self._backend, + ctx=self._ctx.copy() + ) + + def finalize(self): + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + digest = self._ctx.finalize() + self._ctx = None + return digest + + def verify(self, signature): + if not isinstance(signature, bytes): + raise TypeError("signature must be bytes.") + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + + ctx, self._ctx = self._ctx, None + ctx.verify(signature) diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/kdf/__init__.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/kdf/__init__.py new file mode 100644 index 0000000..2d0724e --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/kdf/__init__.py @@ -0,0 +1,26 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc + +import six + + +@six.add_metaclass(abc.ABCMeta) +class KeyDerivationFunction(object): + @abc.abstractmethod + def derive(self, key_material): + """ + Deterministically generates and returns a new key based on the existing + key material. + """ + + @abc.abstractmethod + def verify(self, key_material, expected_key): + """ + Checks whether the key generated by the key material matches the + expected derived key. Raises an exception if they do not match. + """ diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/kdf/concatkdf.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/kdf/concatkdf.py new file mode 100644 index 0000000..c6399e4 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/kdf/concatkdf.py @@ -0,0 +1,125 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import struct + +from cryptography import utils +from cryptography.exceptions import ( + AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons +) +from cryptography.hazmat.backends.interfaces import HMACBackend +from cryptography.hazmat.backends.interfaces import HashBackend +from cryptography.hazmat.primitives import constant_time, hashes, hmac +from cryptography.hazmat.primitives.kdf import KeyDerivationFunction + + +def _int_to_u32be(n): + return struct.pack('>I', n) + + +def _common_args_checks(algorithm, length, otherinfo): + max_length = algorithm.digest_size * (2 ** 32 - 1) + if length > max_length: + raise ValueError( + "Can not derive keys larger than {0} bits.".format( + max_length + )) + if not (otherinfo is None or isinstance(otherinfo, bytes)): + raise TypeError("otherinfo must be bytes.") + + +def _concatkdf_derive(key_material, length, auxfn, otherinfo): + if not isinstance(key_material, bytes): + raise TypeError("key_material must be bytes.") + + output = [b""] + outlen = 0 + counter = 1 + + while (length > outlen): + h = auxfn() + h.update(_int_to_u32be(counter)) + h.update(key_material) + h.update(otherinfo) + output.append(h.finalize()) + outlen += len(output[-1]) + counter += 1 + + return b"".join(output)[:length] + + +@utils.register_interface(KeyDerivationFunction) +class ConcatKDFHash(object): + def __init__(self, algorithm, length, otherinfo, backend): + + _common_args_checks(algorithm, length, otherinfo) + self._algorithm = algorithm + self._length = length + self._otherinfo = otherinfo + if self._otherinfo is None: + self._otherinfo = b"" + + if not isinstance(backend, HashBackend): + raise UnsupportedAlgorithm( + "Backend object does not implement HashBackend.", + _Reasons.BACKEND_MISSING_INTERFACE + ) + self._backend = backend + self._used = False + + def _hash(self): + return hashes.Hash(self._algorithm, self._backend) + + def derive(self, key_material): + if self._used: + raise AlreadyFinalized + self._used = True + return _concatkdf_derive(key_material, self._length, + self._hash, self._otherinfo) + + def verify(self, key_material, expected_key): + if not constant_time.bytes_eq(self.derive(key_material), expected_key): + raise InvalidKey + + +@utils.register_interface(KeyDerivationFunction) +class ConcatKDFHMAC(object): + def __init__(self, algorithm, length, salt, otherinfo, backend): + + _common_args_checks(algorithm, length, otherinfo) + self._algorithm = algorithm + self._length = length + self._otherinfo = otherinfo + if self._otherinfo is None: + self._otherinfo = b"" + + if not (salt is None or isinstance(salt, bytes)): + raise TypeError("salt must be bytes.") + if salt is None: + salt = b"\x00" * algorithm.block_size + self._salt = salt + + if not isinstance(backend, HMACBackend): + raise UnsupportedAlgorithm( + "Backend object does not implement HMACBackend.", + _Reasons.BACKEND_MISSING_INTERFACE + ) + self._backend = backend + self._used = False + + def _hmac(self): + return hmac.HMAC(self._salt, self._algorithm, self._backend) + + def derive(self, key_material): + if self._used: + raise AlreadyFinalized + self._used = True + return _concatkdf_derive(key_material, self._length, + self._hmac, self._otherinfo) + + def verify(self, key_material, expected_key): + if not constant_time.bytes_eq(self.derive(key_material), expected_key): + raise InvalidKey diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py new file mode 100644 index 0000000..917b4e9 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py @@ -0,0 +1,116 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import six + +from cryptography import utils +from cryptography.exceptions import ( + AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons +) +from cryptography.hazmat.backends.interfaces import HMACBackend +from cryptography.hazmat.primitives import constant_time, hmac +from cryptography.hazmat.primitives.kdf import KeyDerivationFunction + + +@utils.register_interface(KeyDerivationFunction) +class HKDF(object): + def __init__(self, algorithm, length, salt, info, backend): + if not isinstance(backend, HMACBackend): + raise UnsupportedAlgorithm( + "Backend object does not implement HMACBackend.", + _Reasons.BACKEND_MISSING_INTERFACE + ) + + self._algorithm = algorithm + + if not (salt is None or isinstance(salt, bytes)): + raise TypeError("salt must be bytes.") + + if salt is None: + salt = b"\x00" * self._algorithm.digest_size + + self._salt = salt + + self._backend = backend + + self._hkdf_expand = HKDFExpand(self._algorithm, length, info, backend) + + def _extract(self, key_material): + h = hmac.HMAC(self._salt, self._algorithm, backend=self._backend) + h.update(key_material) + return h.finalize() + + def derive(self, key_material): + if not isinstance(key_material, bytes): + raise TypeError("key_material must be bytes.") + + return self._hkdf_expand.derive(self._extract(key_material)) + + def verify(self, key_material, expected_key): + if not constant_time.bytes_eq(self.derive(key_material), expected_key): + raise InvalidKey + + +@utils.register_interface(KeyDerivationFunction) +class HKDFExpand(object): + def __init__(self, algorithm, length, info, backend): + if not isinstance(backend, HMACBackend): + raise UnsupportedAlgorithm( + "Backend object does not implement HMACBackend.", + _Reasons.BACKEND_MISSING_INTERFACE + ) + + self._algorithm = algorithm + + self._backend = backend + + max_length = 255 * algorithm.digest_size + + if length > max_length: + raise ValueError( + "Can not derive keys larger than {0} octets.".format( + max_length + )) + + self._length = length + + if not (info is None or isinstance(info, bytes)): + raise TypeError("info must be bytes.") + + if info is None: + info = b"" + + self._info = info + + self._used = False + + def _expand(self, key_material): + output = [b""] + counter = 1 + + while self._algorithm.digest_size * (len(output) - 1) < self._length: + h = hmac.HMAC(key_material, self._algorithm, backend=self._backend) + h.update(output[-1]) + h.update(self._info) + h.update(six.int2byte(counter)) + output.append(h.finalize()) + counter += 1 + + return b"".join(output)[:self._length] + + def derive(self, key_material): + if not isinstance(key_material, bytes): + raise TypeError("key_material must be bytes.") + + if self._used: + raise AlreadyFinalized + + self._used = True + return self._expand(key_material) + + def verify(self, key_material, expected_key): + if not constant_time.bytes_eq(self.derive(key_material), expected_key): + raise InvalidKey diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py new file mode 100644 index 0000000..14de56e --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py @@ -0,0 +1,148 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from enum import Enum + +from six.moves import range + +from cryptography import utils +from cryptography.exceptions import ( + AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons +) +from cryptography.hazmat.backends.interfaces import HMACBackend +from cryptography.hazmat.primitives import constant_time, hashes, hmac +from cryptography.hazmat.primitives.kdf import KeyDerivationFunction + + +class Mode(Enum): + CounterMode = "ctr" + + +class CounterLocation(Enum): + BeforeFixed = "before_fixed" + AfterFixed = "after_fixed" + + +@utils.register_interface(KeyDerivationFunction) +class KBKDFHMAC(object): + def __init__(self, algorithm, mode, length, rlen, llen, + location, label, context, fixed, backend): + if not isinstance(backend, HMACBackend): + raise UnsupportedAlgorithm( + "Backend object does not implement HMACBackend.", + _Reasons.BACKEND_MISSING_INTERFACE + ) + + if not isinstance(algorithm, hashes.HashAlgorithm): + raise UnsupportedAlgorithm( + "Algorithm supplied is not a supported hash algorithm.", + _Reasons.UNSUPPORTED_HASH + ) + + if not backend.hmac_supported(algorithm): + raise UnsupportedAlgorithm( + "Algorithm supplied is not a supported hmac algorithm.", + _Reasons.UNSUPPORTED_HASH + ) + + if not isinstance(mode, Mode): + raise TypeError("mode must be of type Mode") + + if not isinstance(location, CounterLocation): + raise TypeError("location must be of type CounterLocation") + + if (label or context) and fixed: + raise ValueError("When supplying fixed data, " + "label and context are ignored.") + + if rlen is None or not self._valid_byte_length(rlen): + raise ValueError("rlen must be between 1 and 4") + + if llen is None and fixed is None: + raise ValueError("Please specify an llen") + + if llen is not None and not isinstance(llen, int): + raise TypeError("llen must be an integer") + + if label is None: + label = b'' + + if context is None: + context = b'' + + if (not isinstance(label, bytes) or + not isinstance(context, bytes)): + raise TypeError('label and context must be of type bytes') + + self._algorithm = algorithm + self._mode = mode + self._length = length + self._rlen = rlen + self._llen = llen + self._location = location + self._label = label + self._context = context + self._backend = backend + self._used = False + self._fixed_data = fixed + + def _valid_byte_length(self, value): + if not isinstance(value, int): + raise TypeError('value must be of type int') + + value_bin = utils.int_to_bytes(1, value) + if not 1 <= len(value_bin) <= 4: + return False + return True + + def derive(self, key_material): + if self._used: + raise AlreadyFinalized + + if not isinstance(key_material, bytes): + raise TypeError('key_material must be bytes') + self._used = True + + # inverse floor division (equivalent to ceiling) + rounds = -(-self._length // self._algorithm.digest_size) + + output = [b''] + + # For counter mode, the number of iterations shall not be + # larger than 2^r-1, where r <= 32 is the binary length of the counter + # This ensures that the counter values used as an input to the + # PRF will not repeat during a particular call to the KDF function. + r_bin = utils.int_to_bytes(1, self._rlen) + if rounds > pow(2, len(r_bin) * 8) - 1: + raise ValueError('There are too many iterations.') + + for i in range(1, rounds + 1): + h = hmac.HMAC(key_material, self._algorithm, backend=self._backend) + + counter = utils.int_to_bytes(i, self._rlen) + if self._location == CounterLocation.BeforeFixed: + h.update(counter) + + h.update(self._generate_fixed_input()) + + if self._location == CounterLocation.AfterFixed: + h.update(counter) + + output.append(h.finalize()) + + return b''.join(output)[:self._length] + + def _generate_fixed_input(self): + if self._fixed_data and isinstance(self._fixed_data, bytes): + return self._fixed_data + + l_val = utils.int_to_bytes(self._length * 8, self._llen) + + return b"".join([self._label, b"\x00", self._context, l_val]) + + def verify(self, key_material, expected_key): + if not constant_time.bytes_eq(self.derive(key_material), expected_key): + raise InvalidKey diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.py new file mode 100644 index 0000000..f8ce7a3 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.py @@ -0,0 +1,58 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import utils +from cryptography.exceptions import ( + AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons +) +from cryptography.hazmat.backends.interfaces import PBKDF2HMACBackend +from cryptography.hazmat.primitives import constant_time +from cryptography.hazmat.primitives.kdf import KeyDerivationFunction + + +@utils.register_interface(KeyDerivationFunction) +class PBKDF2HMAC(object): + def __init__(self, algorithm, length, salt, iterations, backend): + if not isinstance(backend, PBKDF2HMACBackend): + raise UnsupportedAlgorithm( + "Backend object does not implement PBKDF2HMACBackend.", + _Reasons.BACKEND_MISSING_INTERFACE + ) + + if not backend.pbkdf2_hmac_supported(algorithm): + raise UnsupportedAlgorithm( + "{0} is not supported for PBKDF2 by this backend.".format( + algorithm.name), + _Reasons.UNSUPPORTED_HASH + ) + self._used = False + self._algorithm = algorithm + self._length = length + if not isinstance(salt, bytes): + raise TypeError("salt must be bytes.") + self._salt = salt + self._iterations = iterations + self._backend = backend + + def derive(self, key_material): + if self._used: + raise AlreadyFinalized("PBKDF2 instances can only be used once.") + self._used = True + + if not isinstance(key_material, bytes): + raise TypeError("key_material must be bytes.") + return self._backend.derive_pbkdf2_hmac( + self._algorithm, + self._length, + self._salt, + self._iterations, + key_material + ) + + def verify(self, key_material, expected_key): + derived_key = self.derive(key_material) + if not constant_time.bytes_eq(derived_key, expected_key): + raise InvalidKey("Keys do not match.") diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/kdf/scrypt.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/kdf/scrypt.py new file mode 100644 index 0000000..77dcf9a --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/kdf/scrypt.py @@ -0,0 +1,66 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import sys + +from cryptography import utils +from cryptography.exceptions import ( + AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons +) +from cryptography.hazmat.backends.interfaces import ScryptBackend +from cryptography.hazmat.primitives import constant_time +from cryptography.hazmat.primitives.kdf import KeyDerivationFunction + + +# This is used by the scrypt tests to skip tests that require more memory +# than the MEM_LIMIT +_MEM_LIMIT = sys.maxsize // 2 + + +@utils.register_interface(KeyDerivationFunction) +class Scrypt(object): + def __init__(self, salt, length, n, r, p, backend): + if not isinstance(backend, ScryptBackend): + raise UnsupportedAlgorithm( + "Backend object does not implement ScryptBackend.", + _Reasons.BACKEND_MISSING_INTERFACE + ) + + self._length = length + if not isinstance(salt, bytes): + raise TypeError("salt must be bytes.") + + if n < 2 or (n & (n - 1)) != 0: + raise ValueError("n must be greater than 1 and be a power of 2.") + + if r < 1: + raise ValueError("r must be greater than or equal to 1.") + + if p < 1: + raise ValueError("p must be greater than or equal to 1.") + + self._used = False + self._salt = salt + self._n = n + self._r = r + self._p = p + self._backend = backend + + def derive(self, key_material): + if self._used: + raise AlreadyFinalized("Scrypt instances can only be used once.") + self._used = True + + if not isinstance(key_material, bytes): + raise TypeError("key_material must be bytes.") + return self._backend.derive_scrypt( + key_material, self._salt, self._length, self._n, self._r, self._p + ) + + def verify(self, key_material, expected_key): + derived_key = self.derive(key_material) + if not constant_time.bytes_eq(derived_key, expected_key): + raise InvalidKey("Keys do not match.") diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/kdf/x963kdf.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/kdf/x963kdf.py new file mode 100644 index 0000000..83789b3 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/kdf/x963kdf.py @@ -0,0 +1,70 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import struct + +from cryptography import utils +from cryptography.exceptions import ( + AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons +) +from cryptography.hazmat.backends.interfaces import HashBackend +from cryptography.hazmat.primitives import constant_time, hashes +from cryptography.hazmat.primitives.kdf import KeyDerivationFunction + + +def _int_to_u32be(n): + return struct.pack('>I', n) + + +@utils.register_interface(KeyDerivationFunction) +class X963KDF(object): + def __init__(self, algorithm, length, sharedinfo, backend): + + max_len = algorithm.digest_size * (2 ** 32 - 1) + if length > max_len: + raise ValueError( + "Can not derive keys larger than {0} bits.".format(max_len)) + if not (sharedinfo is None or isinstance(sharedinfo, bytes)): + raise TypeError("sharedinfo must be bytes.") + self._algorithm = algorithm + self._length = length + self._sharedinfo = sharedinfo + + if not isinstance(backend, HashBackend): + raise UnsupportedAlgorithm( + "Backend object does not implement HashBackend.", + _Reasons.BACKEND_MISSING_INTERFACE + ) + self._backend = backend + self._used = False + + def derive(self, key_material): + if self._used: + raise AlreadyFinalized + self._used = True + + if not isinstance(key_material, bytes): + raise TypeError("key_material must be bytes.") + + output = [b""] + outlen = 0 + counter = 1 + + while self._length > outlen: + h = hashes.Hash(self._algorithm, self._backend) + h.update(key_material) + h.update(_int_to_u32be(counter)) + if self._sharedinfo is not None: + h.update(self._sharedinfo) + output.append(h.finalize()) + outlen += len(output[-1]) + counter += 1 + + return b"".join(output)[:self._length] + + def verify(self, key_material, expected_key): + if not constant_time.bytes_eq(self.derive(key_material), expected_key): + raise InvalidKey diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/keywrap.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/keywrap.py new file mode 100644 index 0000000..f55c519 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/keywrap.py @@ -0,0 +1,154 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import struct + +from cryptography.hazmat.primitives.ciphers import Cipher +from cryptography.hazmat.primitives.ciphers.algorithms import AES +from cryptography.hazmat.primitives.ciphers.modes import ECB +from cryptography.hazmat.primitives.constant_time import bytes_eq + + +def _wrap_core(wrapping_key, a, r, backend): + # RFC 3394 Key Wrap - 2.2.1 (index method) + encryptor = Cipher(AES(wrapping_key), ECB(), backend).encryptor() + n = len(r) + for j in range(6): + for i in range(n): + # every encryption operation is a discrete 16 byte chunk (because + # AES has a 128-bit block size) and since we're using ECB it is + # safe to reuse the encryptor for the entire operation + b = encryptor.update(a + r[i]) + # pack/unpack are safe as these are always 64-bit chunks + a = struct.pack( + ">Q", struct.unpack(">Q", b[:8])[0] ^ ((n * j) + i + 1) + ) + r[i] = b[-8:] + + assert encryptor.finalize() == b"" + + return a + b"".join(r) + + +def aes_key_wrap(wrapping_key, key_to_wrap, backend): + if len(wrapping_key) not in [16, 24, 32]: + raise ValueError("The wrapping key must be a valid AES key length") + + if len(key_to_wrap) < 16: + raise ValueError("The key to wrap must be at least 16 bytes") + + if len(key_to_wrap) % 8 != 0: + raise ValueError("The key to wrap must be a multiple of 8 bytes") + + a = b"\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6" + r = [key_to_wrap[i:i + 8] for i in range(0, len(key_to_wrap), 8)] + return _wrap_core(wrapping_key, a, r, backend) + + +def _unwrap_core(wrapping_key, a, r, backend): + # Implement RFC 3394 Key Unwrap - 2.2.2 (index method) + decryptor = Cipher(AES(wrapping_key), ECB(), backend).decryptor() + n = len(r) + for j in reversed(range(6)): + for i in reversed(range(n)): + # pack/unpack are safe as these are always 64-bit chunks + atr = struct.pack( + ">Q", struct.unpack(">Q", a)[0] ^ ((n * j) + i + 1) + ) + r[i] + # every decryption operation is a discrete 16 byte chunk so + # it is safe to reuse the decryptor for the entire operation + b = decryptor.update(atr) + a = b[:8] + r[i] = b[-8:] + + assert decryptor.finalize() == b"" + return a, r + + +def aes_key_wrap_with_padding(wrapping_key, key_to_wrap, backend): + if len(wrapping_key) not in [16, 24, 32]: + raise ValueError("The wrapping key must be a valid AES key length") + + aiv = b"\xA6\x59\x59\xA6" + struct.pack(">i", len(key_to_wrap)) + # pad the key to wrap if necessary + pad = (8 - (len(key_to_wrap) % 8)) % 8 + key_to_wrap = key_to_wrap + b"\x00" * pad + if len(key_to_wrap) == 8: + # RFC 5649 - 4.1 - exactly 8 octets after padding + encryptor = Cipher(AES(wrapping_key), ECB(), backend).encryptor() + b = encryptor.update(aiv + key_to_wrap) + assert encryptor.finalize() == b"" + return b + else: + r = [key_to_wrap[i:i + 8] for i in range(0, len(key_to_wrap), 8)] + return _wrap_core(wrapping_key, aiv, r, backend) + + +def aes_key_unwrap_with_padding(wrapping_key, wrapped_key, backend): + if len(wrapped_key) < 16: + raise InvalidUnwrap("Must be at least 16 bytes") + + if len(wrapping_key) not in [16, 24, 32]: + raise ValueError("The wrapping key must be a valid AES key length") + + if len(wrapped_key) == 16: + # RFC 5649 - 4.2 - exactly two 64-bit blocks + decryptor = Cipher(AES(wrapping_key), ECB(), backend).decryptor() + b = decryptor.update(wrapped_key) + assert decryptor.finalize() == b"" + a = b[:8] + data = b[8:] + n = 1 + else: + r = [wrapped_key[i:i + 8] for i in range(0, len(wrapped_key), 8)] + encrypted_aiv = r.pop(0) + n = len(r) + a, r = _unwrap_core(wrapping_key, encrypted_aiv, r, backend) + data = b"".join(r) + + # 1) Check that MSB(32,A) = A65959A6. + # 2) Check that 8*(n-1) < LSB(32,A) <= 8*n. If so, let + # MLI = LSB(32,A). + # 3) Let b = (8*n)-MLI, and then check that the rightmost b octets of + # the output data are zero. + (mli,) = struct.unpack(">I", a[4:]) + b = (8 * n) - mli + if ( + not bytes_eq(a[:4], b"\xa6\x59\x59\xa6") or not + 8 * (n - 1) < mli <= 8 * n or ( + b != 0 and not bytes_eq(data[-b:], b"\x00" * b) + ) + ): + raise InvalidUnwrap() + + if b == 0: + return data + else: + return data[:-b] + + +def aes_key_unwrap(wrapping_key, wrapped_key, backend): + if len(wrapped_key) < 24: + raise InvalidUnwrap("Must be at least 24 bytes") + + if len(wrapped_key) % 8 != 0: + raise InvalidUnwrap("The wrapped key must be a multiple of 8 bytes") + + if len(wrapping_key) not in [16, 24, 32]: + raise ValueError("The wrapping key must be a valid AES key length") + + aiv = b"\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6" + r = [wrapped_key[i:i + 8] for i in range(0, len(wrapped_key), 8)] + a = r.pop(0) + a, r = _unwrap_core(wrapping_key, a, r, backend) + if not bytes_eq(a, aiv): + raise InvalidUnwrap() + + return b"".join(r) + + +class InvalidUnwrap(Exception): + pass diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/mac.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/mac.py new file mode 100644 index 0000000..4c95190 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/mac.py @@ -0,0 +1,37 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc + +import six + + +@six.add_metaclass(abc.ABCMeta) +class MACContext(object): + @abc.abstractmethod + def update(self, data): + """ + Processes the provided bytes. + """ + + @abc.abstractmethod + def finalize(self): + """ + Returns the message authentication code as bytes. + """ + + @abc.abstractmethod + def copy(self): + """ + Return a MACContext that is a copy of the current context. + """ + + @abc.abstractmethod + def verify(self, signature): + """ + Checks if the generated message authentication code matches the + signature. + """ diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/padding.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/padding.py new file mode 100644 index 0000000..a081976 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/padding.py @@ -0,0 +1,202 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc + +import six + +from cryptography import utils +from cryptography.exceptions import AlreadyFinalized +from cryptography.hazmat.bindings._padding import lib + + +@six.add_metaclass(abc.ABCMeta) +class PaddingContext(object): + @abc.abstractmethod + def update(self, data): + """ + Pads the provided bytes and returns any available data as bytes. + """ + + @abc.abstractmethod + def finalize(self): + """ + Finalize the padding, returns bytes. + """ + + +def _byte_padding_check(block_size): + if not (0 <= block_size <= 2040): + raise ValueError("block_size must be in range(0, 2041).") + + if block_size % 8 != 0: + raise ValueError("block_size must be a multiple of 8.") + + +def _byte_padding_update(buffer_, data, block_size): + if buffer_ is None: + raise AlreadyFinalized("Context was already finalized.") + + if not isinstance(data, bytes): + raise TypeError("data must be bytes.") + + buffer_ += data + + finished_blocks = len(buffer_) // (block_size // 8) + + result = buffer_[:finished_blocks * (block_size // 8)] + buffer_ = buffer_[finished_blocks * (block_size // 8):] + + return buffer_, result + + +def _byte_padding_pad(buffer_, block_size, paddingfn): + if buffer_ is None: + raise AlreadyFinalized("Context was already finalized.") + + pad_size = block_size // 8 - len(buffer_) + return buffer_ + paddingfn(pad_size) + + +def _byte_unpadding_update(buffer_, data, block_size): + if buffer_ is None: + raise AlreadyFinalized("Context was already finalized.") + + if not isinstance(data, bytes): + raise TypeError("data must be bytes.") + + buffer_ += data + + finished_blocks = max(len(buffer_) // (block_size // 8) - 1, 0) + + result = buffer_[:finished_blocks * (block_size // 8)] + buffer_ = buffer_[finished_blocks * (block_size // 8):] + + return buffer_, result + + +def _byte_unpadding_check(buffer_, block_size, checkfn): + if buffer_ is None: + raise AlreadyFinalized("Context was already finalized.") + + if len(buffer_) != block_size // 8: + raise ValueError("Invalid padding bytes.") + + valid = checkfn(buffer_, block_size // 8) + + if not valid: + raise ValueError("Invalid padding bytes.") + + pad_size = six.indexbytes(buffer_, -1) + return buffer_[:-pad_size] + + +class PKCS7(object): + def __init__(self, block_size): + _byte_padding_check(block_size) + self.block_size = block_size + + def padder(self): + return _PKCS7PaddingContext(self.block_size) + + def unpadder(self): + return _PKCS7UnpaddingContext(self.block_size) + + +@utils.register_interface(PaddingContext) +class _PKCS7PaddingContext(object): + def __init__(self, block_size): + self.block_size = block_size + # TODO: more copies than necessary, we should use zero-buffer (#193) + self._buffer = b"" + + def update(self, data): + self._buffer, result = _byte_padding_update( + self._buffer, data, self.block_size) + return result + + def _padding(self, size): + return six.int2byte(size) * size + + def finalize(self): + result = _byte_padding_pad( + self._buffer, self.block_size, self._padding) + self._buffer = None + return result + + +@utils.register_interface(PaddingContext) +class _PKCS7UnpaddingContext(object): + def __init__(self, block_size): + self.block_size = block_size + # TODO: more copies than necessary, we should use zero-buffer (#193) + self._buffer = b"" + + def update(self, data): + self._buffer, result = _byte_unpadding_update( + self._buffer, data, self.block_size) + return result + + def finalize(self): + result = _byte_unpadding_check( + self._buffer, self.block_size, + lib.Cryptography_check_pkcs7_padding) + self._buffer = None + return result + + +class ANSIX923(object): + def __init__(self, block_size): + _byte_padding_check(block_size) + self.block_size = block_size + + def padder(self): + return _ANSIX923PaddingContext(self.block_size) + + def unpadder(self): + return _ANSIX923UnpaddingContext(self.block_size) + + +@utils.register_interface(PaddingContext) +class _ANSIX923PaddingContext(object): + def __init__(self, block_size): + self.block_size = block_size + # TODO: more copies than necessary, we should use zero-buffer (#193) + self._buffer = b"" + + def update(self, data): + self._buffer, result = _byte_padding_update( + self._buffer, data, self.block_size) + return result + + def _padding(self, size): + return six.int2byte(0) * (size - 1) + six.int2byte(size) + + def finalize(self): + result = _byte_padding_pad( + self._buffer, self.block_size, self._padding) + self._buffer = None + return result + + +@utils.register_interface(PaddingContext) +class _ANSIX923UnpaddingContext(object): + def __init__(self, block_size): + self.block_size = block_size + # TODO: more copies than necessary, we should use zero-buffer (#193) + self._buffer = b"" + + def update(self, data): + self._buffer, result = _byte_unpadding_update( + self._buffer, data, self.block_size) + return result + + def finalize(self): + result = _byte_unpadding_check( + self._buffer, self.block_size, + lib.Cryptography_check_ansix923_padding) + self._buffer = None + return result diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/serialization.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/serialization.py new file mode 100644 index 0000000..bd09e6e --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/serialization.py @@ -0,0 +1,209 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc +import base64 +import struct +from enum import Enum + +import six + +from cryptography import utils +from cryptography.exceptions import UnsupportedAlgorithm +from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa + + +def load_pem_private_key(data, password, backend): + return backend.load_pem_private_key(data, password) + + +def load_pem_public_key(data, backend): + return backend.load_pem_public_key(data) + + +def load_pem_parameters(data, backend): + return backend.load_pem_parameters(data) + + +def load_der_private_key(data, password, backend): + return backend.load_der_private_key(data, password) + + +def load_der_public_key(data, backend): + return backend.load_der_public_key(data) + + +def load_der_parameters(data, backend): + return backend.load_der_parameters(data) + + +def load_ssh_public_key(data, backend): + key_parts = data.split(b' ', 2) + + if len(key_parts) < 2: + raise ValueError( + 'Key is not in the proper format or contains extra data.') + + key_type = key_parts[0] + + if key_type == b'ssh-rsa': + loader = _load_ssh_rsa_public_key + elif key_type == b'ssh-dss': + loader = _load_ssh_dss_public_key + elif key_type in [ + b'ecdsa-sha2-nistp256', b'ecdsa-sha2-nistp384', b'ecdsa-sha2-nistp521', + ]: + loader = _load_ssh_ecdsa_public_key + else: + raise UnsupportedAlgorithm('Key type is not supported.') + + key_body = key_parts[1] + + try: + decoded_data = base64.b64decode(key_body) + except TypeError: + raise ValueError('Key is not in the proper format.') + + inner_key_type, rest = _ssh_read_next_string(decoded_data) + + if inner_key_type != key_type: + raise ValueError( + 'Key header and key body contain different key type values.' + ) + + return loader(key_type, rest, backend) + + +def _load_ssh_rsa_public_key(key_type, decoded_data, backend): + e, rest = _ssh_read_next_mpint(decoded_data) + n, rest = _ssh_read_next_mpint(rest) + + if rest: + raise ValueError('Key body contains extra bytes.') + + return rsa.RSAPublicNumbers(e, n).public_key(backend) + + +def _load_ssh_dss_public_key(key_type, decoded_data, backend): + p, rest = _ssh_read_next_mpint(decoded_data) + q, rest = _ssh_read_next_mpint(rest) + g, rest = _ssh_read_next_mpint(rest) + y, rest = _ssh_read_next_mpint(rest) + + if rest: + raise ValueError('Key body contains extra bytes.') + + parameter_numbers = dsa.DSAParameterNumbers(p, q, g) + public_numbers = dsa.DSAPublicNumbers(y, parameter_numbers) + + return public_numbers.public_key(backend) + + +def _load_ssh_ecdsa_public_key(expected_key_type, decoded_data, backend): + curve_name, rest = _ssh_read_next_string(decoded_data) + data, rest = _ssh_read_next_string(rest) + + if expected_key_type != b"ecdsa-sha2-" + curve_name: + raise ValueError( + 'Key header and key body contain different key type values.' + ) + + if rest: + raise ValueError('Key body contains extra bytes.') + + curve = { + b"nistp256": ec.SECP256R1, + b"nistp384": ec.SECP384R1, + b"nistp521": ec.SECP521R1, + }[curve_name]() + + if six.indexbytes(data, 0) != 4: + raise NotImplementedError( + "Compressed elliptic curve points are not supported" + ) + + numbers = ec.EllipticCurvePublicNumbers.from_encoded_point(curve, data) + return numbers.public_key(backend) + + +def _ssh_read_next_string(data): + """ + Retrieves the next RFC 4251 string value from the data. + + While the RFC calls these strings, in Python they are bytes objects. + """ + if len(data) < 4: + raise ValueError("Key is not in the proper format") + + str_len, = struct.unpack('>I', data[:4]) + if len(data) < str_len + 4: + raise ValueError("Key is not in the proper format") + + return data[4:4 + str_len], data[4 + str_len:] + + +def _ssh_read_next_mpint(data): + """ + Reads the next mpint from the data. + + Currently, all mpints are interpreted as unsigned. + """ + mpint_data, rest = _ssh_read_next_string(data) + + return ( + utils.int_from_bytes(mpint_data, byteorder='big', signed=False), rest + ) + + +def _ssh_write_string(data): + return struct.pack(">I", len(data)) + data + + +def _ssh_write_mpint(value): + data = utils.int_to_bytes(value) + if six.indexbytes(data, 0) & 0x80: + data = b"\x00" + data + return _ssh_write_string(data) + + +class Encoding(Enum): + PEM = "PEM" + DER = "DER" + OpenSSH = "OpenSSH" + + +class PrivateFormat(Enum): + PKCS8 = "PKCS8" + TraditionalOpenSSL = "TraditionalOpenSSL" + + +class PublicFormat(Enum): + SubjectPublicKeyInfo = "X.509 subjectPublicKeyInfo with PKCS#1" + PKCS1 = "Raw PKCS#1" + OpenSSH = "OpenSSH" + + +class ParameterFormat(Enum): + PKCS3 = "PKCS3" + + +@six.add_metaclass(abc.ABCMeta) +class KeySerializationEncryption(object): + pass + + +@utils.register_interface(KeySerializationEncryption) +class BestAvailableEncryption(object): + def __init__(self, password): + if not isinstance(password, bytes) or len(password) == 0: + raise ValueError("Password must be 1 or more bytes.") + + self.password = password + + +@utils.register_interface(KeySerializationEncryption) +class NoEncryption(object): + pass diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/twofactor/__init__.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/twofactor/__init__.py new file mode 100644 index 0000000..e71f9e6 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/twofactor/__init__.py @@ -0,0 +1,9 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + + +class InvalidToken(Exception): + pass diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/twofactor/hotp.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/twofactor/hotp.py new file mode 100644 index 0000000..4ad1bdc --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/twofactor/hotp.py @@ -0,0 +1,68 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import struct + +import six + +from cryptography.exceptions import ( + UnsupportedAlgorithm, _Reasons +) +from cryptography.hazmat.backends.interfaces import HMACBackend +from cryptography.hazmat.primitives import constant_time, hmac +from cryptography.hazmat.primitives.hashes import SHA1, SHA256, SHA512 +from cryptography.hazmat.primitives.twofactor import InvalidToken +from cryptography.hazmat.primitives.twofactor.utils import _generate_uri + + +class HOTP(object): + def __init__(self, key, length, algorithm, backend, + enforce_key_length=True): + if not isinstance(backend, HMACBackend): + raise UnsupportedAlgorithm( + "Backend object does not implement HMACBackend.", + _Reasons.BACKEND_MISSING_INTERFACE + ) + + if len(key) < 16 and enforce_key_length is True: + raise ValueError("Key length has to be at least 128 bits.") + + if not isinstance(length, six.integer_types): + raise TypeError("Length parameter must be an integer type.") + + if length < 6 or length > 8: + raise ValueError("Length of HOTP has to be between 6 to 8.") + + if not isinstance(algorithm, (SHA1, SHA256, SHA512)): + raise TypeError("Algorithm must be SHA1, SHA256 or SHA512.") + + self._key = key + self._length = length + self._algorithm = algorithm + self._backend = backend + + def generate(self, counter): + truncated_value = self._dynamic_truncate(counter) + hotp = truncated_value % (10 ** self._length) + return "{0:0{1}}".format(hotp, self._length).encode() + + def verify(self, hotp, counter): + if not constant_time.bytes_eq(self.generate(counter), hotp): + raise InvalidToken("Supplied HOTP value does not match.") + + def _dynamic_truncate(self, counter): + ctx = hmac.HMAC(self._key, self._algorithm, self._backend) + ctx.update(struct.pack(">Q", counter)) + hmac_value = ctx.finalize() + + offset = six.indexbytes(hmac_value, len(hmac_value) - 1) & 0b1111 + p = hmac_value[offset:offset + 4] + return struct.unpack(">I", p)[0] & 0x7fffffff + + def get_provisioning_uri(self, account_name, counter, issuer): + return _generate_uri(self, "hotp", account_name, issuer, [ + ("counter", int(counter)), + ]) diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/twofactor/totp.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/twofactor/totp.py new file mode 100644 index 0000000..499f282 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/twofactor/totp.py @@ -0,0 +1,40 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography.exceptions import ( + UnsupportedAlgorithm, _Reasons +) +from cryptography.hazmat.backends.interfaces import HMACBackend +from cryptography.hazmat.primitives import constant_time +from cryptography.hazmat.primitives.twofactor import InvalidToken +from cryptography.hazmat.primitives.twofactor.hotp import HOTP +from cryptography.hazmat.primitives.twofactor.utils import _generate_uri + + +class TOTP(object): + def __init__(self, key, length, algorithm, time_step, backend, + enforce_key_length=True): + if not isinstance(backend, HMACBackend): + raise UnsupportedAlgorithm( + "Backend object does not implement HMACBackend.", + _Reasons.BACKEND_MISSING_INTERFACE + ) + + self._time_step = time_step + self._hotp = HOTP(key, length, algorithm, backend, enforce_key_length) + + def generate(self, time): + counter = int(time / self._time_step) + return self._hotp.generate(counter) + + def verify(self, totp, time): + if not constant_time.bytes_eq(self.generate(time), totp): + raise InvalidToken("Supplied TOTP value does not match.") + + def get_provisioning_uri(self, account_name, issuer): + return _generate_uri(self._hotp, "totp", account_name, issuer, [ + ("period", int(self._time_step)), + ]) diff --git a/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/twofactor/utils.py b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/twofactor/utils.py new file mode 100644 index 0000000..0ed8c4c --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/hazmat/primitives/twofactor/utils.py @@ -0,0 +1,30 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import base64 + +from six.moves.urllib.parse import quote, urlencode + + +def _generate_uri(hotp, type_name, account_name, issuer, extra_parameters): + parameters = [ + ("digits", hotp._length), + ("secret", base64.b32encode(hotp._key)), + ("algorithm", hotp._algorithm.name.upper()), + ] + + if issuer is not None: + parameters.append(("issuer", issuer)) + + parameters.extend(extra_parameters) + + uriparts = { + "type": type_name, + "label": ("%s:%s" % (quote(issuer), quote(account_name)) if issuer + else quote(account_name)), + "parameters": urlencode(parameters), + } + return "otpauth://{type}/{label}?{parameters}".format(**uriparts) diff --git a/venv/lib/python2.7/site-packages/cryptography/utils.py b/venv/lib/python2.7/site-packages/cryptography/utils.py new file mode 100644 index 0000000..3d45a77 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/utils.py @@ -0,0 +1,165 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc +import binascii +import inspect +import sys +import warnings + + +# We use a UserWarning subclass, instead of DeprecationWarning, because CPython +# decided deprecation warnings should be invisble by default. +class CryptographyDeprecationWarning(UserWarning): + pass + + +# Several APIs were deprecated with no specific end-of-life date because of the +# ubiquity of their use. They should not be removed until we agree on when that +# cycle ends. +PersistentlyDeprecated = CryptographyDeprecationWarning +DeprecatedIn21 = CryptographyDeprecationWarning +DeprecatedIn23 = CryptographyDeprecationWarning + + +def _check_bytes(name, value): + if not isinstance(value, bytes): + raise TypeError("{0} must be bytes".format(name)) + + +def read_only_property(name): + return property(lambda self: getattr(self, name)) + + +def register_interface(iface): + def register_decorator(klass): + verify_interface(iface, klass) + iface.register(klass) + return klass + return register_decorator + + +def register_interface_if(predicate, iface): + def register_decorator(klass): + if predicate: + verify_interface(iface, klass) + iface.register(klass) + return klass + return register_decorator + + +if hasattr(int, "from_bytes"): + int_from_bytes = int.from_bytes +else: + def int_from_bytes(data, byteorder, signed=False): + assert byteorder == 'big' + assert not signed + + return int(binascii.hexlify(data), 16) + + +if hasattr(int, "to_bytes"): + def int_to_bytes(integer, length=None): + return integer.to_bytes( + length or (integer.bit_length() + 7) // 8 or 1, 'big' + ) +else: + def int_to_bytes(integer, length=None): + hex_string = '%x' % integer + if length is None: + n = len(hex_string) + else: + n = length * 2 + return binascii.unhexlify(hex_string.zfill(n + (n & 1))) + + +class InterfaceNotImplemented(Exception): + pass + + +if hasattr(inspect, "signature"): + signature = inspect.signature +else: + signature = inspect.getargspec + + +def verify_interface(iface, klass): + for method in iface.__abstractmethods__: + if not hasattr(klass, method): + raise InterfaceNotImplemented( + "{0} is missing a {1!r} method".format(klass, method) + ) + if isinstance(getattr(iface, method), abc.abstractproperty): + # Can't properly verify these yet. + continue + sig = signature(getattr(iface, method)) + actual = signature(getattr(klass, method)) + if sig != actual: + raise InterfaceNotImplemented( + "{0}.{1}'s signature differs from the expected. Expected: " + "{2!r}. Received: {3!r}".format( + klass, method, sig, actual + ) + ) + + +# No longer needed as of 2.2, but retained because we have external consumers +# who use it. +def bit_length(x): + return x.bit_length() + + +class _DeprecatedValue(object): + def __init__(self, value, message, warning_class): + self.value = value + self.message = message + self.warning_class = warning_class + + +class _ModuleWithDeprecations(object): + def __init__(self, module): + self.__dict__["_module"] = module + + def __getattr__(self, attr): + obj = getattr(self._module, attr) + if isinstance(obj, _DeprecatedValue): + warnings.warn(obj.message, obj.warning_class, stacklevel=2) + obj = obj.value + return obj + + def __setattr__(self, attr, value): + setattr(self._module, attr, value) + + def __delattr__(self, attr): + obj = getattr(self._module, attr) + if isinstance(obj, _DeprecatedValue): + warnings.warn(obj.message, obj.warning_class, stacklevel=2) + + delattr(self._module, attr) + + def __dir__(self): + return ["_module"] + dir(self._module) + + +def deprecated(value, module_name, message, warning_class): + module = sys.modules[module_name] + if not isinstance(module, _ModuleWithDeprecations): + sys.modules[module_name] = _ModuleWithDeprecations(module) + return _DeprecatedValue(value, message, warning_class) + + +def cached_property(func): + cached_name = "_cached_{0}".format(func) + sentinel = object() + + def inner(instance): + cache = getattr(instance, cached_name, sentinel) + if cache is not sentinel: + return cache + result = func(instance) + setattr(instance, cached_name, result) + return result + return property(inner) diff --git a/venv/lib/python2.7/site-packages/cryptography/x509/__init__.py b/venv/lib/python2.7/site-packages/cryptography/x509/__init__.py new file mode 100644 index 0000000..d2f9b04 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/x509/__init__.py @@ -0,0 +1,185 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography.x509 import certificate_transparency +from cryptography.x509.base import ( + Certificate, CertificateBuilder, CertificateRevocationList, + CertificateRevocationListBuilder, + CertificateSigningRequest, CertificateSigningRequestBuilder, + InvalidVersion, RevokedCertificate, RevokedCertificateBuilder, + Version, load_der_x509_certificate, load_der_x509_crl, load_der_x509_csr, + load_pem_x509_certificate, load_pem_x509_crl, load_pem_x509_csr, + random_serial_number, +) +from cryptography.x509.extensions import ( + AccessDescription, AuthorityInformationAccess, + AuthorityKeyIdentifier, BasicConstraints, CRLDistributionPoints, + CRLNumber, CRLReason, CertificateIssuer, CertificatePolicies, + DeltaCRLIndicator, DistributionPoint, DuplicateExtension, ExtendedKeyUsage, + Extension, ExtensionNotFound, ExtensionType, Extensions, FreshestCRL, + GeneralNames, InhibitAnyPolicy, InvalidityDate, IssuerAlternativeName, + KeyUsage, NameConstraints, NoticeReference, OCSPNoCheck, PolicyConstraints, + PolicyInformation, PrecertificateSignedCertificateTimestamps, ReasonFlags, + SubjectAlternativeName, SubjectKeyIdentifier, TLSFeature, TLSFeatureType, + UnrecognizedExtension, UserNotice +) +from cryptography.x509.general_name import ( + DNSName, DirectoryName, GeneralName, IPAddress, OtherName, RFC822Name, + RegisteredID, UniformResourceIdentifier, UnsupportedGeneralNameType, + _GENERAL_NAMES +) +from cryptography.x509.name import ( + Name, NameAttribute, RelativeDistinguishedName +) +from cryptography.x509.oid import ( + AuthorityInformationAccessOID, CRLEntryExtensionOID, + CertificatePoliciesOID, ExtendedKeyUsageOID, ExtensionOID, NameOID, + ObjectIdentifier, SignatureAlgorithmOID, _SIG_OIDS_TO_HASH +) + + +OID_AUTHORITY_INFORMATION_ACCESS = ExtensionOID.AUTHORITY_INFORMATION_ACCESS +OID_AUTHORITY_KEY_IDENTIFIER = ExtensionOID.AUTHORITY_KEY_IDENTIFIER +OID_BASIC_CONSTRAINTS = ExtensionOID.BASIC_CONSTRAINTS +OID_CERTIFICATE_POLICIES = ExtensionOID.CERTIFICATE_POLICIES +OID_CRL_DISTRIBUTION_POINTS = ExtensionOID.CRL_DISTRIBUTION_POINTS +OID_EXTENDED_KEY_USAGE = ExtensionOID.EXTENDED_KEY_USAGE +OID_FRESHEST_CRL = ExtensionOID.FRESHEST_CRL +OID_INHIBIT_ANY_POLICY = ExtensionOID.INHIBIT_ANY_POLICY +OID_ISSUER_ALTERNATIVE_NAME = ExtensionOID.ISSUER_ALTERNATIVE_NAME +OID_KEY_USAGE = ExtensionOID.KEY_USAGE +OID_NAME_CONSTRAINTS = ExtensionOID.NAME_CONSTRAINTS +OID_OCSP_NO_CHECK = ExtensionOID.OCSP_NO_CHECK +OID_POLICY_CONSTRAINTS = ExtensionOID.POLICY_CONSTRAINTS +OID_POLICY_MAPPINGS = ExtensionOID.POLICY_MAPPINGS +OID_SUBJECT_ALTERNATIVE_NAME = ExtensionOID.SUBJECT_ALTERNATIVE_NAME +OID_SUBJECT_DIRECTORY_ATTRIBUTES = ExtensionOID.SUBJECT_DIRECTORY_ATTRIBUTES +OID_SUBJECT_INFORMATION_ACCESS = ExtensionOID.SUBJECT_INFORMATION_ACCESS +OID_SUBJECT_KEY_IDENTIFIER = ExtensionOID.SUBJECT_KEY_IDENTIFIER + +OID_DSA_WITH_SHA1 = SignatureAlgorithmOID.DSA_WITH_SHA1 +OID_DSA_WITH_SHA224 = SignatureAlgorithmOID.DSA_WITH_SHA224 +OID_DSA_WITH_SHA256 = SignatureAlgorithmOID.DSA_WITH_SHA256 +OID_ECDSA_WITH_SHA1 = SignatureAlgorithmOID.ECDSA_WITH_SHA1 +OID_ECDSA_WITH_SHA224 = SignatureAlgorithmOID.ECDSA_WITH_SHA224 +OID_ECDSA_WITH_SHA256 = SignatureAlgorithmOID.ECDSA_WITH_SHA256 +OID_ECDSA_WITH_SHA384 = SignatureAlgorithmOID.ECDSA_WITH_SHA384 +OID_ECDSA_WITH_SHA512 = SignatureAlgorithmOID.ECDSA_WITH_SHA512 +OID_RSA_WITH_MD5 = SignatureAlgorithmOID.RSA_WITH_MD5 +OID_RSA_WITH_SHA1 = SignatureAlgorithmOID.RSA_WITH_SHA1 +OID_RSA_WITH_SHA224 = SignatureAlgorithmOID.RSA_WITH_SHA224 +OID_RSA_WITH_SHA256 = SignatureAlgorithmOID.RSA_WITH_SHA256 +OID_RSA_WITH_SHA384 = SignatureAlgorithmOID.RSA_WITH_SHA384 +OID_RSA_WITH_SHA512 = SignatureAlgorithmOID.RSA_WITH_SHA512 +OID_RSASSA_PSS = SignatureAlgorithmOID.RSASSA_PSS + +OID_COMMON_NAME = NameOID.COMMON_NAME +OID_COUNTRY_NAME = NameOID.COUNTRY_NAME +OID_DOMAIN_COMPONENT = NameOID.DOMAIN_COMPONENT +OID_DN_QUALIFIER = NameOID.DN_QUALIFIER +OID_EMAIL_ADDRESS = NameOID.EMAIL_ADDRESS +OID_GENERATION_QUALIFIER = NameOID.GENERATION_QUALIFIER +OID_GIVEN_NAME = NameOID.GIVEN_NAME +OID_LOCALITY_NAME = NameOID.LOCALITY_NAME +OID_ORGANIZATIONAL_UNIT_NAME = NameOID.ORGANIZATIONAL_UNIT_NAME +OID_ORGANIZATION_NAME = NameOID.ORGANIZATION_NAME +OID_PSEUDONYM = NameOID.PSEUDONYM +OID_SERIAL_NUMBER = NameOID.SERIAL_NUMBER +OID_STATE_OR_PROVINCE_NAME = NameOID.STATE_OR_PROVINCE_NAME +OID_SURNAME = NameOID.SURNAME +OID_TITLE = NameOID.TITLE + +OID_CLIENT_AUTH = ExtendedKeyUsageOID.CLIENT_AUTH +OID_CODE_SIGNING = ExtendedKeyUsageOID.CODE_SIGNING +OID_EMAIL_PROTECTION = ExtendedKeyUsageOID.EMAIL_PROTECTION +OID_OCSP_SIGNING = ExtendedKeyUsageOID.OCSP_SIGNING +OID_SERVER_AUTH = ExtendedKeyUsageOID.SERVER_AUTH +OID_TIME_STAMPING = ExtendedKeyUsageOID.TIME_STAMPING + +OID_ANY_POLICY = CertificatePoliciesOID.ANY_POLICY +OID_CPS_QUALIFIER = CertificatePoliciesOID.CPS_QUALIFIER +OID_CPS_USER_NOTICE = CertificatePoliciesOID.CPS_USER_NOTICE + +OID_CERTIFICATE_ISSUER = CRLEntryExtensionOID.CERTIFICATE_ISSUER +OID_CRL_REASON = CRLEntryExtensionOID.CRL_REASON +OID_INVALIDITY_DATE = CRLEntryExtensionOID.INVALIDITY_DATE + +OID_CA_ISSUERS = AuthorityInformationAccessOID.CA_ISSUERS +OID_OCSP = AuthorityInformationAccessOID.OCSP + +__all__ = [ + "certificate_transparency", + "load_pem_x509_certificate", + "load_der_x509_certificate", + "load_pem_x509_csr", + "load_der_x509_csr", + "load_pem_x509_crl", + "load_der_x509_crl", + "random_serial_number", + "InvalidVersion", + "DeltaCRLIndicator", + "DuplicateExtension", + "ExtensionNotFound", + "UnsupportedGeneralNameType", + "NameAttribute", + "Name", + "RelativeDistinguishedName", + "ObjectIdentifier", + "ExtensionType", + "Extensions", + "Extension", + "ExtendedKeyUsage", + "FreshestCRL", + "TLSFeature", + "TLSFeatureType", + "OCSPNoCheck", + "BasicConstraints", + "CRLNumber", + "KeyUsage", + "AuthorityInformationAccess", + "AccessDescription", + "CertificatePolicies", + "PolicyInformation", + "UserNotice", + "NoticeReference", + "SubjectKeyIdentifier", + "NameConstraints", + "CRLDistributionPoints", + "DistributionPoint", + "ReasonFlags", + "InhibitAnyPolicy", + "SubjectAlternativeName", + "IssuerAlternativeName", + "AuthorityKeyIdentifier", + "GeneralNames", + "GeneralName", + "RFC822Name", + "DNSName", + "UniformResourceIdentifier", + "RegisteredID", + "DirectoryName", + "IPAddress", + "OtherName", + "Certificate", + "CertificateRevocationList", + "CertificateRevocationListBuilder", + "CertificateSigningRequest", + "RevokedCertificate", + "RevokedCertificateBuilder", + "CertificateSigningRequestBuilder", + "CertificateBuilder", + "Version", + "_SIG_OIDS_TO_HASH", + "OID_CA_ISSUERS", + "OID_OCSP", + "_GENERAL_NAMES", + "CertificateIssuer", + "CRLReason", + "InvalidityDate", + "UnrecognizedExtension", + "PolicyConstraints", + "PrecertificateSignedCertificateTimestamps", +] diff --git a/venv/lib/python2.7/site-packages/cryptography/x509/base.py b/venv/lib/python2.7/site-packages/cryptography/x509/base.py new file mode 100644 index 0000000..b14499c --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/x509/base.py @@ -0,0 +1,743 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc +import datetime +import os +from enum import Enum + +import six + +from cryptography import utils +from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa +from cryptography.x509.extensions import Extension, ExtensionType +from cryptography.x509.name import Name + + +_UNIX_EPOCH = datetime.datetime(1970, 1, 1) + + +def _convert_to_naive_utc_time(time): + """Normalizes a datetime to a naive datetime in UTC. + + time -- datetime to normalize. Assumed to be in UTC if not timezone + aware. + """ + if time.tzinfo is not None: + offset = time.utcoffset() + offset = offset if offset else datetime.timedelta() + return time.replace(tzinfo=None) - offset + else: + return time + + +class Version(Enum): + v1 = 0 + v3 = 2 + + +def load_pem_x509_certificate(data, backend): + return backend.load_pem_x509_certificate(data) + + +def load_der_x509_certificate(data, backend): + return backend.load_der_x509_certificate(data) + + +def load_pem_x509_csr(data, backend): + return backend.load_pem_x509_csr(data) + + +def load_der_x509_csr(data, backend): + return backend.load_der_x509_csr(data) + + +def load_pem_x509_crl(data, backend): + return backend.load_pem_x509_crl(data) + + +def load_der_x509_crl(data, backend): + return backend.load_der_x509_crl(data) + + +class InvalidVersion(Exception): + def __init__(self, msg, parsed_version): + super(InvalidVersion, self).__init__(msg) + self.parsed_version = parsed_version + + +@six.add_metaclass(abc.ABCMeta) +class Certificate(object): + @abc.abstractmethod + def fingerprint(self, algorithm): + """ + Returns bytes using digest passed. + """ + + @abc.abstractproperty + def serial_number(self): + """ + Returns certificate serial number + """ + + @abc.abstractproperty + def version(self): + """ + Returns the certificate version + """ + + @abc.abstractmethod + def public_key(self): + """ + Returns the public key + """ + + @abc.abstractproperty + def not_valid_before(self): + """ + Not before time (represented as UTC datetime) + """ + + @abc.abstractproperty + def not_valid_after(self): + """ + Not after time (represented as UTC datetime) + """ + + @abc.abstractproperty + def issuer(self): + """ + Returns the issuer name object. + """ + + @abc.abstractproperty + def subject(self): + """ + Returns the subject name object. + """ + + @abc.abstractproperty + def signature_hash_algorithm(self): + """ + Returns a HashAlgorithm corresponding to the type of the digest signed + in the certificate. + """ + + @abc.abstractproperty + def signature_algorithm_oid(self): + """ + Returns the ObjectIdentifier of the signature algorithm. + """ + + @abc.abstractproperty + def extensions(self): + """ + Returns an Extensions object. + """ + + @abc.abstractproperty + def signature(self): + """ + Returns the signature bytes. + """ + + @abc.abstractproperty + def tbs_certificate_bytes(self): + """ + Returns the tbsCertificate payload bytes as defined in RFC 5280. + """ + + @abc.abstractmethod + def __eq__(self, other): + """ + Checks equality. + """ + + @abc.abstractmethod + def __ne__(self, other): + """ + Checks not equal. + """ + + @abc.abstractmethod + def __hash__(self): + """ + Computes a hash. + """ + + @abc.abstractmethod + def public_bytes(self, encoding): + """ + Serializes the certificate to PEM or DER format. + """ + + +@six.add_metaclass(abc.ABCMeta) +class CertificateRevocationList(object): + @abc.abstractmethod + def public_bytes(self, encoding): + """ + Serializes the CRL to PEM or DER format. + """ + + @abc.abstractmethod + def fingerprint(self, algorithm): + """ + Returns bytes using digest passed. + """ + + @abc.abstractmethod + def get_revoked_certificate_by_serial_number(self, serial_number): + """ + Returns an instance of RevokedCertificate or None if the serial_number + is not in the CRL. + """ + + @abc.abstractproperty + def signature_hash_algorithm(self): + """ + Returns a HashAlgorithm corresponding to the type of the digest signed + in the certificate. + """ + + @abc.abstractproperty + def signature_algorithm_oid(self): + """ + Returns the ObjectIdentifier of the signature algorithm. + """ + + @abc.abstractproperty + def issuer(self): + """ + Returns the X509Name with the issuer of this CRL. + """ + + @abc.abstractproperty + def next_update(self): + """ + Returns the date of next update for this CRL. + """ + + @abc.abstractproperty + def last_update(self): + """ + Returns the date of last update for this CRL. + """ + + @abc.abstractproperty + def extensions(self): + """ + Returns an Extensions object containing a list of CRL extensions. + """ + + @abc.abstractproperty + def signature(self): + """ + Returns the signature bytes. + """ + + @abc.abstractproperty + def tbs_certlist_bytes(self): + """ + Returns the tbsCertList payload bytes as defined in RFC 5280. + """ + + @abc.abstractmethod + def __eq__(self, other): + """ + Checks equality. + """ + + @abc.abstractmethod + def __ne__(self, other): + """ + Checks not equal. + """ + + @abc.abstractmethod + def is_signature_valid(self, public_key): + """ + Verifies signature of revocation list against given public key. + """ + + +@six.add_metaclass(abc.ABCMeta) +class CertificateSigningRequest(object): + @abc.abstractmethod + def __eq__(self, other): + """ + Checks equality. + """ + + @abc.abstractmethod + def __ne__(self, other): + """ + Checks not equal. + """ + + @abc.abstractmethod + def __hash__(self): + """ + Computes a hash. + """ + + @abc.abstractmethod + def public_key(self): + """ + Returns the public key + """ + + @abc.abstractproperty + def subject(self): + """ + Returns the subject name object. + """ + + @abc.abstractproperty + def signature_hash_algorithm(self): + """ + Returns a HashAlgorithm corresponding to the type of the digest signed + in the certificate. + """ + + @abc.abstractproperty + def signature_algorithm_oid(self): + """ + Returns the ObjectIdentifier of the signature algorithm. + """ + + @abc.abstractproperty + def extensions(self): + """ + Returns the extensions in the signing request. + """ + + @abc.abstractmethod + def public_bytes(self, encoding): + """ + Encodes the request to PEM or DER format. + """ + + @abc.abstractproperty + def signature(self): + """ + Returns the signature bytes. + """ + + @abc.abstractproperty + def tbs_certrequest_bytes(self): + """ + Returns the PKCS#10 CertificationRequestInfo bytes as defined in RFC + 2986. + """ + + @abc.abstractproperty + def is_signature_valid(self): + """ + Verifies signature of signing request. + """ + + +@six.add_metaclass(abc.ABCMeta) +class RevokedCertificate(object): + @abc.abstractproperty + def serial_number(self): + """ + Returns the serial number of the revoked certificate. + """ + + @abc.abstractproperty + def revocation_date(self): + """ + Returns the date of when this certificate was revoked. + """ + + @abc.abstractproperty + def extensions(self): + """ + Returns an Extensions object containing a list of Revoked extensions. + """ + + +class CertificateSigningRequestBuilder(object): + def __init__(self, subject_name=None, extensions=[]): + """ + Creates an empty X.509 certificate request (v1). + """ + self._subject_name = subject_name + self._extensions = extensions + + def subject_name(self, name): + """ + Sets the certificate requestor's distinguished name. + """ + if not isinstance(name, Name): + raise TypeError('Expecting x509.Name object.') + if self._subject_name is not None: + raise ValueError('The subject name may only be set once.') + return CertificateSigningRequestBuilder(name, self._extensions) + + def add_extension(self, extension, critical): + """ + Adds an X.509 extension to the certificate request. + """ + if not isinstance(extension, ExtensionType): + raise TypeError("extension must be an ExtensionType") + + extension = Extension(extension.oid, critical, extension) + + # TODO: This is quadratic in the number of extensions + for e in self._extensions: + if e.oid == extension.oid: + raise ValueError('This extension has already been set.') + return CertificateSigningRequestBuilder( + self._subject_name, self._extensions + [extension] + ) + + def sign(self, private_key, algorithm, backend): + """ + Signs the request using the requestor's private key. + """ + if self._subject_name is None: + raise ValueError("A CertificateSigningRequest must have a subject") + return backend.create_x509_csr(self, private_key, algorithm) + + +class CertificateBuilder(object): + def __init__(self, issuer_name=None, subject_name=None, + public_key=None, serial_number=None, not_valid_before=None, + not_valid_after=None, extensions=[]): + self._version = Version.v3 + self._issuer_name = issuer_name + self._subject_name = subject_name + self._public_key = public_key + self._serial_number = serial_number + self._not_valid_before = not_valid_before + self._not_valid_after = not_valid_after + self._extensions = extensions + + def issuer_name(self, name): + """ + Sets the CA's distinguished name. + """ + if not isinstance(name, Name): + raise TypeError('Expecting x509.Name object.') + if self._issuer_name is not None: + raise ValueError('The issuer name may only be set once.') + return CertificateBuilder( + name, self._subject_name, self._public_key, + self._serial_number, self._not_valid_before, + self._not_valid_after, self._extensions + ) + + def subject_name(self, name): + """ + Sets the requestor's distinguished name. + """ + if not isinstance(name, Name): + raise TypeError('Expecting x509.Name object.') + if self._subject_name is not None: + raise ValueError('The subject name may only be set once.') + return CertificateBuilder( + self._issuer_name, name, self._public_key, + self._serial_number, self._not_valid_before, + self._not_valid_after, self._extensions + ) + + def public_key(self, key): + """ + Sets the requestor's public key (as found in the signing request). + """ + if not isinstance(key, (dsa.DSAPublicKey, rsa.RSAPublicKey, + ec.EllipticCurvePublicKey)): + raise TypeError('Expecting one of DSAPublicKey, RSAPublicKey,' + ' or EllipticCurvePublicKey.') + if self._public_key is not None: + raise ValueError('The public key may only be set once.') + return CertificateBuilder( + self._issuer_name, self._subject_name, key, + self._serial_number, self._not_valid_before, + self._not_valid_after, self._extensions + ) + + def serial_number(self, number): + """ + Sets the certificate serial number. + """ + if not isinstance(number, six.integer_types): + raise TypeError('Serial number must be of integral type.') + if self._serial_number is not None: + raise ValueError('The serial number may only be set once.') + if number <= 0: + raise ValueError('The serial number should be positive.') + + # ASN.1 integers are always signed, so most significant bit must be + # zero. + if number.bit_length() >= 160: # As defined in RFC 5280 + raise ValueError('The serial number should not be more than 159 ' + 'bits.') + return CertificateBuilder( + self._issuer_name, self._subject_name, + self._public_key, number, self._not_valid_before, + self._not_valid_after, self._extensions + ) + + def not_valid_before(self, time): + """ + Sets the certificate activation time. + """ + if not isinstance(time, datetime.datetime): + raise TypeError('Expecting datetime object.') + if self._not_valid_before is not None: + raise ValueError('The not valid before may only be set once.') + time = _convert_to_naive_utc_time(time) + if time <= _UNIX_EPOCH: + raise ValueError('The not valid before date must be after the unix' + ' epoch (1970 January 1).') + if self._not_valid_after is not None and time > self._not_valid_after: + raise ValueError( + 'The not valid before date must be before the not valid after ' + 'date.' + ) + return CertificateBuilder( + self._issuer_name, self._subject_name, + self._public_key, self._serial_number, time, + self._not_valid_after, self._extensions + ) + + def not_valid_after(self, time): + """ + Sets the certificate expiration time. + """ + if not isinstance(time, datetime.datetime): + raise TypeError('Expecting datetime object.') + if self._not_valid_after is not None: + raise ValueError('The not valid after may only be set once.') + time = _convert_to_naive_utc_time(time) + if time <= _UNIX_EPOCH: + raise ValueError('The not valid after date must be after the unix' + ' epoch (1970 January 1).') + if (self._not_valid_before is not None and + time < self._not_valid_before): + raise ValueError( + 'The not valid after date must be after the not valid before ' + 'date.' + ) + return CertificateBuilder( + self._issuer_name, self._subject_name, + self._public_key, self._serial_number, self._not_valid_before, + time, self._extensions + ) + + def add_extension(self, extension, critical): + """ + Adds an X.509 extension to the certificate. + """ + if not isinstance(extension, ExtensionType): + raise TypeError("extension must be an ExtensionType") + + extension = Extension(extension.oid, critical, extension) + + # TODO: This is quadratic in the number of extensions + for e in self._extensions: + if e.oid == extension.oid: + raise ValueError('This extension has already been set.') + + return CertificateBuilder( + self._issuer_name, self._subject_name, + self._public_key, self._serial_number, self._not_valid_before, + self._not_valid_after, self._extensions + [extension] + ) + + def sign(self, private_key, algorithm, backend): + """ + Signs the certificate using the CA's private key. + """ + if self._subject_name is None: + raise ValueError("A certificate must have a subject name") + + if self._issuer_name is None: + raise ValueError("A certificate must have an issuer name") + + if self._serial_number is None: + raise ValueError("A certificate must have a serial number") + + if self._not_valid_before is None: + raise ValueError("A certificate must have a not valid before time") + + if self._not_valid_after is None: + raise ValueError("A certificate must have a not valid after time") + + if self._public_key is None: + raise ValueError("A certificate must have a public key") + + return backend.create_x509_certificate(self, private_key, algorithm) + + +class CertificateRevocationListBuilder(object): + def __init__(self, issuer_name=None, last_update=None, next_update=None, + extensions=[], revoked_certificates=[]): + self._issuer_name = issuer_name + self._last_update = last_update + self._next_update = next_update + self._extensions = extensions + self._revoked_certificates = revoked_certificates + + def issuer_name(self, issuer_name): + if not isinstance(issuer_name, Name): + raise TypeError('Expecting x509.Name object.') + if self._issuer_name is not None: + raise ValueError('The issuer name may only be set once.') + return CertificateRevocationListBuilder( + issuer_name, self._last_update, self._next_update, + self._extensions, self._revoked_certificates + ) + + def last_update(self, last_update): + if not isinstance(last_update, datetime.datetime): + raise TypeError('Expecting datetime object.') + if self._last_update is not None: + raise ValueError('Last update may only be set once.') + last_update = _convert_to_naive_utc_time(last_update) + if last_update <= _UNIX_EPOCH: + raise ValueError('The last update date must be after the unix' + ' epoch (1970 January 1).') + if self._next_update is not None and last_update > self._next_update: + raise ValueError( + 'The last update date must be before the next update date.' + ) + return CertificateRevocationListBuilder( + self._issuer_name, last_update, self._next_update, + self._extensions, self._revoked_certificates + ) + + def next_update(self, next_update): + if not isinstance(next_update, datetime.datetime): + raise TypeError('Expecting datetime object.') + if self._next_update is not None: + raise ValueError('Last update may only be set once.') + next_update = _convert_to_naive_utc_time(next_update) + if next_update <= _UNIX_EPOCH: + raise ValueError('The last update date must be after the unix' + ' epoch (1970 January 1).') + if self._last_update is not None and next_update < self._last_update: + raise ValueError( + 'The next update date must be after the last update date.' + ) + return CertificateRevocationListBuilder( + self._issuer_name, self._last_update, next_update, + self._extensions, self._revoked_certificates + ) + + def add_extension(self, extension, critical): + """ + Adds an X.509 extension to the certificate revocation list. + """ + if not isinstance(extension, ExtensionType): + raise TypeError("extension must be an ExtensionType") + + extension = Extension(extension.oid, critical, extension) + + # TODO: This is quadratic in the number of extensions + for e in self._extensions: + if e.oid == extension.oid: + raise ValueError('This extension has already been set.') + return CertificateRevocationListBuilder( + self._issuer_name, self._last_update, self._next_update, + self._extensions + [extension], self._revoked_certificates + ) + + def add_revoked_certificate(self, revoked_certificate): + """ + Adds a revoked certificate to the CRL. + """ + if not isinstance(revoked_certificate, RevokedCertificate): + raise TypeError("Must be an instance of RevokedCertificate") + + return CertificateRevocationListBuilder( + self._issuer_name, self._last_update, + self._next_update, self._extensions, + self._revoked_certificates + [revoked_certificate] + ) + + def sign(self, private_key, algorithm, backend): + if self._issuer_name is None: + raise ValueError("A CRL must have an issuer name") + + if self._last_update is None: + raise ValueError("A CRL must have a last update time") + + if self._next_update is None: + raise ValueError("A CRL must have a next update time") + + return backend.create_x509_crl(self, private_key, algorithm) + + +class RevokedCertificateBuilder(object): + def __init__(self, serial_number=None, revocation_date=None, + extensions=[]): + self._serial_number = serial_number + self._revocation_date = revocation_date + self._extensions = extensions + + def serial_number(self, number): + if not isinstance(number, six.integer_types): + raise TypeError('Serial number must be of integral type.') + if self._serial_number is not None: + raise ValueError('The serial number may only be set once.') + if number <= 0: + raise ValueError('The serial number should be positive') + + # ASN.1 integers are always signed, so most significant bit must be + # zero. + if number.bit_length() >= 160: # As defined in RFC 5280 + raise ValueError('The serial number should not be more than 159 ' + 'bits.') + return RevokedCertificateBuilder( + number, self._revocation_date, self._extensions + ) + + def revocation_date(self, time): + if not isinstance(time, datetime.datetime): + raise TypeError('Expecting datetime object.') + if self._revocation_date is not None: + raise ValueError('The revocation date may only be set once.') + time = _convert_to_naive_utc_time(time) + if time <= _UNIX_EPOCH: + raise ValueError('The revocation date must be after the unix' + ' epoch (1970 January 1).') + return RevokedCertificateBuilder( + self._serial_number, time, self._extensions + ) + + def add_extension(self, extension, critical): + if not isinstance(extension, ExtensionType): + raise TypeError("extension must be an ExtensionType") + + extension = Extension(extension.oid, critical, extension) + + # TODO: This is quadratic in the number of extensions + for e in self._extensions: + if e.oid == extension.oid: + raise ValueError('This extension has already been set.') + return RevokedCertificateBuilder( + self._serial_number, self._revocation_date, + self._extensions + [extension] + ) + + def build(self, backend): + if self._serial_number is None: + raise ValueError("A revoked certificate must have a serial number") + if self._revocation_date is None: + raise ValueError( + "A revoked certificate must have a revocation date" + ) + + return backend.create_x509_revoked_certificate(self) + + +def random_serial_number(): + return utils.int_from_bytes(os.urandom(20), "big") >> 1 diff --git a/venv/lib/python2.7/site-packages/cryptography/x509/certificate_transparency.py b/venv/lib/python2.7/site-packages/cryptography/x509/certificate_transparency.py new file mode 100644 index 0000000..d00fe81 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/x509/certificate_transparency.py @@ -0,0 +1,46 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc +from enum import Enum + +import six + + +class LogEntryType(Enum): + X509_CERTIFICATE = 0 + PRE_CERTIFICATE = 1 + + +class Version(Enum): + v1 = 0 + + +@six.add_metaclass(abc.ABCMeta) +class SignedCertificateTimestamp(object): + @abc.abstractproperty + def version(self): + """ + Returns the SCT version. + """ + + @abc.abstractproperty + def log_id(self): + """ + Returns an identifier indicating which log this SCT is for. + """ + + @abc.abstractproperty + def timestamp(self): + """ + Returns the timestamp for this SCT. + """ + + @abc.abstractproperty + def entry_type(self): + """ + Returns whether this is an SCT for a certificate or pre-certificate. + """ diff --git a/venv/lib/python2.7/site-packages/cryptography/x509/extensions.py b/venv/lib/python2.7/site-packages/cryptography/x509/extensions.py new file mode 100644 index 0000000..eb4b927 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/x509/extensions.py @@ -0,0 +1,1429 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc +import datetime +import hashlib +import ipaddress +from enum import Enum + +from asn1crypto.keys import PublicKeyInfo + +import six + +from cryptography import utils +from cryptography.hazmat.primitives import constant_time, serialization +from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey +from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey +from cryptography.x509.certificate_transparency import ( + SignedCertificateTimestamp +) +from cryptography.x509.general_name import GeneralName, IPAddress, OtherName +from cryptography.x509.name import RelativeDistinguishedName +from cryptography.x509.oid import ( + CRLEntryExtensionOID, ExtensionOID, ObjectIdentifier +) + + +def _key_identifier_from_public_key(public_key): + if isinstance(public_key, RSAPublicKey): + data = public_key.public_bytes( + serialization.Encoding.DER, + serialization.PublicFormat.PKCS1, + ) + elif isinstance(public_key, EllipticCurvePublicKey): + data = public_key.public_numbers().encode_point() + else: + # This is a very slow way to do this. + serialized = public_key.public_bytes( + serialization.Encoding.DER, + serialization.PublicFormat.SubjectPublicKeyInfo + ) + + data = six.binary_type(PublicKeyInfo.load(serialized)['public_key']) + + return hashlib.sha1(data).digest() + + +class DuplicateExtension(Exception): + def __init__(self, msg, oid): + super(DuplicateExtension, self).__init__(msg) + self.oid = oid + + +class ExtensionNotFound(Exception): + def __init__(self, msg, oid): + super(ExtensionNotFound, self).__init__(msg) + self.oid = oid + + +@six.add_metaclass(abc.ABCMeta) +class ExtensionType(object): + @abc.abstractproperty + def oid(self): + """ + Returns the oid associated with the given extension type. + """ + + +class Extensions(object): + def __init__(self, extensions): + self._extensions = extensions + + def get_extension_for_oid(self, oid): + for ext in self: + if ext.oid == oid: + return ext + + raise ExtensionNotFound("No {0} extension was found".format(oid), oid) + + def get_extension_for_class(self, extclass): + if extclass is UnrecognizedExtension: + raise TypeError( + "UnrecognizedExtension can't be used with " + "get_extension_for_class because more than one instance of the" + " class may be present." + ) + + for ext in self: + if isinstance(ext.value, extclass): + return ext + + raise ExtensionNotFound( + "No {0} extension was found".format(extclass), extclass.oid + ) + + def __iter__(self): + return iter(self._extensions) + + def __len__(self): + return len(self._extensions) + + def __getitem__(self, idx): + return self._extensions[idx] + + def __repr__(self): + return ( + "".format(self._extensions) + ) + + +@utils.register_interface(ExtensionType) +class CRLNumber(object): + oid = ExtensionOID.CRL_NUMBER + + def __init__(self, crl_number): + if not isinstance(crl_number, six.integer_types): + raise TypeError("crl_number must be an integer") + + self._crl_number = crl_number + + def __eq__(self, other): + if not isinstance(other, CRLNumber): + return NotImplemented + + return self.crl_number == other.crl_number + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(self.crl_number) + + def __repr__(self): + return "".format(self.crl_number) + + crl_number = utils.read_only_property("_crl_number") + + +@utils.register_interface(ExtensionType) +class AuthorityKeyIdentifier(object): + oid = ExtensionOID.AUTHORITY_KEY_IDENTIFIER + + def __init__(self, key_identifier, authority_cert_issuer, + authority_cert_serial_number): + if (authority_cert_issuer is None) != ( + authority_cert_serial_number is None + ): + raise ValueError( + "authority_cert_issuer and authority_cert_serial_number " + "must both be present or both None" + ) + + if authority_cert_issuer is not None: + authority_cert_issuer = list(authority_cert_issuer) + if not all( + isinstance(x, GeneralName) for x in authority_cert_issuer + ): + raise TypeError( + "authority_cert_issuer must be a list of GeneralName " + "objects" + ) + + if authority_cert_serial_number is not None and not isinstance( + authority_cert_serial_number, six.integer_types + ): + raise TypeError( + "authority_cert_serial_number must be an integer" + ) + + self._key_identifier = key_identifier + self._authority_cert_issuer = authority_cert_issuer + self._authority_cert_serial_number = authority_cert_serial_number + + @classmethod + def from_issuer_public_key(cls, public_key): + digest = _key_identifier_from_public_key(public_key) + return cls( + key_identifier=digest, + authority_cert_issuer=None, + authority_cert_serial_number=None + ) + + @classmethod + def from_issuer_subject_key_identifier(cls, ski): + return cls( + key_identifier=ski.value.digest, + authority_cert_issuer=None, + authority_cert_serial_number=None + ) + + def __repr__(self): + return ( + "".format(self) + ) + + def __eq__(self, other): + if not isinstance(other, AuthorityKeyIdentifier): + return NotImplemented + + return ( + self.key_identifier == other.key_identifier and + self.authority_cert_issuer == other.authority_cert_issuer and + self.authority_cert_serial_number == + other.authority_cert_serial_number + ) + + def __ne__(self, other): + return not self == other + + def __hash__(self): + if self.authority_cert_issuer is None: + aci = None + else: + aci = tuple(self.authority_cert_issuer) + return hash(( + self.key_identifier, aci, self.authority_cert_serial_number + )) + + key_identifier = utils.read_only_property("_key_identifier") + authority_cert_issuer = utils.read_only_property("_authority_cert_issuer") + authority_cert_serial_number = utils.read_only_property( + "_authority_cert_serial_number" + ) + + +@utils.register_interface(ExtensionType) +class SubjectKeyIdentifier(object): + oid = ExtensionOID.SUBJECT_KEY_IDENTIFIER + + def __init__(self, digest): + self._digest = digest + + @classmethod + def from_public_key(cls, public_key): + return cls(_key_identifier_from_public_key(public_key)) + + digest = utils.read_only_property("_digest") + + def __repr__(self): + return "".format(self.digest) + + def __eq__(self, other): + if not isinstance(other, SubjectKeyIdentifier): + return NotImplemented + + return constant_time.bytes_eq(self.digest, other.digest) + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(self.digest) + + +@utils.register_interface(ExtensionType) +class AuthorityInformationAccess(object): + oid = ExtensionOID.AUTHORITY_INFORMATION_ACCESS + + def __init__(self, descriptions): + descriptions = list(descriptions) + if not all(isinstance(x, AccessDescription) for x in descriptions): + raise TypeError( + "Every item in the descriptions list must be an " + "AccessDescription" + ) + + self._descriptions = descriptions + + def __iter__(self): + return iter(self._descriptions) + + def __len__(self): + return len(self._descriptions) + + def __repr__(self): + return "".format(self._descriptions) + + def __eq__(self, other): + if not isinstance(other, AuthorityInformationAccess): + return NotImplemented + + return self._descriptions == other._descriptions + + def __ne__(self, other): + return not self == other + + def __getitem__(self, idx): + return self._descriptions[idx] + + def __hash__(self): + return hash(tuple(self._descriptions)) + + +class AccessDescription(object): + def __init__(self, access_method, access_location): + if not isinstance(access_method, ObjectIdentifier): + raise TypeError("access_method must be an ObjectIdentifier") + + if not isinstance(access_location, GeneralName): + raise TypeError("access_location must be a GeneralName") + + self._access_method = access_method + self._access_location = access_location + + def __repr__(self): + return ( + "".format(self) + ) + + def __eq__(self, other): + if not isinstance(other, AccessDescription): + return NotImplemented + + return ( + self.access_method == other.access_method and + self.access_location == other.access_location + ) + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash((self.access_method, self.access_location)) + + access_method = utils.read_only_property("_access_method") + access_location = utils.read_only_property("_access_location") + + +@utils.register_interface(ExtensionType) +class BasicConstraints(object): + oid = ExtensionOID.BASIC_CONSTRAINTS + + def __init__(self, ca, path_length): + if not isinstance(ca, bool): + raise TypeError("ca must be a boolean value") + + if path_length is not None and not ca: + raise ValueError("path_length must be None when ca is False") + + if ( + path_length is not None and + (not isinstance(path_length, six.integer_types) or path_length < 0) + ): + raise TypeError( + "path_length must be a non-negative integer or None" + ) + + self._ca = ca + self._path_length = path_length + + ca = utils.read_only_property("_ca") + path_length = utils.read_only_property("_path_length") + + def __repr__(self): + return ("").format(self) + + def __eq__(self, other): + if not isinstance(other, BasicConstraints): + return NotImplemented + + return self.ca == other.ca and self.path_length == other.path_length + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash((self.ca, self.path_length)) + + +@utils.register_interface(ExtensionType) +class DeltaCRLIndicator(object): + oid = ExtensionOID.DELTA_CRL_INDICATOR + + def __init__(self, crl_number): + if not isinstance(crl_number, six.integer_types): + raise TypeError("crl_number must be an integer") + + self._crl_number = crl_number + + crl_number = utils.read_only_property("_crl_number") + + def __eq__(self, other): + if not isinstance(other, DeltaCRLIndicator): + return NotImplemented + + return self.crl_number == other.crl_number + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(self.crl_number) + + def __repr__(self): + return "".format(self) + + +@utils.register_interface(ExtensionType) +class CRLDistributionPoints(object): + oid = ExtensionOID.CRL_DISTRIBUTION_POINTS + + def __init__(self, distribution_points): + distribution_points = list(distribution_points) + if not all( + isinstance(x, DistributionPoint) for x in distribution_points + ): + raise TypeError( + "distribution_points must be a list of DistributionPoint " + "objects" + ) + + self._distribution_points = distribution_points + + def __iter__(self): + return iter(self._distribution_points) + + def __len__(self): + return len(self._distribution_points) + + def __repr__(self): + return "".format(self._distribution_points) + + def __eq__(self, other): + if not isinstance(other, CRLDistributionPoints): + return NotImplemented + + return self._distribution_points == other._distribution_points + + def __ne__(self, other): + return not self == other + + def __getitem__(self, idx): + return self._distribution_points[idx] + + def __hash__(self): + return hash(tuple(self._distribution_points)) + + +@utils.register_interface(ExtensionType) +class FreshestCRL(object): + oid = ExtensionOID.FRESHEST_CRL + + def __init__(self, distribution_points): + distribution_points = list(distribution_points) + if not all( + isinstance(x, DistributionPoint) for x in distribution_points + ): + raise TypeError( + "distribution_points must be a list of DistributionPoint " + "objects" + ) + + self._distribution_points = distribution_points + + def __iter__(self): + return iter(self._distribution_points) + + def __len__(self): + return len(self._distribution_points) + + def __repr__(self): + return "".format(self._distribution_points) + + def __eq__(self, other): + if not isinstance(other, FreshestCRL): + return NotImplemented + + return self._distribution_points == other._distribution_points + + def __ne__(self, other): + return not self == other + + def __getitem__(self, idx): + return self._distribution_points[idx] + + def __hash__(self): + return hash(tuple(self._distribution_points)) + + +class DistributionPoint(object): + def __init__(self, full_name, relative_name, reasons, crl_issuer): + if full_name and relative_name: + raise ValueError( + "You cannot provide both full_name and relative_name, at " + "least one must be None." + ) + + if full_name: + full_name = list(full_name) + if not all(isinstance(x, GeneralName) for x in full_name): + raise TypeError( + "full_name must be a list of GeneralName objects" + ) + + if relative_name: + if not isinstance(relative_name, RelativeDistinguishedName): + raise TypeError( + "relative_name must be a RelativeDistinguishedName" + ) + + if crl_issuer: + crl_issuer = list(crl_issuer) + if not all(isinstance(x, GeneralName) for x in crl_issuer): + raise TypeError( + "crl_issuer must be None or a list of general names" + ) + + if reasons and (not isinstance(reasons, frozenset) or not all( + isinstance(x, ReasonFlags) for x in reasons + )): + raise TypeError("reasons must be None or frozenset of ReasonFlags") + + if reasons and ( + ReasonFlags.unspecified in reasons or + ReasonFlags.remove_from_crl in reasons + ): + raise ValueError( + "unspecified and remove_from_crl are not valid reasons in a " + "DistributionPoint" + ) + + if reasons and not crl_issuer and not (full_name or relative_name): + raise ValueError( + "You must supply crl_issuer, full_name, or relative_name when " + "reasons is not None" + ) + + self._full_name = full_name + self._relative_name = relative_name + self._reasons = reasons + self._crl_issuer = crl_issuer + + def __repr__(self): + return ( + "".format(self) + ) + + def __eq__(self, other): + if not isinstance(other, DistributionPoint): + return NotImplemented + + return ( + self.full_name == other.full_name and + self.relative_name == other.relative_name and + self.reasons == other.reasons and + self.crl_issuer == other.crl_issuer + ) + + def __ne__(self, other): + return not self == other + + def __hash__(self): + if self.full_name is not None: + fn = tuple(self.full_name) + else: + fn = None + + if self.crl_issuer is not None: + crl_issuer = tuple(self.crl_issuer) + else: + crl_issuer = None + + return hash((fn, self.relative_name, self.reasons, crl_issuer)) + + full_name = utils.read_only_property("_full_name") + relative_name = utils.read_only_property("_relative_name") + reasons = utils.read_only_property("_reasons") + crl_issuer = utils.read_only_property("_crl_issuer") + + +class ReasonFlags(Enum): + unspecified = "unspecified" + key_compromise = "keyCompromise" + ca_compromise = "cACompromise" + affiliation_changed = "affiliationChanged" + superseded = "superseded" + cessation_of_operation = "cessationOfOperation" + certificate_hold = "certificateHold" + privilege_withdrawn = "privilegeWithdrawn" + aa_compromise = "aACompromise" + remove_from_crl = "removeFromCRL" + + +@utils.register_interface(ExtensionType) +class PolicyConstraints(object): + oid = ExtensionOID.POLICY_CONSTRAINTS + + def __init__(self, require_explicit_policy, inhibit_policy_mapping): + if require_explicit_policy is not None and not isinstance( + require_explicit_policy, six.integer_types + ): + raise TypeError( + "require_explicit_policy must be a non-negative integer or " + "None" + ) + + if inhibit_policy_mapping is not None and not isinstance( + inhibit_policy_mapping, six.integer_types + ): + raise TypeError( + "inhibit_policy_mapping must be a non-negative integer or None" + ) + + if inhibit_policy_mapping is None and require_explicit_policy is None: + raise ValueError( + "At least one of require_explicit_policy and " + "inhibit_policy_mapping must not be None" + ) + + self._require_explicit_policy = require_explicit_policy + self._inhibit_policy_mapping = inhibit_policy_mapping + + def __repr__(self): + return ( + u"".format(self) + ) + + def __eq__(self, other): + if not isinstance(other, PolicyConstraints): + return NotImplemented + + return ( + self.require_explicit_policy == other.require_explicit_policy and + self.inhibit_policy_mapping == other.inhibit_policy_mapping + ) + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash( + (self.require_explicit_policy, self.inhibit_policy_mapping) + ) + + require_explicit_policy = utils.read_only_property( + "_require_explicit_policy" + ) + inhibit_policy_mapping = utils.read_only_property( + "_inhibit_policy_mapping" + ) + + +@utils.register_interface(ExtensionType) +class CertificatePolicies(object): + oid = ExtensionOID.CERTIFICATE_POLICIES + + def __init__(self, policies): + policies = list(policies) + if not all(isinstance(x, PolicyInformation) for x in policies): + raise TypeError( + "Every item in the policies list must be a " + "PolicyInformation" + ) + + self._policies = policies + + def __iter__(self): + return iter(self._policies) + + def __len__(self): + return len(self._policies) + + def __repr__(self): + return "".format(self._policies) + + def __eq__(self, other): + if not isinstance(other, CertificatePolicies): + return NotImplemented + + return self._policies == other._policies + + def __ne__(self, other): + return not self == other + + def __getitem__(self, idx): + return self._policies[idx] + + def __hash__(self): + return hash(tuple(self._policies)) + + +class PolicyInformation(object): + def __init__(self, policy_identifier, policy_qualifiers): + if not isinstance(policy_identifier, ObjectIdentifier): + raise TypeError("policy_identifier must be an ObjectIdentifier") + + self._policy_identifier = policy_identifier + + if policy_qualifiers: + policy_qualifiers = list(policy_qualifiers) + if not all( + isinstance(x, (six.text_type, UserNotice)) + for x in policy_qualifiers + ): + raise TypeError( + "policy_qualifiers must be a list of strings and/or " + "UserNotice objects or None" + ) + + self._policy_qualifiers = policy_qualifiers + + def __repr__(self): + return ( + "".format(self) + ) + + def __eq__(self, other): + if not isinstance(other, PolicyInformation): + return NotImplemented + + return ( + self.policy_identifier == other.policy_identifier and + self.policy_qualifiers == other.policy_qualifiers + ) + + def __ne__(self, other): + return not self == other + + def __hash__(self): + if self.policy_qualifiers is not None: + pq = tuple(self.policy_qualifiers) + else: + pq = None + + return hash((self.policy_identifier, pq)) + + policy_identifier = utils.read_only_property("_policy_identifier") + policy_qualifiers = utils.read_only_property("_policy_qualifiers") + + +class UserNotice(object): + def __init__(self, notice_reference, explicit_text): + if notice_reference and not isinstance( + notice_reference, NoticeReference + ): + raise TypeError( + "notice_reference must be None or a NoticeReference" + ) + + self._notice_reference = notice_reference + self._explicit_text = explicit_text + + def __repr__(self): + return ( + "".format(self) + ) + + def __eq__(self, other): + if not isinstance(other, UserNotice): + return NotImplemented + + return ( + self.notice_reference == other.notice_reference and + self.explicit_text == other.explicit_text + ) + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash((self.notice_reference, self.explicit_text)) + + notice_reference = utils.read_only_property("_notice_reference") + explicit_text = utils.read_only_property("_explicit_text") + + +class NoticeReference(object): + def __init__(self, organization, notice_numbers): + self._organization = organization + notice_numbers = list(notice_numbers) + if not all(isinstance(x, int) for x in notice_numbers): + raise TypeError( + "notice_numbers must be a list of integers" + ) + + self._notice_numbers = notice_numbers + + def __repr__(self): + return ( + "".format(self) + ) + + def __eq__(self, other): + if not isinstance(other, NoticeReference): + return NotImplemented + + return ( + self.organization == other.organization and + self.notice_numbers == other.notice_numbers + ) + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash((self.organization, tuple(self.notice_numbers))) + + organization = utils.read_only_property("_organization") + notice_numbers = utils.read_only_property("_notice_numbers") + + +@utils.register_interface(ExtensionType) +class ExtendedKeyUsage(object): + oid = ExtensionOID.EXTENDED_KEY_USAGE + + def __init__(self, usages): + usages = list(usages) + if not all(isinstance(x, ObjectIdentifier) for x in usages): + raise TypeError( + "Every item in the usages list must be an ObjectIdentifier" + ) + + self._usages = usages + + def __iter__(self): + return iter(self._usages) + + def __len__(self): + return len(self._usages) + + def __repr__(self): + return "".format(self._usages) + + def __eq__(self, other): + if not isinstance(other, ExtendedKeyUsage): + return NotImplemented + + return self._usages == other._usages + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(tuple(self._usages)) + + +@utils.register_interface(ExtensionType) +class OCSPNoCheck(object): + oid = ExtensionOID.OCSP_NO_CHECK + + +@utils.register_interface(ExtensionType) +class TLSFeature(object): + oid = ExtensionOID.TLS_FEATURE + + def __init__(self, features): + features = list(features) + if ( + not all(isinstance(x, TLSFeatureType) for x in features) or + len(features) == 0 + ): + raise TypeError( + "features must be a list of elements from the TLSFeatureType " + "enum" + ) + + self._features = features + + def __iter__(self): + return iter(self._features) + + def __len__(self): + return len(self._features) + + def __repr__(self): + return "".format(self) + + def __eq__(self, other): + if not isinstance(other, TLSFeature): + return NotImplemented + + return self._features == other._features + + def __getitem__(self, idx): + return self._features[idx] + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(tuple(self._features)) + + +class TLSFeatureType(Enum): + # status_request is defined in RFC 6066 and is used for what is commonly + # called OCSP Must-Staple when present in the TLS Feature extension in an + # X.509 certificate. + status_request = 5 + # status_request_v2 is defined in RFC 6961 and allows multiple OCSP + # responses to be provided. It is not currently in use by clients or + # servers. + status_request_v2 = 17 + + +_TLS_FEATURE_TYPE_TO_ENUM = dict((x.value, x) for x in TLSFeatureType) + + +@utils.register_interface(ExtensionType) +class InhibitAnyPolicy(object): + oid = ExtensionOID.INHIBIT_ANY_POLICY + + def __init__(self, skip_certs): + if not isinstance(skip_certs, six.integer_types): + raise TypeError("skip_certs must be an integer") + + if skip_certs < 0: + raise ValueError("skip_certs must be a non-negative integer") + + self._skip_certs = skip_certs + + def __repr__(self): + return "".format(self) + + def __eq__(self, other): + if not isinstance(other, InhibitAnyPolicy): + return NotImplemented + + return self.skip_certs == other.skip_certs + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(self.skip_certs) + + skip_certs = utils.read_only_property("_skip_certs") + + +@utils.register_interface(ExtensionType) +class KeyUsage(object): + oid = ExtensionOID.KEY_USAGE + + def __init__(self, digital_signature, content_commitment, key_encipherment, + data_encipherment, key_agreement, key_cert_sign, crl_sign, + encipher_only, decipher_only): + if not key_agreement and (encipher_only or decipher_only): + raise ValueError( + "encipher_only and decipher_only can only be true when " + "key_agreement is true" + ) + + self._digital_signature = digital_signature + self._content_commitment = content_commitment + self._key_encipherment = key_encipherment + self._data_encipherment = data_encipherment + self._key_agreement = key_agreement + self._key_cert_sign = key_cert_sign + self._crl_sign = crl_sign + self._encipher_only = encipher_only + self._decipher_only = decipher_only + + digital_signature = utils.read_only_property("_digital_signature") + content_commitment = utils.read_only_property("_content_commitment") + key_encipherment = utils.read_only_property("_key_encipherment") + data_encipherment = utils.read_only_property("_data_encipherment") + key_agreement = utils.read_only_property("_key_agreement") + key_cert_sign = utils.read_only_property("_key_cert_sign") + crl_sign = utils.read_only_property("_crl_sign") + + @property + def encipher_only(self): + if not self.key_agreement: + raise ValueError( + "encipher_only is undefined unless key_agreement is true" + ) + else: + return self._encipher_only + + @property + def decipher_only(self): + if not self.key_agreement: + raise ValueError( + "decipher_only is undefined unless key_agreement is true" + ) + else: + return self._decipher_only + + def __repr__(self): + try: + encipher_only = self.encipher_only + decipher_only = self.decipher_only + except ValueError: + encipher_only = None + decipher_only = None + + return ("").format( + self, encipher_only, decipher_only) + + def __eq__(self, other): + if not isinstance(other, KeyUsage): + return NotImplemented + + return ( + self.digital_signature == other.digital_signature and + self.content_commitment == other.content_commitment and + self.key_encipherment == other.key_encipherment and + self.data_encipherment == other.data_encipherment and + self.key_agreement == other.key_agreement and + self.key_cert_sign == other.key_cert_sign and + self.crl_sign == other.crl_sign and + self._encipher_only == other._encipher_only and + self._decipher_only == other._decipher_only + ) + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(( + self.digital_signature, self.content_commitment, + self.key_encipherment, self.data_encipherment, + self.key_agreement, self.key_cert_sign, + self.crl_sign, self._encipher_only, + self._decipher_only + )) + + +@utils.register_interface(ExtensionType) +class NameConstraints(object): + oid = ExtensionOID.NAME_CONSTRAINTS + + def __init__(self, permitted_subtrees, excluded_subtrees): + if permitted_subtrees is not None: + permitted_subtrees = list(permitted_subtrees) + if not all( + isinstance(x, GeneralName) for x in permitted_subtrees + ): + raise TypeError( + "permitted_subtrees must be a list of GeneralName objects " + "or None" + ) + + self._validate_ip_name(permitted_subtrees) + + if excluded_subtrees is not None: + excluded_subtrees = list(excluded_subtrees) + if not all( + isinstance(x, GeneralName) for x in excluded_subtrees + ): + raise TypeError( + "excluded_subtrees must be a list of GeneralName objects " + "or None" + ) + + self._validate_ip_name(excluded_subtrees) + + if permitted_subtrees is None and excluded_subtrees is None: + raise ValueError( + "At least one of permitted_subtrees and excluded_subtrees " + "must not be None" + ) + + self._permitted_subtrees = permitted_subtrees + self._excluded_subtrees = excluded_subtrees + + def __eq__(self, other): + if not isinstance(other, NameConstraints): + return NotImplemented + + return ( + self.excluded_subtrees == other.excluded_subtrees and + self.permitted_subtrees == other.permitted_subtrees + ) + + def __ne__(self, other): + return not self == other + + def _validate_ip_name(self, tree): + if any(isinstance(name, IPAddress) and not isinstance( + name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network) + ) for name in tree): + raise TypeError( + "IPAddress name constraints must be an IPv4Network or" + " IPv6Network object" + ) + + def __repr__(self): + return ( + u"".format(self) + ) + + def __hash__(self): + if self.permitted_subtrees is not None: + ps = tuple(self.permitted_subtrees) + else: + ps = None + + if self.excluded_subtrees is not None: + es = tuple(self.excluded_subtrees) + else: + es = None + + return hash((ps, es)) + + permitted_subtrees = utils.read_only_property("_permitted_subtrees") + excluded_subtrees = utils.read_only_property("_excluded_subtrees") + + +class Extension(object): + def __init__(self, oid, critical, value): + if not isinstance(oid, ObjectIdentifier): + raise TypeError( + "oid argument must be an ObjectIdentifier instance." + ) + + if not isinstance(critical, bool): + raise TypeError("critical must be a boolean value") + + self._oid = oid + self._critical = critical + self._value = value + + oid = utils.read_only_property("_oid") + critical = utils.read_only_property("_critical") + value = utils.read_only_property("_value") + + def __repr__(self): + return ("").format(self) + + def __eq__(self, other): + if not isinstance(other, Extension): + return NotImplemented + + return ( + self.oid == other.oid and + self.critical == other.critical and + self.value == other.value + ) + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash((self.oid, self.critical, self.value)) + + +class GeneralNames(object): + def __init__(self, general_names): + general_names = list(general_names) + if not all(isinstance(x, GeneralName) for x in general_names): + raise TypeError( + "Every item in the general_names list must be an " + "object conforming to the GeneralName interface" + ) + + self._general_names = general_names + + def __iter__(self): + return iter(self._general_names) + + def __len__(self): + return len(self._general_names) + + def get_values_for_type(self, type): + # Return the value of each GeneralName, except for OtherName instances + # which we return directly because it has two important properties not + # just one value. + objs = (i for i in self if isinstance(i, type)) + if type != OtherName: + objs = (i.value for i in objs) + return list(objs) + + def __repr__(self): + return "".format(self._general_names) + + def __eq__(self, other): + if not isinstance(other, GeneralNames): + return NotImplemented + + return self._general_names == other._general_names + + def __ne__(self, other): + return not self == other + + def __getitem__(self, idx): + return self._general_names[idx] + + def __hash__(self): + return hash(tuple(self._general_names)) + + +@utils.register_interface(ExtensionType) +class SubjectAlternativeName(object): + oid = ExtensionOID.SUBJECT_ALTERNATIVE_NAME + + def __init__(self, general_names): + self._general_names = GeneralNames(general_names) + + def __iter__(self): + return iter(self._general_names) + + def __len__(self): + return len(self._general_names) + + def get_values_for_type(self, type): + return self._general_names.get_values_for_type(type) + + def __repr__(self): + return "".format(self._general_names) + + def __eq__(self, other): + if not isinstance(other, SubjectAlternativeName): + return NotImplemented + + return self._general_names == other._general_names + + def __getitem__(self, idx): + return self._general_names[idx] + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(self._general_names) + + +@utils.register_interface(ExtensionType) +class IssuerAlternativeName(object): + oid = ExtensionOID.ISSUER_ALTERNATIVE_NAME + + def __init__(self, general_names): + self._general_names = GeneralNames(general_names) + + def __iter__(self): + return iter(self._general_names) + + def __len__(self): + return len(self._general_names) + + def get_values_for_type(self, type): + return self._general_names.get_values_for_type(type) + + def __repr__(self): + return "".format(self._general_names) + + def __eq__(self, other): + if not isinstance(other, IssuerAlternativeName): + return NotImplemented + + return self._general_names == other._general_names + + def __ne__(self, other): + return not self == other + + def __getitem__(self, idx): + return self._general_names[idx] + + def __hash__(self): + return hash(self._general_names) + + +@utils.register_interface(ExtensionType) +class CertificateIssuer(object): + oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER + + def __init__(self, general_names): + self._general_names = GeneralNames(general_names) + + def __iter__(self): + return iter(self._general_names) + + def __len__(self): + return len(self._general_names) + + def get_values_for_type(self, type): + return self._general_names.get_values_for_type(type) + + def __repr__(self): + return "".format(self._general_names) + + def __eq__(self, other): + if not isinstance(other, CertificateIssuer): + return NotImplemented + + return self._general_names == other._general_names + + def __ne__(self, other): + return not self == other + + def __getitem__(self, idx): + return self._general_names[idx] + + def __hash__(self): + return hash(self._general_names) + + +@utils.register_interface(ExtensionType) +class CRLReason(object): + oid = CRLEntryExtensionOID.CRL_REASON + + def __init__(self, reason): + if not isinstance(reason, ReasonFlags): + raise TypeError("reason must be an element from ReasonFlags") + + self._reason = reason + + def __repr__(self): + return "".format(self._reason) + + def __eq__(self, other): + if not isinstance(other, CRLReason): + return NotImplemented + + return self.reason == other.reason + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(self.reason) + + reason = utils.read_only_property("_reason") + + +@utils.register_interface(ExtensionType) +class InvalidityDate(object): + oid = CRLEntryExtensionOID.INVALIDITY_DATE + + def __init__(self, invalidity_date): + if not isinstance(invalidity_date, datetime.datetime): + raise TypeError("invalidity_date must be a datetime.datetime") + + self._invalidity_date = invalidity_date + + def __repr__(self): + return "".format( + self._invalidity_date + ) + + def __eq__(self, other): + if not isinstance(other, InvalidityDate): + return NotImplemented + + return self.invalidity_date == other.invalidity_date + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(self.invalidity_date) + + invalidity_date = utils.read_only_property("_invalidity_date") + + +@utils.register_interface(ExtensionType) +class PrecertificateSignedCertificateTimestamps(object): + oid = ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS + + def __init__(self, signed_certificate_timestamps): + signed_certificate_timestamps = list(signed_certificate_timestamps) + if not all( + isinstance(sct, SignedCertificateTimestamp) + for sct in signed_certificate_timestamps + ): + raise TypeError( + "Every item in the signed_certificate_timestamps list must be " + "a SignedCertificateTimestamp" + ) + self._signed_certificate_timestamps = signed_certificate_timestamps + + def __iter__(self): + return iter(self._signed_certificate_timestamps) + + def __len__(self): + return len(self._signed_certificate_timestamps) + + def __getitem__(self, idx): + return self._signed_certificate_timestamps[idx] + + def __repr__(self): + return ( + "".format( + list(self) + ) + ) + + +@utils.register_interface(ExtensionType) +class UnrecognizedExtension(object): + def __init__(self, oid, value): + if not isinstance(oid, ObjectIdentifier): + raise TypeError("oid must be an ObjectIdentifier") + self._oid = oid + self._value = value + + oid = utils.read_only_property("_oid") + value = utils.read_only_property("_value") + + def __repr__(self): + return ( + "".format( + self + ) + ) + + def __eq__(self, other): + if not isinstance(other, UnrecognizedExtension): + return NotImplemented + + return self.oid == other.oid and self.value == other.value + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash((self.oid, self.value)) diff --git a/venv/lib/python2.7/site-packages/cryptography/x509/general_name.py b/venv/lib/python2.7/site-packages/cryptography/x509/general_name.py new file mode 100644 index 0000000..26f389a --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/x509/general_name.py @@ -0,0 +1,345 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc +import ipaddress +import warnings +from email.utils import parseaddr + +import idna + +import six +from six.moves import urllib_parse + +from cryptography import utils +from cryptography.x509.name import Name +from cryptography.x509.oid import ObjectIdentifier + + +_GENERAL_NAMES = { + 0: "otherName", + 1: "rfc822Name", + 2: "dNSName", + 3: "x400Address", + 4: "directoryName", + 5: "ediPartyName", + 6: "uniformResourceIdentifier", + 7: "iPAddress", + 8: "registeredID", +} + + +class UnsupportedGeneralNameType(Exception): + def __init__(self, msg, type): + super(UnsupportedGeneralNameType, self).__init__(msg) + self.type = type + + +@six.add_metaclass(abc.ABCMeta) +class GeneralName(object): + @abc.abstractproperty + def value(self): + """ + Return the value of the object + """ + + +@utils.register_interface(GeneralName) +class RFC822Name(object): + def __init__(self, value): + if isinstance(value, six.text_type): + try: + value.encode("ascii") + except UnicodeEncodeError: + value = self._idna_encode(value) + warnings.warn( + "RFC822Name values should be passed as an A-label string. " + "This means unicode characters should be encoded via " + "idna. Support for passing unicode strings (aka U-label) " + "will be removed in a future version.", + utils.DeprecatedIn21, + stacklevel=2, + ) + else: + raise TypeError("value must be string") + + name, address = parseaddr(value) + if name or not address: + # parseaddr has found a name (e.g. Name ) or the entire + # value is an empty string. + raise ValueError("Invalid rfc822name value") + + self._value = value + + value = utils.read_only_property("_value") + + @classmethod + def _init_without_validation(cls, value): + instance = cls.__new__(cls) + instance._value = value + return instance + + def _idna_encode(self, value): + _, address = parseaddr(value) + parts = address.split(u"@") + return parts[0] + "@" + idna.encode(parts[1]).decode("ascii") + + def __repr__(self): + return "".format(self.value) + + def __eq__(self, other): + if not isinstance(other, RFC822Name): + return NotImplemented + + return self.value == other.value + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(self.value) + + +def _idna_encode(value): + # Retain prefixes '*.' for common/alt names and '.' for name constraints + for prefix in ['*.', '.']: + if value.startswith(prefix): + value = value[len(prefix):] + return prefix + idna.encode(value).decode("ascii") + return idna.encode(value).decode("ascii") + + +@utils.register_interface(GeneralName) +class DNSName(object): + def __init__(self, value): + if isinstance(value, six.text_type): + try: + value.encode("ascii") + except UnicodeEncodeError: + value = _idna_encode(value) + warnings.warn( + "DNSName values should be passed as an A-label string. " + "This means unicode characters should be encoded via " + "idna. Support for passing unicode strings (aka U-label) " + "will be removed in a future version.", + utils.DeprecatedIn21, + stacklevel=2, + ) + else: + raise TypeError("value must be string") + + self._value = value + + value = utils.read_only_property("_value") + + @classmethod + def _init_without_validation(cls, value): + instance = cls.__new__(cls) + instance._value = value + return instance + + def __repr__(self): + return "".format(self.value) + + def __eq__(self, other): + if not isinstance(other, DNSName): + return NotImplemented + + return self.value == other.value + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(self.value) + + +@utils.register_interface(GeneralName) +class UniformResourceIdentifier(object): + def __init__(self, value): + if isinstance(value, six.text_type): + try: + value.encode("ascii") + except UnicodeEncodeError: + value = self._idna_encode(value) + warnings.warn( + "URI values should be passed as an A-label string. " + "This means unicode characters should be encoded via " + "idna. Support for passing unicode strings (aka U-label) " + " will be removed in a future version.", + utils.DeprecatedIn21, + stacklevel=2, + ) + else: + raise TypeError("value must be string") + + self._value = value + + value = utils.read_only_property("_value") + + @classmethod + def _init_without_validation(cls, value): + instance = cls.__new__(cls) + instance._value = value + return instance + + def _idna_encode(self, value): + parsed = urllib_parse.urlparse(value) + if parsed.port: + netloc = ( + idna.encode(parsed.hostname) + + ":{0}".format(parsed.port).encode("ascii") + ).decode("ascii") + else: + netloc = idna.encode(parsed.hostname).decode("ascii") + + # Note that building a URL in this fashion means it should be + # semantically indistinguishable from the original but is not + # guaranteed to be exactly the same. + return urllib_parse.urlunparse(( + parsed.scheme, + netloc, + parsed.path, + parsed.params, + parsed.query, + parsed.fragment + )) + + def __repr__(self): + return "".format(self.value) + + def __eq__(self, other): + if not isinstance(other, UniformResourceIdentifier): + return NotImplemented + + return self.value == other.value + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(self.value) + + +@utils.register_interface(GeneralName) +class DirectoryName(object): + def __init__(self, value): + if not isinstance(value, Name): + raise TypeError("value must be a Name") + + self._value = value + + value = utils.read_only_property("_value") + + def __repr__(self): + return "".format(self.value) + + def __eq__(self, other): + if not isinstance(other, DirectoryName): + return NotImplemented + + return self.value == other.value + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(self.value) + + +@utils.register_interface(GeneralName) +class RegisteredID(object): + def __init__(self, value): + if not isinstance(value, ObjectIdentifier): + raise TypeError("value must be an ObjectIdentifier") + + self._value = value + + value = utils.read_only_property("_value") + + def __repr__(self): + return "".format(self.value) + + def __eq__(self, other): + if not isinstance(other, RegisteredID): + return NotImplemented + + return self.value == other.value + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(self.value) + + +@utils.register_interface(GeneralName) +class IPAddress(object): + def __init__(self, value): + if not isinstance( + value, + ( + ipaddress.IPv4Address, + ipaddress.IPv6Address, + ipaddress.IPv4Network, + ipaddress.IPv6Network + ) + ): + raise TypeError( + "value must be an instance of ipaddress.IPv4Address, " + "ipaddress.IPv6Address, ipaddress.IPv4Network, or " + "ipaddress.IPv6Network" + ) + + self._value = value + + value = utils.read_only_property("_value") + + def __repr__(self): + return "".format(self.value) + + def __eq__(self, other): + if not isinstance(other, IPAddress): + return NotImplemented + + return self.value == other.value + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(self.value) + + +@utils.register_interface(GeneralName) +class OtherName(object): + def __init__(self, type_id, value): + if not isinstance(type_id, ObjectIdentifier): + raise TypeError("type_id must be an ObjectIdentifier") + if not isinstance(value, bytes): + raise TypeError("value must be a binary string") + + self._type_id = type_id + self._value = value + + type_id = utils.read_only_property("_type_id") + value = utils.read_only_property("_value") + + def __repr__(self): + return "".format( + self.type_id, self.value) + + def __eq__(self, other): + if not isinstance(other, OtherName): + return NotImplemented + + return self.type_id == other.type_id and self.value == other.value + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash((self.type_id, self.value)) diff --git a/venv/lib/python2.7/site-packages/cryptography/x509/name.py b/venv/lib/python2.7/site-packages/cryptography/x509/name.py new file mode 100644 index 0000000..5548eda --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/x509/name.py @@ -0,0 +1,190 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from enum import Enum + +import six + +from cryptography import utils +from cryptography.x509.oid import NameOID, ObjectIdentifier + + +class _ASN1Type(Enum): + UTF8String = 12 + NumericString = 18 + PrintableString = 19 + T61String = 20 + IA5String = 22 + UTCTime = 23 + GeneralizedTime = 24 + VisibleString = 26 + UniversalString = 28 + BMPString = 30 + + +_ASN1_TYPE_TO_ENUM = dict((i.value, i) for i in _ASN1Type) +_SENTINEL = object() +_NAMEOID_DEFAULT_TYPE = { + NameOID.COUNTRY_NAME: _ASN1Type.PrintableString, + NameOID.JURISDICTION_COUNTRY_NAME: _ASN1Type.PrintableString, + NameOID.SERIAL_NUMBER: _ASN1Type.PrintableString, + NameOID.DN_QUALIFIER: _ASN1Type.PrintableString, + NameOID.EMAIL_ADDRESS: _ASN1Type.IA5String, + NameOID.DOMAIN_COMPONENT: _ASN1Type.IA5String, +} + + +class NameAttribute(object): + def __init__(self, oid, value, _type=_SENTINEL): + if not isinstance(oid, ObjectIdentifier): + raise TypeError( + "oid argument must be an ObjectIdentifier instance." + ) + + if not isinstance(value, six.text_type): + raise TypeError( + "value argument must be a text type." + ) + + if ( + oid == NameOID.COUNTRY_NAME or + oid == NameOID.JURISDICTION_COUNTRY_NAME + ): + if len(value.encode("utf8")) != 2: + raise ValueError( + "Country name must be a 2 character country code" + ) + + if len(value) == 0: + raise ValueError("Value cannot be an empty string") + + # The appropriate ASN1 string type varies by OID and is defined across + # multiple RFCs including 2459, 3280, and 5280. In general UTF8String + # is preferred (2459), but 3280 and 5280 specify several OIDs with + # alternate types. This means when we see the sentinel value we need + # to look up whether the OID has a non-UTF8 type. If it does, set it + # to that. Otherwise, UTF8! + if _type == _SENTINEL: + _type = _NAMEOID_DEFAULT_TYPE.get(oid, _ASN1Type.UTF8String) + + if not isinstance(_type, _ASN1Type): + raise TypeError("_type must be from the _ASN1Type enum") + + self._oid = oid + self._value = value + self._type = _type + + oid = utils.read_only_property("_oid") + value = utils.read_only_property("_value") + + def __eq__(self, other): + if not isinstance(other, NameAttribute): + return NotImplemented + + return ( + self.oid == other.oid and + self.value == other.value + ) + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash((self.oid, self.value)) + + def __repr__(self): + return "".format(self) + + +class RelativeDistinguishedName(object): + def __init__(self, attributes): + attributes = list(attributes) + if not attributes: + raise ValueError("a relative distinguished name cannot be empty") + if not all(isinstance(x, NameAttribute) for x in attributes): + raise TypeError("attributes must be an iterable of NameAttribute") + + # Keep list and frozenset to preserve attribute order where it matters + self._attributes = attributes + self._attribute_set = frozenset(attributes) + + if len(self._attribute_set) != len(attributes): + raise ValueError("duplicate attributes are not allowed") + + def get_attributes_for_oid(self, oid): + return [i for i in self if i.oid == oid] + + def __eq__(self, other): + if not isinstance(other, RelativeDistinguishedName): + return NotImplemented + + return self._attribute_set == other._attribute_set + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(self._attribute_set) + + def __iter__(self): + return iter(self._attributes) + + def __len__(self): + return len(self._attributes) + + def __repr__(self): + return "".format(list(self)) + + +class Name(object): + def __init__(self, attributes): + attributes = list(attributes) + if all(isinstance(x, NameAttribute) for x in attributes): + self._attributes = [ + RelativeDistinguishedName([x]) for x in attributes + ] + elif all(isinstance(x, RelativeDistinguishedName) for x in attributes): + self._attributes = attributes + else: + raise TypeError( + "attributes must be a list of NameAttribute" + " or a list RelativeDistinguishedName" + ) + + def get_attributes_for_oid(self, oid): + return [i for i in self if i.oid == oid] + + @property + def rdns(self): + return self._attributes + + def public_bytes(self, backend): + return backend.x509_name_bytes(self) + + def __eq__(self, other): + if not isinstance(other, Name): + return NotImplemented + + return self._attributes == other._attributes + + def __ne__(self, other): + return not self == other + + def __hash__(self): + # TODO: this is relatively expensive, if this looks like a bottleneck + # for you, consider optimizing! + return hash(tuple(self._attributes)) + + def __iter__(self): + for rdn in self._attributes: + for ava in rdn: + yield ava + + def __len__(self): + return sum(len(rdn) for rdn in self._attributes) + + def __repr__(self): + return "".format(list(self)) diff --git a/venv/lib/python2.7/site-packages/cryptography/x509/oid.py b/venv/lib/python2.7/site-packages/cryptography/x509/oid.py new file mode 100644 index 0000000..90003d7 --- /dev/null +++ b/venv/lib/python2.7/site-packages/cryptography/x509/oid.py @@ -0,0 +1,271 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import utils +from cryptography.hazmat.primitives import hashes + + +class ObjectIdentifier(object): + def __init__(self, dotted_string): + self._dotted_string = dotted_string + + nodes = self._dotted_string.split(".") + intnodes = [] + + # There must be at least 2 nodes, the first node must be 0..2, and + # if less than 2, the second node cannot have a value outside the + # range 0..39. All nodes must be integers. + for node in nodes: + try: + intnodes.append(int(node, 0)) + except ValueError: + raise ValueError( + "Malformed OID: %s (non-integer nodes)" % ( + self._dotted_string)) + + if len(nodes) < 2: + raise ValueError( + "Malformed OID: %s (insufficient number of nodes)" % ( + self._dotted_string)) + + if intnodes[0] > 2: + raise ValueError( + "Malformed OID: %s (first node outside valid range)" % ( + self._dotted_string)) + + if intnodes[0] < 2 and intnodes[1] >= 40: + raise ValueError( + "Malformed OID: %s (second node outside valid range)" % ( + self._dotted_string)) + + def __eq__(self, other): + if not isinstance(other, ObjectIdentifier): + return NotImplemented + + return self.dotted_string == other.dotted_string + + def __ne__(self, other): + return not self == other + + def __repr__(self): + return "".format( + self.dotted_string, + self._name + ) + + def __hash__(self): + return hash(self.dotted_string) + + @property + def _name(self): + return _OID_NAMES.get(self, "Unknown OID") + + dotted_string = utils.read_only_property("_dotted_string") + + +class ExtensionOID(object): + SUBJECT_DIRECTORY_ATTRIBUTES = ObjectIdentifier("2.5.29.9") + SUBJECT_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.14") + KEY_USAGE = ObjectIdentifier("2.5.29.15") + SUBJECT_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.17") + ISSUER_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.18") + BASIC_CONSTRAINTS = ObjectIdentifier("2.5.29.19") + NAME_CONSTRAINTS = ObjectIdentifier("2.5.29.30") + CRL_DISTRIBUTION_POINTS = ObjectIdentifier("2.5.29.31") + CERTIFICATE_POLICIES = ObjectIdentifier("2.5.29.32") + POLICY_MAPPINGS = ObjectIdentifier("2.5.29.33") + AUTHORITY_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.35") + POLICY_CONSTRAINTS = ObjectIdentifier("2.5.29.36") + EXTENDED_KEY_USAGE = ObjectIdentifier("2.5.29.37") + FRESHEST_CRL = ObjectIdentifier("2.5.29.46") + INHIBIT_ANY_POLICY = ObjectIdentifier("2.5.29.54") + AUTHORITY_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.1") + SUBJECT_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.11") + OCSP_NO_CHECK = ObjectIdentifier("1.3.6.1.5.5.7.48.1.5") + TLS_FEATURE = ObjectIdentifier("1.3.6.1.5.5.7.1.24") + CRL_NUMBER = ObjectIdentifier("2.5.29.20") + DELTA_CRL_INDICATOR = ObjectIdentifier("2.5.29.27") + PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS = ( + ObjectIdentifier("1.3.6.1.4.1.11129.2.4.2") + ) + + +class CRLEntryExtensionOID(object): + CERTIFICATE_ISSUER = ObjectIdentifier("2.5.29.29") + CRL_REASON = ObjectIdentifier("2.5.29.21") + INVALIDITY_DATE = ObjectIdentifier("2.5.29.24") + + +class NameOID(object): + COMMON_NAME = ObjectIdentifier("2.5.4.3") + COUNTRY_NAME = ObjectIdentifier("2.5.4.6") + LOCALITY_NAME = ObjectIdentifier("2.5.4.7") + STATE_OR_PROVINCE_NAME = ObjectIdentifier("2.5.4.8") + STREET_ADDRESS = ObjectIdentifier("2.5.4.9") + ORGANIZATION_NAME = ObjectIdentifier("2.5.4.10") + ORGANIZATIONAL_UNIT_NAME = ObjectIdentifier("2.5.4.11") + SERIAL_NUMBER = ObjectIdentifier("2.5.4.5") + SURNAME = ObjectIdentifier("2.5.4.4") + GIVEN_NAME = ObjectIdentifier("2.5.4.42") + TITLE = ObjectIdentifier("2.5.4.12") + GENERATION_QUALIFIER = ObjectIdentifier("2.5.4.44") + X500_UNIQUE_IDENTIFIER = ObjectIdentifier("2.5.4.45") + DN_QUALIFIER = ObjectIdentifier("2.5.4.46") + PSEUDONYM = ObjectIdentifier("2.5.4.65") + USER_ID = ObjectIdentifier("0.9.2342.19200300.100.1.1") + DOMAIN_COMPONENT = ObjectIdentifier("0.9.2342.19200300.100.1.25") + EMAIL_ADDRESS = ObjectIdentifier("1.2.840.113549.1.9.1") + JURISDICTION_COUNTRY_NAME = ObjectIdentifier("1.3.6.1.4.1.311.60.2.1.3") + JURISDICTION_LOCALITY_NAME = ObjectIdentifier("1.3.6.1.4.1.311.60.2.1.1") + JURISDICTION_STATE_OR_PROVINCE_NAME = ObjectIdentifier( + "1.3.6.1.4.1.311.60.2.1.2" + ) + BUSINESS_CATEGORY = ObjectIdentifier("2.5.4.15") + POSTAL_ADDRESS = ObjectIdentifier("2.5.4.16") + POSTAL_CODE = ObjectIdentifier("2.5.4.17") + + +class SignatureAlgorithmOID(object): + RSA_WITH_MD5 = ObjectIdentifier("1.2.840.113549.1.1.4") + RSA_WITH_SHA1 = ObjectIdentifier("1.2.840.113549.1.1.5") + # This is an alternate OID for RSA with SHA1 that is occasionally seen + _RSA_WITH_SHA1 = ObjectIdentifier("1.3.14.3.2.29") + RSA_WITH_SHA224 = ObjectIdentifier("1.2.840.113549.1.1.14") + RSA_WITH_SHA256 = ObjectIdentifier("1.2.840.113549.1.1.11") + RSA_WITH_SHA384 = ObjectIdentifier("1.2.840.113549.1.1.12") + RSA_WITH_SHA512 = ObjectIdentifier("1.2.840.113549.1.1.13") + RSASSA_PSS = ObjectIdentifier("1.2.840.113549.1.1.10") + ECDSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10045.4.1") + ECDSA_WITH_SHA224 = ObjectIdentifier("1.2.840.10045.4.3.1") + ECDSA_WITH_SHA256 = ObjectIdentifier("1.2.840.10045.4.3.2") + ECDSA_WITH_SHA384 = ObjectIdentifier("1.2.840.10045.4.3.3") + ECDSA_WITH_SHA512 = ObjectIdentifier("1.2.840.10045.4.3.4") + DSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10040.4.3") + DSA_WITH_SHA224 = ObjectIdentifier("2.16.840.1.101.3.4.3.1") + DSA_WITH_SHA256 = ObjectIdentifier("2.16.840.1.101.3.4.3.2") + + +_SIG_OIDS_TO_HASH = { + SignatureAlgorithmOID.RSA_WITH_MD5: hashes.MD5(), + SignatureAlgorithmOID.RSA_WITH_SHA1: hashes.SHA1(), + SignatureAlgorithmOID._RSA_WITH_SHA1: hashes.SHA1(), + SignatureAlgorithmOID.RSA_WITH_SHA224: hashes.SHA224(), + SignatureAlgorithmOID.RSA_WITH_SHA256: hashes.SHA256(), + SignatureAlgorithmOID.RSA_WITH_SHA384: hashes.SHA384(), + SignatureAlgorithmOID.RSA_WITH_SHA512: hashes.SHA512(), + SignatureAlgorithmOID.ECDSA_WITH_SHA1: hashes.SHA1(), + SignatureAlgorithmOID.ECDSA_WITH_SHA224: hashes.SHA224(), + SignatureAlgorithmOID.ECDSA_WITH_SHA256: hashes.SHA256(), + SignatureAlgorithmOID.ECDSA_WITH_SHA384: hashes.SHA384(), + SignatureAlgorithmOID.ECDSA_WITH_SHA512: hashes.SHA512(), + SignatureAlgorithmOID.DSA_WITH_SHA1: hashes.SHA1(), + SignatureAlgorithmOID.DSA_WITH_SHA224: hashes.SHA224(), + SignatureAlgorithmOID.DSA_WITH_SHA256: hashes.SHA256() +} + + +class ExtendedKeyUsageOID(object): + SERVER_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.1") + CLIENT_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.2") + CODE_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.3") + EMAIL_PROTECTION = ObjectIdentifier("1.3.6.1.5.5.7.3.4") + TIME_STAMPING = ObjectIdentifier("1.3.6.1.5.5.7.3.8") + OCSP_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.9") + ANY_EXTENDED_KEY_USAGE = ObjectIdentifier("2.5.29.37.0") + + +class AuthorityInformationAccessOID(object): + CA_ISSUERS = ObjectIdentifier("1.3.6.1.5.5.7.48.2") + OCSP = ObjectIdentifier("1.3.6.1.5.5.7.48.1") + + +class CertificatePoliciesOID(object): + CPS_QUALIFIER = ObjectIdentifier("1.3.6.1.5.5.7.2.1") + CPS_USER_NOTICE = ObjectIdentifier("1.3.6.1.5.5.7.2.2") + ANY_POLICY = ObjectIdentifier("2.5.29.32.0") + + +_OID_NAMES = { + NameOID.COMMON_NAME: "commonName", + NameOID.COUNTRY_NAME: "countryName", + NameOID.LOCALITY_NAME: "localityName", + NameOID.STATE_OR_PROVINCE_NAME: "stateOrProvinceName", + NameOID.STREET_ADDRESS: "streetAddress", + NameOID.ORGANIZATION_NAME: "organizationName", + NameOID.ORGANIZATIONAL_UNIT_NAME: "organizationalUnitName", + NameOID.SERIAL_NUMBER: "serialNumber", + NameOID.SURNAME: "surname", + NameOID.GIVEN_NAME: "givenName", + NameOID.TITLE: "title", + NameOID.GENERATION_QUALIFIER: "generationQualifier", + NameOID.X500_UNIQUE_IDENTIFIER: "x500UniqueIdentifier", + NameOID.DN_QUALIFIER: "dnQualifier", + NameOID.PSEUDONYM: "pseudonym", + NameOID.USER_ID: "userID", + NameOID.DOMAIN_COMPONENT: "domainComponent", + NameOID.EMAIL_ADDRESS: "emailAddress", + NameOID.JURISDICTION_COUNTRY_NAME: "jurisdictionCountryName", + NameOID.JURISDICTION_LOCALITY_NAME: "jurisdictionLocalityName", + NameOID.JURISDICTION_STATE_OR_PROVINCE_NAME: ( + "jurisdictionStateOrProvinceName" + ), + NameOID.BUSINESS_CATEGORY: "businessCategory", + NameOID.POSTAL_ADDRESS: "postalAddress", + NameOID.POSTAL_CODE: "postalCode", + + SignatureAlgorithmOID.RSA_WITH_MD5: "md5WithRSAEncryption", + SignatureAlgorithmOID.RSA_WITH_SHA1: "sha1WithRSAEncryption", + SignatureAlgorithmOID.RSA_WITH_SHA224: "sha224WithRSAEncryption", + SignatureAlgorithmOID.RSA_WITH_SHA256: "sha256WithRSAEncryption", + SignatureAlgorithmOID.RSA_WITH_SHA384: "sha384WithRSAEncryption", + SignatureAlgorithmOID.RSA_WITH_SHA512: "sha512WithRSAEncryption", + SignatureAlgorithmOID.RSASSA_PSS: "RSASSA-PSS", + SignatureAlgorithmOID.ECDSA_WITH_SHA1: "ecdsa-with-SHA1", + SignatureAlgorithmOID.ECDSA_WITH_SHA224: "ecdsa-with-SHA224", + SignatureAlgorithmOID.ECDSA_WITH_SHA256: "ecdsa-with-SHA256", + SignatureAlgorithmOID.ECDSA_WITH_SHA384: "ecdsa-with-SHA384", + SignatureAlgorithmOID.ECDSA_WITH_SHA512: "ecdsa-with-SHA512", + SignatureAlgorithmOID.DSA_WITH_SHA1: "dsa-with-sha1", + SignatureAlgorithmOID.DSA_WITH_SHA224: "dsa-with-sha224", + SignatureAlgorithmOID.DSA_WITH_SHA256: "dsa-with-sha256", + ExtendedKeyUsageOID.SERVER_AUTH: "serverAuth", + ExtendedKeyUsageOID.CLIENT_AUTH: "clientAuth", + ExtendedKeyUsageOID.CODE_SIGNING: "codeSigning", + ExtendedKeyUsageOID.EMAIL_PROTECTION: "emailProtection", + ExtendedKeyUsageOID.TIME_STAMPING: "timeStamping", + ExtendedKeyUsageOID.OCSP_SIGNING: "OCSPSigning", + ExtensionOID.SUBJECT_DIRECTORY_ATTRIBUTES: "subjectDirectoryAttributes", + ExtensionOID.SUBJECT_KEY_IDENTIFIER: "subjectKeyIdentifier", + ExtensionOID.KEY_USAGE: "keyUsage", + ExtensionOID.SUBJECT_ALTERNATIVE_NAME: "subjectAltName", + ExtensionOID.ISSUER_ALTERNATIVE_NAME: "issuerAltName", + ExtensionOID.BASIC_CONSTRAINTS: "basicConstraints", + ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS: ( + "signedCertificateTimestampList" + ), + CRLEntryExtensionOID.CRL_REASON: "cRLReason", + CRLEntryExtensionOID.INVALIDITY_DATE: "invalidityDate", + CRLEntryExtensionOID.CERTIFICATE_ISSUER: "certificateIssuer", + ExtensionOID.NAME_CONSTRAINTS: "nameConstraints", + ExtensionOID.CRL_DISTRIBUTION_POINTS: "cRLDistributionPoints", + ExtensionOID.CERTIFICATE_POLICIES: "certificatePolicies", + ExtensionOID.POLICY_MAPPINGS: "policyMappings", + ExtensionOID.AUTHORITY_KEY_IDENTIFIER: "authorityKeyIdentifier", + ExtensionOID.POLICY_CONSTRAINTS: "policyConstraints", + ExtensionOID.EXTENDED_KEY_USAGE: "extendedKeyUsage", + ExtensionOID.FRESHEST_CRL: "freshestCRL", + ExtensionOID.INHIBIT_ANY_POLICY: "inhibitAnyPolicy", + ExtensionOID.AUTHORITY_INFORMATION_ACCESS: "authorityInfoAccess", + ExtensionOID.SUBJECT_INFORMATION_ACCESS: "subjectInfoAccess", + ExtensionOID.OCSP_NO_CHECK: "OCSPNoCheck", + ExtensionOID.CRL_NUMBER: "cRLNumber", + ExtensionOID.DELTA_CRL_INDICATOR: "deltaCRLIndicator", + ExtensionOID.TLS_FEATURE: "TLSFeature", + AuthorityInformationAccessOID.OCSP: "OCSP", + AuthorityInformationAccessOID.CA_ISSUERS: "caIssuers", + CertificatePoliciesOID.CPS_QUALIFIER: "id-qt-cps", + CertificatePoliciesOID.CPS_USER_NOTICE: "id-qt-unotice", +} diff --git a/venv/lib/python2.7/site-packages/easy_install.py b/venv/lib/python2.7/site-packages/easy_install.py new file mode 100644 index 0000000..d87e984 --- /dev/null +++ b/venv/lib/python2.7/site-packages/easy_install.py @@ -0,0 +1,5 @@ +"""Run the EasyInstall command""" + +if __name__ == '__main__': + from setuptools.command.easy_install import main + main() diff --git a/venv/lib/python2.7/site-packages/enum/LICENSE b/venv/lib/python2.7/site-packages/enum/LICENSE new file mode 100644 index 0000000..9003b88 --- /dev/null +++ b/venv/lib/python2.7/site-packages/enum/LICENSE @@ -0,0 +1,32 @@ +Copyright (c) 2013, Ethan Furman. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + + Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + Neither the name Ethan Furman nor the names of any + contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/lib/python2.7/site-packages/enum/README b/venv/lib/python2.7/site-packages/enum/README new file mode 100644 index 0000000..aa2333d --- /dev/null +++ b/venv/lib/python2.7/site-packages/enum/README @@ -0,0 +1,3 @@ +enum34 is the new Python stdlib enum module available in Python 3.4 +backported for previous versions of Python from 2.4 to 3.3. +tested on 2.6, 2.7, and 3.3+ diff --git a/venv/lib/python2.7/site-packages/enum/__init__.py b/venv/lib/python2.7/site-packages/enum/__init__.py new file mode 100644 index 0000000..d6ffb3a --- /dev/null +++ b/venv/lib/python2.7/site-packages/enum/__init__.py @@ -0,0 +1,837 @@ +"""Python Enumerations""" + +import sys as _sys + +__all__ = ['Enum', 'IntEnum', 'unique'] + +version = 1, 1, 6 + +pyver = float('%s.%s' % _sys.version_info[:2]) + +try: + any +except NameError: + def any(iterable): + for element in iterable: + if element: + return True + return False + +try: + from collections import OrderedDict +except ImportError: + OrderedDict = None + +try: + basestring +except NameError: + # In Python 2 basestring is the ancestor of both str and unicode + # in Python 3 it's just str, but was missing in 3.1 + basestring = str + +try: + unicode +except NameError: + # In Python 3 unicode no longer exists (it's just str) + unicode = str + +class _RouteClassAttributeToGetattr(object): + """Route attribute access on a class to __getattr__. + + This is a descriptor, used to define attributes that act differently when + accessed through an instance and through a class. Instance access remains + normal, but access to an attribute through a class will be routed to the + class's __getattr__ method; this is done by raising AttributeError. + + """ + def __init__(self, fget=None): + self.fget = fget + + def __get__(self, instance, ownerclass=None): + if instance is None: + raise AttributeError() + return self.fget(instance) + + def __set__(self, instance, value): + raise AttributeError("can't set attribute") + + def __delete__(self, instance): + raise AttributeError("can't delete attribute") + + +def _is_descriptor(obj): + """Returns True if obj is a descriptor, False otherwise.""" + return ( + hasattr(obj, '__get__') or + hasattr(obj, '__set__') or + hasattr(obj, '__delete__')) + + +def _is_dunder(name): + """Returns True if a __dunder__ name, False otherwise.""" + return (name[:2] == name[-2:] == '__' and + name[2:3] != '_' and + name[-3:-2] != '_' and + len(name) > 4) + + +def _is_sunder(name): + """Returns True if a _sunder_ name, False otherwise.""" + return (name[0] == name[-1] == '_' and + name[1:2] != '_' and + name[-2:-1] != '_' and + len(name) > 2) + + +def _make_class_unpicklable(cls): + """Make the given class un-picklable.""" + def _break_on_call_reduce(self, protocol=None): + raise TypeError('%r cannot be pickled' % self) + cls.__reduce_ex__ = _break_on_call_reduce + cls.__module__ = '' + + +class _EnumDict(dict): + """Track enum member order and ensure member names are not reused. + + EnumMeta will use the names found in self._member_names as the + enumeration member names. + + """ + def __init__(self): + super(_EnumDict, self).__init__() + self._member_names = [] + + def __setitem__(self, key, value): + """Changes anything not dundered or not a descriptor. + + If a descriptor is added with the same name as an enum member, the name + is removed from _member_names (this may leave a hole in the numerical + sequence of values). + + If an enum member name is used twice, an error is raised; duplicate + values are not checked for. + + Single underscore (sunder) names are reserved. + + Note: in 3.x __order__ is simply discarded as a not necessary piece + leftover from 2.x + + """ + if pyver >= 3.0 and key in ('_order_', '__order__'): + return + elif key == '__order__': + key = '_order_' + if _is_sunder(key): + if key != '_order_': + raise ValueError('_names_ are reserved for future Enum use') + elif _is_dunder(key): + pass + elif key in self._member_names: + # descriptor overwriting an enum? + raise TypeError('Attempted to reuse key: %r' % key) + elif not _is_descriptor(value): + if key in self: + # enum overwriting a descriptor? + raise TypeError('Key already defined as: %r' % self[key]) + self._member_names.append(key) + super(_EnumDict, self).__setitem__(key, value) + + +# Dummy value for Enum as EnumMeta explicity checks for it, but of course until +# EnumMeta finishes running the first time the Enum class doesn't exist. This +# is also why there are checks in EnumMeta like `if Enum is not None` +Enum = None + + +class EnumMeta(type): + """Metaclass for Enum""" + @classmethod + def __prepare__(metacls, cls, bases): + return _EnumDict() + + def __new__(metacls, cls, bases, classdict): + # an Enum class is final once enumeration items have been defined; it + # cannot be mixed with other types (int, float, etc.) if it has an + # inherited __new__ unless a new __new__ is defined (or the resulting + # class will fail). + if type(classdict) is dict: + original_dict = classdict + classdict = _EnumDict() + for k, v in original_dict.items(): + classdict[k] = v + + member_type, first_enum = metacls._get_mixins_(bases) + __new__, save_new, use_args = metacls._find_new_(classdict, member_type, + first_enum) + # save enum items into separate mapping so they don't get baked into + # the new class + members = dict((k, classdict[k]) for k in classdict._member_names) + for name in classdict._member_names: + del classdict[name] + + # py2 support for definition order + _order_ = classdict.get('_order_') + if _order_ is None: + if pyver < 3.0: + try: + _order_ = [name for (name, value) in sorted(members.items(), key=lambda item: item[1])] + except TypeError: + _order_ = [name for name in sorted(members.keys())] + else: + _order_ = classdict._member_names + else: + del classdict['_order_'] + if pyver < 3.0: + _order_ = _order_.replace(',', ' ').split() + aliases = [name for name in members if name not in _order_] + _order_ += aliases + + # check for illegal enum names (any others?) + invalid_names = set(members) & set(['mro']) + if invalid_names: + raise ValueError('Invalid enum member name(s): %s' % ( + ', '.join(invalid_names), )) + + # save attributes from super classes so we know if we can take + # the shortcut of storing members in the class dict + base_attributes = set([a for b in bases for a in b.__dict__]) + # create our new Enum type + enum_class = super(EnumMeta, metacls).__new__(metacls, cls, bases, classdict) + enum_class._member_names_ = [] # names in random order + if OrderedDict is not None: + enum_class._member_map_ = OrderedDict() + else: + enum_class._member_map_ = {} # name->value map + enum_class._member_type_ = member_type + + # Reverse value->name map for hashable values. + enum_class._value2member_map_ = {} + + # instantiate them, checking for duplicates as we go + # we instantiate first instead of checking for duplicates first in case + # a custom __new__ is doing something funky with the values -- such as + # auto-numbering ;) + if __new__ is None: + __new__ = enum_class.__new__ + for member_name in _order_: + value = members[member_name] + if not isinstance(value, tuple): + args = (value, ) + else: + args = value + if member_type is tuple: # special case for tuple enums + args = (args, ) # wrap it one more time + if not use_args or not args: + enum_member = __new__(enum_class) + if not hasattr(enum_member, '_value_'): + enum_member._value_ = value + else: + enum_member = __new__(enum_class, *args) + if not hasattr(enum_member, '_value_'): + enum_member._value_ = member_type(*args) + value = enum_member._value_ + enum_member._name_ = member_name + enum_member.__objclass__ = enum_class + enum_member.__init__(*args) + # If another member with the same value was already defined, the + # new member becomes an alias to the existing one. + for name, canonical_member in enum_class._member_map_.items(): + if canonical_member.value == enum_member._value_: + enum_member = canonical_member + break + else: + # Aliases don't appear in member names (only in __members__). + enum_class._member_names_.append(member_name) + # performance boost for any member that would not shadow + # a DynamicClassAttribute (aka _RouteClassAttributeToGetattr) + if member_name not in base_attributes: + setattr(enum_class, member_name, enum_member) + # now add to _member_map_ + enum_class._member_map_[member_name] = enum_member + try: + # This may fail if value is not hashable. We can't add the value + # to the map, and by-value lookups for this value will be + # linear. + enum_class._value2member_map_[value] = enum_member + except TypeError: + pass + + + # If a custom type is mixed into the Enum, and it does not know how + # to pickle itself, pickle.dumps will succeed but pickle.loads will + # fail. Rather than have the error show up later and possibly far + # from the source, sabotage the pickle protocol for this class so + # that pickle.dumps also fails. + # + # However, if the new class implements its own __reduce_ex__, do not + # sabotage -- it's on them to make sure it works correctly. We use + # __reduce_ex__ instead of any of the others as it is preferred by + # pickle over __reduce__, and it handles all pickle protocols. + unpicklable = False + if '__reduce_ex__' not in classdict: + if member_type is not object: + methods = ('__getnewargs_ex__', '__getnewargs__', + '__reduce_ex__', '__reduce__') + if not any(m in member_type.__dict__ for m in methods): + _make_class_unpicklable(enum_class) + unpicklable = True + + + # double check that repr and friends are not the mixin's or various + # things break (such as pickle) + for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'): + class_method = getattr(enum_class, name) + obj_method = getattr(member_type, name, None) + enum_method = getattr(first_enum, name, None) + if name not in classdict and class_method is not enum_method: + if name == '__reduce_ex__' and unpicklable: + continue + setattr(enum_class, name, enum_method) + + # method resolution and int's are not playing nice + # Python's less than 2.6 use __cmp__ + + if pyver < 2.6: + + if issubclass(enum_class, int): + setattr(enum_class, '__cmp__', getattr(int, '__cmp__')) + + elif pyver < 3.0: + + if issubclass(enum_class, int): + for method in ( + '__le__', + '__lt__', + '__gt__', + '__ge__', + '__eq__', + '__ne__', + '__hash__', + ): + setattr(enum_class, method, getattr(int, method)) + + # replace any other __new__ with our own (as long as Enum is not None, + # anyway) -- again, this is to support pickle + if Enum is not None: + # if the user defined their own __new__, save it before it gets + # clobbered in case they subclass later + if save_new: + setattr(enum_class, '__member_new__', enum_class.__dict__['__new__']) + setattr(enum_class, '__new__', Enum.__dict__['__new__']) + return enum_class + + def __bool__(cls): + """ + classes/types should always be True. + """ + return True + + def __call__(cls, value, names=None, module=None, type=None, start=1): + """Either returns an existing member, or creates a new enum class. + + This method is used both when an enum class is given a value to match + to an enumeration member (i.e. Color(3)) and for the functional API + (i.e. Color = Enum('Color', names='red green blue')). + + When used for the functional API: `module`, if set, will be stored in + the new class' __module__ attribute; `type`, if set, will be mixed in + as the first base class. + + Note: if `module` is not set this routine will attempt to discover the + calling module by walking the frame stack; if this is unsuccessful + the resulting class will not be pickleable. + + """ + if names is None: # simple value lookup + return cls.__new__(cls, value) + # otherwise, functional API: we're creating a new Enum type + return cls._create_(value, names, module=module, type=type, start=start) + + def __contains__(cls, member): + return isinstance(member, cls) and member.name in cls._member_map_ + + def __delattr__(cls, attr): + # nicer error message when someone tries to delete an attribute + # (see issue19025). + if attr in cls._member_map_: + raise AttributeError( + "%s: cannot delete Enum member." % cls.__name__) + super(EnumMeta, cls).__delattr__(attr) + + def __dir__(self): + return (['__class__', '__doc__', '__members__', '__module__'] + + self._member_names_) + + @property + def __members__(cls): + """Returns a mapping of member name->value. + + This mapping lists all enum members, including aliases. Note that this + is a copy of the internal mapping. + + """ + return cls._member_map_.copy() + + def __getattr__(cls, name): + """Return the enum member matching `name` + + We use __getattr__ instead of descriptors or inserting into the enum + class' __dict__ in order to support `name` and `value` being both + properties for enum members (which live in the class' __dict__) and + enum members themselves. + + """ + if _is_dunder(name): + raise AttributeError(name) + try: + return cls._member_map_[name] + except KeyError: + raise AttributeError(name) + + def __getitem__(cls, name): + return cls._member_map_[name] + + def __iter__(cls): + return (cls._member_map_[name] for name in cls._member_names_) + + def __reversed__(cls): + return (cls._member_map_[name] for name in reversed(cls._member_names_)) + + def __len__(cls): + return len(cls._member_names_) + + __nonzero__ = __bool__ + + def __repr__(cls): + return "" % cls.__name__ + + def __setattr__(cls, name, value): + """Block attempts to reassign Enum members. + + A simple assignment to the class namespace only changes one of the + several possible ways to get an Enum member from the Enum class, + resulting in an inconsistent Enumeration. + + """ + member_map = cls.__dict__.get('_member_map_', {}) + if name in member_map: + raise AttributeError('Cannot reassign members.') + super(EnumMeta, cls).__setattr__(name, value) + + def _create_(cls, class_name, names=None, module=None, type=None, start=1): + """Convenience method to create a new Enum class. + + `names` can be: + + * A string containing member names, separated either with spaces or + commas. Values are auto-numbered from 1. + * An iterable of member names. Values are auto-numbered from 1. + * An iterable of (member name, value) pairs. + * A mapping of member name -> value. + + """ + if pyver < 3.0: + # if class_name is unicode, attempt a conversion to ASCII + if isinstance(class_name, unicode): + try: + class_name = class_name.encode('ascii') + except UnicodeEncodeError: + raise TypeError('%r is not representable in ASCII' % class_name) + metacls = cls.__class__ + if type is None: + bases = (cls, ) + else: + bases = (type, cls) + classdict = metacls.__prepare__(class_name, bases) + _order_ = [] + + # special processing needed for names? + if isinstance(names, basestring): + names = names.replace(',', ' ').split() + if isinstance(names, (tuple, list)) and isinstance(names[0], basestring): + names = [(e, i+start) for (i, e) in enumerate(names)] + + # Here, names is either an iterable of (name, value) or a mapping. + item = None # in case names is empty + for item in names: + if isinstance(item, basestring): + member_name, member_value = item, names[item] + else: + member_name, member_value = item + classdict[member_name] = member_value + _order_.append(member_name) + # only set _order_ in classdict if name/value was not from a mapping + if not isinstance(item, basestring): + classdict['_order_'] = ' '.join(_order_) + enum_class = metacls.__new__(metacls, class_name, bases, classdict) + + # TODO: replace the frame hack if a blessed way to know the calling + # module is ever developed + if module is None: + try: + module = _sys._getframe(2).f_globals['__name__'] + except (AttributeError, ValueError): + pass + if module is None: + _make_class_unpicklable(enum_class) + else: + enum_class.__module__ = module + + return enum_class + + @staticmethod + def _get_mixins_(bases): + """Returns the type for creating enum members, and the first inherited + enum class. + + bases: the tuple of bases that was given to __new__ + + """ + if not bases or Enum is None: + return object, Enum + + + # double check that we are not subclassing a class with existing + # enumeration members; while we're at it, see if any other data + # type has been mixed in so we can use the correct __new__ + member_type = first_enum = None + for base in bases: + if (base is not Enum and + issubclass(base, Enum) and + base._member_names_): + raise TypeError("Cannot extend enumerations") + # base is now the last base in bases + if not issubclass(base, Enum): + raise TypeError("new enumerations must be created as " + "`ClassName([mixin_type,] enum_type)`") + + # get correct mix-in type (either mix-in type of Enum subclass, or + # first base if last base is Enum) + if not issubclass(bases[0], Enum): + member_type = bases[0] # first data type + first_enum = bases[-1] # enum type + else: + for base in bases[0].__mro__: + # most common: (IntEnum, int, Enum, object) + # possible: (, , + # , , + # ) + if issubclass(base, Enum): + if first_enum is None: + first_enum = base + else: + if member_type is None: + member_type = base + + return member_type, first_enum + + if pyver < 3.0: + @staticmethod + def _find_new_(classdict, member_type, first_enum): + """Returns the __new__ to be used for creating the enum members. + + classdict: the class dictionary given to __new__ + member_type: the data type whose __new__ will be used by default + first_enum: enumeration to check for an overriding __new__ + + """ + # now find the correct __new__, checking to see of one was defined + # by the user; also check earlier enum classes in case a __new__ was + # saved as __member_new__ + __new__ = classdict.get('__new__', None) + if __new__: + return None, True, True # __new__, save_new, use_args + + N__new__ = getattr(None, '__new__') + O__new__ = getattr(object, '__new__') + if Enum is None: + E__new__ = N__new__ + else: + E__new__ = Enum.__dict__['__new__'] + # check all possibles for __member_new__ before falling back to + # __new__ + for method in ('__member_new__', '__new__'): + for possible in (member_type, first_enum): + try: + target = possible.__dict__[method] + except (AttributeError, KeyError): + target = getattr(possible, method, None) + if target not in [ + None, + N__new__, + O__new__, + E__new__, + ]: + if method == '__member_new__': + classdict['__new__'] = target + return None, False, True + if isinstance(target, staticmethod): + target = target.__get__(member_type) + __new__ = target + break + if __new__ is not None: + break + else: + __new__ = object.__new__ + + # if a non-object.__new__ is used then whatever value/tuple was + # assigned to the enum member name will be passed to __new__ and to the + # new enum member's __init__ + if __new__ is object.__new__: + use_args = False + else: + use_args = True + + return __new__, False, use_args + else: + @staticmethod + def _find_new_(classdict, member_type, first_enum): + """Returns the __new__ to be used for creating the enum members. + + classdict: the class dictionary given to __new__ + member_type: the data type whose __new__ will be used by default + first_enum: enumeration to check for an overriding __new__ + + """ + # now find the correct __new__, checking to see of one was defined + # by the user; also check earlier enum classes in case a __new__ was + # saved as __member_new__ + __new__ = classdict.get('__new__', None) + + # should __new__ be saved as __member_new__ later? + save_new = __new__ is not None + + if __new__ is None: + # check all possibles for __member_new__ before falling back to + # __new__ + for method in ('__member_new__', '__new__'): + for possible in (member_type, first_enum): + target = getattr(possible, method, None) + if target not in ( + None, + None.__new__, + object.__new__, + Enum.__new__, + ): + __new__ = target + break + if __new__ is not None: + break + else: + __new__ = object.__new__ + + # if a non-object.__new__ is used then whatever value/tuple was + # assigned to the enum member name will be passed to __new__ and to the + # new enum member's __init__ + if __new__ is object.__new__: + use_args = False + else: + use_args = True + + return __new__, save_new, use_args + + +######################################################## +# In order to support Python 2 and 3 with a single +# codebase we have to create the Enum methods separately +# and then use the `type(name, bases, dict)` method to +# create the class. +######################################################## +temp_enum_dict = {} +temp_enum_dict['__doc__'] = "Generic enumeration.\n\n Derive from this class to define new enumerations.\n\n" + +def __new__(cls, value): + # all enum instances are actually created during class construction + # without calling this method; this method is called by the metaclass' + # __call__ (i.e. Color(3) ), and by pickle + if type(value) is cls: + # For lookups like Color(Color.red) + value = value.value + #return value + # by-value search for a matching enum member + # see if it's in the reverse mapping (for hashable values) + try: + if value in cls._value2member_map_: + return cls._value2member_map_[value] + except TypeError: + # not there, now do long search -- O(n) behavior + for member in cls._member_map_.values(): + if member.value == value: + return member + raise ValueError("%s is not a valid %s" % (value, cls.__name__)) +temp_enum_dict['__new__'] = __new__ +del __new__ + +def __repr__(self): + return "<%s.%s: %r>" % ( + self.__class__.__name__, self._name_, self._value_) +temp_enum_dict['__repr__'] = __repr__ +del __repr__ + +def __str__(self): + return "%s.%s" % (self.__class__.__name__, self._name_) +temp_enum_dict['__str__'] = __str__ +del __str__ + +if pyver >= 3.0: + def __dir__(self): + added_behavior = [ + m + for cls in self.__class__.mro() + for m in cls.__dict__ + if m[0] != '_' and m not in self._member_map_ + ] + return (['__class__', '__doc__', '__module__', ] + added_behavior) + temp_enum_dict['__dir__'] = __dir__ + del __dir__ + +def __format__(self, format_spec): + # mixed-in Enums should use the mixed-in type's __format__, otherwise + # we can get strange results with the Enum name showing up instead of + # the value + + # pure Enum branch + if self._member_type_ is object: + cls = str + val = str(self) + # mix-in branch + else: + cls = self._member_type_ + val = self.value + return cls.__format__(val, format_spec) +temp_enum_dict['__format__'] = __format__ +del __format__ + + +#################################### +# Python's less than 2.6 use __cmp__ + +if pyver < 2.6: + + def __cmp__(self, other): + if type(other) is self.__class__: + if self is other: + return 0 + return -1 + return NotImplemented + raise TypeError("unorderable types: %s() and %s()" % (self.__class__.__name__, other.__class__.__name__)) + temp_enum_dict['__cmp__'] = __cmp__ + del __cmp__ + +else: + + def __le__(self, other): + raise TypeError("unorderable types: %s() <= %s()" % (self.__class__.__name__, other.__class__.__name__)) + temp_enum_dict['__le__'] = __le__ + del __le__ + + def __lt__(self, other): + raise TypeError("unorderable types: %s() < %s()" % (self.__class__.__name__, other.__class__.__name__)) + temp_enum_dict['__lt__'] = __lt__ + del __lt__ + + def __ge__(self, other): + raise TypeError("unorderable types: %s() >= %s()" % (self.__class__.__name__, other.__class__.__name__)) + temp_enum_dict['__ge__'] = __ge__ + del __ge__ + + def __gt__(self, other): + raise TypeError("unorderable types: %s() > %s()" % (self.__class__.__name__, other.__class__.__name__)) + temp_enum_dict['__gt__'] = __gt__ + del __gt__ + + +def __eq__(self, other): + if type(other) is self.__class__: + return self is other + return NotImplemented +temp_enum_dict['__eq__'] = __eq__ +del __eq__ + +def __ne__(self, other): + if type(other) is self.__class__: + return self is not other + return NotImplemented +temp_enum_dict['__ne__'] = __ne__ +del __ne__ + +def __hash__(self): + return hash(self._name_) +temp_enum_dict['__hash__'] = __hash__ +del __hash__ + +def __reduce_ex__(self, proto): + return self.__class__, (self._value_, ) +temp_enum_dict['__reduce_ex__'] = __reduce_ex__ +del __reduce_ex__ + +# _RouteClassAttributeToGetattr is used to provide access to the `name` +# and `value` properties of enum members while keeping some measure of +# protection from modification, while still allowing for an enumeration +# to have members named `name` and `value`. This works because enumeration +# members are not set directly on the enum class -- __getattr__ is +# used to look them up. + +@_RouteClassAttributeToGetattr +def name(self): + return self._name_ +temp_enum_dict['name'] = name +del name + +@_RouteClassAttributeToGetattr +def value(self): + return self._value_ +temp_enum_dict['value'] = value +del value + +@classmethod +def _convert(cls, name, module, filter, source=None): + """ + Create a new Enum subclass that replaces a collection of global constants + """ + # convert all constants from source (or module) that pass filter() to + # a new Enum called name, and export the enum and its members back to + # module; + # also, replace the __reduce_ex__ method so unpickling works in + # previous Python versions + module_globals = vars(_sys.modules[module]) + if source: + source = vars(source) + else: + source = module_globals + members = dict((name, value) for name, value in source.items() if filter(name)) + cls = cls(name, members, module=module) + cls.__reduce_ex__ = _reduce_ex_by_name + module_globals.update(cls.__members__) + module_globals[name] = cls + return cls +temp_enum_dict['_convert'] = _convert +del _convert + +Enum = EnumMeta('Enum', (object, ), temp_enum_dict) +del temp_enum_dict + +# Enum has now been created +########################### + +class IntEnum(int, Enum): + """Enum where members are also (and must be) ints""" + +def _reduce_ex_by_name(self, proto): + return self.name + +def unique(enumeration): + """Class decorator that ensures only unique members exist in an enumeration.""" + duplicates = [] + for name, member in enumeration.__members__.items(): + if name != member.name: + duplicates.append((name, member.name)) + if duplicates: + duplicate_names = ', '.join( + ["%s -> %s" % (alias, name) for (alias, name) in duplicates] + ) + raise ValueError('duplicate names found in %r: %s' % + (enumeration, duplicate_names) + ) + return enumeration diff --git a/venv/lib/python2.7/site-packages/enum34-1.1.6.dist-info/DESCRIPTION.rst b/venv/lib/python2.7/site-packages/enum34-1.1.6.dist-info/DESCRIPTION.rst new file mode 100644 index 0000000..ff89b8d --- /dev/null +++ b/venv/lib/python2.7/site-packages/enum34-1.1.6.dist-info/DESCRIPTION.rst @@ -0,0 +1,41 @@ +enum --- support for enumerations +======================================== + +An enumeration is a set of symbolic names (members) bound to unique, constant +values. Within an enumeration, the members can be compared by identity, and +the enumeration itself can be iterated over. + + from enum import Enum + + class Fruit(Enum): + apple = 1 + banana = 2 + orange = 3 + + list(Fruit) + # [, , ] + + len(Fruit) + # 3 + + Fruit.banana + # + + Fruit['banana'] + # + + Fruit(2) + # + + Fruit.banana is Fruit['banana'] is Fruit(2) + # True + + Fruit.banana.name + # 'banana' + + Fruit.banana.value + # 2 + +Repository and Issue Tracker at https://bitbucket.org/stoneleaf/enum34. + + diff --git a/venv/lib/python2.7/site-packages/enum34-1.1.6.dist-info/INSTALLER b/venv/lib/python2.7/site-packages/enum34-1.1.6.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python2.7/site-packages/enum34-1.1.6.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python2.7/site-packages/enum34-1.1.6.dist-info/METADATA b/venv/lib/python2.7/site-packages/enum34-1.1.6.dist-info/METADATA new file mode 100644 index 0000000..49ee3e5 --- /dev/null +++ b/venv/lib/python2.7/site-packages/enum34-1.1.6.dist-info/METADATA @@ -0,0 +1,64 @@ +Metadata-Version: 2.0 +Name: enum34 +Version: 1.1.6 +Summary: Python 3.4 Enum backported to 3.3, 3.2, 3.1, 2.7, 2.6, 2.5, and 2.4 +Home-page: https://bitbucket.org/stoneleaf/enum34 +Author: Ethan Furman +Author-email: ethan@stoneleaf.us +License: BSD License +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Programming Language :: Python +Classifier: Topic :: Software Development +Classifier: Programming Language :: Python :: 2.4 +Classifier: Programming Language :: Python :: 2.5 +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Provides: enum + +enum --- support for enumerations +======================================== + +An enumeration is a set of symbolic names (members) bound to unique, constant +values. Within an enumeration, the members can be compared by identity, and +the enumeration itself can be iterated over. + + from enum import Enum + + class Fruit(Enum): + apple = 1 + banana = 2 + orange = 3 + + list(Fruit) + # [, , ] + + len(Fruit) + # 3 + + Fruit.banana + # + + Fruit['banana'] + # + + Fruit(2) + # + + Fruit.banana is Fruit['banana'] is Fruit(2) + # True + + Fruit.banana.name + # 'banana' + + Fruit.banana.value + # 2 + +Repository and Issue Tracker at https://bitbucket.org/stoneleaf/enum34. + + diff --git a/venv/lib/python2.7/site-packages/enum34-1.1.6.dist-info/RECORD b/venv/lib/python2.7/site-packages/enum34-1.1.6.dist-info/RECORD new file mode 100644 index 0000000..7be1808 --- /dev/null +++ b/venv/lib/python2.7/site-packages/enum34-1.1.6.dist-info/RECORD @@ -0,0 +1,11 @@ +enum/LICENSE,sha256=iOxqbI6vo7l1fnRXg5OL7z9eTV48drHbV2qjq1IOXh0,1508 +enum/README,sha256=fyStyG6c3wxR2bHyZhLPNtc_ASDxGw-l8G6LzVxmkig,157 +enum/__init__.py,sha256=JSdYSXeZ1QSp67gjfI24quiePPtrlNXhXvm-pav8nuQ,31054 +enum34-1.1.6.dist-info/DESCRIPTION.rst,sha256=d1LpTdx9M07jJN0AmT-p6AAwLrX2guxOfmetcp_jljY,817 +enum34-1.1.6.dist-info/METADATA,sha256=p3ABlAtPlmU7-55UMHiwAd8o-wwS4EfZMsQWNoH1klg,1689 +enum34-1.1.6.dist-info/RECORD,, +enum34-1.1.6.dist-info/WHEEL,sha256=bee59qcPjkyXfMaxNWjl2CGotqfumWx9pC1hlVLr2mM,92 +enum34-1.1.6.dist-info/metadata.json,sha256=1su5Y0gBxpWTAdey-06LrBSQzh-B1vAixlBxx4DJMOI,972 +enum34-1.1.6.dist-info/top_level.txt,sha256=jayVFfXRwPLUdgRN9GzacnFrOtEKQaAScXIY8mwgP8g,5 +enum34-1.1.6.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +enum/__init__.pyc,, diff --git a/venv/lib/python2.7/site-packages/enum34-1.1.6.dist-info/WHEEL b/venv/lib/python2.7/site-packages/enum34-1.1.6.dist-info/WHEEL new file mode 100644 index 0000000..511d954 --- /dev/null +++ b/venv/lib/python2.7/site-packages/enum34-1.1.6.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.29.0) +Root-Is-Purelib: true +Tag: py2-none-any + diff --git a/venv/lib/python2.7/site-packages/enum34-1.1.6.dist-info/metadata.json b/venv/lib/python2.7/site-packages/enum34-1.1.6.dist-info/metadata.json new file mode 100644 index 0000000..6a1cc20 --- /dev/null +++ b/venv/lib/python2.7/site-packages/enum34-1.1.6.dist-info/metadata.json @@ -0,0 +1 @@ +{"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Programming Language :: Python", "Topic :: Software Development", "Programming Language :: Python :: 2.4", "Programming Language :: Python :: 2.5", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5"], "extensions": {"python.details": {"contacts": [{"email": "ethan@stoneleaf.us", "name": "Ethan Furman", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://bitbucket.org/stoneleaf/enum34"}}}, "generator": "bdist_wheel (0.29.0)", "license": "BSD License", "metadata_version": "2.0", "name": "enum34", "provides": "enum", "summary": "Python 3.4 Enum backported to 3.3, 3.2, 3.1, 2.7, 2.6, 2.5, and 2.4", "version": "1.1.6"} \ No newline at end of file diff --git a/venv/lib/python2.7/site-packages/enum34-1.1.6.dist-info/top_level.txt b/venv/lib/python2.7/site-packages/enum34-1.1.6.dist-info/top_level.txt new file mode 100644 index 0000000..e3caefb --- /dev/null +++ b/venv/lib/python2.7/site-packages/enum34-1.1.6.dist-info/top_level.txt @@ -0,0 +1 @@ +enum diff --git a/venv/lib/python2.7/site-packages/exifread/__init__.py b/venv/lib/python2.7/site-packages/exifread/__init__.py new file mode 100644 index 0000000..3c18720 --- /dev/null +++ b/venv/lib/python2.7/site-packages/exifread/__init__.py @@ -0,0 +1,262 @@ +""" +Read Exif metadata from tiff and jpeg files. +""" + +from .exif_log import get_logger +from .classes import * +from .tags import * +from .utils import ord_ + +__version__ = '2.1.2' + +logger = get_logger() + + +def increment_base(data, base): + return ord_(data[base + 2]) * 256 + ord_(data[base + 3]) + 2 + + +def process_file(f, stop_tag=DEFAULT_STOP_TAG, details=True, strict=False, debug=False): + """ + Process an image file (expects an open file object). + + This is the function that has to deal with all the arbitrary nasty bits + of the EXIF standard. + """ + + # by default do not fake an EXIF beginning + fake_exif = 0 + + # determine whether it's a JPEG or TIFF + data = f.read(12) + if data[0:4] in [b'II*\x00', b'MM\x00*']: + # it's a TIFF file + logger.debug("TIFF format recognized in data[0:4]") + f.seek(0) + endian = f.read(1) + f.read(1) + offset = 0 + elif data[0:2] == b'\xFF\xD8': + # it's a JPEG file + logger.debug("JPEG format recognized data[0:2]=0x%X%X", ord_(data[0]), ord_(data[1])) + base = 2 + logger.debug("data[2]=0x%X data[3]=0x%X data[6:10]=%s", + ord_(data[2]), ord_(data[3]), data[6:10]) + while ord_(data[2]) == 0xFF and data[6:10] in (b'JFIF', b'JFXX', b'OLYM', b'Phot'): + length = ord_(data[4]) * 256 + ord_(data[5]) + logger.debug(" Length offset is %s", length) + f.read(length - 8) + # fake an EXIF beginning of file + # I don't think this is used. --gd + data = b'\xFF\x00' + f.read(10) + fake_exif = 1 + if base > 2: + logger.debug(" Added to base") + base = base + length + 4 - 2 + else: + logger.debug(" Added to zero") + base = length + 4 + logger.debug(" Set segment base to 0x%X", base) + + # Big ugly patch to deal with APP2 (or other) data coming before APP1 + f.seek(0) + # in theory, this could be insufficient since 64K is the maximum size--gd + data = f.read(base + 4000) + # base = 2 + while 1: + logger.debug(" Segment base 0x%X", base) + if data[base:base + 2] == b'\xFF\xE1': + # APP1 + logger.debug(" APP1 at base 0x%X", base) + logger.debug(" Length: 0x%X 0x%X", ord_(data[base + 2]), + ord_(data[base + 3])) + logger.debug(" Code: %s", data[base + 4:base + 8]) + if data[base + 4:base + 8] == b"Exif": + logger.debug(" Decrement base by 2 to get to pre-segment header (for compatibility with later code)") + base -= 2 + break + increment = increment_base(data, base) + logger.debug(" Increment base by %s", increment) + base += increment + elif data[base:base + 2] == b'\xFF\xE0': + # APP0 + logger.debug(" APP0 at base 0x%X", base) + logger.debug(" Length: 0x%X 0x%X", ord_(data[base + 2]), + ord_(data[base + 3])) + logger.debug(" Code: %s", data[base + 4:base + 8]) + increment = increment_base(data, base) + logger.debug(" Increment base by %s", increment) + base += increment + elif data[base:base + 2] == b'\xFF\xE2': + # APP2 + logger.debug(" APP2 at base 0x%X", base) + logger.debug(" Length: 0x%X 0x%X", ord_(data[base + 2]), + ord_(data[base + 3])) + logger.debug(" Code: %s", data[base + 4:base + 8]) + increment = increment_base(data, base) + logger.debug(" Increment base by %s", increment) + base += increment + elif data[base:base + 2] == b'\xFF\xEE': + # APP14 + logger.debug(" APP14 Adobe segment at base 0x%X", base) + logger.debug(" Length: 0x%X 0x%X", ord_(data[base + 2]), + ord_(data[base + 3])) + logger.debug(" Code: %s", data[base + 4:base + 8]) + increment = increment_base(data, base) + logger.debug(" Increment base by %s", increment) + base += increment + logger.debug(" There is useful EXIF-like data here, but we have no parser for it.") + elif data[base:base + 2] == b'\xFF\xDB': + logger.debug(" JPEG image data at base 0x%X No more segments are expected.", + base) + break + elif data[base:base + 2] == b'\xFF\xD8': + # APP12 + logger.debug(" FFD8 segment at base 0x%X", base) + logger.debug(" Got 0x%X 0x%X and %s instead", + ord_(data[base]), + ord_(data[base + 1]), + data[4 + base:10 + base]) + logger.debug(" Length: 0x%X 0x%X", ord_(data[base + 2]), + ord_(data[base + 3])) + logger.debug(" Code: %s", data[base + 4:base + 8]) + increment = increment_base(data, base) + logger.debug(" Increment base by %s", increment) + base += increment + elif data[base:base + 2] == b'\xFF\xEC': + # APP12 + logger.debug(" APP12 XMP (Ducky) or Pictureinfo segment at base 0x%X", + base) + logger.debug(" Got 0x%X and 0x%X instead", ord_(data[base]), + ord_(data[base + 1])) + logger.debug(" Length: 0x%X 0x%X", + ord_(data[base + 2]), + ord_(data[base + 3])) + logger.debug("Code: %s", data[base + 4:base + 8]) + increment = increment_base(data, base) + logger.debug(" Increment base by %s", increment) + base += increment + logger.debug( + " There is useful EXIF-like data here (quality, comment, copyright), but we have no parser for it.") + else: + try: + increment = increment_base(data, base) + logger.debug(" Got 0x%X and 0x%X instead", + ord_(data[base]), + ord_(data[base + 1])) + except IndexError: + logger.debug(" Unexpected/unhandled segment type or file content.") + return {} + else: + logger.debug(" Increment base by %s", increment) + base += increment + f.seek(base + 12) + if ord_(data[2 + base]) == 0xFF and data[6 + base:10 + base] == b'Exif': + # detected EXIF header + offset = f.tell() + endian = f.read(1) + #HACK TEST: endian = 'M' + elif ord_(data[2 + base]) == 0xFF and data[6 + base:10 + base + 1] == b'Ducky': + # detected Ducky header. + logger.debug("EXIF-like header (normally 0xFF and code): 0x%X and %s", + ord_(data[2 + base]), data[6 + base:10 + base + 1]) + offset = f.tell() + endian = f.read(1) + elif ord_(data[2 + base]) == 0xFF and data[6 + base:10 + base + 1] == b'Adobe': + # detected APP14 (Adobe) + logger.debug("EXIF-like header (normally 0xFF and code): 0x%X and %s", + ord_(data[2 + base]), data[6 + base:10 + base + 1]) + offset = f.tell() + endian = f.read(1) + else: + # no EXIF information + logger.debug("No EXIF header expected data[2+base]==0xFF and data[6+base:10+base]===Exif (or Duck)") + logger.debug("Did get 0x%X and %s", + ord_(data[2 + base]), data[6 + base:10 + base + 1]) + return {} + else: + # file format not recognized + logger.debug("File format not recognized.") + return {} + + endian = chr(ord_(endian[0])) + # deal with the EXIF info we found + logger.debug("Endian format is %s (%s)", endian, { + 'I': 'Intel', + 'M': 'Motorola', + '\x01': 'Adobe Ducky', + 'd': 'XMP/Adobe unknown' + }[endian]) + + hdr = ExifHeader(f, endian, offset, fake_exif, strict, debug, details) + ifd_list = hdr.list_ifd() + thumb_ifd = False + ctr = 0 + for ifd in ifd_list: + if ctr == 0: + ifd_name = 'Image' + elif ctr == 1: + ifd_name = 'Thumbnail' + thumb_ifd = ifd + else: + ifd_name = 'IFD %d' % ctr + logger.debug('IFD %d (%s) at offset %s:', ctr, ifd_name, ifd) + hdr.dump_ifd(ifd, ifd_name, stop_tag=stop_tag) + ctr += 1 + # EXIF IFD + exif_off = hdr.tags.get('Image ExifOffset') + if exif_off: + logger.debug('Exif SubIFD at offset %s:', exif_off.values[0]) + hdr.dump_ifd(exif_off.values[0], 'EXIF', stop_tag=stop_tag) + + # deal with MakerNote contained in EXIF IFD + # (Some apps use MakerNote tags but do not use a format for which we + # have a description, do not process these). + if details and 'EXIF MakerNote' in hdr.tags and 'Image Make' in hdr.tags: + hdr.decode_maker_note() + + # extract thumbnails + if details and thumb_ifd: + hdr.extract_tiff_thumbnail(thumb_ifd) + hdr.extract_jpeg_thumbnail() + + # parse XMP tags (experimental) + if debug and details: + xmp_string = b'' + # Easy we already have them + if 'Image ApplicationNotes' in hdr.tags: + logger.debug('XMP present in Exif') + xmp_string = make_string(hdr.tags['Image ApplicationNotes'].values) + # We need to look in the entire file for the XML + else: + logger.debug('XMP not in Exif, searching file for XMP info...') + xml_started = False + xml_finished = False + for line in f: + open_tag = line.find(b'') + + if open_tag != -1: + xml_started = True + line = line[open_tag:] + logger.debug('XMP found opening tag at line position %s' % open_tag) + + if close_tag != -1: + logger.debug('XMP found closing tag at line position %s' % close_tag) + line_offset = 0 + if open_tag != -1: + line_offset = open_tag + line = line[:(close_tag - line_offset) + 12] + xml_finished = True + + if xml_started: + xmp_string += line + + if xml_finished: + break + + logger.debug('XMP Finished searching for info') + if xmp_string: + hdr.parse_xmp(xmp_string) + + return hdr.tags diff --git a/venv/lib/python2.7/site-packages/exifread/classes.py b/venv/lib/python2.7/site-packages/exifread/classes.py new file mode 100644 index 0000000..91d6b93 --- /dev/null +++ b/venv/lib/python2.7/site-packages/exifread/classes.py @@ -0,0 +1,553 @@ +import struct +import re + +from .exif_log import get_logger +from .utils import s2n_motorola, s2n_intel, Ratio +from .tags import * + +logger = get_logger() + + +class IfdTag: + """ + Eases dealing with tags. + """ + + def __init__(self, printable, tag, field_type, values, field_offset, + field_length): + # printable version of data + self.printable = printable + # tag ID number + self.tag = tag + # field type as index into FIELD_TYPES + self.field_type = field_type + # offset of start of field in bytes from beginning of IFD + self.field_offset = field_offset + # length of data field in bytes + self.field_length = field_length + # either a string or array of data items + self.values = values + + def __str__(self): + return self.printable + + def __repr__(self): + try: + s = '(0x%04X) %s=%s @ %d' % (self.tag, + FIELD_TYPES[self.field_type][2], + self.printable, + self.field_offset) + except: + s = '(%s) %s=%s @ %s' % (str(self.tag), + FIELD_TYPES[self.field_type][2], + self.printable, + str(self.field_offset)) + return s + + +class ExifHeader: + """ + Handle an EXIF header. + """ + + def __init__(self, file, endian, offset, fake_exif, strict, + debug=False, detailed=True): + self.file = file + self.endian = endian + self.offset = offset + self.fake_exif = fake_exif + self.strict = strict + self.debug = debug + self.detailed = detailed + self.tags = {} + + def s2n(self, offset, length, signed=0): + """ + Convert slice to integer, based on sign and endian flags. + + Usually this offset is assumed to be relative to the beginning of the + start of the EXIF information. + For some cameras that use relative tags, this offset may be relative + to some other starting point. + """ + self.file.seek(self.offset + offset) + sliced = self.file.read(length) + if self.endian == 'I': + val = s2n_intel(sliced) + else: + val = s2n_motorola(sliced) + # Sign extension? + if signed: + msb = 1 << (8 * length - 1) + if val & msb: + val -= (msb << 1) + return val + + def n2s(self, offset, length): + """Convert offset to string.""" + s = '' + for dummy in range(length): + if self.endian == 'I': + s += chr(offset & 0xFF) + else: + s = chr(offset & 0xFF) + s + offset = offset >> 8 + return s + + def _first_ifd(self): + """Return first IFD.""" + return self.s2n(4, 4) + + def _next_ifd(self, ifd): + """Return the pointer to next IFD.""" + entries = self.s2n(ifd, 2) + next_ifd = self.s2n(ifd + 2 + 12 * entries, 4) + if next_ifd == ifd: + return 0 + else: + return next_ifd + + def list_ifd(self): + """Return the list of IFDs in the header.""" + i = self._first_ifd() + ifds = [] + while i: + ifds.append(i) + i = self._next_ifd(i) + return ifds + + def dump_ifd(self, ifd, ifd_name, tag_dict=EXIF_TAGS, relative=0, stop_tag=DEFAULT_STOP_TAG): + """ + Return a list of entries in the given IFD. + """ + # make sure we can process the entries + try: + entries = self.s2n(ifd, 2) + except TypeError: + logger.warning("Possibly corrupted IFD: %s" % ifd) + return + + for i in range(entries): + # entry is index of start of this IFD in the file + entry = ifd + 2 + 12 * i + tag = self.s2n(entry, 2) + + # get tag name early to avoid errors, help debug + tag_entry = tag_dict.get(tag) + if tag_entry: + tag_name = tag_entry[0] + else: + tag_name = 'Tag 0x%04X' % tag + + # ignore certain tags for faster processing + if not (not self.detailed and tag in IGNORE_TAGS): + field_type = self.s2n(entry + 2, 2) + + # unknown field type + if not 0 < field_type < len(FIELD_TYPES): + if not self.strict: + continue + else: + raise ValueError('Unknown type %d in tag 0x%04X' % (field_type, tag)) + + type_length = FIELD_TYPES[field_type][0] + count = self.s2n(entry + 4, 4) + # Adjust for tag id/type/count (2+2+4 bytes) + # Now we point at either the data or the 2nd level offset + offset = entry + 8 + + # If the value fits in 4 bytes, it is inlined, else we + # need to jump ahead again. + if count * type_length > 4: + # offset is not the value; it's a pointer to the value + # if relative we set things up so s2n will seek to the right + # place when it adds self.offset. Note that this 'relative' + # is for the Nikon type 3 makernote. Other cameras may use + # other relative offsets, which would have to be computed here + # slightly differently. + if relative: + tmp_offset = self.s2n(offset, 4) + offset = tmp_offset + ifd - 8 + if self.fake_exif: + offset += 18 + else: + offset = self.s2n(offset, 4) + + field_offset = offset + values = None + if field_type == 2: + # special case: null-terminated ASCII string + # XXX investigate + # sometimes gets too big to fit in int value + if count != 0: # and count < (2**31): # 2E31 is hardware dependant. --gd + file_position = self.offset + offset + try: + self.file.seek(file_position) + values = self.file.read(count) + #print(values) + # Drop any garbage after a null. + values = values.split(b'\x00', 1)[0] + if isinstance(values, bytes): + try: + values = values.decode("utf-8") + except UnicodeDecodeError: + logger.warning("Possibly corrupted field %s in %s IFD", tag_name, ifd_name) + except OverflowError: + logger.warn('OverflowError at position: %s, length: %s', file_position, count) + values = '' + except MemoryError: + logger.warn('MemoryError at position: %s, length: %s', file_position, count) + values = '' + else: + values = [] + signed = (field_type in [6, 8, 9, 10]) + + # XXX investigate + # some entries get too big to handle could be malformed + # file or problem with self.s2n + if count < 1000: + for dummy in range(count): + if field_type in (5, 10): + # a ratio + value = Ratio(self.s2n(offset, 4, signed), + self.s2n(offset + 4, 4, signed)) + else: + value = self.s2n(offset, type_length, signed) + values.append(value) + offset = offset + type_length + # The test above causes problems with tags that are + # supposed to have long values! Fix up one important case. + elif tag_name in ('MakerNote', makernote.canon.CAMERA_INFO_TAG_NAME): + for dummy in range(count): + value = self.s2n(offset, type_length, signed) + values.append(value) + offset = offset + type_length + + # now 'values' is either a string or an array + if count == 1 and field_type != 2: + printable = str(values[0]) + elif count > 50 and len(values) > 20: + printable = str(values[0:20])[0:-1] + ", ... ]" + else: + try: + printable = str(values) + # fix for python2's handling of unicode values + except UnicodeEncodeError: + printable = unicode(values) + + # compute printable version of values + if tag_entry: + # optional 2nd tag element is present + if len(tag_entry) != 1: + if callable(tag_entry[1]): + # call mapping function + printable = tag_entry[1](values) + elif type(tag_entry[1]) is tuple: + ifd_info = tag_entry[1] + try: + logger.debug('%s SubIFD at offset %d:', ifd_info[0], values[0]) + self.dump_ifd(values[0], ifd_info[0], tag_dict=ifd_info[1], stop_tag=stop_tag) + except IndexError: + logger.warn('No values found for %s SubIFD', ifd_info[0]) + else: + printable = '' + for i in values: + # use lookup table for this tag + printable += tag_entry[1].get(i, repr(i)) + + self.tags[ifd_name + ' ' + tag_name] = IfdTag(printable, tag, + field_type, + values, field_offset, + count * type_length) + try: + tag_value = repr(self.tags[ifd_name + ' ' + tag_name]) + # fix for python2's handling of unicode values + except UnicodeEncodeError: + tag_value = unicode(self.tags[ifd_name + ' ' + tag_name]) + logger.debug(' %s: %s', tag_name, tag_value) + + if tag_name == stop_tag: + break + + def extract_tiff_thumbnail(self, thumb_ifd): + """ + Extract uncompressed TIFF thumbnail. + + Take advantage of the pre-existing layout in the thumbnail IFD as + much as possible + """ + thumb = self.tags.get('Thumbnail Compression') + if not thumb or thumb.printable != 'Uncompressed TIFF': + return + + entries = self.s2n(thumb_ifd, 2) + # this is header plus offset to IFD ... + if self.endian == 'M': + tiff = 'MM\x00*\x00\x00\x00\x08' + else: + tiff = 'II*\x00\x08\x00\x00\x00' + # ... plus thumbnail IFD data plus a null "next IFD" pointer + self.file.seek(self.offset + thumb_ifd) + tiff += self.file.read(entries * 12 + 2) + '\x00\x00\x00\x00' + + # fix up large value offset pointers into data area + for i in range(entries): + entry = thumb_ifd + 2 + 12 * i + tag = self.s2n(entry, 2) + field_type = self.s2n(entry + 2, 2) + type_length = FIELD_TYPES[field_type][0] + count = self.s2n(entry + 4, 4) + old_offset = self.s2n(entry + 8, 4) + # start of the 4-byte pointer area in entry + ptr = i * 12 + 18 + # remember strip offsets location + if tag == 0x0111: + strip_off = ptr + strip_len = count * type_length + # is it in the data area? + if count * type_length > 4: + # update offset pointer (nasty "strings are immutable" crap) + # should be able to say "tiff[ptr:ptr+4]=newoff" + newoff = len(tiff) + tiff = tiff[:ptr] + self.n2s(newoff, 4) + tiff[ptr + 4:] + # remember strip offsets location + if tag == 0x0111: + strip_off = newoff + strip_len = 4 + # get original data and store it + self.file.seek(self.offset + old_offset) + tiff += self.file.read(count * type_length) + + # add pixel strips and update strip offset info + old_offsets = self.tags['Thumbnail StripOffsets'].values + old_counts = self.tags['Thumbnail StripByteCounts'].values + for i in range(len(old_offsets)): + # update offset pointer (more nasty "strings are immutable" crap) + offset = self.n2s(len(tiff), strip_len) + tiff = tiff[:strip_off] + offset + tiff[strip_off + strip_len:] + strip_off += strip_len + # add pixel strip to end + self.file.seek(self.offset + old_offsets[i]) + tiff += self.file.read(old_counts[i]) + + self.tags['TIFFThumbnail'] = tiff + + def extract_jpeg_thumbnail(self): + """ + Extract JPEG thumbnail. + + (Thankfully the JPEG data is stored as a unit.) + """ + thumb_offset = self.tags.get('Thumbnail JPEGInterchangeFormat') + if thumb_offset: + self.file.seek(self.offset + thumb_offset.values[0]) + size = self.tags['Thumbnail JPEGInterchangeFormatLength'].values[0] + self.tags['JPEGThumbnail'] = self.file.read(size) + + # Sometimes in a TIFF file, a JPEG thumbnail is hidden in the MakerNote + # since it's not allowed in a uncompressed TIFF IFD + if 'JPEGThumbnail' not in self.tags: + thumb_offset = self.tags.get('MakerNote JPEGThumbnail') + if thumb_offset: + self.file.seek(self.offset + thumb_offset.values[0]) + self.tags['JPEGThumbnail'] = self.file.read(thumb_offset.field_length) + + def decode_maker_note(self): + """ + Decode all the camera-specific MakerNote formats + + Note is the data that comprises this MakerNote. + The MakerNote will likely have pointers in it that point to other + parts of the file. We'll use self.offset as the starting point for + most of those pointers, since they are relative to the beginning + of the file. + If the MakerNote is in a newer format, it may use relative addressing + within the MakerNote. In that case we'll use relative addresses for + the pointers. + As an aside: it's not just to be annoying that the manufacturers use + relative offsets. It's so that if the makernote has to be moved by the + picture software all of the offsets don't have to be adjusted. Overall, + this is probably the right strategy for makernotes, though the spec is + ambiguous. + The spec does not appear to imagine that makernotes would + follow EXIF format internally. Once they did, it's ambiguous whether + the offsets should be from the header at the start of all the EXIF info, + or from the header at the start of the makernote. + """ + note = self.tags['EXIF MakerNote'] + + # Some apps use MakerNote tags but do not use a format for which we + # have a description, so just do a raw dump for these. + make = self.tags['Image Make'].printable + + # Nikon + # The maker note usually starts with the word Nikon, followed by the + # type of the makernote (1 or 2, as a short). If the word Nikon is + # not at the start of the makernote, it's probably type 2, since some + # cameras work that way. + if 'NIKON' in make: + if note.values[0:7] == [78, 105, 107, 111, 110, 0, 1]: + logger.debug("Looks like a type 1 Nikon MakerNote.") + self.dump_ifd(note.field_offset + 8, 'MakerNote', + tag_dict=makernote.nikon.TAGS_OLD) + elif note.values[0:7] == [78, 105, 107, 111, 110, 0, 2]: + logger.debug("Looks like a labeled type 2 Nikon MakerNote") + if note.values[12:14] != [0, 42] and note.values[12:14] != [42, 0]: + raise ValueError("Missing marker tag '42' in MakerNote.") + # skip the Makernote label and the TIFF header + self.dump_ifd(note.field_offset + 10 + 8, 'MakerNote', + tag_dict=makernote.nikon.TAGS_NEW, relative=1) + else: + # E99x or D1 + logger.debug("Looks like an unlabeled type 2 Nikon MakerNote") + self.dump_ifd(note.field_offset, 'MakerNote', + tag_dict=makernote.nikon.TAGS_NEW) + return + + # Olympus + if make.startswith('OLYMPUS'): + self.dump_ifd(note.field_offset + 8, 'MakerNote', + tag_dict=makernote.olympus.TAGS) + # TODO + #for i in (('MakerNote Tag 0x2020', makernote.OLYMPUS_TAG_0x2020),): + # self.decode_olympus_tag(self.tags[i[0]].values, i[1]) + #return + + # Casio + if 'CASIO' in make or 'Casio' in make: + self.dump_ifd(note.field_offset, 'MakerNote', + tag_dict=makernote.casio.TAGS) + return + + # Fujifilm + if make == 'FUJIFILM': + # bug: everything else is "Motorola" endian, but the MakerNote + # is "Intel" endian + endian = self.endian + self.endian = 'I' + # bug: IFD offsets are from beginning of MakerNote, not + # beginning of file header + offset = self.offset + self.offset += note.field_offset + # process note with bogus values (note is actually at offset 12) + self.dump_ifd(12, 'MakerNote', tag_dict=makernote.fujifilm.TAGS) + # reset to correct values + self.endian = endian + self.offset = offset + return + + # Apple + if make == 'Apple' and \ + note.values[0:10] == [65, 112, 112, 108, 101, 32, 105, 79, 83, 0]: + t = self.offset + self.offset += note.field_offset+14 + self.dump_ifd(0, 'MakerNote', + tag_dict=makernote.apple.TAGS) + self.offset = t + return + + # Canon + if make == 'Canon': + self.dump_ifd(note.field_offset, 'MakerNote', + tag_dict=makernote.canon.TAGS) + + for i in (('MakerNote Tag 0x0001', makernote.canon.CAMERA_SETTINGS), + ('MakerNote Tag 0x0002', makernote.canon.FOCAL_LENGTH), + ('MakerNote Tag 0x0004', makernote.canon.SHOT_INFO), + ('MakerNote Tag 0x0026', makernote.canon.AF_INFO_2), + ('MakerNote Tag 0x0093', makernote.canon.FILE_INFO)): + if i[0] in self.tags: + logger.debug('Canon ' + i[0]) + self._canon_decode_tag(self.tags[i[0]].values, i[1]) + del self.tags[i[0]] + if makernote.canon.CAMERA_INFO_TAG_NAME in self.tags: + tag = self.tags[makernote.canon.CAMERA_INFO_TAG_NAME] + logger.debug('Canon CameraInfo') + self._canon_decode_camera_info(tag) + del self.tags[makernote.canon.CAMERA_INFO_TAG_NAME] + return + + def _olympus_decode_tag(self, value, mn_tags): + """ TODO Decode Olympus MakerNote tag based on offset within tag.""" + pass + + def _canon_decode_tag(self, value, mn_tags): + """ + Decode Canon MakerNote tag based on offset within tag. + + See http://www.burren.cx/david/canon.html by David Burren + """ + for i in range(1, len(value)): + tag = mn_tags.get(i, ('Unknown', )) + name = tag[0] + if len(tag) > 1: + val = tag[1].get(value[i], 'Unknown') + else: + val = value[i] + try: + logger.debug(" %s %s %s", i, name, hex(value[i])) + except TypeError: + logger.debug(" %s %s %s", i, name, value[i]) + + # it's not a real IFD Tag but we fake one to make everybody + # happy. this will have a "proprietary" type + self.tags['MakerNote ' + name] = IfdTag(str(val), None, 0, None, + None, None) + + def _canon_decode_camera_info(self, camera_info_tag): + """ + Decode the variable length encoded camera info section. + """ + model = self.tags.get('Image Model', None) + if not model: + return + model = str(model.values) + + camera_info_tags = None + for (model_name_re, tag_desc) in makernote.canon.CAMERA_INFO_MODEL_MAP.items(): + if re.search(model_name_re, model): + camera_info_tags = tag_desc + break + else: + return + + # We are assuming here that these are all unsigned bytes (Byte or + # Unknown) + if camera_info_tag.field_type not in (1, 7): + return + camera_info = struct.pack('<%dB' % len(camera_info_tag.values), + *camera_info_tag.values) + + # Look for each data value and decode it appropriately. + for offset, tag in camera_info_tags.items(): + tag_format = tag[1] + tag_size = struct.calcsize(tag_format) + if len(camera_info) < offset + tag_size: + continue + packed_tag_value = camera_info[offset:offset + tag_size] + tag_value = struct.unpack(tag_format, packed_tag_value)[0] + + tag_name = tag[0] + if len(tag) > 2: + if callable(tag[2]): + tag_value = tag[2](tag_value) + else: + tag_value = tag[2].get(tag_value, tag_value) + logger.debug(" %s %s", tag_name, tag_value) + + self.tags['MakerNote ' + tag_name] = IfdTag(str(tag_value), None, + 0, None, None, None) + + def parse_xmp(self, xmp_string): + import xml.dom.minidom + + logger.debug('XMP cleaning data') + + xml = xml.dom.minidom.parseString(xmp_string) + pretty = xml.toprettyxml() + cleaned = [] + for line in pretty.splitlines(): + if line.strip(): + cleaned.append(line) + self.tags['Image ApplicationNotes'] = IfdTag('\n'.join(cleaned), None, + 1, None, None, None) diff --git a/venv/lib/python2.7/site-packages/exifread/exif_log.py b/venv/lib/python2.7/site-packages/exifread/exif_log.py new file mode 100644 index 0000000..82d5aea --- /dev/null +++ b/venv/lib/python2.7/site-packages/exifread/exif_log.py @@ -0,0 +1,76 @@ +""" +Custom log output +""" + +import sys +import logging + +TEXT_NORMAL = 0 +TEXT_BOLD = 1 +TEXT_RED = 31 +TEXT_GREEN = 32 +TEXT_YELLOW = 33 +TEXT_BLUE = 34 +TEXT_MAGENTA = 35 +TEXT_CYAN = 36 + + +def get_logger(): + return logging.getLogger('exifread') + + +def setup_logger(debug, color): + """Configure the logger.""" + if debug: + log_level = logging.DEBUG + else: + log_level = logging.INFO + + logger = logging.getLogger('exifread') + stream = Handler(log_level, debug, color) + logger.addHandler(stream) + logger.setLevel(log_level) + + +class Formatter(logging.Formatter): + + def __init__(self, debug=False, color=False): + self.color = color + self.debug = debug + if self.debug: + log_format = '%(levelname)-6s %(message)s' + else: + log_format = '%(message)s' + logging.Formatter.__init__(self, log_format) + + def format(self, record): + if self.debug and self.color: + if record.levelno >= logging.CRITICAL: + color = TEXT_RED + elif record.levelno >= logging.ERROR: + color = TEXT_RED + elif record.levelno >= logging.WARNING: + color = TEXT_YELLOW + elif record.levelno >= logging.INFO: + color = TEXT_GREEN + elif record.levelno >= logging.DEBUG: + color = TEXT_CYAN + else: + color = TEXT_NORMAL + record.levelname = "\x1b[%sm%s\x1b[%sm" % (color, record.levelname, TEXT_NORMAL) + return logging.Formatter.format(self, record) + + +class Handler(logging.StreamHandler): + + def __init__(self, log_level, debug=False, color=False): + self.color = color + self.debug = debug + logging.StreamHandler.__init__(self, sys.stdout) + self.setFormatter(Formatter(debug, color)) + self.setLevel(log_level) +""" + def emit(self, record): + record.msg = "\x1b[%sm%s\x1b[%sm" % (TEXT_BOLD, record.msg, TEXT_NORMAL) + logging.StreamHandler.emit(self, record) +""" \ No newline at end of file diff --git a/venv/lib/python2.7/site-packages/exifread/tags/__init__.py b/venv/lib/python2.7/site-packages/exifread/tags/__init__.py new file mode 100644 index 0000000..174de2e --- /dev/null +++ b/venv/lib/python2.7/site-packages/exifread/tags/__init__.py @@ -0,0 +1,30 @@ +""" +Tag definitions +""" + +from .exif import * +from .makernote import * + +DEFAULT_STOP_TAG = 'UNDEF' + +# field type descriptions as (length, abbreviation, full name) tuples +FIELD_TYPES = ( + (0, 'X', 'Proprietary'), # no such type + (1, 'B', 'Byte'), + (1, 'A', 'ASCII'), + (2, 'S', 'Short'), + (4, 'L', 'Long'), + (8, 'R', 'Ratio'), + (1, 'SB', 'Signed Byte'), + (1, 'U', 'Undefined'), + (2, 'SS', 'Signed Short'), + (4, 'SL', 'Signed Long'), + (8, 'SR', 'Signed Ratio'), +) + +# To ignore when quick processing +IGNORE_TAGS = ( + 0x9286, # user comment + 0x927C, # MakerNote Tags + 0x02BC, # XPM +) diff --git a/venv/lib/python2.7/site-packages/exifread/tags/exif.py b/venv/lib/python2.7/site-packages/exifread/tags/exif.py new file mode 100644 index 0000000..4349421 --- /dev/null +++ b/venv/lib/python2.7/site-packages/exifread/tags/exif.py @@ -0,0 +1,441 @@ +""" +Standard tag definitions. +""" + +from ..utils import make_string, make_string_uc + +# Interoperability tags +INTEROP_TAGS = { + 0x0001: ('InteroperabilityIndex', ), + 0x0002: ('InteroperabilityVersion', ), + 0x1000: ('RelatedImageFileFormat', ), + 0x1001: ('RelatedImageWidth', ), + 0x1002: ('RelatedImageLength', ), +} +INTEROP_INFO = ( + 'Interoperability', + INTEROP_TAGS +) + +# GPS tags +GPS_TAGS = { + 0x0000: ('GPSVersionID', ), + 0x0001: ('GPSLatitudeRef', ), + 0x0002: ('GPSLatitude', ), + 0x0003: ('GPSLongitudeRef', ), + 0x0004: ('GPSLongitude', ), + 0x0005: ('GPSAltitudeRef', ), + 0x0006: ('GPSAltitude', ), + 0x0007: ('GPSTimeStamp', ), + 0x0008: ('GPSSatellites', ), + 0x0009: ('GPSStatus', ), + 0x000A: ('GPSMeasureMode', ), + 0x000B: ('GPSDOP', ), + 0x000C: ('GPSSpeedRef', ), + 0x000D: ('GPSSpeed', ), + 0x000E: ('GPSTrackRef', ), + 0x000F: ('GPSTrack', ), + 0x0010: ('GPSImgDirectionRef', ), + 0x0011: ('GPSImgDirection', ), + 0x0012: ('GPSMapDatum', ), + 0x0013: ('GPSDestLatitudeRef', ), + 0x0014: ('GPSDestLatitude', ), + 0x0015: ('GPSDestLongitudeRef', ), + 0x0016: ('GPSDestLongitude', ), + 0x0017: ('GPSDestBearingRef', ), + 0x0018: ('GPSDestBearing', ), + 0x0019: ('GPSDestDistanceRef', ), + 0x001A: ('GPSDestDistance', ), + 0x001B: ('GPSProcessingMethod', ), + 0x001C: ('GPSAreaInformation', ), + 0x001D: ('GPSDate', ), + 0x001E: ('GPSDifferential', ), +} +GPS_INFO = ( + 'GPS', + GPS_TAGS +) + +# Main Exif tag names +EXIF_TAGS = { + 0x00FE: ('SubfileType', { + 0x0: 'Full-resolution Image', + 0x1: 'Reduced-resolution image', + 0x2: 'Single page of multi-page image', + 0x3: 'Single page of multi-page reduced-resolution image', + 0x4: 'Transparency mask', + 0x5: 'Transparency mask of reduced-resolution image', + 0x6: 'Transparency mask of multi-page image', + 0x7: 'Transparency mask of reduced-resolution multi-page image', + 0x10001: 'Alternate reduced-resolution image', + 0xffffffff: 'invalid ', + }), + 0x00FF: ('OldSubfileType', { + 1: 'Full-resolution image', + 2: 'Reduced-resolution image', + 3: 'Single page of multi-page image', + }), + 0x0100: ('ImageWidth', ), + 0x0101: ('ImageLength', ), + 0x0102: ('BitsPerSample', ), + 0x0103: ('Compression', { + 1: 'Uncompressed', + 2: 'CCITT 1D', + 3: 'T4/Group 3 Fax', + 4: 'T6/Group 4 Fax', + 5: 'LZW', + 6: 'JPEG (old-style)', + 7: 'JPEG', + 8: 'Adobe Deflate', + 9: 'JBIG B&W', + 10: 'JBIG Color', + 32766: 'Next', + 32769: 'Epson ERF Compressed', + 32771: 'CCIRLEW', + 32773: 'PackBits', + 32809: 'Thunderscan', + 32895: 'IT8CTPAD', + 32896: 'IT8LW', + 32897: 'IT8MP', + 32898: 'IT8BL', + 32908: 'PixarFilm', + 32909: 'PixarLog', + 32946: 'Deflate', + 32947: 'DCS', + 34661: 'JBIG', + 34676: 'SGILog', + 34677: 'SGILog24', + 34712: 'JPEG 2000', + 34713: 'Nikon NEF Compressed', + 65000: 'Kodak DCR Compressed', + 65535: 'Pentax PEF Compressed' + }), + 0x0106: ('PhotometricInterpretation', ), + 0x0107: ('Thresholding', ), + 0x0108: ('CellWidth', ), + 0x0109: ('CellLength', ), + 0x010A: ('FillOrder', ), + 0x010D: ('DocumentName', ), + 0x010E: ('ImageDescription', ), + 0x010F: ('Make', ), + 0x0110: ('Model', ), + 0x0111: ('StripOffsets', ), + 0x0112: ('Orientation', { + 1: 'Horizontal (normal)', + 2: 'Mirrored horizontal', + 3: 'Rotated 180', + 4: 'Mirrored vertical', + 5: 'Mirrored horizontal then rotated 90 CCW', + 6: 'Rotated 90 CW', + 7: 'Mirrored horizontal then rotated 90 CW', + 8: 'Rotated 90 CCW' + }), + 0x0115: ('SamplesPerPixel', ), + 0x0116: ('RowsPerStrip', ), + 0x0117: ('StripByteCounts', ), + 0x0118: ('MinSampleValue', ), + 0x0119: ('MaxSampleValue', ), + 0x011A: ('XResolution', ), + 0x011B: ('YResolution', ), + 0x011C: ('PlanarConfiguration', ), + 0x011D: ('PageName', make_string), + 0x011E: ('XPosition', ), + 0x011F: ('YPosition', ), + 0x0122: ('GrayResponseUnit', { + 1: '0.1', + 2: '0.001', + 3: '0.0001', + 4: '1e-05', + 5: '1e-06', + }), + 0x0123: ('GrayResponseCurve', ), + 0x0124: ('T4Options', ), + 0x0125: ('T6Options', ), + 0x0128: ('ResolutionUnit', { + 1: 'Not Absolute', + 2: 'Pixels/Inch', + 3: 'Pixels/Centimeter' + }), + 0x0129: ('PageNumber', ), + 0x012C: ('ColorResponseUnit', ), + 0x012D: ('TransferFunction', ), + 0x0131: ('Software', ), + 0x0132: ('DateTime', ), + 0x013B: ('Artist', ), + 0x013C: ('HostComputer', ), + 0x013D: ('Predictor', { + 1: 'None', + 2: 'Horizontal differencing' + }), + 0x013E: ('WhitePoint', ), + 0x013F: ('PrimaryChromaticities', ), + 0x0140: ('ColorMap', ), + 0x0141: ('HalftoneHints', ), + 0x0142: ('TileWidth', ), + 0x0143: ('TileLength', ), + 0x0144: ('TileOffsets', ), + 0x0145: ('TileByteCounts', ), + 0x0146: ('BadFaxLines', ), + 0x0147: ('CleanFaxData', { + 0: 'Clean', + 1: 'Regenerated', + 2: 'Unclean' + }), + 0x0148: ('ConsecutiveBadFaxLines', ), + 0x014C: ('InkSet', { + 1: 'CMYK', + 2: 'Not CMYK' + }), + 0x014D: ('InkNames', ), + 0x014E: ('NumberofInks', ), + 0x0150: ('DotRange', ), + 0x0151: ('TargetPrinter', ), + 0x0152: ('ExtraSamples', { + 0: 'Unspecified', + 1: 'Associated Alpha', + 2: 'Unassociated Alpha' + }), + 0x0153: ('SampleFormat', { + 1: 'Unsigned', + 2: 'Signed', + 3: 'Float', + 4: 'Undefined', + 5: 'Complex int', + 6: 'Complex float' + }), + 0x0154: ('SMinSampleValue', ), + 0x0155: ('SMaxSampleValue', ), + 0x0156: ('TransferRange', ), + 0x0157: ('ClipPath', ), + 0x0200: ('JPEGProc', ), + 0x0201: ('JPEGInterchangeFormat', ), + 0x0202: ('JPEGInterchangeFormatLength', ), + 0x0211: ('YCbCrCoefficients', ), + 0x0212: ('YCbCrSubSampling', ), + 0x0213: ('YCbCrPositioning', { + 1: 'Centered', + 2: 'Co-sited' + }), + 0x0214: ('ReferenceBlackWhite', ), + 0x02BC: ('ApplicationNotes', ), # XPM Info + 0x4746: ('Rating', ), + 0x828D: ('CFARepeatPatternDim', ), + 0x828E: ('CFAPattern', ), + 0x828F: ('BatteryLevel', ), + 0x8298: ('Copyright', ), + 0x829A: ('ExposureTime', ), + 0x829D: ('FNumber', ), + 0x83BB: ('IPTC/NAA', ), + 0x8769: ('ExifOffset', ), # Exif Tags + 0x8773: ('InterColorProfile', ), + 0x8822: ('ExposureProgram', { + 0: 'Unidentified', + 1: 'Manual', + 2: 'Program Normal', + 3: 'Aperture Priority', + 4: 'Shutter Priority', + 5: 'Program Creative', + 6: 'Program Action', + 7: 'Portrait Mode', + 8: 'Landscape Mode' + }), + 0x8824: ('SpectralSensitivity', ), + 0x8825: ('GPSInfo', GPS_INFO), # GPS tags + 0x8827: ('ISOSpeedRatings', ), + 0x8828: ('OECF', ), + 0x8830: ('SensitivityType', { + 0: 'Unknown', + 1: 'Standard Output Sensitivity', + 2: 'Recommended Exposure Index', + 3: 'ISO Speed', + 4: 'Standard Output Sensitivity and Recommended Exposure Index', + 5: 'Standard Output Sensitivity and ISO Speed', + 6: 'Recommended Exposure Index and ISO Speed', + 7: 'Standard Output Sensitivity, Recommended Exposure Index and ISO Speed' + }), + 0x8832: ('RecommendedExposureIndex', ), + 0x8833: ('ISOSpeed', ), + 0x9000: ('ExifVersion', make_string), + 0x9003: ('DateTimeOriginal', ), + 0x9004: ('DateTimeDigitized', ), + 0x9101: ('ComponentsConfiguration', { + 0: '', + 1: 'Y', + 2: 'Cb', + 3: 'Cr', + 4: 'Red', + 5: 'Green', + 6: 'Blue' + }), + 0x9102: ('CompressedBitsPerPixel', ), + 0x9201: ('ShutterSpeedValue', ), + 0x9202: ('ApertureValue', ), + 0x9203: ('BrightnessValue', ), + 0x9204: ('ExposureBiasValue', ), + 0x9205: ('MaxApertureValue', ), + 0x9206: ('SubjectDistance', ), + 0x9207: ('MeteringMode', { + 0: 'Unidentified', + 1: 'Average', + 2: 'CenterWeightedAverage', + 3: 'Spot', + 4: 'MultiSpot', + 5: 'Pattern', + 6: 'Partial', + 255: 'other' + }), + 0x9208: ('LightSource', { + 0: 'Unknown', + 1: 'Daylight', + 2: 'Fluorescent', + 3: 'Tungsten (incandescent light)', + 4: 'Flash', + 9: 'Fine weather', + 10: 'Cloudy weather', + 11: 'Shade', + 12: 'Daylight fluorescent (D 5700 - 7100K)', + 13: 'Day white fluorescent (N 4600 - 5400K)', + 14: 'Cool white fluorescent (W 3900 - 4500K)', + 15: 'White fluorescent (WW 3200 - 3700K)', + 17: 'Standard light A', + 18: 'Standard light B', + 19: 'Standard light C', + 20: 'D55', + 21: 'D65', + 22: 'D75', + 23: 'D50', + 24: 'ISO studio tungsten', + 255: 'other light source' + }), + 0x9209: ('Flash', { + 0: 'Flash did not fire', + 1: 'Flash fired', + 5: 'Strobe return light not detected', + 7: 'Strobe return light detected', + 9: 'Flash fired, compulsory flash mode', + 13: 'Flash fired, compulsory flash mode, return light not detected', + 15: 'Flash fired, compulsory flash mode, return light detected', + 16: 'Flash did not fire, compulsory flash mode', + 24: 'Flash did not fire, auto mode', + 25: 'Flash fired, auto mode', + 29: 'Flash fired, auto mode, return light not detected', + 31: 'Flash fired, auto mode, return light detected', + 32: 'No flash function', + 65: 'Flash fired, red-eye reduction mode', + 69: 'Flash fired, red-eye reduction mode, return light not detected', + 71: 'Flash fired, red-eye reduction mode, return light detected', + 73: 'Flash fired, compulsory flash mode, red-eye reduction mode', + 77: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected', + 79: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light detected', + 89: 'Flash fired, auto mode, red-eye reduction mode', + 93: 'Flash fired, auto mode, return light not detected, red-eye reduction mode', + 95: 'Flash fired, auto mode, return light detected, red-eye reduction mode' + }), + 0x920A: ('FocalLength', ), + 0x9214: ('SubjectArea', ), + 0x927C: ('MakerNote', ), + 0x9286: ('UserComment', make_string_uc), + 0x9290: ('SubSecTime', ), + 0x9291: ('SubSecTimeOriginal', ), + 0x9292: ('SubSecTimeDigitized', ), + + # used by Windows Explorer + 0x9C9B: ('XPTitle', ), + 0x9C9C: ('XPComment', ), + 0x9C9D: ('XPAuthor', make_string), # (ignored by Windows Explorer if Artist exists) + 0x9C9E: ('XPKeywords', ), + 0x9C9F: ('XPSubject', ), + 0xA000: ('FlashPixVersion', make_string), + 0xA001: ('ColorSpace', { + 1: 'sRGB', + 2: 'Adobe RGB', + 65535: 'Uncalibrated' + }), + 0xA002: ('ExifImageWidth', ), + 0xA003: ('ExifImageLength', ), + 0xA004: ('RelatedSoundFile', ), + 0xA005: ('InteroperabilityOffset', INTEROP_INFO), + 0xA20B: ('FlashEnergy', ), # 0x920B in TIFF/EP + 0xA20C: ('SpatialFrequencyResponse', ), # 0x920C + 0xA20E: ('FocalPlaneXResolution', ), # 0x920E + 0xA20F: ('FocalPlaneYResolution', ), # 0x920F + 0xA210: ('FocalPlaneResolutionUnit', ), # 0x9210 + 0xA214: ('SubjectLocation', ), # 0x9214 + 0xA215: ('ExposureIndex', ), # 0x9215 + 0xA217: ('SensingMethod', { # 0x9217 + 1: 'Not defined', + 2: 'One-chip color area', + 3: 'Two-chip color area', + 4: 'Three-chip color area', + 5: 'Color sequential area', + 7: 'Trilinear', + 8: 'Color sequential linear' + }), + 0xA300: ('FileSource', { + 1: 'Film Scanner', + 2: 'Reflection Print Scanner', + 3: 'Digital Camera' + }), + 0xA301: ('SceneType', { + 1: 'Directly Photographed' + }), + 0xA302: ('CVAPattern', ), + 0xA401: ('CustomRendered', { + 0: 'Normal', + 1: 'Custom' + }), + 0xA402: ('ExposureMode', { + 0: 'Auto Exposure', + 1: 'Manual Exposure', + 2: 'Auto Bracket' + }), + 0xA403: ('WhiteBalance', { + 0: 'Auto', + 1: 'Manual' + }), + 0xA404: ('DigitalZoomRatio', ), + 0xA405: ('FocalLengthIn35mmFilm', ), + 0xA406: ('SceneCaptureType', { + 0: 'Standard', + 1: 'Landscape', + 2: 'Portrait', + 3: 'Night)' + }), + 0xA407: ('GainControl', { + 0: 'None', + 1: 'Low gain up', + 2: 'High gain up', + 3: 'Low gain down', + 4: 'High gain down' + }), + 0xA408: ('Contrast', { + 0: 'Normal', + 1: 'Soft', + 2: 'Hard' + }), + 0xA409: ('Saturation', { + 0: 'Normal', + 1: 'Soft', + 2: 'Hard' + }), + 0xA40A: ('Sharpness', { + 0: 'Normal', + 1: 'Soft', + 2: 'Hard' + }), + 0xA40B: ('DeviceSettingDescription', ), + 0xA40C: ('SubjectDistanceRange', ), + 0xA420: ('ImageUniqueID', ), + 0xA430: ('CameraOwnerName', ), + 0xA431: ('BodySerialNumber', ), + 0xA432: ('LensSpecification', ), + 0xA433: ('LensMake', ), + 0xA434: ('LensModel', ), + 0xA435: ('LensSerialNumber', ), + 0xA500: ('Gamma', ), + 0xC4A5: ('PrintIM', ), + 0xEA1C: ('Padding', ), + 0xEA1D: ('OffsetSchema', ), + 0xFDE8: ('OwnerName', ), + 0xFDE9: ('SerialNumber', ), +} diff --git a/venv/lib/python2.7/site-packages/exifread/tags/makernote.py b/venv/lib/python2.7/site-packages/exifread/tags/makernote.py new file mode 100644 index 0000000..5e77d48 --- /dev/null +++ b/venv/lib/python2.7/site-packages/exifread/tags/makernote.py @@ -0,0 +1,608 @@ +""" +Makernote tag definitions. +""" + +from ..utils import make_string, make_string_uc, Ratio +from . import makernote_canon as canon +from . import makernote_apple as apple +from . import makernote_fujifilm as fujifilm + + +def nikon_ev_bias(seq): + """ + First digit seems to be in steps of 1/6 EV. + Does the third value mean the step size? It is usually 6, + but it is 12 for the ExposureDifference. + Check for an error condition that could cause a crash. + This only happens if something has gone really wrong in + reading the Nikon MakerNote. + http://tomtia.plala.jp/DigitalCamera/MakerNote/index.asp + """ + if len(seq) < 4: + return '' + if seq == [252, 1, 6, 0]: + return '-2/3 EV' + if seq == [253, 1, 6, 0]: + return '-1/2 EV' + if seq == [254, 1, 6, 0]: + return '-1/3 EV' + if seq == [0, 1, 6, 0]: + return '0 EV' + if seq == [2, 1, 6, 0]: + return '+1/3 EV' + if seq == [3, 1, 6, 0]: + return '+1/2 EV' + if seq == [4, 1, 6, 0]: + return '+2/3 EV' + # Handle combinations not in the table. + a = seq[0] + # Causes headaches for the +/- logic, so special case it. + if a == 0: + return '0 EV' + if a > 127: + a = 256 - a + ret_str = '-' + else: + ret_str = '+' + step = seq[2] # Assume third value means the step size + whole = a / step + a = a % step + if whole != 0: + ret_str = '%s%s ' % (ret_str, str(whole)) + if a == 0: + ret_str += 'EV' + else: + r = Ratio(a, step) + ret_str = ret_str + r.__repr__() + ' EV' + return ret_str + +# Nikon E99x MakerNote Tags +NIKON_NEW = { + 0x0001: ('MakernoteVersion', make_string), # Sometimes binary + 0x0002: ('ISOSetting', make_string), + 0x0003: ('ColorMode', ), + 0x0004: ('Quality', ), + 0x0005: ('Whitebalance', ), + 0x0006: ('ImageSharpening', ), + 0x0007: ('FocusMode', ), + 0x0008: ('FlashSetting', ), + 0x0009: ('AutoFlashMode', ), + 0x000B: ('WhiteBalanceBias', ), + 0x000C: ('WhiteBalanceRBCoeff', ), + 0x000D: ('ProgramShift', nikon_ev_bias), + # Nearly the same as the other EV vals, but step size is 1/12 EV (?) + 0x000E: ('ExposureDifference', nikon_ev_bias), + 0x000F: ('ISOSelection', ), + 0x0010: ('DataDump', ), + 0x0011: ('NikonPreview', ), + 0x0012: ('FlashCompensation', nikon_ev_bias), + 0x0013: ('ISOSpeedRequested', ), + 0x0016: ('PhotoCornerCoordinates', ), + 0x0017: ('ExternalFlashExposureComp', nikon_ev_bias), + 0x0018: ('FlashBracketCompensationApplied', nikon_ev_bias), + 0x0019: ('AEBracketCompensationApplied', ), + 0x001A: ('ImageProcessing', ), + 0x001B: ('CropHiSpeed', ), + 0x001C: ('ExposureTuning', ), + 0x001D: ('SerialNumber', ), # Conflict with 0x00A0 ? + 0x001E: ('ColorSpace', ), + 0x001F: ('VRInfo', ), + 0x0020: ('ImageAuthentication', ), + 0x0022: ('ActiveDLighting', ), + 0x0023: ('PictureControl', ), + 0x0024: ('WorldTime', ), + 0x0025: ('ISOInfo', ), + 0x0080: ('ImageAdjustment', ), + 0x0081: ('ToneCompensation', ), + 0x0082: ('AuxiliaryLens', ), + 0x0083: ('LensType', ), + 0x0084: ('LensMinMaxFocalMaxAperture', ), + 0x0085: ('ManualFocusDistance', ), + 0x0086: ('DigitalZoomFactor', ), + 0x0087: ('FlashMode', { + 0x00: 'Did Not Fire', + 0x01: 'Fired, Manual', + 0x07: 'Fired, External', + 0x08: 'Fired, Commander Mode ', + 0x09: 'Fired, TTL Mode', + }), + 0x0088: ('AFFocusPosition', { + 0x0000: 'Center', + 0x0100: 'Top', + 0x0200: 'Bottom', + 0x0300: 'Left', + 0x0400: 'Right', + }), + 0x0089: ('BracketingMode', { + 0x00: 'Single frame, no bracketing', + 0x01: 'Continuous, no bracketing', + 0x02: 'Timer, no bracketing', + 0x10: 'Single frame, exposure bracketing', + 0x11: 'Continuous, exposure bracketing', + 0x12: 'Timer, exposure bracketing', + 0x40: 'Single frame, white balance bracketing', + 0x41: 'Continuous, white balance bracketing', + 0x42: 'Timer, white balance bracketing' + }), + 0x008A: ('AutoBracketRelease', ), + 0x008B: ('LensFStops', ), + 0x008C: ('NEFCurve1', ), # ExifTool calls this 'ContrastCurve' + 0x008D: ('ColorMode', ), + 0x008F: ('SceneMode', ), + 0x0090: ('LightingType', ), + 0x0091: ('ShotInfo', ), # First 4 bytes are a version number in ASCII + 0x0092: ('HueAdjustment', ), + # ExifTool calls this 'NEFCompression', should be 1-4 + 0x0093: ('Compression', ), + 0x0094: ('Saturation', { + -3: 'B&W', + -2: '-2', + -1: '-1', + 0: '0', + 1: '1', + 2: '2', + }), + 0x0095: ('NoiseReduction', ), + 0x0096: ('NEFCurve2', ), # ExifTool calls this 'LinearizationTable' + 0x0097: ('ColorBalance', ), # First 4 bytes are a version number in ASCII + 0x0098: ('LensData', ), # First 4 bytes are a version number in ASCII + 0x0099: ('RawImageCenter', ), + 0x009A: ('SensorPixelSize', ), + 0x009C: ('Scene Assist', ), + 0x009E: ('RetouchHistory', ), + 0x00A0: ('SerialNumber', ), + 0x00A2: ('ImageDataSize', ), + # 00A3: unknown - a single byte 0 + # 00A4: In NEF, looks like a 4 byte ASCII version number ('0200') + 0x00A5: ('ImageCount', ), + 0x00A6: ('DeletedImageCount', ), + 0x00A7: ('TotalShutterReleases', ), + # First 4 bytes are a version number in ASCII, with version specific + # info to follow. Its hard to treat it as a string due to embedded nulls. + 0x00A8: ('FlashInfo', ), + 0x00A9: ('ImageOptimization', ), + 0x00AA: ('Saturation', ), + 0x00AB: ('DigitalVariProgram', ), + 0x00AC: ('ImageStabilization', ), + 0x00AD: ('AFResponse', ), + 0x00B0: ('MultiExposure', ), + 0x00B1: ('HighISONoiseReduction', ), + 0x00B6: ('PowerUpTime', ), + 0x00B7: ('AFInfo2', ), + 0x00B8: ('FileInfo', ), + 0x00B9: ('AFTune', ), + 0x0100: ('DigitalICE', ), + 0x0103: ('PreviewCompression', { + 1: 'Uncompressed', + 2: 'CCITT 1D', + 3: 'T4/Group 3 Fax', + 4: 'T6/Group 4 Fax', + 5: 'LZW', + 6: 'JPEG (old-style)', + 7: 'JPEG', + 8: 'Adobe Deflate', + 9: 'JBIG B&W', + 10: 'JBIG Color', + 32766: 'Next', + 32769: 'Epson ERF Compressed', + 32771: 'CCIRLEW', + 32773: 'PackBits', + 32809: 'Thunderscan', + 32895: 'IT8CTPAD', + 32896: 'IT8LW', + 32897: 'IT8MP', + 32898: 'IT8BL', + 32908: 'PixarFilm', + 32909: 'PixarLog', + 32946: 'Deflate', + 32947: 'DCS', + 34661: 'JBIG', + 34676: 'SGILog', + 34677: 'SGILog24', + 34712: 'JPEG 2000', + 34713: 'Nikon NEF Compressed', + 65000: 'Kodak DCR Compressed', + 65535: 'Pentax PEF Compressed', + }), + 0x0201: ('PreviewImageStart', ), + 0x0202: ('PreviewImageLength', ), + 0x0213: ('PreviewYCbCrPositioning', { + 1: 'Centered', + 2: 'Co-sited', + }), + 0x0E09: ('NikonCaptureVersion', ), + 0x0E0E: ('NikonCaptureOffsets', ), + 0x0E10: ('NikonScan', ), + 0x0E22: ('NEFBitDepth', ), +} + +NIKON_OLD = { + 0x0003: ('Quality', { + 1: 'VGA Basic', + 2: 'VGA Normal', + 3: 'VGA Fine', + 4: 'SXGA Basic', + 5: 'SXGA Normal', + 6: 'SXGA Fine', + }), + 0x0004: ('ColorMode', { + 1: 'Color', + 2: 'Monochrome', + }), + 0x0005: ('ImageAdjustment', { + 0: 'Normal', + 1: 'Bright+', + 2: 'Bright-', + 3: 'Contrast+', + 4: 'Contrast-', + }), + 0x0006: ('CCDSpeed', { + 0: 'ISO 80', + 2: 'ISO 160', + 4: 'ISO 320', + 5: 'ISO 100', + }), + 0x0007: ('WhiteBalance', { + 0: 'Auto', + 1: 'Preset', + 2: 'Daylight', + 3: 'Incandescent', + 4: 'Fluorescent', + 5: 'Cloudy', + 6: 'Speed Light', + }), +} + + +def olympus_special_mode(v): + """decode Olympus SpecialMode tag in MakerNote""" + mode1 = { + 0: 'Normal', + 1: 'Unknown', + 2: 'Fast', + 3: 'Panorama', + } + mode2 = { + 0: 'Non-panoramic', + 1: 'Left to right', + 2: 'Right to left', + 3: 'Bottom to top', + 4: 'Top to bottom', + } + if not v or (v[0] not in mode1 or v[2] not in mode2): + return v + return '%s - sequence %d - %s' % (mode1[v[0]], v[1], mode2[v[2]]) + + +OLYMPUS = { + # ah HAH! those sneeeeeaky bastids! this is how they get past the fact + # that a JPEG thumbnail is not allowed in an uncompressed TIFF file + 0x0100: ('JPEGThumbnail', ), + 0x0200: ('SpecialMode', olympus_special_mode), + 0x0201: ('JPEGQual', { + 1: 'SQ', + 2: 'HQ', + 3: 'SHQ', + }), + 0x0202: ('Macro', { + 0: 'Normal', + 1: 'Macro', + 2: 'SuperMacro' + }), + 0x0203: ('BWMode', { + 0: 'Off', + 1: 'On' + }), + 0x0204: ('DigitalZoom', ), + 0x0205: ('FocalPlaneDiagonal', ), + 0x0206: ('LensDistortionParams', ), + 0x0207: ('SoftwareRelease', ), + 0x0208: ('PictureInfo', ), + 0x0209: ('CameraID', make_string), # print as string + 0x0F00: ('DataDump', ), + 0x0300: ('PreCaptureFrames', ), + 0x0404: ('SerialNumber', ), + 0x1000: ('ShutterSpeedValue', ), + 0x1001: ('ISOValue', ), + 0x1002: ('ApertureValue', ), + 0x1003: ('BrightnessValue', ), + 0x1004: ('FlashMode', { + 2: 'On', + 3: 'Off' + }), + 0x1005: ('FlashDevice', { + 0: 'None', + 1: 'Internal', + 4: 'External', + 5: 'Internal + External' + }), + 0x1006: ('ExposureCompensation', ), + 0x1007: ('SensorTemperature', ), + 0x1008: ('LensTemperature', ), + 0x100b: ('FocusMode', { + 0: 'Auto', + 1: 'Manual' + }), + 0x1017: ('RedBalance', ), + 0x1018: ('BlueBalance', ), + 0x101a: ('SerialNumber', ), + 0x1023: ('FlashExposureComp', ), + 0x1026: ('ExternalFlashBounce', { + 0: 'No', + 1: 'Yes' + }), + 0x1027: ('ExternalFlashZoom', ), + 0x1028: ('ExternalFlashMode', ), + 0x1029: ('Contrast int16u', { + 0: 'High', + 1: 'Normal', + 2: 'Low' + }), + 0x102a: ('SharpnessFactor', ), + 0x102b: ('ColorControl', ), + 0x102c: ('ValidBits', ), + 0x102d: ('CoringFilter', ), + 0x102e: ('OlympusImageWidth', ), + 0x102f: ('OlympusImageHeight', ), + 0x1034: ('CompressionRatio', ), + 0x1035: ('PreviewImageValid', { + 0: 'No', + 1: 'Yes' + }), + 0x1036: ('PreviewImageStart', ), + 0x1037: ('PreviewImageLength', ), + 0x1039: ('CCDScanMode', { + 0: 'Interlaced', + 1: 'Progressive' + }), + 0x103a: ('NoiseReduction', { + 0: 'Off', + 1: 'On' + }), + 0x103b: ('InfinityLensStep', ), + 0x103c: ('NearLensStep', ), + + # TODO - these need extra definitions + # http://search.cpan.org/src/EXIFTOOL/Image-ExifTool-6.90/html/TagNames/Olympus.html + 0x2010: ('Equipment', ), + 0x2020: ('CameraSettings', ), + 0x2030: ('RawDevelopment', ), + 0x2040: ('ImageProcessing', ), + 0x2050: ('FocusInfo', ), + 0x3000: ('RawInfo ', ), +} + +# 0x2020 CameraSettings +OLYMPUS_TAG_0x2020 = { + 0x0100: ('PreviewImageValid', { + 0: 'No', + 1: 'Yes' + }), + 0x0101: ('PreviewImageStart', ), + 0x0102: ('PreviewImageLength', ), + 0x0200: ('ExposureMode', { + 1: 'Manual', + 2: 'Program', + 3: 'Aperture-priority AE', + 4: 'Shutter speed priority AE', + 5: 'Program-shift' + }), + 0x0201: ('AELock', { + 0: 'Off', + 1: 'On' + }), + 0x0202: ('MeteringMode', { + 2: 'Center Weighted', + 3: 'Spot', + 5: 'ESP', + 261: 'Pattern+AF', + 515: 'Spot+Highlight control', + 1027: 'Spot+Shadow control' + }), + 0x0300: ('MacroMode', { + 0: 'Off', + 1: 'On' + }), + 0x0301: ('FocusMode', { + 0: 'Single AF', + 1: 'Sequential shooting AF', + 2: 'Continuous AF', + 3: 'Multi AF', + 10: 'MF' + }), + 0x0302: ('FocusProcess', { + 0: 'AF Not Used', + 1: 'AF Used' + }), + 0x0303: ('AFSearch', { + 0: 'Not Ready', + 1: 'Ready' + }), + 0x0304: ('AFAreas', ), + 0x0401: ('FlashExposureCompensation', ), + 0x0500: ('WhiteBalance2', { + 0: 'Auto', + 16: '7500K (Fine Weather with Shade)', + 17: '6000K (Cloudy)', + 18: '5300K (Fine Weather)', + 20: '3000K (Tungsten light)', + 21: '3600K (Tungsten light-like)', + 33: '6600K (Daylight fluorescent)', + 34: '4500K (Neutral white fluorescent)', + 35: '4000K (Cool white fluorescent)', + 48: '3600K (Tungsten light-like)', + 256: 'Custom WB 1', + 257: 'Custom WB 2', + 258: 'Custom WB 3', + 259: 'Custom WB 4', + 512: 'Custom WB 5400K', + 513: 'Custom WB 2900K', + 514: 'Custom WB 8000K', + }), + 0x0501: ('WhiteBalanceTemperature', ), + 0x0502: ('WhiteBalanceBracket', ), + 0x0503: ('CustomSaturation', ), # (3 numbers: 1. CS Value, 2. Min, 3. Max) + 0x0504: ('ModifiedSaturation', { + 0: 'Off', + 1: 'CM1 (Red Enhance)', + 2: 'CM2 (Green Enhance)', + 3: 'CM3 (Blue Enhance)', + 4: 'CM4 (Skin Tones)', + }), + 0x0505: ('ContrastSetting', ), # (3 numbers: 1. Contrast, 2. Min, 3. Max) + 0x0506: ('SharpnessSetting', ), # (3 numbers: 1. Sharpness, 2. Min, 3. Max) + 0x0507: ('ColorSpace', { + 0: 'sRGB', + 1: 'Adobe RGB', + 2: 'Pro Photo RGB' + }), + 0x0509: ('SceneMode', { + 0: 'Standard', + 6: 'Auto', + 7: 'Sport', + 8: 'Portrait', + 9: 'Landscape+Portrait', + 10: 'Landscape', + 11: 'Night scene', + 13: 'Panorama', + 16: 'Landscape+Portrait', + 17: 'Night+Portrait', + 19: 'Fireworks', + 20: 'Sunset', + 22: 'Macro', + 25: 'Documents', + 26: 'Museum', + 28: 'Beach&Snow', + 30: 'Candle', + 35: 'Underwater Wide1', + 36: 'Underwater Macro', + 39: 'High Key', + 40: 'Digital Image Stabilization', + 44: 'Underwater Wide2', + 45: 'Low Key', + 46: 'Children', + 48: 'Nature Macro', + }), + 0x050a: ('NoiseReduction', { + 0: 'Off', + 1: 'Noise Reduction', + 2: 'Noise Filter', + 3: 'Noise Reduction + Noise Filter', + 4: 'Noise Filter (ISO Boost)', + 5: 'Noise Reduction + Noise Filter (ISO Boost)' + }), + 0x050b: ('DistortionCorrection', { + 0: 'Off', + 1: 'On' + }), + 0x050c: ('ShadingCompensation', { + 0: 'Off', + 1: 'On' + }), + 0x050d: ('CompressionFactor', ), + 0x050f: ('Gradation', { + '-1 -1 1': 'Low Key', + '0 -1 1': 'Normal', + '1 -1 1': 'High Key' + }), + 0x0520: ('PictureMode', { + 1: 'Vivid', + 2: 'Natural', + 3: 'Muted', + 256: 'Monotone', + 512: 'Sepia' + }), + 0x0521: ('PictureModeSaturation', ), + 0x0522: ('PictureModeHue?', ), + 0x0523: ('PictureModeContrast', ), + 0x0524: ('PictureModeSharpness', ), + 0x0525: ('PictureModeBWFilter', { + 0: 'n/a', + 1: 'Neutral', + 2: 'Yellow', + 3: 'Orange', + 4: 'Red', + 5: 'Green' + }), + 0x0526: ('PictureModeTone', { + 0: 'n/a', + 1: 'Neutral', + 2: 'Sepia', + 3: 'Blue', + 4: 'Purple', + 5: 'Green' + }), + 0x0600: ('Sequence', ), # 2 or 3 numbers: 1. Mode, 2. Shot number, 3. Mode bits + 0x0601: ('PanoramaMode', ), # (2 numbers: 1. Mode, 2. Shot number) + 0x0603: ('ImageQuality2', { + 1: 'SQ', + 2: 'HQ', + 3: 'SHQ', + 4: 'RAW', + }), + 0x0901: ('ManometerReading', ), +} + +CASIO = { + 0x0001: ('RecordingMode', { + 1: 'Single Shutter', + 2: 'Panorama', + 3: 'Night Scene', + 4: 'Portrait', + 5: 'Landscape', + }), + 0x0002: ('Quality', { + 1: 'Economy', + 2: 'Normal', + 3: 'Fine' + }), + 0x0003: ('FocusingMode', { + 2: 'Macro', + 3: 'Auto Focus', + 4: 'Manual Focus', + 5: 'Infinity' + }), + 0x0004: ('FlashMode', { + 1: 'Auto', + 2: 'On', + 3: 'Off', + 4: 'Red Eye Reduction', + }), + 0x0005: ('FlashIntensity', { + 11: 'Weak', + 13: 'Normal', + 15: 'Strong' + }), + 0x0006: ('Object Distance', ), + 0x0007: ('WhiteBalance', { + 1: 'Auto', + 2: 'Tungsten', + 3: 'Daylight', + 4: 'Fluorescent', + 5: 'Shade', + 129: 'Manual' + }), + 0x000B: ('Sharpness', { + 0: 'Normal', + 1: 'Soft', + 2: 'Hard', + }), + 0x000C: ('Contrast', { + 0: 'Normal', + 1: 'Low', + 2: 'High', + }), + 0x000D: ('Saturation', { + 0: 'Normal', + 1: 'Low', + 2: 'High', + }), + 0x0014: ('CCDSpeed', { + 64: 'Normal', + 80: 'Normal', + 100: 'High', + 125: '+1.0', + 244: '+3.0', + 250: '+2.0' + }), +} diff --git a/venv/lib/python2.7/site-packages/exifread/tags/makernote/__init__.py b/venv/lib/python2.7/site-packages/exifread/tags/makernote/__init__.py new file mode 100644 index 0000000..a0dfb97 --- /dev/null +++ b/venv/lib/python2.7/site-packages/exifread/tags/makernote/__init__.py @@ -0,0 +1,10 @@ +""" +Makernote tag definitions. +""" + +from . import apple +from . import canon +from . import casio +from . import fujifilm +from . import nikon +from . import olympus diff --git a/venv/lib/python2.7/site-packages/exifread/tags/makernote/apple.py b/venv/lib/python2.7/site-packages/exifread/tags/makernote/apple.py new file mode 100644 index 0000000..57717ca --- /dev/null +++ b/venv/lib/python2.7/site-packages/exifread/tags/makernote/apple.py @@ -0,0 +1,13 @@ +""" +Makernote (proprietary) tag definitions for Apple iOS + +Based on version 1.01 of ExifTool -> Image/ExifTool/Apple.pm +http://owl.phy.queensu.ca/~phil/exiftool/ +""" + +TAGS = { + 0x000a: ('HDRImageType', { + 3: 'HDR Image', + 4: 'Original Image', + }), +} diff --git a/venv/lib/python2.7/site-packages/exifread/tags/makernote/canon.py b/venv/lib/python2.7/site-packages/exifread/tags/makernote/canon.py new file mode 100644 index 0000000..f41c84c --- /dev/null +++ b/venv/lib/python2.7/site-packages/exifread/tags/makernote/canon.py @@ -0,0 +1,711 @@ +""" +Makernote (proprietary) tag definitions for Canon. + +http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Canon.html +""" + +TAGS = { + 0x0003: ('FlashInfo',), + 0x0006: ('ImageType', ), + 0x0007: ('FirmwareVersion', ), + 0x0008: ('ImageNumber', ), + 0x0009: ('OwnerName', ), + 0x000c: ('SerialNumber', ), + 0x000e: ('FileLength', ), + 0x0010: ('ModelID', { + 0x1010000: 'PowerShot A30', + 0x1040000: 'PowerShot S300 / Digital IXUS 300 / IXY Digital 300', + 0x1060000: 'PowerShot A20', + 0x1080000: 'PowerShot A10', + 0x1090000: 'PowerShot S110 / Digital IXUS v / IXY Digital 200', + 0x1100000: 'PowerShot G2', + 0x1110000: 'PowerShot S40', + 0x1120000: 'PowerShot S30', + 0x1130000: 'PowerShot A40', + 0x1140000: 'EOS D30', + 0x1150000: 'PowerShot A100', + 0x1160000: 'PowerShot S200 / Digital IXUS v2 / IXY Digital 200a', + 0x1170000: 'PowerShot A200', + 0x1180000: 'PowerShot S330 / Digital IXUS 330 / IXY Digital 300a', + 0x1190000: 'PowerShot G3', + 0x1210000: 'PowerShot S45', + 0x1230000: 'PowerShot SD100 / Digital IXUS II / IXY Digital 30', + 0x1240000: 'PowerShot S230 / Digital IXUS v3 / IXY Digital 320', + 0x1250000: 'PowerShot A70', + 0x1260000: 'PowerShot A60', + 0x1270000: 'PowerShot S400 / Digital IXUS 400 / IXY Digital 400', + 0x1290000: 'PowerShot G5', + 0x1300000: 'PowerShot A300', + 0x1310000: 'PowerShot S50', + 0x1340000: 'PowerShot A80', + 0x1350000: 'PowerShot SD10 / Digital IXUS i / IXY Digital L', + 0x1360000: 'PowerShot S1 IS', + 0x1370000: 'PowerShot Pro1', + 0x1380000: 'PowerShot S70', + 0x1390000: 'PowerShot S60', + 0x1400000: 'PowerShot G6', + 0x1410000: 'PowerShot S500 / Digital IXUS 500 / IXY Digital 500', + 0x1420000: 'PowerShot A75', + 0x1440000: 'PowerShot SD110 / Digital IXUS IIs / IXY Digital 30a', + 0x1450000: 'PowerShot A400', + 0x1470000: 'PowerShot A310', + 0x1490000: 'PowerShot A85', + 0x1520000: 'PowerShot S410 / Digital IXUS 430 / IXY Digital 450', + 0x1530000: 'PowerShot A95', + 0x1540000: 'PowerShot SD300 / Digital IXUS 40 / IXY Digital 50', + 0x1550000: 'PowerShot SD200 / Digital IXUS 30 / IXY Digital 40', + 0x1560000: 'PowerShot A520', + 0x1570000: 'PowerShot A510', + 0x1590000: 'PowerShot SD20 / Digital IXUS i5 / IXY Digital L2', + 0x1640000: 'PowerShot S2 IS', + 0x1650000: 'PowerShot SD430 / Digital IXUS Wireless / IXY Digital Wireless', + 0x1660000: 'PowerShot SD500 / Digital IXUS 700 / IXY Digital 600', + 0x1668000: 'EOS D60', + 0x1700000: 'PowerShot SD30 / Digital IXUS i Zoom / IXY Digital L3', + 0x1740000: 'PowerShot A430', + 0x1750000: 'PowerShot A410', + 0x1760000: 'PowerShot S80', + 0x1780000: 'PowerShot A620', + 0x1790000: 'PowerShot A610', + 0x1800000: 'PowerShot SD630 / Digital IXUS 65 / IXY Digital 80', + 0x1810000: 'PowerShot SD450 / Digital IXUS 55 / IXY Digital 60', + 0x1820000: 'PowerShot TX1', + 0x1870000: 'PowerShot SD400 / Digital IXUS 50 / IXY Digital 55', + 0x1880000: 'PowerShot A420', + 0x1890000: 'PowerShot SD900 / Digital IXUS 900 Ti / IXY Digital 1000', + 0x1900000: 'PowerShot SD550 / Digital IXUS 750 / IXY Digital 700', + 0x1920000: 'PowerShot A700', + 0x1940000: 'PowerShot SD700 IS / Digital IXUS 800 IS / IXY Digital 800 IS', + 0x1950000: 'PowerShot S3 IS', + 0x1960000: 'PowerShot A540', + 0x1970000: 'PowerShot SD600 / Digital IXUS 60 / IXY Digital 70', + 0x1980000: 'PowerShot G7', + 0x1990000: 'PowerShot A530', + 0x2000000: 'PowerShot SD800 IS / Digital IXUS 850 IS / IXY Digital 900 IS', + 0x2010000: 'PowerShot SD40 / Digital IXUS i7 / IXY Digital L4', + 0x2020000: 'PowerShot A710 IS', + 0x2030000: 'PowerShot A640', + 0x2040000: 'PowerShot A630', + 0x2090000: 'PowerShot S5 IS', + 0x2100000: 'PowerShot A460', + 0x2120000: 'PowerShot SD850 IS / Digital IXUS 950 IS / IXY Digital 810 IS', + 0x2130000: 'PowerShot A570 IS', + 0x2140000: 'PowerShot A560', + 0x2150000: 'PowerShot SD750 / Digital IXUS 75 / IXY Digital 90', + 0x2160000: 'PowerShot SD1000 / Digital IXUS 70 / IXY Digital 10', + 0x2180000: 'PowerShot A550', + 0x2190000: 'PowerShot A450', + 0x2230000: 'PowerShot G9', + 0x2240000: 'PowerShot A650 IS', + 0x2260000: 'PowerShot A720 IS', + 0x2290000: 'PowerShot SX100 IS', + 0x2300000: 'PowerShot SD950 IS / Digital IXUS 960 IS / IXY Digital 2000 IS', + 0x2310000: 'PowerShot SD870 IS / Digital IXUS 860 IS / IXY Digital 910 IS', + 0x2320000: 'PowerShot SD890 IS / Digital IXUS 970 IS / IXY Digital 820 IS', + 0x2360000: 'PowerShot SD790 IS / Digital IXUS 90 IS / IXY Digital 95 IS', + 0x2370000: 'PowerShot SD770 IS / Digital IXUS 85 IS / IXY Digital 25 IS', + 0x2380000: 'PowerShot A590 IS', + 0x2390000: 'PowerShot A580', + 0x2420000: 'PowerShot A470', + 0x2430000: 'PowerShot SD1100 IS / Digital IXUS 80 IS / IXY Digital 20 IS', + 0x2460000: 'PowerShot SX1 IS', + 0x2470000: 'PowerShot SX10 IS', + 0x2480000: 'PowerShot A1000 IS', + 0x2490000: 'PowerShot G10', + 0x2510000: 'PowerShot A2000 IS', + 0x2520000: 'PowerShot SX110 IS', + 0x2530000: 'PowerShot SD990 IS / Digital IXUS 980 IS / IXY Digital 3000 IS', + 0x2540000: 'PowerShot SD880 IS / Digital IXUS 870 IS / IXY Digital 920 IS', + 0x2550000: 'PowerShot E1', + 0x2560000: 'PowerShot D10', + 0x2570000: 'PowerShot SD960 IS / Digital IXUS 110 IS / IXY Digital 510 IS', + 0x2580000: 'PowerShot A2100 IS', + 0x2590000: 'PowerShot A480', + 0x2600000: 'PowerShot SX200 IS', + 0x2610000: 'PowerShot SD970 IS / Digital IXUS 990 IS / IXY Digital 830 IS', + 0x2620000: 'PowerShot SD780 IS / Digital IXUS 100 IS / IXY Digital 210 IS', + 0x2630000: 'PowerShot A1100 IS', + 0x2640000: 'PowerShot SD1200 IS / Digital IXUS 95 IS / IXY Digital 110 IS', + 0x2700000: 'PowerShot G11', + 0x2710000: 'PowerShot SX120 IS', + 0x2720000: 'PowerShot S90', + 0x2750000: 'PowerShot SX20 IS', + 0x2760000: 'PowerShot SD980 IS / Digital IXUS 200 IS / IXY Digital 930 IS', + 0x2770000: 'PowerShot SD940 IS / Digital IXUS 120 IS / IXY Digital 220 IS', + 0x2800000: 'PowerShot A495', + 0x2810000: 'PowerShot A490', + 0x2820000: 'PowerShot A3100 IS / A3150 IS', + 0x2830000: 'PowerShot A3000 IS', + 0x2840000: 'PowerShot SD1400 IS / IXUS 130 / IXY 400F', + 0x2850000: 'PowerShot SD1300 IS / IXUS 105 / IXY 200F', + 0x2860000: 'PowerShot SD3500 IS / IXUS 210 / IXY 10S', + 0x2870000: 'PowerShot SX210 IS', + 0x2880000: 'PowerShot SD4000 IS / IXUS 300 HS / IXY 30S', + 0x2890000: 'PowerShot SD4500 IS / IXUS 1000 HS / IXY 50S', + 0x2920000: 'PowerShot G12', + 0x2930000: 'PowerShot SX30 IS', + 0x2940000: 'PowerShot SX130 IS', + 0x2950000: 'PowerShot S95', + 0x2980000: 'PowerShot A3300 IS', + 0x2990000: 'PowerShot A3200 IS', + 0x3000000: 'PowerShot ELPH 500 HS / IXUS 310 HS / IXY 31S', + 0x3010000: 'PowerShot Pro90 IS', + 0x3010001: 'PowerShot A800', + 0x3020000: 'PowerShot ELPH 100 HS / IXUS 115 HS / IXY 210F', + 0x3030000: 'PowerShot SX230 HS', + 0x3040000: 'PowerShot ELPH 300 HS / IXUS 220 HS / IXY 410F', + 0x3050000: 'PowerShot A2200', + 0x3060000: 'PowerShot A1200', + 0x3070000: 'PowerShot SX220 HS', + 0x3080000: 'PowerShot G1 X', + 0x3090000: 'PowerShot SX150 IS', + 0x3100000: 'PowerShot ELPH 510 HS / IXUS 1100 HS / IXY 51S', + 0x3110000: 'PowerShot S100 (new)', + 0x3130000: 'PowerShot SX40 HS', + 0x3120000: 'PowerShot ELPH 310 HS / IXUS 230 HS / IXY 600F', + 0x3160000: 'PowerShot A1300', + 0x3170000: 'PowerShot A810', + 0x3180000: 'PowerShot ELPH 320 HS / IXUS 240 HS / IXY 420F', + 0x3190000: 'PowerShot ELPH 110 HS / IXUS 125 HS / IXY 220F', + 0x3200000: 'PowerShot D20', + 0x3210000: 'PowerShot A4000 IS', + 0x3220000: 'PowerShot SX260 HS', + 0x3230000: 'PowerShot SX240 HS', + 0x3240000: 'PowerShot ELPH 530 HS / IXUS 510 HS / IXY 1', + 0x3250000: 'PowerShot ELPH 520 HS / IXUS 500 HS / IXY 3', + 0x3260000: 'PowerShot A3400 IS', + 0x3270000: 'PowerShot A2400 IS', + 0x3280000: 'PowerShot A2300', + 0x3330000: 'PowerShot G15', + 0x3340000: 'PowerShot SX50', + 0x3350000: 'PowerShot SX160 IS', + 0x3360000: 'PowerShot S110 (new)', + 0x3370000: 'PowerShot SX500 IS', + 0x3380000: 'PowerShot N', + 0x3390000: 'IXUS 245 HS / IXY 430F', + 0x3400000: 'PowerShot SX280 HS', + 0x3410000: 'PowerShot SX270 HS', + 0x3420000: 'PowerShot A3500 IS', + 0x3430000: 'PowerShot A2600', + 0x3450000: 'PowerShot A1400', + 0x3460000: 'PowerShot ELPH 130 IS / IXUS 140 / IXY 110F', + 0x3470000: 'PowerShot ELPH 115/120 IS / IXUS 132/135 / IXY 90F/100F', + 0x3490000: 'PowerShot ELPH 330 HS / IXUS 255 HS / IXY 610F', + 0x3510000: 'PowerShot A2500', + 0x3540000: 'PowerShot G16', + 0x3550000: 'PowerShot S120', + 0x3560000: 'PowerShot SX170 IS', + 0x3580000: 'PowerShot SX510 HS', + 0x3590000: 'PowerShot S200 (new)', + 0x3600000: 'IXY 620F', + 0x3610000: 'PowerShot N100', + 0x3640000: 'PowerShot G1 X Mark II', + 0x3650000: 'PowerShot D30', + 0x3660000: 'PowerShot SX700 HS', + 0x3670000: 'PowerShot SX600 HS', + 0x3680000: 'PowerShot ELPH 140 IS / IXUS 150 / IXY 130', + 0x3690000: 'PowerShot ELPH 135 / IXUS 145 / IXY 120', + 0x3700000: 'PowerShot ELPH 340 HS / IXUS 265 HS / IXY 630', + 0x3710000: 'PowerShot ELPH 150 IS / IXUS 155 / IXY 140', + 0x3740000: 'EOS M3', + 0x3750000: 'PowerShot SX60 HS', + 0x3760000: 'PowerShot SX520 HS', + 0x3770000: 'PowerShot SX400 IS', + 0x3780000: 'PowerShot G7 X', + 0x3790000: 'PowerShot N2', + 0x3800000: 'PowerShot SX530 HS', + 0x3820000: 'PowerShot SX710 HS', + 0x3830000: 'PowerShot SX610 HS', + 0x3870000: 'PowerShot ELPH 160 / IXUS 160', + 0x3890000: 'PowerShot ELPH 170 IS / IXUS 170', + 0x3910000: 'PowerShot SX410 IS', + 0x4040000: 'PowerShot G1', + 0x6040000: 'PowerShot S100 / Digital IXUS / IXY Digital', + 0x4007d673: 'DC19/DC21/DC22', + 0x4007d674: 'XH A1', + 0x4007d675: 'HV10', + 0x4007d676: 'MD130/MD140/MD150/MD160/ZR850', + 0x4007d777: 'DC50', + 0x4007d778: 'HV20', + 0x4007d779: 'DC211', + 0x4007d77a: 'HG10', + 0x4007d77b: 'HR10', + 0x4007d77d: 'MD255/ZR950', + 0x4007d81c: 'HF11', + 0x4007d878: 'HV30', + 0x4007d87c: 'XH A1S', + 0x4007d87e: 'DC301/DC310/DC311/DC320/DC330', + 0x4007d87f: 'FS100', + 0x4007d880: 'HF10', + 0x4007d882: 'HG20/HG21', + 0x4007d925: 'HF21', + 0x4007d926: 'HF S11', + 0x4007d978: 'HV40', + 0x4007d987: 'DC410/DC411/DC420', + 0x4007d988: 'FS19/FS20/FS21/FS22/FS200', + 0x4007d989: 'HF20/HF200', + 0x4007d98a: 'HF S10/S100', + 0x4007da8e: 'HF R10/R16/R17/R18/R100/R106', + 0x4007da8f: 'HF M30/M31/M36/M300/M306', + 0x4007da90: 'HF S20/S21/S200', + 0x4007da92: 'FS31/FS36/FS37/FS300/FS305/FS306/FS307', + 0x4007dda9: 'HF G25', + 0x80000001: 'EOS-1D', + 0x80000167: 'EOS-1DS', + 0x80000168: 'EOS 10D', + 0x80000169: 'EOS-1D Mark III', + 0x80000170: 'EOS Digital Rebel / 300D / Kiss Digital', + 0x80000174: 'EOS-1D Mark II', + 0x80000175: 'EOS 20D', + 0x80000176: 'EOS Digital Rebel XSi / 450D / Kiss X2', + 0x80000188: 'EOS-1Ds Mark II', + 0x80000189: 'EOS Digital Rebel XT / 350D / Kiss Digital N', + 0x80000190: 'EOS 40D', + 0x80000213: 'EOS 5D', + 0x80000215: 'EOS-1Ds Mark III', + 0x80000218: 'EOS 5D Mark II', + 0x80000219: 'WFT-E1', + 0x80000232: 'EOS-1D Mark II N', + 0x80000234: 'EOS 30D', + 0x80000236: 'EOS Digital Rebel XTi / 400D / Kiss Digital X', + 0x80000241: 'WFT-E2', + 0x80000246: 'WFT-E3', + 0x80000250: 'EOS 7D', + 0x80000252: 'EOS Rebel T1i / 500D / Kiss X3', + 0x80000254: 'EOS Rebel XS / 1000D / Kiss F', + 0x80000261: 'EOS 50D', + 0x80000269: 'EOS-1D X', + 0x80000270: 'EOS Rebel T2i / 550D / Kiss X4', + 0x80000271: 'WFT-E4', + 0x80000273: 'WFT-E5', + 0x80000281: 'EOS-1D Mark IV', + 0x80000285: 'EOS 5D Mark III', + 0x80000286: 'EOS Rebel T3i / 600D / Kiss X5', + 0x80000287: 'EOS 60D', + 0x80000288: 'EOS Rebel T3 / 1100D / Kiss X50', + 0x80000289: 'EOS 7D Mark II', + 0x80000297: 'WFT-E2 II', + 0x80000298: 'WFT-E4 II', + 0x80000301: 'EOS Rebel T4i / 650D / Kiss X6i', + 0x80000302: 'EOS 6D', + 0x80000324: 'EOS-1D C', + 0x80000325: 'EOS 70D', + 0x80000326: 'EOS Rebel T5i / 700D / Kiss X7i', + 0x80000327: 'EOS Rebel T5 / 1200D / Kiss X70', + 0x80000331: 'EOS M', + 0x80000355: 'EOS M2', + 0x80000346: 'EOS Rebel SL1 / 100D / Kiss X7', + 0x80000347: 'EOS Rebel T6s / 760D / 8000D', + 0x80000382: 'EOS 5DS', + 0x80000393: 'EOS Rebel T6i / 750D / Kiss X8i', + 0x80000401: 'EOS 5DS R', + }), + 0x0013: ('ThumbnailImageValidArea', ), + 0x0015: ('SerialNumberFormat', { + 0x90000000: 'Format 1', + 0xA0000000: 'Format 2' + }), + 0x001a: ('SuperMacro', { + 0: 'Off', + 1: 'On (1)', + 2: 'On (2)' + }), + 0x001c: ('DateStampMode', { + 0: 'Off', + 1: 'Date', + 2: 'Date & Time', + }), + 0x001e: ('FirmwareRevision', ), + 0x0028: ('ImageUniqueID', ), + 0x0095: ('LensModel', ), + 0x0096: ('InternalSerialNumber ', ), + 0x0097: ('DustRemovalData ', ), + 0x0098: ('CropInfo ', ), + 0x009a: ('AspectInfo', ), + 0x00b4: ('ColorSpace', { + 1: 'sRGB', + 2: 'Adobe RGB' + }), +} + +# this is in element offset, name, optional value dictionary format +# 0x0001 +CAMERA_SETTINGS = { + 1: ('Macromode', { + 1: 'Macro', + 2: 'Normal' + }), + 2: ('SelfTimer', ), + 3: ('Quality', { + 1: 'Economy', + 2: 'Normal', + 3: 'Fine', + 5: 'Superfine' + }), + 4: ('FlashMode', { + 0: 'Flash Not Fired', + 1: 'Auto', + 2: 'On', + 3: 'Red-Eye Reduction', + 4: 'Slow Synchro', + 5: 'Auto + Red-Eye Reduction', + 6: 'On + Red-Eye Reduction', + 16: 'external flash' + }), + 5: ('ContinuousDriveMode', { + 0: 'Single Or Timer', + 1: 'Continuous', + 2: 'Movie', + }), + 7: ('FocusMode', { + 0: 'One-Shot', + 1: 'AI Servo', + 2: 'AI Focus', + 3: 'MF', + 4: 'Single', + 5: 'Continuous', + 6: 'MF' + }), + 9: ('RecordMode', { + 1: 'JPEG', + 2: 'CRW+THM', + 3: 'AVI+THM', + 4: 'TIF', + 5: 'TIF+JPEG', + 6: 'CR2', + 7: 'CR2+JPEG', + 9: 'Video' + }), + 10: ('ImageSize', { + 0: 'Large', + 1: 'Medium', + 2: 'Small' + }), + 11: ('EasyShootingMode', { + 0: 'Full Auto', + 1: 'Manual', + 2: 'Landscape', + 3: 'Fast Shutter', + 4: 'Slow Shutter', + 5: 'Night', + 6: 'B&W', + 7: 'Sepia', + 8: 'Portrait', + 9: 'Sports', + 10: 'Macro/Close-Up', + 11: 'Pan Focus', + 51: 'High Dynamic Range', + }), + 12: ('DigitalZoom', { + 0: 'None', + 1: '2x', + 2: '4x', + 3: 'Other' + }), + 13: ('Contrast', { + 0xFFFF: 'Low', + 0: 'Normal', + 1: 'High' + }), + 14: ('Saturation', { + 0xFFFF: 'Low', + 0: 'Normal', + 1: 'High' + }), + 15: ('Sharpness', { + 0xFFFF: 'Low', + 0: 'Normal', + 1: 'High' + }), + 16: ('ISO', { + 0: 'See ISOSpeedRatings Tag', + 15: 'Auto', + 16: '50', + 17: '100', + 18: '200', + 19: '400' + }), + 17: ('MeteringMode', { + 0: 'Default', + 1: 'Spot', + 2: 'Average', + 3: 'Evaluative', + 4: 'Partial', + 5: 'Center-weighted' + }), + 18: ('FocusType', { + 0: 'Manual', + 1: 'Auto', + 3: 'Close-Up (Macro)', + 8: 'Locked (Pan Mode)' + }), + 19: ('AFPointSelected', { + 0x3000: 'None (MF)', + 0x3001: 'Auto-Selected', + 0x3002: 'Right', + 0x3003: 'Center', + 0x3004: 'Left' + }), + 20: ('ExposureMode', { + 0: 'Easy Shooting', + 1: 'Program', + 2: 'Tv-priority', + 3: 'Av-priority', + 4: 'Manual', + 5: 'A-DEP' + }), + 22: ('LensType', ), + 23: ('LongFocalLengthOfLensInFocalUnits', ), + 24: ('ShortFocalLengthOfLensInFocalUnits', ), + 25: ('FocalUnitsPerMM', ), + 28: ('FlashActivity', { + 0: 'Did Not Fire', + 1: 'Fired' + }), + 29: ('FlashDetails', { + 0: 'Manual', + 1: 'TTL', + 2: 'A-TTL', + 3: 'E-TTL', + 4: 'FP Sync Enabled', + 7: '2nd("Rear")-Curtain Sync Used', + 11: 'FP Sync Used', + 13: 'Internal Flash', + 14: 'External E-TTL' + }), + 32: ('FocusMode', { + 0: 'Single', + 1: 'Continuous', + 8: 'Manual' + }), + 33: ('AESetting', { + 0: 'Normal AE', + 1: 'Exposure Compensation', + 2: 'AE Lock', + 3: 'AE Lock + Exposure Comp.', + 4: 'No AE' + }), + 34: ('ImageStabilization', { + 0: 'Off', + 1: 'On', + 2: 'Shoot Only', + 3: 'Panning', + 4: 'Dynamic', + 256: 'Off', + 257: 'On', + 258: 'Shoot Only', + 259: 'Panning', + 260: 'Dynamic' + }), + 39: ('SpotMeteringMode', { + 0: 'Center', + 1: 'AF Point' + }), + 41: ('ManualFlashOutput', { + 0x0: 'n/a', + 0x500: 'Full', + 0x502: 'Medium', + 0x504: 'Low', + 0x7fff: 'n/a' + }), +} + +# 0x0002 +FOCAL_LENGTH = { + 1: ('FocalType', { + 1: 'Fixed', + 2: 'Zoom', + }), + 2: ('FocalLength', ), +} + +# 0x0004 +SHOT_INFO = { + 7: ('WhiteBalance', { + 0: 'Auto', + 1: 'Sunny', + 2: 'Cloudy', + 3: 'Tungsten', + 4: 'Fluorescent', + 5: 'Flash', + 6: 'Custom' + }), + 8: ('SlowShutter', { + -1: 'n/a', + 0: 'Off', + 1: 'Night Scene', + 2: 'On', + 3: 'None' + }), + 9: ('SequenceNumber', ), + 14: ('AFPointUsed', ), + 15: ('FlashBias', { + 0xFFC0: '-2 EV', + 0xFFCC: '-1.67 EV', + 0xFFD0: '-1.50 EV', + 0xFFD4: '-1.33 EV', + 0xFFE0: '-1 EV', + 0xFFEC: '-0.67 EV', + 0xFFF0: '-0.50 EV', + 0xFFF4: '-0.33 EV', + 0x0000: '0 EV', + 0x000c: '0.33 EV', + 0x0010: '0.50 EV', + 0x0014: '0.67 EV', + 0x0020: '1 EV', + 0x002c: '1.33 EV', + 0x0030: '1.50 EV', + 0x0034: '1.67 EV', + 0x0040: '2 EV' + }), + 19: ('SubjectDistance', ), +} + +# 0x0026 +AF_INFO_2 = { + 2: ('AFAreaMode', { + 0: 'Off (Manual Focus)', + 2: 'Single-point AF', + 4: 'Multi-point AF or AI AF', + 5: 'Face Detect AF', + 6: 'Face + Tracking', + 7: 'Zone AF', + 8: 'AF Point Expansion', + 9: 'Spot AF', + 11: 'Flexizone Multi', + 13: 'Flexizone Single', + }), + 3: ('NumAFPoints', ), + 4: ('ValidAFPoints', ), + 5: ('CanonImageWidth', ), +} + +# 0x0093 +FILE_INFO = { + 1: ('FileNumber', ), + 3: ('BracketMode', { + 0: 'Off', + 1: 'AEB', + 2: 'FEB', + 3: 'ISO', + 4: 'WB', + }), + 4: ('BracketValue', ), + 5: ('BracketShotNumber', ), + 6: ('RawJpgQuality', { + 0xFFFF: 'n/a', + 1: 'Economy', + 2: 'Normal', + 3: 'Fine', + 4: 'RAW', + 5: 'Superfine', + 130: 'Normal Movie' + }), + 7: ('RawJpgSize', { + 0: 'Large', + 1: 'Medium', + 2: 'Small', + 5: 'Medium 1', + 6: 'Medium 2', + 7: 'Medium 3', + 8: 'Postcard', + 9: 'Widescreen', + 10: 'Medium Widescreen', + 14: 'Small 1', + 15: 'Small 2', + 16: 'Small 3', + 128: '640x480 Movie', + 129: 'Medium Movie', + 130: 'Small Movie', + 137: '1280x720 Movie', + 142: '1920x1080 Movie', + }), + 8: ('LongExposureNoiseReduction2', { + 0: 'Off', + 1: 'On (1D)', + 2: 'On', + 3: 'Auto' + }), + 9: ('WBBracketMode', { + 0: 'Off', + 1: 'On (shift AB)', + 2: 'On (shift GM)' + }), + 12: ('WBBracketValueAB', ), + 13: ('WBBracketValueGM', ), + 14: ('FilterEffect', { + 0: 'None', + 1: 'Yellow', + 2: 'Orange', + 3: 'Red', + 4: 'Green' + }), + 15: ('ToningEffect', { + 0: 'None', + 1: 'Sepia', + 2: 'Blue', + 3: 'Purple', + 4: 'Green', + }), + 16: ('MacroMagnification', ), + 19: ('LiveViewShooting', { + 0: 'Off', + 1: 'On' + }), + 25: ('FlashExposureLock', { + 0: 'Off', + 1: 'On' + }) +} + + +def add_one(value): + return value + 1 + + +def subtract_one(value): + return value - 1 + + +def convert_temp(value): + return '%d C' % (value - 128) + +# CameraInfo data structures have variable sized members. Each entry here is: +# byte offset: (item name, data item type, decoding map). +# Note that the data item type is fed directly to struct.unpack at the +# specified offset. +CAMERA_INFO_TAG_NAME = 'MakerNote Tag 0x000D' + +CAMERA_INFO_5D = { + 23: ('CameraTemperature', ' 127: + a = 256 - a + ret_str = '-' + else: + ret_str = '+' + step = seq[2] # Assume third value means the step size + whole = a / step + a = a % step + if whole != 0: + ret_str = '%s%s ' % (ret_str, str(whole)) + if a == 0: + ret_str += 'EV' + else: + r = Ratio(a, step) + ret_str = ret_str + r.__repr__() + ' EV' + return ret_str + +# Nikon E99x MakerNote Tags +TAGS_NEW = { + 0x0001: ('MakernoteVersion', make_string), # Sometimes binary + 0x0002: ('ISOSetting', make_string), + 0x0003: ('ColorMode', ), + 0x0004: ('Quality', ), + 0x0005: ('Whitebalance', ), + 0x0006: ('ImageSharpening', ), + 0x0007: ('FocusMode', ), + 0x0008: ('FlashSetting', ), + 0x0009: ('AutoFlashMode', ), + 0x000B: ('WhiteBalanceBias', ), + 0x000C: ('WhiteBalanceRBCoeff', ), + 0x000D: ('ProgramShift', ev_bias), + # Nearly the same as the other EV vals, but step size is 1/12 EV (?) + 0x000E: ('ExposureDifference', ev_bias), + 0x000F: ('ISOSelection', ), + 0x0010: ('DataDump', ), + 0x0011: ('NikonPreview', ), + 0x0012: ('FlashCompensation', ev_bias), + 0x0013: ('ISOSpeedRequested', ), + 0x0016: ('PhotoCornerCoordinates', ), + 0x0017: ('ExternalFlashExposureComp', ev_bias), + 0x0018: ('FlashBracketCompensationApplied', ev_bias), + 0x0019: ('AEBracketCompensationApplied', ), + 0x001A: ('ImageProcessing', ), + 0x001B: ('CropHiSpeed', ), + 0x001C: ('ExposureTuning', ), + 0x001D: ('SerialNumber', ), # Conflict with 0x00A0 ? + 0x001E: ('ColorSpace', ), + 0x001F: ('VRInfo', ), + 0x0020: ('ImageAuthentication', ), + 0x0022: ('ActiveDLighting', ), + 0x0023: ('PictureControl', ), + 0x0024: ('WorldTime', ), + 0x0025: ('ISOInfo', ), + 0x0080: ('ImageAdjustment', ), + 0x0081: ('ToneCompensation', ), + 0x0082: ('AuxiliaryLens', ), + 0x0083: ('LensType', ), + 0x0084: ('LensMinMaxFocalMaxAperture', ), + 0x0085: ('ManualFocusDistance', ), + 0x0086: ('DigitalZoomFactor', ), + 0x0087: ('FlashMode', { + 0x00: 'Did Not Fire', + 0x01: 'Fired, Manual', + 0x07: 'Fired, External', + 0x08: 'Fired, Commander Mode ', + 0x09: 'Fired, TTL Mode', + }), + 0x0088: ('AFFocusPosition', { + 0x0000: 'Center', + 0x0100: 'Top', + 0x0200: 'Bottom', + 0x0300: 'Left', + 0x0400: 'Right', + }), + 0x0089: ('BracketingMode', { + 0x00: 'Single frame, no bracketing', + 0x01: 'Continuous, no bracketing', + 0x02: 'Timer, no bracketing', + 0x10: 'Single frame, exposure bracketing', + 0x11: 'Continuous, exposure bracketing', + 0x12: 'Timer, exposure bracketing', + 0x40: 'Single frame, white balance bracketing', + 0x41: 'Continuous, white balance bracketing', + 0x42: 'Timer, white balance bracketing' + }), + 0x008A: ('AutoBracketRelease', ), + 0x008B: ('LensFStops', ), + 0x008C: ('NEFCurve1', ), # ExifTool calls this 'ContrastCurve' + 0x008D: ('ColorMode', ), + 0x008F: ('SceneMode', ), + 0x0090: ('LightingType', ), + 0x0091: ('ShotInfo', ), # First 4 bytes are a version number in ASCII + 0x0092: ('HueAdjustment', ), + # ExifTool calls this 'NEFCompression', should be 1-4 + 0x0093: ('Compression', ), + 0x0094: ('Saturation', { + -3: 'B&W', + -2: '-2', + -1: '-1', + 0: '0', + 1: '1', + 2: '2', + }), + 0x0095: ('NoiseReduction', ), + 0x0096: ('NEFCurve2', ), # ExifTool calls this 'LinearizationTable' + 0x0097: ('ColorBalance', ), # First 4 bytes are a version number in ASCII + 0x0098: ('LensData', ), # First 4 bytes are a version number in ASCII + 0x0099: ('RawImageCenter', ), + 0x009A: ('SensorPixelSize', ), + 0x009C: ('Scene Assist', ), + 0x009E: ('RetouchHistory', ), + 0x00A0: ('SerialNumber', ), + 0x00A2: ('ImageDataSize', ), + # 00A3: unknown - a single byte 0 + # 00A4: In NEF, looks like a 4 byte ASCII version number ('0200') + 0x00A5: ('ImageCount', ), + 0x00A6: ('DeletedImageCount', ), + 0x00A7: ('TotalShutterReleases', ), + # First 4 bytes are a version number in ASCII, with version specific + # info to follow. Its hard to treat it as a string due to embedded nulls. + 0x00A8: ('FlashInfo', ), + 0x00A9: ('ImageOptimization', ), + 0x00AA: ('Saturation', ), + 0x00AB: ('DigitalVariProgram', ), + 0x00AC: ('ImageStabilization', ), + 0x00AD: ('AFResponse', ), + 0x00B0: ('MultiExposure', ), + 0x00B1: ('HighISONoiseReduction', ), + 0x00B6: ('PowerUpTime', ), + 0x00B7: ('AFInfo2', ), + 0x00B8: ('FileInfo', ), + 0x00B9: ('AFTune', ), + 0x0100: ('DigitalICE', ), + 0x0103: ('PreviewCompression', { + 1: 'Uncompressed', + 2: 'CCITT 1D', + 3: 'T4/Group 3 Fax', + 4: 'T6/Group 4 Fax', + 5: 'LZW', + 6: 'JPEG (old-style)', + 7: 'JPEG', + 8: 'Adobe Deflate', + 9: 'JBIG B&W', + 10: 'JBIG Color', + 32766: 'Next', + 32769: 'Epson ERF Compressed', + 32771: 'CCIRLEW', + 32773: 'PackBits', + 32809: 'Thunderscan', + 32895: 'IT8CTPAD', + 32896: 'IT8LW', + 32897: 'IT8MP', + 32898: 'IT8BL', + 32908: 'PixarFilm', + 32909: 'PixarLog', + 32946: 'Deflate', + 32947: 'DCS', + 34661: 'JBIG', + 34676: 'SGILog', + 34677: 'SGILog24', + 34712: 'JPEG 2000', + 34713: 'Nikon NEF Compressed', + 65000: 'Kodak DCR Compressed', + 65535: 'Pentax PEF Compressed', + }), + 0x0201: ('PreviewImageStart', ), + 0x0202: ('PreviewImageLength', ), + 0x0213: ('PreviewYCbCrPositioning', { + 1: 'Centered', + 2: 'Co-sited', + }), + 0x0E09: ('NikonCaptureVersion', ), + 0x0E0E: ('NikonCaptureOffsets', ), + 0x0E10: ('NikonScan', ), + 0x0E22: ('NEFBitDepth', ), +} + +TAGS_OLD = { + 0x0003: ('Quality', { + 1: 'VGA Basic', + 2: 'VGA Normal', + 3: 'VGA Fine', + 4: 'SXGA Basic', + 5: 'SXGA Normal', + 6: 'SXGA Fine', + }), + 0x0004: ('ColorMode', { + 1: 'Color', + 2: 'Monochrome', + }), + 0x0005: ('ImageAdjustment', { + 0: 'Normal', + 1: 'Bright+', + 2: 'Bright-', + 3: 'Contrast+', + 4: 'Contrast-', + }), + 0x0006: ('CCDSpeed', { + 0: 'ISO 80', + 2: 'ISO 160', + 4: 'ISO 320', + 5: 'ISO 100', + }), + 0x0007: ('WhiteBalance', { + 0: 'Auto', + 1: 'Preset', + 2: 'Daylight', + 3: 'Incandescent', + 4: 'Fluorescent', + 5: 'Cloudy', + 6: 'Speed Light', + }), +} diff --git a/venv/lib/python2.7/site-packages/exifread/tags/makernote/olympus.py b/venv/lib/python2.7/site-packages/exifread/tags/makernote/olympus.py new file mode 100644 index 0000000..a915a59 --- /dev/null +++ b/venv/lib/python2.7/site-packages/exifread/tags/makernote/olympus.py @@ -0,0 +1,291 @@ + +from ...utils import make_string + +def special_mode(v): + """decode Olympus SpecialMode tag in MakerNote""" + mode1 = { + 0: 'Normal', + 1: 'Unknown', + 2: 'Fast', + 3: 'Panorama', + } + mode2 = { + 0: 'Non-panoramic', + 1: 'Left to right', + 2: 'Right to left', + 3: 'Bottom to top', + 4: 'Top to bottom', + } + if not v or (v[0] not in mode1 or v[2] not in mode2): + return v + return '%s - sequence %d - %s' % (mode1[v[0]], v[1], mode2[v[2]]) + + +TAGS = { + # ah HAH! those sneeeeeaky bastids! this is how they get past the fact + # that a JPEG thumbnail is not allowed in an uncompressed TIFF file + 0x0100: ('JPEGThumbnail', ), + 0x0200: ('SpecialMode', special_mode), + 0x0201: ('JPEGQual', { + 1: 'SQ', + 2: 'HQ', + 3: 'SHQ', + }), + 0x0202: ('Macro', { + 0: 'Normal', + 1: 'Macro', + 2: 'SuperMacro' + }), + 0x0203: ('BWMode', { + 0: 'Off', + 1: 'On' + }), + 0x0204: ('DigitalZoom', ), + 0x0205: ('FocalPlaneDiagonal', ), + 0x0206: ('LensDistortionParams', ), + 0x0207: ('SoftwareRelease', ), + 0x0208: ('PictureInfo', ), + 0x0209: ('CameraID', make_string), # print as string + 0x0F00: ('DataDump', ), + 0x0300: ('PreCaptureFrames', ), + 0x0404: ('SerialNumber', ), + 0x1000: ('ShutterSpeedValue', ), + 0x1001: ('ISOValue', ), + 0x1002: ('ApertureValue', ), + 0x1003: ('BrightnessValue', ), + 0x1004: ('FlashMode', { + 2: 'On', + 3: 'Off' + }), + 0x1005: ('FlashDevice', { + 0: 'None', + 1: 'Internal', + 4: 'External', + 5: 'Internal + External' + }), + 0x1006: ('ExposureCompensation', ), + 0x1007: ('SensorTemperature', ), + 0x1008: ('LensTemperature', ), + 0x100b: ('FocusMode', { + 0: 'Auto', + 1: 'Manual' + }), + 0x1017: ('RedBalance', ), + 0x1018: ('BlueBalance', ), + 0x101a: ('SerialNumber', ), + 0x1023: ('FlashExposureComp', ), + 0x1026: ('ExternalFlashBounce', { + 0: 'No', + 1: 'Yes' + }), + 0x1027: ('ExternalFlashZoom', ), + 0x1028: ('ExternalFlashMode', ), + 0x1029: ('Contrast int16u', { + 0: 'High', + 1: 'Normal', + 2: 'Low' + }), + 0x102a: ('SharpnessFactor', ), + 0x102b: ('ColorControl', ), + 0x102c: ('ValidBits', ), + 0x102d: ('CoringFilter', ), + 0x102e: ('OlympusImageWidth', ), + 0x102f: ('OlympusImageHeight', ), + 0x1034: ('CompressionRatio', ), + 0x1035: ('PreviewImageValid', { + 0: 'No', + 1: 'Yes' + }), + 0x1036: ('PreviewImageStart', ), + 0x1037: ('PreviewImageLength', ), + 0x1039: ('CCDScanMode', { + 0: 'Interlaced', + 1: 'Progressive' + }), + 0x103a: ('NoiseReduction', { + 0: 'Off', + 1: 'On' + }), + 0x103b: ('InfinityLensStep', ), + 0x103c: ('NearLensStep', ), + + # TODO - these need extra definitions + # http://search.cpan.org/src/EXIFTOOL/Image-ExifTool-6.90/html/TagNames/Olympus.html + 0x2010: ('Equipment', ), + 0x2020: ('CameraSettings', ), + 0x2030: ('RawDevelopment', ), + 0x2040: ('ImageProcessing', ), + 0x2050: ('FocusInfo', ), + 0x3000: ('RawInfo ', ), +} + +# 0x2020 CameraSettings +TAG_0x2020 = { + 0x0100: ('PreviewImageValid', { + 0: 'No', + 1: 'Yes' + }), + 0x0101: ('PreviewImageStart', ), + 0x0102: ('PreviewImageLength', ), + 0x0200: ('ExposureMode', { + 1: 'Manual', + 2: 'Program', + 3: 'Aperture-priority AE', + 4: 'Shutter speed priority AE', + 5: 'Program-shift' + }), + 0x0201: ('AELock', { + 0: 'Off', + 1: 'On' + }), + 0x0202: ('MeteringMode', { + 2: 'Center Weighted', + 3: 'Spot', + 5: 'ESP', + 261: 'Pattern+AF', + 515: 'Spot+Highlight control', + 1027: 'Spot+Shadow control' + }), + 0x0300: ('MacroMode', { + 0: 'Off', + 1: 'On' + }), + 0x0301: ('FocusMode', { + 0: 'Single AF', + 1: 'Sequential shooting AF', + 2: 'Continuous AF', + 3: 'Multi AF', + 10: 'MF' + }), + 0x0302: ('FocusProcess', { + 0: 'AF Not Used', + 1: 'AF Used' + }), + 0x0303: ('AFSearch', { + 0: 'Not Ready', + 1: 'Ready' + }), + 0x0304: ('AFAreas', ), + 0x0401: ('FlashExposureCompensation', ), + 0x0500: ('WhiteBalance2', { + 0: 'Auto', + 16: '7500K (Fine Weather with Shade)', + 17: '6000K (Cloudy)', + 18: '5300K (Fine Weather)', + 20: '3000K (Tungsten light)', + 21: '3600K (Tungsten light-like)', + 33: '6600K (Daylight fluorescent)', + 34: '4500K (Neutral white fluorescent)', + 35: '4000K (Cool white fluorescent)', + 48: '3600K (Tungsten light-like)', + 256: 'Custom WB 1', + 257: 'Custom WB 2', + 258: 'Custom WB 3', + 259: 'Custom WB 4', + 512: 'Custom WB 5400K', + 513: 'Custom WB 2900K', + 514: 'Custom WB 8000K', + }), + 0x0501: ('WhiteBalanceTemperature', ), + 0x0502: ('WhiteBalanceBracket', ), + 0x0503: ('CustomSaturation', ), # (3 numbers: 1. CS Value, 2. Min, 3. Max) + 0x0504: ('ModifiedSaturation', { + 0: 'Off', + 1: 'CM1 (Red Enhance)', + 2: 'CM2 (Green Enhance)', + 3: 'CM3 (Blue Enhance)', + 4: 'CM4 (Skin Tones)', + }), + 0x0505: ('ContrastSetting', ), # (3 numbers: 1. Contrast, 2. Min, 3. Max) + 0x0506: ('SharpnessSetting', ), # (3 numbers: 1. Sharpness, 2. Min, 3. Max) + 0x0507: ('ColorSpace', { + 0: 'sRGB', + 1: 'Adobe RGB', + 2: 'Pro Photo RGB' + }), + 0x0509: ('SceneMode', { + 0: 'Standard', + 6: 'Auto', + 7: 'Sport', + 8: 'Portrait', + 9: 'Landscape+Portrait', + 10: 'Landscape', + 11: 'Night scene', + 13: 'Panorama', + 16: 'Landscape+Portrait', + 17: 'Night+Portrait', + 19: 'Fireworks', + 20: 'Sunset', + 22: 'Macro', + 25: 'Documents', + 26: 'Museum', + 28: 'Beach&Snow', + 30: 'Candle', + 35: 'Underwater Wide1', + 36: 'Underwater Macro', + 39: 'High Key', + 40: 'Digital Image Stabilization', + 44: 'Underwater Wide2', + 45: 'Low Key', + 46: 'Children', + 48: 'Nature Macro', + }), + 0x050a: ('NoiseReduction', { + 0: 'Off', + 1: 'Noise Reduction', + 2: 'Noise Filter', + 3: 'Noise Reduction + Noise Filter', + 4: 'Noise Filter (ISO Boost)', + 5: 'Noise Reduction + Noise Filter (ISO Boost)' + }), + 0x050b: ('DistortionCorrection', { + 0: 'Off', + 1: 'On' + }), + 0x050c: ('ShadingCompensation', { + 0: 'Off', + 1: 'On' + }), + 0x050d: ('CompressionFactor', ), + 0x050f: ('Gradation', { + '-1 -1 1': 'Low Key', + '0 -1 1': 'Normal', + '1 -1 1': 'High Key' + }), + 0x0520: ('PictureMode', { + 1: 'Vivid', + 2: 'Natural', + 3: 'Muted', + 256: 'Monotone', + 512: 'Sepia' + }), + 0x0521: ('PictureModeSaturation', ), + 0x0522: ('PictureModeHue?', ), + 0x0523: ('PictureModeContrast', ), + 0x0524: ('PictureModeSharpness', ), + 0x0525: ('PictureModeBWFilter', { + 0: 'n/a', + 1: 'Neutral', + 2: 'Yellow', + 3: 'Orange', + 4: 'Red', + 5: 'Green' + }), + 0x0526: ('PictureModeTone', { + 0: 'n/a', + 1: 'Neutral', + 2: 'Sepia', + 3: 'Blue', + 4: 'Purple', + 5: 'Green' + }), + 0x0600: ('Sequence', ), # 2 or 3 numbers: 1. Mode, 2. Shot number, 3. Mode bits + 0x0601: ('PanoramaMode', ), # (2 numbers: 1. Mode, 2. Shot number) + 0x0603: ('ImageQuality2', { + 1: 'SQ', + 2: 'HQ', + 3: 'SHQ', + 4: 'RAW', + }), + 0x0901: ('ManometerReading', ), +} diff --git a/venv/lib/python2.7/site-packages/exifread/tags/makernote_apple.py b/venv/lib/python2.7/site-packages/exifread/tags/makernote_apple.py new file mode 100644 index 0000000..57717ca --- /dev/null +++ b/venv/lib/python2.7/site-packages/exifread/tags/makernote_apple.py @@ -0,0 +1,13 @@ +""" +Makernote (proprietary) tag definitions for Apple iOS + +Based on version 1.01 of ExifTool -> Image/ExifTool/Apple.pm +http://owl.phy.queensu.ca/~phil/exiftool/ +""" + +TAGS = { + 0x000a: ('HDRImageType', { + 3: 'HDR Image', + 4: 'Original Image', + }), +} diff --git a/venv/lib/python2.7/site-packages/exifread/tags/makernote_canon.py b/venv/lib/python2.7/site-packages/exifread/tags/makernote_canon.py new file mode 100644 index 0000000..f41c84c --- /dev/null +++ b/venv/lib/python2.7/site-packages/exifread/tags/makernote_canon.py @@ -0,0 +1,711 @@ +""" +Makernote (proprietary) tag definitions for Canon. + +http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Canon.html +""" + +TAGS = { + 0x0003: ('FlashInfo',), + 0x0006: ('ImageType', ), + 0x0007: ('FirmwareVersion', ), + 0x0008: ('ImageNumber', ), + 0x0009: ('OwnerName', ), + 0x000c: ('SerialNumber', ), + 0x000e: ('FileLength', ), + 0x0010: ('ModelID', { + 0x1010000: 'PowerShot A30', + 0x1040000: 'PowerShot S300 / Digital IXUS 300 / IXY Digital 300', + 0x1060000: 'PowerShot A20', + 0x1080000: 'PowerShot A10', + 0x1090000: 'PowerShot S110 / Digital IXUS v / IXY Digital 200', + 0x1100000: 'PowerShot G2', + 0x1110000: 'PowerShot S40', + 0x1120000: 'PowerShot S30', + 0x1130000: 'PowerShot A40', + 0x1140000: 'EOS D30', + 0x1150000: 'PowerShot A100', + 0x1160000: 'PowerShot S200 / Digital IXUS v2 / IXY Digital 200a', + 0x1170000: 'PowerShot A200', + 0x1180000: 'PowerShot S330 / Digital IXUS 330 / IXY Digital 300a', + 0x1190000: 'PowerShot G3', + 0x1210000: 'PowerShot S45', + 0x1230000: 'PowerShot SD100 / Digital IXUS II / IXY Digital 30', + 0x1240000: 'PowerShot S230 / Digital IXUS v3 / IXY Digital 320', + 0x1250000: 'PowerShot A70', + 0x1260000: 'PowerShot A60', + 0x1270000: 'PowerShot S400 / Digital IXUS 400 / IXY Digital 400', + 0x1290000: 'PowerShot G5', + 0x1300000: 'PowerShot A300', + 0x1310000: 'PowerShot S50', + 0x1340000: 'PowerShot A80', + 0x1350000: 'PowerShot SD10 / Digital IXUS i / IXY Digital L', + 0x1360000: 'PowerShot S1 IS', + 0x1370000: 'PowerShot Pro1', + 0x1380000: 'PowerShot S70', + 0x1390000: 'PowerShot S60', + 0x1400000: 'PowerShot G6', + 0x1410000: 'PowerShot S500 / Digital IXUS 500 / IXY Digital 500', + 0x1420000: 'PowerShot A75', + 0x1440000: 'PowerShot SD110 / Digital IXUS IIs / IXY Digital 30a', + 0x1450000: 'PowerShot A400', + 0x1470000: 'PowerShot A310', + 0x1490000: 'PowerShot A85', + 0x1520000: 'PowerShot S410 / Digital IXUS 430 / IXY Digital 450', + 0x1530000: 'PowerShot A95', + 0x1540000: 'PowerShot SD300 / Digital IXUS 40 / IXY Digital 50', + 0x1550000: 'PowerShot SD200 / Digital IXUS 30 / IXY Digital 40', + 0x1560000: 'PowerShot A520', + 0x1570000: 'PowerShot A510', + 0x1590000: 'PowerShot SD20 / Digital IXUS i5 / IXY Digital L2', + 0x1640000: 'PowerShot S2 IS', + 0x1650000: 'PowerShot SD430 / Digital IXUS Wireless / IXY Digital Wireless', + 0x1660000: 'PowerShot SD500 / Digital IXUS 700 / IXY Digital 600', + 0x1668000: 'EOS D60', + 0x1700000: 'PowerShot SD30 / Digital IXUS i Zoom / IXY Digital L3', + 0x1740000: 'PowerShot A430', + 0x1750000: 'PowerShot A410', + 0x1760000: 'PowerShot S80', + 0x1780000: 'PowerShot A620', + 0x1790000: 'PowerShot A610', + 0x1800000: 'PowerShot SD630 / Digital IXUS 65 / IXY Digital 80', + 0x1810000: 'PowerShot SD450 / Digital IXUS 55 / IXY Digital 60', + 0x1820000: 'PowerShot TX1', + 0x1870000: 'PowerShot SD400 / Digital IXUS 50 / IXY Digital 55', + 0x1880000: 'PowerShot A420', + 0x1890000: 'PowerShot SD900 / Digital IXUS 900 Ti / IXY Digital 1000', + 0x1900000: 'PowerShot SD550 / Digital IXUS 750 / IXY Digital 700', + 0x1920000: 'PowerShot A700', + 0x1940000: 'PowerShot SD700 IS / Digital IXUS 800 IS / IXY Digital 800 IS', + 0x1950000: 'PowerShot S3 IS', + 0x1960000: 'PowerShot A540', + 0x1970000: 'PowerShot SD600 / Digital IXUS 60 / IXY Digital 70', + 0x1980000: 'PowerShot G7', + 0x1990000: 'PowerShot A530', + 0x2000000: 'PowerShot SD800 IS / Digital IXUS 850 IS / IXY Digital 900 IS', + 0x2010000: 'PowerShot SD40 / Digital IXUS i7 / IXY Digital L4', + 0x2020000: 'PowerShot A710 IS', + 0x2030000: 'PowerShot A640', + 0x2040000: 'PowerShot A630', + 0x2090000: 'PowerShot S5 IS', + 0x2100000: 'PowerShot A460', + 0x2120000: 'PowerShot SD850 IS / Digital IXUS 950 IS / IXY Digital 810 IS', + 0x2130000: 'PowerShot A570 IS', + 0x2140000: 'PowerShot A560', + 0x2150000: 'PowerShot SD750 / Digital IXUS 75 / IXY Digital 90', + 0x2160000: 'PowerShot SD1000 / Digital IXUS 70 / IXY Digital 10', + 0x2180000: 'PowerShot A550', + 0x2190000: 'PowerShot A450', + 0x2230000: 'PowerShot G9', + 0x2240000: 'PowerShot A650 IS', + 0x2260000: 'PowerShot A720 IS', + 0x2290000: 'PowerShot SX100 IS', + 0x2300000: 'PowerShot SD950 IS / Digital IXUS 960 IS / IXY Digital 2000 IS', + 0x2310000: 'PowerShot SD870 IS / Digital IXUS 860 IS / IXY Digital 910 IS', + 0x2320000: 'PowerShot SD890 IS / Digital IXUS 970 IS / IXY Digital 820 IS', + 0x2360000: 'PowerShot SD790 IS / Digital IXUS 90 IS / IXY Digital 95 IS', + 0x2370000: 'PowerShot SD770 IS / Digital IXUS 85 IS / IXY Digital 25 IS', + 0x2380000: 'PowerShot A590 IS', + 0x2390000: 'PowerShot A580', + 0x2420000: 'PowerShot A470', + 0x2430000: 'PowerShot SD1100 IS / Digital IXUS 80 IS / IXY Digital 20 IS', + 0x2460000: 'PowerShot SX1 IS', + 0x2470000: 'PowerShot SX10 IS', + 0x2480000: 'PowerShot A1000 IS', + 0x2490000: 'PowerShot G10', + 0x2510000: 'PowerShot A2000 IS', + 0x2520000: 'PowerShot SX110 IS', + 0x2530000: 'PowerShot SD990 IS / Digital IXUS 980 IS / IXY Digital 3000 IS', + 0x2540000: 'PowerShot SD880 IS / Digital IXUS 870 IS / IXY Digital 920 IS', + 0x2550000: 'PowerShot E1', + 0x2560000: 'PowerShot D10', + 0x2570000: 'PowerShot SD960 IS / Digital IXUS 110 IS / IXY Digital 510 IS', + 0x2580000: 'PowerShot A2100 IS', + 0x2590000: 'PowerShot A480', + 0x2600000: 'PowerShot SX200 IS', + 0x2610000: 'PowerShot SD970 IS / Digital IXUS 990 IS / IXY Digital 830 IS', + 0x2620000: 'PowerShot SD780 IS / Digital IXUS 100 IS / IXY Digital 210 IS', + 0x2630000: 'PowerShot A1100 IS', + 0x2640000: 'PowerShot SD1200 IS / Digital IXUS 95 IS / IXY Digital 110 IS', + 0x2700000: 'PowerShot G11', + 0x2710000: 'PowerShot SX120 IS', + 0x2720000: 'PowerShot S90', + 0x2750000: 'PowerShot SX20 IS', + 0x2760000: 'PowerShot SD980 IS / Digital IXUS 200 IS / IXY Digital 930 IS', + 0x2770000: 'PowerShot SD940 IS / Digital IXUS 120 IS / IXY Digital 220 IS', + 0x2800000: 'PowerShot A495', + 0x2810000: 'PowerShot A490', + 0x2820000: 'PowerShot A3100 IS / A3150 IS', + 0x2830000: 'PowerShot A3000 IS', + 0x2840000: 'PowerShot SD1400 IS / IXUS 130 / IXY 400F', + 0x2850000: 'PowerShot SD1300 IS / IXUS 105 / IXY 200F', + 0x2860000: 'PowerShot SD3500 IS / IXUS 210 / IXY 10S', + 0x2870000: 'PowerShot SX210 IS', + 0x2880000: 'PowerShot SD4000 IS / IXUS 300 HS / IXY 30S', + 0x2890000: 'PowerShot SD4500 IS / IXUS 1000 HS / IXY 50S', + 0x2920000: 'PowerShot G12', + 0x2930000: 'PowerShot SX30 IS', + 0x2940000: 'PowerShot SX130 IS', + 0x2950000: 'PowerShot S95', + 0x2980000: 'PowerShot A3300 IS', + 0x2990000: 'PowerShot A3200 IS', + 0x3000000: 'PowerShot ELPH 500 HS / IXUS 310 HS / IXY 31S', + 0x3010000: 'PowerShot Pro90 IS', + 0x3010001: 'PowerShot A800', + 0x3020000: 'PowerShot ELPH 100 HS / IXUS 115 HS / IXY 210F', + 0x3030000: 'PowerShot SX230 HS', + 0x3040000: 'PowerShot ELPH 300 HS / IXUS 220 HS / IXY 410F', + 0x3050000: 'PowerShot A2200', + 0x3060000: 'PowerShot A1200', + 0x3070000: 'PowerShot SX220 HS', + 0x3080000: 'PowerShot G1 X', + 0x3090000: 'PowerShot SX150 IS', + 0x3100000: 'PowerShot ELPH 510 HS / IXUS 1100 HS / IXY 51S', + 0x3110000: 'PowerShot S100 (new)', + 0x3130000: 'PowerShot SX40 HS', + 0x3120000: 'PowerShot ELPH 310 HS / IXUS 230 HS / IXY 600F', + 0x3160000: 'PowerShot A1300', + 0x3170000: 'PowerShot A810', + 0x3180000: 'PowerShot ELPH 320 HS / IXUS 240 HS / IXY 420F', + 0x3190000: 'PowerShot ELPH 110 HS / IXUS 125 HS / IXY 220F', + 0x3200000: 'PowerShot D20', + 0x3210000: 'PowerShot A4000 IS', + 0x3220000: 'PowerShot SX260 HS', + 0x3230000: 'PowerShot SX240 HS', + 0x3240000: 'PowerShot ELPH 530 HS / IXUS 510 HS / IXY 1', + 0x3250000: 'PowerShot ELPH 520 HS / IXUS 500 HS / IXY 3', + 0x3260000: 'PowerShot A3400 IS', + 0x3270000: 'PowerShot A2400 IS', + 0x3280000: 'PowerShot A2300', + 0x3330000: 'PowerShot G15', + 0x3340000: 'PowerShot SX50', + 0x3350000: 'PowerShot SX160 IS', + 0x3360000: 'PowerShot S110 (new)', + 0x3370000: 'PowerShot SX500 IS', + 0x3380000: 'PowerShot N', + 0x3390000: 'IXUS 245 HS / IXY 430F', + 0x3400000: 'PowerShot SX280 HS', + 0x3410000: 'PowerShot SX270 HS', + 0x3420000: 'PowerShot A3500 IS', + 0x3430000: 'PowerShot A2600', + 0x3450000: 'PowerShot A1400', + 0x3460000: 'PowerShot ELPH 130 IS / IXUS 140 / IXY 110F', + 0x3470000: 'PowerShot ELPH 115/120 IS / IXUS 132/135 / IXY 90F/100F', + 0x3490000: 'PowerShot ELPH 330 HS / IXUS 255 HS / IXY 610F', + 0x3510000: 'PowerShot A2500', + 0x3540000: 'PowerShot G16', + 0x3550000: 'PowerShot S120', + 0x3560000: 'PowerShot SX170 IS', + 0x3580000: 'PowerShot SX510 HS', + 0x3590000: 'PowerShot S200 (new)', + 0x3600000: 'IXY 620F', + 0x3610000: 'PowerShot N100', + 0x3640000: 'PowerShot G1 X Mark II', + 0x3650000: 'PowerShot D30', + 0x3660000: 'PowerShot SX700 HS', + 0x3670000: 'PowerShot SX600 HS', + 0x3680000: 'PowerShot ELPH 140 IS / IXUS 150 / IXY 130', + 0x3690000: 'PowerShot ELPH 135 / IXUS 145 / IXY 120', + 0x3700000: 'PowerShot ELPH 340 HS / IXUS 265 HS / IXY 630', + 0x3710000: 'PowerShot ELPH 150 IS / IXUS 155 / IXY 140', + 0x3740000: 'EOS M3', + 0x3750000: 'PowerShot SX60 HS', + 0x3760000: 'PowerShot SX520 HS', + 0x3770000: 'PowerShot SX400 IS', + 0x3780000: 'PowerShot G7 X', + 0x3790000: 'PowerShot N2', + 0x3800000: 'PowerShot SX530 HS', + 0x3820000: 'PowerShot SX710 HS', + 0x3830000: 'PowerShot SX610 HS', + 0x3870000: 'PowerShot ELPH 160 / IXUS 160', + 0x3890000: 'PowerShot ELPH 170 IS / IXUS 170', + 0x3910000: 'PowerShot SX410 IS', + 0x4040000: 'PowerShot G1', + 0x6040000: 'PowerShot S100 / Digital IXUS / IXY Digital', + 0x4007d673: 'DC19/DC21/DC22', + 0x4007d674: 'XH A1', + 0x4007d675: 'HV10', + 0x4007d676: 'MD130/MD140/MD150/MD160/ZR850', + 0x4007d777: 'DC50', + 0x4007d778: 'HV20', + 0x4007d779: 'DC211', + 0x4007d77a: 'HG10', + 0x4007d77b: 'HR10', + 0x4007d77d: 'MD255/ZR950', + 0x4007d81c: 'HF11', + 0x4007d878: 'HV30', + 0x4007d87c: 'XH A1S', + 0x4007d87e: 'DC301/DC310/DC311/DC320/DC330', + 0x4007d87f: 'FS100', + 0x4007d880: 'HF10', + 0x4007d882: 'HG20/HG21', + 0x4007d925: 'HF21', + 0x4007d926: 'HF S11', + 0x4007d978: 'HV40', + 0x4007d987: 'DC410/DC411/DC420', + 0x4007d988: 'FS19/FS20/FS21/FS22/FS200', + 0x4007d989: 'HF20/HF200', + 0x4007d98a: 'HF S10/S100', + 0x4007da8e: 'HF R10/R16/R17/R18/R100/R106', + 0x4007da8f: 'HF M30/M31/M36/M300/M306', + 0x4007da90: 'HF S20/S21/S200', + 0x4007da92: 'FS31/FS36/FS37/FS300/FS305/FS306/FS307', + 0x4007dda9: 'HF G25', + 0x80000001: 'EOS-1D', + 0x80000167: 'EOS-1DS', + 0x80000168: 'EOS 10D', + 0x80000169: 'EOS-1D Mark III', + 0x80000170: 'EOS Digital Rebel / 300D / Kiss Digital', + 0x80000174: 'EOS-1D Mark II', + 0x80000175: 'EOS 20D', + 0x80000176: 'EOS Digital Rebel XSi / 450D / Kiss X2', + 0x80000188: 'EOS-1Ds Mark II', + 0x80000189: 'EOS Digital Rebel XT / 350D / Kiss Digital N', + 0x80000190: 'EOS 40D', + 0x80000213: 'EOS 5D', + 0x80000215: 'EOS-1Ds Mark III', + 0x80000218: 'EOS 5D Mark II', + 0x80000219: 'WFT-E1', + 0x80000232: 'EOS-1D Mark II N', + 0x80000234: 'EOS 30D', + 0x80000236: 'EOS Digital Rebel XTi / 400D / Kiss Digital X', + 0x80000241: 'WFT-E2', + 0x80000246: 'WFT-E3', + 0x80000250: 'EOS 7D', + 0x80000252: 'EOS Rebel T1i / 500D / Kiss X3', + 0x80000254: 'EOS Rebel XS / 1000D / Kiss F', + 0x80000261: 'EOS 50D', + 0x80000269: 'EOS-1D X', + 0x80000270: 'EOS Rebel T2i / 550D / Kiss X4', + 0x80000271: 'WFT-E4', + 0x80000273: 'WFT-E5', + 0x80000281: 'EOS-1D Mark IV', + 0x80000285: 'EOS 5D Mark III', + 0x80000286: 'EOS Rebel T3i / 600D / Kiss X5', + 0x80000287: 'EOS 60D', + 0x80000288: 'EOS Rebel T3 / 1100D / Kiss X50', + 0x80000289: 'EOS 7D Mark II', + 0x80000297: 'WFT-E2 II', + 0x80000298: 'WFT-E4 II', + 0x80000301: 'EOS Rebel T4i / 650D / Kiss X6i', + 0x80000302: 'EOS 6D', + 0x80000324: 'EOS-1D C', + 0x80000325: 'EOS 70D', + 0x80000326: 'EOS Rebel T5i / 700D / Kiss X7i', + 0x80000327: 'EOS Rebel T5 / 1200D / Kiss X70', + 0x80000331: 'EOS M', + 0x80000355: 'EOS M2', + 0x80000346: 'EOS Rebel SL1 / 100D / Kiss X7', + 0x80000347: 'EOS Rebel T6s / 760D / 8000D', + 0x80000382: 'EOS 5DS', + 0x80000393: 'EOS Rebel T6i / 750D / Kiss X8i', + 0x80000401: 'EOS 5DS R', + }), + 0x0013: ('ThumbnailImageValidArea', ), + 0x0015: ('SerialNumberFormat', { + 0x90000000: 'Format 1', + 0xA0000000: 'Format 2' + }), + 0x001a: ('SuperMacro', { + 0: 'Off', + 1: 'On (1)', + 2: 'On (2)' + }), + 0x001c: ('DateStampMode', { + 0: 'Off', + 1: 'Date', + 2: 'Date & Time', + }), + 0x001e: ('FirmwareRevision', ), + 0x0028: ('ImageUniqueID', ), + 0x0095: ('LensModel', ), + 0x0096: ('InternalSerialNumber ', ), + 0x0097: ('DustRemovalData ', ), + 0x0098: ('CropInfo ', ), + 0x009a: ('AspectInfo', ), + 0x00b4: ('ColorSpace', { + 1: 'sRGB', + 2: 'Adobe RGB' + }), +} + +# this is in element offset, name, optional value dictionary format +# 0x0001 +CAMERA_SETTINGS = { + 1: ('Macromode', { + 1: 'Macro', + 2: 'Normal' + }), + 2: ('SelfTimer', ), + 3: ('Quality', { + 1: 'Economy', + 2: 'Normal', + 3: 'Fine', + 5: 'Superfine' + }), + 4: ('FlashMode', { + 0: 'Flash Not Fired', + 1: 'Auto', + 2: 'On', + 3: 'Red-Eye Reduction', + 4: 'Slow Synchro', + 5: 'Auto + Red-Eye Reduction', + 6: 'On + Red-Eye Reduction', + 16: 'external flash' + }), + 5: ('ContinuousDriveMode', { + 0: 'Single Or Timer', + 1: 'Continuous', + 2: 'Movie', + }), + 7: ('FocusMode', { + 0: 'One-Shot', + 1: 'AI Servo', + 2: 'AI Focus', + 3: 'MF', + 4: 'Single', + 5: 'Continuous', + 6: 'MF' + }), + 9: ('RecordMode', { + 1: 'JPEG', + 2: 'CRW+THM', + 3: 'AVI+THM', + 4: 'TIF', + 5: 'TIF+JPEG', + 6: 'CR2', + 7: 'CR2+JPEG', + 9: 'Video' + }), + 10: ('ImageSize', { + 0: 'Large', + 1: 'Medium', + 2: 'Small' + }), + 11: ('EasyShootingMode', { + 0: 'Full Auto', + 1: 'Manual', + 2: 'Landscape', + 3: 'Fast Shutter', + 4: 'Slow Shutter', + 5: 'Night', + 6: 'B&W', + 7: 'Sepia', + 8: 'Portrait', + 9: 'Sports', + 10: 'Macro/Close-Up', + 11: 'Pan Focus', + 51: 'High Dynamic Range', + }), + 12: ('DigitalZoom', { + 0: 'None', + 1: '2x', + 2: '4x', + 3: 'Other' + }), + 13: ('Contrast', { + 0xFFFF: 'Low', + 0: 'Normal', + 1: 'High' + }), + 14: ('Saturation', { + 0xFFFF: 'Low', + 0: 'Normal', + 1: 'High' + }), + 15: ('Sharpness', { + 0xFFFF: 'Low', + 0: 'Normal', + 1: 'High' + }), + 16: ('ISO', { + 0: 'See ISOSpeedRatings Tag', + 15: 'Auto', + 16: '50', + 17: '100', + 18: '200', + 19: '400' + }), + 17: ('MeteringMode', { + 0: 'Default', + 1: 'Spot', + 2: 'Average', + 3: 'Evaluative', + 4: 'Partial', + 5: 'Center-weighted' + }), + 18: ('FocusType', { + 0: 'Manual', + 1: 'Auto', + 3: 'Close-Up (Macro)', + 8: 'Locked (Pan Mode)' + }), + 19: ('AFPointSelected', { + 0x3000: 'None (MF)', + 0x3001: 'Auto-Selected', + 0x3002: 'Right', + 0x3003: 'Center', + 0x3004: 'Left' + }), + 20: ('ExposureMode', { + 0: 'Easy Shooting', + 1: 'Program', + 2: 'Tv-priority', + 3: 'Av-priority', + 4: 'Manual', + 5: 'A-DEP' + }), + 22: ('LensType', ), + 23: ('LongFocalLengthOfLensInFocalUnits', ), + 24: ('ShortFocalLengthOfLensInFocalUnits', ), + 25: ('FocalUnitsPerMM', ), + 28: ('FlashActivity', { + 0: 'Did Not Fire', + 1: 'Fired' + }), + 29: ('FlashDetails', { + 0: 'Manual', + 1: 'TTL', + 2: 'A-TTL', + 3: 'E-TTL', + 4: 'FP Sync Enabled', + 7: '2nd("Rear")-Curtain Sync Used', + 11: 'FP Sync Used', + 13: 'Internal Flash', + 14: 'External E-TTL' + }), + 32: ('FocusMode', { + 0: 'Single', + 1: 'Continuous', + 8: 'Manual' + }), + 33: ('AESetting', { + 0: 'Normal AE', + 1: 'Exposure Compensation', + 2: 'AE Lock', + 3: 'AE Lock + Exposure Comp.', + 4: 'No AE' + }), + 34: ('ImageStabilization', { + 0: 'Off', + 1: 'On', + 2: 'Shoot Only', + 3: 'Panning', + 4: 'Dynamic', + 256: 'Off', + 257: 'On', + 258: 'Shoot Only', + 259: 'Panning', + 260: 'Dynamic' + }), + 39: ('SpotMeteringMode', { + 0: 'Center', + 1: 'AF Point' + }), + 41: ('ManualFlashOutput', { + 0x0: 'n/a', + 0x500: 'Full', + 0x502: 'Medium', + 0x504: 'Low', + 0x7fff: 'n/a' + }), +} + +# 0x0002 +FOCAL_LENGTH = { + 1: ('FocalType', { + 1: 'Fixed', + 2: 'Zoom', + }), + 2: ('FocalLength', ), +} + +# 0x0004 +SHOT_INFO = { + 7: ('WhiteBalance', { + 0: 'Auto', + 1: 'Sunny', + 2: 'Cloudy', + 3: 'Tungsten', + 4: 'Fluorescent', + 5: 'Flash', + 6: 'Custom' + }), + 8: ('SlowShutter', { + -1: 'n/a', + 0: 'Off', + 1: 'Night Scene', + 2: 'On', + 3: 'None' + }), + 9: ('SequenceNumber', ), + 14: ('AFPointUsed', ), + 15: ('FlashBias', { + 0xFFC0: '-2 EV', + 0xFFCC: '-1.67 EV', + 0xFFD0: '-1.50 EV', + 0xFFD4: '-1.33 EV', + 0xFFE0: '-1 EV', + 0xFFEC: '-0.67 EV', + 0xFFF0: '-0.50 EV', + 0xFFF4: '-0.33 EV', + 0x0000: '0 EV', + 0x000c: '0.33 EV', + 0x0010: '0.50 EV', + 0x0014: '0.67 EV', + 0x0020: '1 EV', + 0x002c: '1.33 EV', + 0x0030: '1.50 EV', + 0x0034: '1.67 EV', + 0x0040: '2 EV' + }), + 19: ('SubjectDistance', ), +} + +# 0x0026 +AF_INFO_2 = { + 2: ('AFAreaMode', { + 0: 'Off (Manual Focus)', + 2: 'Single-point AF', + 4: 'Multi-point AF or AI AF', + 5: 'Face Detect AF', + 6: 'Face + Tracking', + 7: 'Zone AF', + 8: 'AF Point Expansion', + 9: 'Spot AF', + 11: 'Flexizone Multi', + 13: 'Flexizone Single', + }), + 3: ('NumAFPoints', ), + 4: ('ValidAFPoints', ), + 5: ('CanonImageWidth', ), +} + +# 0x0093 +FILE_INFO = { + 1: ('FileNumber', ), + 3: ('BracketMode', { + 0: 'Off', + 1: 'AEB', + 2: 'FEB', + 3: 'ISO', + 4: 'WB', + }), + 4: ('BracketValue', ), + 5: ('BracketShotNumber', ), + 6: ('RawJpgQuality', { + 0xFFFF: 'n/a', + 1: 'Economy', + 2: 'Normal', + 3: 'Fine', + 4: 'RAW', + 5: 'Superfine', + 130: 'Normal Movie' + }), + 7: ('RawJpgSize', { + 0: 'Large', + 1: 'Medium', + 2: 'Small', + 5: 'Medium 1', + 6: 'Medium 2', + 7: 'Medium 3', + 8: 'Postcard', + 9: 'Widescreen', + 10: 'Medium Widescreen', + 14: 'Small 1', + 15: 'Small 2', + 16: 'Small 3', + 128: '640x480 Movie', + 129: 'Medium Movie', + 130: 'Small Movie', + 137: '1280x720 Movie', + 142: '1920x1080 Movie', + }), + 8: ('LongExposureNoiseReduction2', { + 0: 'Off', + 1: 'On (1D)', + 2: 'On', + 3: 'Auto' + }), + 9: ('WBBracketMode', { + 0: 'Off', + 1: 'On (shift AB)', + 2: 'On (shift GM)' + }), + 12: ('WBBracketValueAB', ), + 13: ('WBBracketValueGM', ), + 14: ('FilterEffect', { + 0: 'None', + 1: 'Yellow', + 2: 'Orange', + 3: 'Red', + 4: 'Green' + }), + 15: ('ToningEffect', { + 0: 'None', + 1: 'Sepia', + 2: 'Blue', + 3: 'Purple', + 4: 'Green', + }), + 16: ('MacroMagnification', ), + 19: ('LiveViewShooting', { + 0: 'Off', + 1: 'On' + }), + 25: ('FlashExposureLock', { + 0: 'Off', + 1: 'On' + }) +} + + +def add_one(value): + return value + 1 + + +def subtract_one(value): + return value - 1 + + +def convert_temp(value): + return '%d C' % (value - 128) + +# CameraInfo data structures have variable sized members. Each entry here is: +# byte offset: (item name, data item type, decoding map). +# Note that the data item type is fed directly to struct.unpack at the +# specified offset. +CAMERA_INFO_TAG_NAME = 'MakerNote Tag 0x000D' + +CAMERA_INFO_5D = { + 23: ('CameraTemperature', ' 1: + self.num = self.num // div + self.den = self.den // div + diff --git a/venv/lib/python2.7/site-packages/flask/__init__.py b/venv/lib/python2.7/site-packages/flask/__init__.py new file mode 100644 index 0000000..ded1982 --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/__init__.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +""" + flask + ~~~~~ + + A microframework based on Werkzeug. It's extensively documented + and follows best practice patterns. + + :copyright: © 2010 by the Pallets team. + :license: BSD, see LICENSE for more details. +""" + +__version__ = '1.0.2' + +# utilities we import from Werkzeug and Jinja2 that are unused +# in the module but are exported as public interface. +from werkzeug.exceptions import abort +from werkzeug.utils import redirect +from jinja2 import Markup, escape + +from .app import Flask, Request, Response +from .config import Config +from .helpers import url_for, flash, send_file, send_from_directory, \ + get_flashed_messages, get_template_attribute, make_response, safe_join, \ + stream_with_context +from .globals import current_app, g, request, session, _request_ctx_stack, \ + _app_ctx_stack +from .ctx import has_request_context, has_app_context, \ + after_this_request, copy_current_request_context +from .blueprints import Blueprint +from .templating import render_template, render_template_string + +# the signals +from .signals import signals_available, template_rendered, request_started, \ + request_finished, got_request_exception, request_tearing_down, \ + appcontext_tearing_down, appcontext_pushed, \ + appcontext_popped, message_flashed, before_render_template + +# We're not exposing the actual json module but a convenient wrapper around +# it. +from . import json + +# This was the only thing that Flask used to export at one point and it had +# a more generic name. +jsonify = json.jsonify + +# backwards compat, goes away in 1.0 +from .sessions import SecureCookieSession as Session +json_available = True diff --git a/venv/lib/python2.7/site-packages/flask/__main__.py b/venv/lib/python2.7/site-packages/flask/__main__.py new file mode 100644 index 0000000..4aee654 --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/__main__.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +""" + flask.__main__ + ~~~~~~~~~~~~~~ + + Alias for flask.run for the command line. + + :copyright: © 2010 by the Pallets team. + :license: BSD, see LICENSE for more details. +""" + +if __name__ == '__main__': + from .cli import main + main(as_module=True) diff --git a/venv/lib/python2.7/site-packages/flask/_compat.py b/venv/lib/python2.7/site-packages/flask/_compat.py new file mode 100644 index 0000000..a3b5b9c --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/_compat.py @@ -0,0 +1,99 @@ +# -*- coding: utf-8 -*- +""" + flask._compat + ~~~~~~~~~~~~~ + + Some py2/py3 compatibility support based on a stripped down + version of six so we don't have to depend on a specific version + of it. + + :copyright: © 2010 by the Pallets team. + :license: BSD, see LICENSE for more details. +""" + +import sys + +PY2 = sys.version_info[0] == 2 +_identity = lambda x: x + + +if not PY2: + text_type = str + string_types = (str,) + integer_types = (int,) + + iterkeys = lambda d: iter(d.keys()) + itervalues = lambda d: iter(d.values()) + iteritems = lambda d: iter(d.items()) + + from inspect import getfullargspec as getargspec + from io import StringIO + + def reraise(tp, value, tb=None): + if value.__traceback__ is not tb: + raise value.with_traceback(tb) + raise value + + implements_to_string = _identity + +else: + text_type = unicode + string_types = (str, unicode) + integer_types = (int, long) + + iterkeys = lambda d: d.iterkeys() + itervalues = lambda d: d.itervalues() + iteritems = lambda d: d.iteritems() + + from inspect import getargspec + from cStringIO import StringIO + + exec('def reraise(tp, value, tb=None):\n raise tp, value, tb') + + def implements_to_string(cls): + cls.__unicode__ = cls.__str__ + cls.__str__ = lambda x: x.__unicode__().encode('utf-8') + return cls + + +def with_metaclass(meta, *bases): + """Create a base class with a metaclass.""" + # This requires a bit of explanation: the basic idea is to make a + # dummy metaclass for one level of class instantiation that replaces + # itself with the actual metaclass. + class metaclass(type): + def __new__(cls, name, this_bases, d): + return meta(name, bases, d) + return type.__new__(metaclass, 'temporary_class', (), {}) + + +# Certain versions of pypy have a bug where clearing the exception stack +# breaks the __exit__ function in a very peculiar way. The second level of +# exception blocks is necessary because pypy seems to forget to check if an +# exception happened until the next bytecode instruction? +# +# Relevant PyPy bugfix commit: +# https://bitbucket.org/pypy/pypy/commits/77ecf91c635a287e88e60d8ddb0f4e9df4003301 +# According to ronan on #pypy IRC, it is released in PyPy2 2.3 and later +# versions. +# +# Ubuntu 14.04 has PyPy 2.2.1, which does exhibit this bug. +BROKEN_PYPY_CTXMGR_EXIT = False +if hasattr(sys, 'pypy_version_info'): + class _Mgr(object): + def __enter__(self): + return self + def __exit__(self, *args): + if hasattr(sys, 'exc_clear'): + # Python 3 (PyPy3) doesn't have exc_clear + sys.exc_clear() + try: + try: + with _Mgr(): + raise AssertionError() + except: + raise + except TypeError: + BROKEN_PYPY_CTXMGR_EXIT = True + except AssertionError: + pass diff --git a/venv/lib/python2.7/site-packages/flask/app.py b/venv/lib/python2.7/site-packages/flask/app.py new file mode 100644 index 0000000..87c5900 --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/app.py @@ -0,0 +1,2315 @@ +# -*- coding: utf-8 -*- +""" + flask.app + ~~~~~~~~~ + + This module implements the central WSGI application object. + + :copyright: © 2010 by the Pallets team. + :license: BSD, see LICENSE for more details. +""" + +import os +import sys +import warnings +from datetime import timedelta +from functools import update_wrapper +from itertools import chain +from threading import Lock + +from werkzeug.datastructures import Headers, ImmutableDict +from werkzeug.exceptions import BadRequest, BadRequestKeyError, HTTPException, \ + InternalServerError, MethodNotAllowed, default_exceptions +from werkzeug.routing import BuildError, Map, RequestRedirect, Rule + +from . import cli, json +from ._compat import integer_types, reraise, string_types, text_type +from .config import Config, ConfigAttribute +from .ctx import AppContext, RequestContext, _AppCtxGlobals +from .globals import _request_ctx_stack, g, request, session +from .helpers import ( + _PackageBoundObject, + _endpoint_from_view_func, find_package, get_env, get_debug_flag, + get_flashed_messages, locked_cached_property, url_for, get_load_dotenv +) +from .logging import create_logger +from .sessions import SecureCookieSessionInterface +from .signals import appcontext_tearing_down, got_request_exception, \ + request_finished, request_started, request_tearing_down +from .templating import DispatchingJinjaLoader, Environment, \ + _default_template_ctx_processor +from .wrappers import Request, Response + +# a singleton sentinel value for parameter defaults +_sentinel = object() + + +def _make_timedelta(value): + if not isinstance(value, timedelta): + return timedelta(seconds=value) + return value + + +def setupmethod(f): + """Wraps a method so that it performs a check in debug mode if the + first request was already handled. + """ + def wrapper_func(self, *args, **kwargs): + if self.debug and self._got_first_request: + raise AssertionError('A setup function was called after the ' + 'first request was handled. This usually indicates a bug ' + 'in the application where a module was not imported ' + 'and decorators or other functionality was called too late.\n' + 'To fix this make sure to import all your view modules, ' + 'database models and everything related at a central place ' + 'before the application starts serving requests.') + return f(self, *args, **kwargs) + return update_wrapper(wrapper_func, f) + + +class Flask(_PackageBoundObject): + """The flask object implements a WSGI application and acts as the central + object. It is passed the name of the module or package of the + application. Once it is created it will act as a central registry for + the view functions, the URL rules, template configuration and much more. + + The name of the package is used to resolve resources from inside the + package or the folder the module is contained in depending on if the + package parameter resolves to an actual python package (a folder with + an :file:`__init__.py` file inside) or a standard module (just a ``.py`` file). + + For more information about resource loading, see :func:`open_resource`. + + Usually you create a :class:`Flask` instance in your main module or + in the :file:`__init__.py` file of your package like this:: + + from flask import Flask + app = Flask(__name__) + + .. admonition:: About the First Parameter + + The idea of the first parameter is to give Flask an idea of what + belongs to your application. This name is used to find resources + on the filesystem, can be used by extensions to improve debugging + information and a lot more. + + So it's important what you provide there. If you are using a single + module, `__name__` is always the correct value. If you however are + using a package, it's usually recommended to hardcode the name of + your package there. + + For example if your application is defined in :file:`yourapplication/app.py` + you should create it with one of the two versions below:: + + app = Flask('yourapplication') + app = Flask(__name__.split('.')[0]) + + Why is that? The application will work even with `__name__`, thanks + to how resources are looked up. However it will make debugging more + painful. Certain extensions can make assumptions based on the + import name of your application. For example the Flask-SQLAlchemy + extension will look for the code in your application that triggered + an SQL query in debug mode. If the import name is not properly set + up, that debugging information is lost. (For example it would only + pick up SQL queries in `yourapplication.app` and not + `yourapplication.views.frontend`) + + .. versionadded:: 0.7 + The `static_url_path`, `static_folder`, and `template_folder` + parameters were added. + + .. versionadded:: 0.8 + The `instance_path` and `instance_relative_config` parameters were + added. + + .. versionadded:: 0.11 + The `root_path` parameter was added. + + .. versionadded:: 1.0 + The ``host_matching`` and ``static_host`` parameters were added. + + .. versionadded:: 1.0 + The ``subdomain_matching`` parameter was added. Subdomain + matching needs to be enabled manually now. Setting + :data:`SERVER_NAME` does not implicitly enable it. + + :param import_name: the name of the application package + :param static_url_path: can be used to specify a different path for the + static files on the web. Defaults to the name + of the `static_folder` folder. + :param static_folder: the folder with static files that should be served + at `static_url_path`. Defaults to the ``'static'`` + folder in the root path of the application. + :param static_host: the host to use when adding the static route. + Defaults to None. Required when using ``host_matching=True`` + with a ``static_folder`` configured. + :param host_matching: set ``url_map.host_matching`` attribute. + Defaults to False. + :param subdomain_matching: consider the subdomain relative to + :data:`SERVER_NAME` when matching routes. Defaults to False. + :param template_folder: the folder that contains the templates that should + be used by the application. Defaults to + ``'templates'`` folder in the root path of the + application. + :param instance_path: An alternative instance path for the application. + By default the folder ``'instance'`` next to the + package or module is assumed to be the instance + path. + :param instance_relative_config: if set to ``True`` relative filenames + for loading the config are assumed to + be relative to the instance path instead + of the application root. + :param root_path: Flask by default will automatically calculate the path + to the root of the application. In certain situations + this cannot be achieved (for instance if the package + is a Python 3 namespace package) and needs to be + manually defined. + """ + + #: The class that is used for request objects. See :class:`~flask.Request` + #: for more information. + request_class = Request + + #: The class that is used for response objects. See + #: :class:`~flask.Response` for more information. + response_class = Response + + #: The class that is used for the Jinja environment. + #: + #: .. versionadded:: 0.11 + jinja_environment = Environment + + #: The class that is used for the :data:`~flask.g` instance. + #: + #: Example use cases for a custom class: + #: + #: 1. Store arbitrary attributes on flask.g. + #: 2. Add a property for lazy per-request database connectors. + #: 3. Return None instead of AttributeError on unexpected attributes. + #: 4. Raise exception if an unexpected attr is set, a "controlled" flask.g. + #: + #: In Flask 0.9 this property was called `request_globals_class` but it + #: was changed in 0.10 to :attr:`app_ctx_globals_class` because the + #: flask.g object is now application context scoped. + #: + #: .. versionadded:: 0.10 + app_ctx_globals_class = _AppCtxGlobals + + #: The class that is used for the ``config`` attribute of this app. + #: Defaults to :class:`~flask.Config`. + #: + #: Example use cases for a custom class: + #: + #: 1. Default values for certain config options. + #: 2. Access to config values through attributes in addition to keys. + #: + #: .. versionadded:: 0.11 + config_class = Config + + #: The testing flag. Set this to ``True`` to enable the test mode of + #: Flask extensions (and in the future probably also Flask itself). + #: For example this might activate test helpers that have an + #: additional runtime cost which should not be enabled by default. + #: + #: If this is enabled and PROPAGATE_EXCEPTIONS is not changed from the + #: default it's implicitly enabled. + #: + #: This attribute can also be configured from the config with the + #: ``TESTING`` configuration key. Defaults to ``False``. + testing = ConfigAttribute('TESTING') + + #: If a secret key is set, cryptographic components can use this to + #: sign cookies and other things. Set this to a complex random value + #: when you want to use the secure cookie for instance. + #: + #: This attribute can also be configured from the config with the + #: :data:`SECRET_KEY` configuration key. Defaults to ``None``. + secret_key = ConfigAttribute('SECRET_KEY') + + #: The secure cookie uses this for the name of the session cookie. + #: + #: This attribute can also be configured from the config with the + #: ``SESSION_COOKIE_NAME`` configuration key. Defaults to ``'session'`` + session_cookie_name = ConfigAttribute('SESSION_COOKIE_NAME') + + #: A :class:`~datetime.timedelta` which is used to set the expiration + #: date of a permanent session. The default is 31 days which makes a + #: permanent session survive for roughly one month. + #: + #: This attribute can also be configured from the config with the + #: ``PERMANENT_SESSION_LIFETIME`` configuration key. Defaults to + #: ``timedelta(days=31)`` + permanent_session_lifetime = ConfigAttribute('PERMANENT_SESSION_LIFETIME', + get_converter=_make_timedelta) + + #: A :class:`~datetime.timedelta` which is used as default cache_timeout + #: for the :func:`send_file` functions. The default is 12 hours. + #: + #: This attribute can also be configured from the config with the + #: ``SEND_FILE_MAX_AGE_DEFAULT`` configuration key. This configuration + #: variable can also be set with an integer value used as seconds. + #: Defaults to ``timedelta(hours=12)`` + send_file_max_age_default = ConfigAttribute('SEND_FILE_MAX_AGE_DEFAULT', + get_converter=_make_timedelta) + + #: Enable this if you want to use the X-Sendfile feature. Keep in + #: mind that the server has to support this. This only affects files + #: sent with the :func:`send_file` method. + #: + #: .. versionadded:: 0.2 + #: + #: This attribute can also be configured from the config with the + #: ``USE_X_SENDFILE`` configuration key. Defaults to ``False``. + use_x_sendfile = ConfigAttribute('USE_X_SENDFILE') + + #: The JSON encoder class to use. Defaults to :class:`~flask.json.JSONEncoder`. + #: + #: .. versionadded:: 0.10 + json_encoder = json.JSONEncoder + + #: The JSON decoder class to use. Defaults to :class:`~flask.json.JSONDecoder`. + #: + #: .. versionadded:: 0.10 + json_decoder = json.JSONDecoder + + #: Options that are passed directly to the Jinja2 environment. + jinja_options = ImmutableDict( + extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_'] + ) + + #: Default configuration parameters. + default_config = ImmutableDict({ + 'ENV': None, + 'DEBUG': None, + 'TESTING': False, + 'PROPAGATE_EXCEPTIONS': None, + 'PRESERVE_CONTEXT_ON_EXCEPTION': None, + 'SECRET_KEY': None, + 'PERMANENT_SESSION_LIFETIME': timedelta(days=31), + 'USE_X_SENDFILE': False, + 'SERVER_NAME': None, + 'APPLICATION_ROOT': '/', + 'SESSION_COOKIE_NAME': 'session', + 'SESSION_COOKIE_DOMAIN': None, + 'SESSION_COOKIE_PATH': None, + 'SESSION_COOKIE_HTTPONLY': True, + 'SESSION_COOKIE_SECURE': False, + 'SESSION_COOKIE_SAMESITE': None, + 'SESSION_REFRESH_EACH_REQUEST': True, + 'MAX_CONTENT_LENGTH': None, + 'SEND_FILE_MAX_AGE_DEFAULT': timedelta(hours=12), + 'TRAP_BAD_REQUEST_ERRORS': None, + 'TRAP_HTTP_EXCEPTIONS': False, + 'EXPLAIN_TEMPLATE_LOADING': False, + 'PREFERRED_URL_SCHEME': 'http', + 'JSON_AS_ASCII': True, + 'JSON_SORT_KEYS': True, + 'JSONIFY_PRETTYPRINT_REGULAR': False, + 'JSONIFY_MIMETYPE': 'application/json', + 'TEMPLATES_AUTO_RELOAD': None, + 'MAX_COOKIE_SIZE': 4093, + }) + + #: The rule object to use for URL rules created. This is used by + #: :meth:`add_url_rule`. Defaults to :class:`werkzeug.routing.Rule`. + #: + #: .. versionadded:: 0.7 + url_rule_class = Rule + + #: the test client that is used with when `test_client` is used. + #: + #: .. versionadded:: 0.7 + test_client_class = None + + #: The :class:`~click.testing.CliRunner` subclass, by default + #: :class:`~flask.testing.FlaskCliRunner` that is used by + #: :meth:`test_cli_runner`. Its ``__init__`` method should take a + #: Flask app object as the first argument. + #: + #: .. versionadded:: 1.0 + test_cli_runner_class = None + + #: the session interface to use. By default an instance of + #: :class:`~flask.sessions.SecureCookieSessionInterface` is used here. + #: + #: .. versionadded:: 0.8 + session_interface = SecureCookieSessionInterface() + + # TODO remove the next three attrs when Sphinx :inherited-members: works + # https://github.com/sphinx-doc/sphinx/issues/741 + + #: The name of the package or module that this app belongs to. Do not + #: change this once it is set by the constructor. + import_name = None + + #: Location of the template files to be added to the template lookup. + #: ``None`` if templates should not be added. + template_folder = None + + #: Absolute path to the package on the filesystem. Used to look up + #: resources contained in the package. + root_path = None + + def __init__( + self, + import_name, + static_url_path=None, + static_folder='static', + static_host=None, + host_matching=False, + subdomain_matching=False, + template_folder='templates', + instance_path=None, + instance_relative_config=False, + root_path=None + ): + _PackageBoundObject.__init__( + self, + import_name, + template_folder=template_folder, + root_path=root_path + ) + + if static_url_path is not None: + self.static_url_path = static_url_path + + if static_folder is not None: + self.static_folder = static_folder + + if instance_path is None: + instance_path = self.auto_find_instance_path() + elif not os.path.isabs(instance_path): + raise ValueError( + 'If an instance path is provided it must be absolute.' + ' A relative path was given instead.' + ) + + #: Holds the path to the instance folder. + #: + #: .. versionadded:: 0.8 + self.instance_path = instance_path + + #: The configuration dictionary as :class:`Config`. This behaves + #: exactly like a regular dictionary but supports additional methods + #: to load a config from files. + self.config = self.make_config(instance_relative_config) + + #: A dictionary of all view functions registered. The keys will + #: be function names which are also used to generate URLs and + #: the values are the function objects themselves. + #: To register a view function, use the :meth:`route` decorator. + self.view_functions = {} + + #: A dictionary of all registered error handlers. The key is ``None`` + #: for error handlers active on the application, otherwise the key is + #: the name of the blueprint. Each key points to another dictionary + #: where the key is the status code of the http exception. The + #: special key ``None`` points to a list of tuples where the first item + #: is the class for the instance check and the second the error handler + #: function. + #: + #: To register an error handler, use the :meth:`errorhandler` + #: decorator. + self.error_handler_spec = {} + + #: A list of functions that are called when :meth:`url_for` raises a + #: :exc:`~werkzeug.routing.BuildError`. Each function registered here + #: is called with `error`, `endpoint` and `values`. If a function + #: returns ``None`` or raises a :exc:`BuildError` the next function is + #: tried. + #: + #: .. versionadded:: 0.9 + self.url_build_error_handlers = [] + + #: A dictionary with lists of functions that will be called at the + #: beginning of each request. The key of the dictionary is the name of + #: the blueprint this function is active for, or ``None`` for all + #: requests. To register a function, use the :meth:`before_request` + #: decorator. + self.before_request_funcs = {} + + #: A list of functions that will be called at the beginning of the + #: first request to this instance. To register a function, use the + #: :meth:`before_first_request` decorator. + #: + #: .. versionadded:: 0.8 + self.before_first_request_funcs = [] + + #: A dictionary with lists of functions that should be called after + #: each request. The key of the dictionary is the name of the blueprint + #: this function is active for, ``None`` for all requests. This can for + #: example be used to close database connections. To register a function + #: here, use the :meth:`after_request` decorator. + self.after_request_funcs = {} + + #: A dictionary with lists of functions that are called after + #: each request, even if an exception has occurred. The key of the + #: dictionary is the name of the blueprint this function is active for, + #: ``None`` for all requests. These functions are not allowed to modify + #: the request, and their return values are ignored. If an exception + #: occurred while processing the request, it gets passed to each + #: teardown_request function. To register a function here, use the + #: :meth:`teardown_request` decorator. + #: + #: .. versionadded:: 0.7 + self.teardown_request_funcs = {} + + #: A list of functions that are called when the application context + #: is destroyed. Since the application context is also torn down + #: if the request ends this is the place to store code that disconnects + #: from databases. + #: + #: .. versionadded:: 0.9 + self.teardown_appcontext_funcs = [] + + #: A dictionary with lists of functions that are called before the + #: :attr:`before_request_funcs` functions. The key of the dictionary is + #: the name of the blueprint this function is active for, or ``None`` + #: for all requests. To register a function, use + #: :meth:`url_value_preprocessor`. + #: + #: .. versionadded:: 0.7 + self.url_value_preprocessors = {} + + #: A dictionary with lists of functions that can be used as URL value + #: preprocessors. The key ``None`` here is used for application wide + #: callbacks, otherwise the key is the name of the blueprint. + #: Each of these functions has the chance to modify the dictionary + #: of URL values before they are used as the keyword arguments of the + #: view function. For each function registered this one should also + #: provide a :meth:`url_defaults` function that adds the parameters + #: automatically again that were removed that way. + #: + #: .. versionadded:: 0.7 + self.url_default_functions = {} + + #: A dictionary with list of functions that are called without argument + #: to populate the template context. The key of the dictionary is the + #: name of the blueprint this function is active for, ``None`` for all + #: requests. Each returns a dictionary that the template context is + #: updated with. To register a function here, use the + #: :meth:`context_processor` decorator. + self.template_context_processors = { + None: [_default_template_ctx_processor] + } + + #: A list of shell context processor functions that should be run + #: when a shell context is created. + #: + #: .. versionadded:: 0.11 + self.shell_context_processors = [] + + #: all the attached blueprints in a dictionary by name. Blueprints + #: can be attached multiple times so this dictionary does not tell + #: you how often they got attached. + #: + #: .. versionadded:: 0.7 + self.blueprints = {} + self._blueprint_order = [] + + #: a place where extensions can store application specific state. For + #: example this is where an extension could store database engines and + #: similar things. For backwards compatibility extensions should register + #: themselves like this:: + #: + #: if not hasattr(app, 'extensions'): + #: app.extensions = {} + #: app.extensions['extensionname'] = SomeObject() + #: + #: The key must match the name of the extension module. For example in + #: case of a "Flask-Foo" extension in `flask_foo`, the key would be + #: ``'foo'``. + #: + #: .. versionadded:: 0.7 + self.extensions = {} + + #: The :class:`~werkzeug.routing.Map` for this instance. You can use + #: this to change the routing converters after the class was created + #: but before any routes are connected. Example:: + #: + #: from werkzeug.routing import BaseConverter + #: + #: class ListConverter(BaseConverter): + #: def to_python(self, value): + #: return value.split(',') + #: def to_url(self, values): + #: return ','.join(super(ListConverter, self).to_url(value) + #: for value in values) + #: + #: app = Flask(__name__) + #: app.url_map.converters['list'] = ListConverter + self.url_map = Map() + + self.url_map.host_matching = host_matching + self.subdomain_matching = subdomain_matching + + # tracks internally if the application already handled at least one + # request. + self._got_first_request = False + self._before_request_lock = Lock() + + # Add a static route using the provided static_url_path, static_host, + # and static_folder if there is a configured static_folder. + # Note we do this without checking if static_folder exists. + # For one, it might be created while the server is running (e.g. during + # development). Also, Google App Engine stores static files somewhere + if self.has_static_folder: + assert bool(static_host) == host_matching, 'Invalid static_host/host_matching combination' + self.add_url_rule( + self.static_url_path + '/', + endpoint='static', + host=static_host, + view_func=self.send_static_file + ) + + #: The click command line context for this application. Commands + #: registered here show up in the :command:`flask` command once the + #: application has been discovered. The default commands are + #: provided by Flask itself and can be overridden. + #: + #: This is an instance of a :class:`click.Group` object. + self.cli = cli.AppGroup(self.name) + + @locked_cached_property + def name(self): + """The name of the application. This is usually the import name + with the difference that it's guessed from the run file if the + import name is main. This name is used as a display name when + Flask needs the name of the application. It can be set and overridden + to change the value. + + .. versionadded:: 0.8 + """ + if self.import_name == '__main__': + fn = getattr(sys.modules['__main__'], '__file__', None) + if fn is None: + return '__main__' + return os.path.splitext(os.path.basename(fn))[0] + return self.import_name + + @property + def propagate_exceptions(self): + """Returns the value of the ``PROPAGATE_EXCEPTIONS`` configuration + value in case it's set, otherwise a sensible default is returned. + + .. versionadded:: 0.7 + """ + rv = self.config['PROPAGATE_EXCEPTIONS'] + if rv is not None: + return rv + return self.testing or self.debug + + @property + def preserve_context_on_exception(self): + """Returns the value of the ``PRESERVE_CONTEXT_ON_EXCEPTION`` + configuration value in case it's set, otherwise a sensible default + is returned. + + .. versionadded:: 0.7 + """ + rv = self.config['PRESERVE_CONTEXT_ON_EXCEPTION'] + if rv is not None: + return rv + return self.debug + + @locked_cached_property + def logger(self): + """The ``'flask.app'`` logger, a standard Python + :class:`~logging.Logger`. + + In debug mode, the logger's :attr:`~logging.Logger.level` will be set + to :data:`~logging.DEBUG`. + + If there are no handlers configured, a default handler will be added. + See :ref:`logging` for more information. + + .. versionchanged:: 1.0 + Behavior was simplified. The logger is always named + ``flask.app``. The level is only set during configuration, it + doesn't check ``app.debug`` each time. Only one format is used, + not different ones depending on ``app.debug``. No handlers are + removed, and a handler is only added if no handlers are already + configured. + + .. versionadded:: 0.3 + """ + return create_logger(self) + + @locked_cached_property + def jinja_env(self): + """The Jinja2 environment used to load templates.""" + return self.create_jinja_environment() + + @property + def got_first_request(self): + """This attribute is set to ``True`` if the application started + handling the first request. + + .. versionadded:: 0.8 + """ + return self._got_first_request + + def make_config(self, instance_relative=False): + """Used to create the config attribute by the Flask constructor. + The `instance_relative` parameter is passed in from the constructor + of Flask (there named `instance_relative_config`) and indicates if + the config should be relative to the instance path or the root path + of the application. + + .. versionadded:: 0.8 + """ + root_path = self.root_path + if instance_relative: + root_path = self.instance_path + defaults = dict(self.default_config) + defaults['ENV'] = get_env() + defaults['DEBUG'] = get_debug_flag() + return self.config_class(root_path, defaults) + + def auto_find_instance_path(self): + """Tries to locate the instance path if it was not provided to the + constructor of the application class. It will basically calculate + the path to a folder named ``instance`` next to your main file or + the package. + + .. versionadded:: 0.8 + """ + prefix, package_path = find_package(self.import_name) + if prefix is None: + return os.path.join(package_path, 'instance') + return os.path.join(prefix, 'var', self.name + '-instance') + + def open_instance_resource(self, resource, mode='rb'): + """Opens a resource from the application's instance folder + (:attr:`instance_path`). Otherwise works like + :meth:`open_resource`. Instance resources can also be opened for + writing. + + :param resource: the name of the resource. To access resources within + subfolders use forward slashes as separator. + :param mode: resource file opening mode, default is 'rb'. + """ + return open(os.path.join(self.instance_path, resource), mode) + + def _get_templates_auto_reload(self): + """Reload templates when they are changed. Used by + :meth:`create_jinja_environment`. + + This attribute can be configured with :data:`TEMPLATES_AUTO_RELOAD`. If + not set, it will be enabled in debug mode. + + .. versionadded:: 1.0 + This property was added but the underlying config and behavior + already existed. + """ + rv = self.config['TEMPLATES_AUTO_RELOAD'] + return rv if rv is not None else self.debug + + def _set_templates_auto_reload(self, value): + self.config['TEMPLATES_AUTO_RELOAD'] = value + + templates_auto_reload = property( + _get_templates_auto_reload, _set_templates_auto_reload + ) + del _get_templates_auto_reload, _set_templates_auto_reload + + def create_jinja_environment(self): + """Creates the Jinja2 environment based on :attr:`jinja_options` + and :meth:`select_jinja_autoescape`. Since 0.7 this also adds + the Jinja2 globals and filters after initialization. Override + this function to customize the behavior. + + .. versionadded:: 0.5 + .. versionchanged:: 0.11 + ``Environment.auto_reload`` set in accordance with + ``TEMPLATES_AUTO_RELOAD`` configuration option. + """ + options = dict(self.jinja_options) + + if 'autoescape' not in options: + options['autoescape'] = self.select_jinja_autoescape + + if 'auto_reload' not in options: + options['auto_reload'] = self.templates_auto_reload + + rv = self.jinja_environment(self, **options) + rv.globals.update( + url_for=url_for, + get_flashed_messages=get_flashed_messages, + config=self.config, + # request, session and g are normally added with the + # context processor for efficiency reasons but for imported + # templates we also want the proxies in there. + request=request, + session=session, + g=g + ) + rv.filters['tojson'] = json.tojson_filter + return rv + + def create_global_jinja_loader(self): + """Creates the loader for the Jinja2 environment. Can be used to + override just the loader and keeping the rest unchanged. It's + discouraged to override this function. Instead one should override + the :meth:`jinja_loader` function instead. + + The global loader dispatches between the loaders of the application + and the individual blueprints. + + .. versionadded:: 0.7 + """ + return DispatchingJinjaLoader(self) + + def select_jinja_autoescape(self, filename): + """Returns ``True`` if autoescaping should be active for the given + template name. If no template name is given, returns `True`. + + .. versionadded:: 0.5 + """ + if filename is None: + return True + return filename.endswith(('.html', '.htm', '.xml', '.xhtml')) + + def update_template_context(self, context): + """Update the template context with some commonly used variables. + This injects request, session, config and g into the template + context as well as everything template context processors want + to inject. Note that the as of Flask 0.6, the original values + in the context will not be overridden if a context processor + decides to return a value with the same key. + + :param context: the context as a dictionary that is updated in place + to add extra variables. + """ + funcs = self.template_context_processors[None] + reqctx = _request_ctx_stack.top + if reqctx is not None: + bp = reqctx.request.blueprint + if bp is not None and bp in self.template_context_processors: + funcs = chain(funcs, self.template_context_processors[bp]) + orig_ctx = context.copy() + for func in funcs: + context.update(func()) + # make sure the original values win. This makes it possible to + # easier add new variables in context processors without breaking + # existing views. + context.update(orig_ctx) + + def make_shell_context(self): + """Returns the shell context for an interactive shell for this + application. This runs all the registered shell context + processors. + + .. versionadded:: 0.11 + """ + rv = {'app': self, 'g': g} + for processor in self.shell_context_processors: + rv.update(processor()) + return rv + + #: What environment the app is running in. Flask and extensions may + #: enable behaviors based on the environment, such as enabling debug + #: mode. This maps to the :data:`ENV` config key. This is set by the + #: :envvar:`FLASK_ENV` environment variable and may not behave as + #: expected if set in code. + #: + #: **Do not enable development when deploying in production.** + #: + #: Default: ``'production'`` + env = ConfigAttribute('ENV') + + def _get_debug(self): + return self.config['DEBUG'] + + def _set_debug(self, value): + self.config['DEBUG'] = value + self.jinja_env.auto_reload = self.templates_auto_reload + + #: Whether debug mode is enabled. When using ``flask run`` to start + #: the development server, an interactive debugger will be shown for + #: unhandled exceptions, and the server will be reloaded when code + #: changes. This maps to the :data:`DEBUG` config key. This is + #: enabled when :attr:`env` is ``'development'`` and is overridden + #: by the ``FLASK_DEBUG`` environment variable. It may not behave as + #: expected if set in code. + #: + #: **Do not enable debug mode when deploying in production.** + #: + #: Default: ``True`` if :attr:`env` is ``'development'``, or + #: ``False`` otherwise. + debug = property(_get_debug, _set_debug) + del _get_debug, _set_debug + + def run(self, host=None, port=None, debug=None, + load_dotenv=True, **options): + """Runs the application on a local development server. + + Do not use ``run()`` in a production setting. It is not intended to + meet security and performance requirements for a production server. + Instead, see :ref:`deployment` for WSGI server recommendations. + + If the :attr:`debug` flag is set the server will automatically reload + for code changes and show a debugger in case an exception happened. + + If you want to run the application in debug mode, but disable the + code execution on the interactive debugger, you can pass + ``use_evalex=False`` as parameter. This will keep the debugger's + traceback screen active, but disable code execution. + + It is not recommended to use this function for development with + automatic reloading as this is badly supported. Instead you should + be using the :command:`flask` command line script's ``run`` support. + + .. admonition:: Keep in Mind + + Flask will suppress any server error with a generic error page + unless it is in debug mode. As such to enable just the + interactive debugger without the code reloading, you have to + invoke :meth:`run` with ``debug=True`` and ``use_reloader=False``. + Setting ``use_debugger`` to ``True`` without being in debug mode + won't catch any exceptions because there won't be any to + catch. + + :param host: the hostname to listen on. Set this to ``'0.0.0.0'`` to + have the server available externally as well. Defaults to + ``'127.0.0.1'`` or the host in the ``SERVER_NAME`` config variable + if present. + :param port: the port of the webserver. Defaults to ``5000`` or the + port defined in the ``SERVER_NAME`` config variable if present. + :param debug: if given, enable or disable debug mode. See + :attr:`debug`. + :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv` + files to set environment variables. Will also change the working + directory to the directory containing the first file found. + :param options: the options to be forwarded to the underlying Werkzeug + server. See :func:`werkzeug.serving.run_simple` for more + information. + + .. versionchanged:: 1.0 + If installed, python-dotenv will be used to load environment + variables from :file:`.env` and :file:`.flaskenv` files. + + If set, the :envvar:`FLASK_ENV` and :envvar:`FLASK_DEBUG` + environment variables will override :attr:`env` and + :attr:`debug`. + + Threaded mode is enabled by default. + + .. versionchanged:: 0.10 + The default port is now picked from the ``SERVER_NAME`` + variable. + """ + # Change this into a no-op if the server is invoked from the + # command line. Have a look at cli.py for more information. + if os.environ.get('FLASK_RUN_FROM_CLI') == 'true': + from .debughelpers import explain_ignored_app_run + explain_ignored_app_run() + return + + if get_load_dotenv(load_dotenv): + cli.load_dotenv() + + # if set, let env vars override previous values + if 'FLASK_ENV' in os.environ: + self.env = get_env() + self.debug = get_debug_flag() + elif 'FLASK_DEBUG' in os.environ: + self.debug = get_debug_flag() + + # debug passed to method overrides all other sources + if debug is not None: + self.debug = bool(debug) + + _host = '127.0.0.1' + _port = 5000 + server_name = self.config.get('SERVER_NAME') + sn_host, sn_port = None, None + + if server_name: + sn_host, _, sn_port = server_name.partition(':') + + host = host or sn_host or _host + port = int(port or sn_port or _port) + + options.setdefault('use_reloader', self.debug) + options.setdefault('use_debugger', self.debug) + options.setdefault('threaded', True) + + cli.show_server_banner(self.env, self.debug, self.name, False) + + from werkzeug.serving import run_simple + + try: + run_simple(host, port, self, **options) + finally: + # reset the first request information if the development server + # reset normally. This makes it possible to restart the server + # without reloader and that stuff from an interactive shell. + self._got_first_request = False + + def test_client(self, use_cookies=True, **kwargs): + """Creates a test client for this application. For information + about unit testing head over to :ref:`testing`. + + Note that if you are testing for assertions or exceptions in your + application code, you must set ``app.testing = True`` in order for the + exceptions to propagate to the test client. Otherwise, the exception + will be handled by the application (not visible to the test client) and + the only indication of an AssertionError or other exception will be a + 500 status code response to the test client. See the :attr:`testing` + attribute. For example:: + + app.testing = True + client = app.test_client() + + The test client can be used in a ``with`` block to defer the closing down + of the context until the end of the ``with`` block. This is useful if + you want to access the context locals for testing:: + + with app.test_client() as c: + rv = c.get('/?vodka=42') + assert request.args['vodka'] == '42' + + Additionally, you may pass optional keyword arguments that will then + be passed to the application's :attr:`test_client_class` constructor. + For example:: + + from flask.testing import FlaskClient + + class CustomClient(FlaskClient): + def __init__(self, *args, **kwargs): + self._authentication = kwargs.pop("authentication") + super(CustomClient,self).__init__( *args, **kwargs) + + app.test_client_class = CustomClient + client = app.test_client(authentication='Basic ....') + + See :class:`~flask.testing.FlaskClient` for more information. + + .. versionchanged:: 0.4 + added support for ``with`` block usage for the client. + + .. versionadded:: 0.7 + The `use_cookies` parameter was added as well as the ability + to override the client to be used by setting the + :attr:`test_client_class` attribute. + + .. versionchanged:: 0.11 + Added `**kwargs` to support passing additional keyword arguments to + the constructor of :attr:`test_client_class`. + """ + cls = self.test_client_class + if cls is None: + from flask.testing import FlaskClient as cls + return cls(self, self.response_class, use_cookies=use_cookies, **kwargs) + + def test_cli_runner(self, **kwargs): + """Create a CLI runner for testing CLI commands. + See :ref:`testing-cli`. + + Returns an instance of :attr:`test_cli_runner_class`, by default + :class:`~flask.testing.FlaskCliRunner`. The Flask app object is + passed as the first argument. + + .. versionadded:: 1.0 + """ + cls = self.test_cli_runner_class + + if cls is None: + from flask.testing import FlaskCliRunner as cls + + return cls(self, **kwargs) + + def open_session(self, request): + """Creates or opens a new session. Default implementation stores all + session data in a signed cookie. This requires that the + :attr:`secret_key` is set. Instead of overriding this method + we recommend replacing the :class:`session_interface`. + + .. deprecated: 1.0 + Will be removed in 1.1. Use ``session_interface.open_session`` + instead. + + :param request: an instance of :attr:`request_class`. + """ + + warnings.warn(DeprecationWarning( + '"open_session" is deprecated and will be removed in 1.1. Use' + ' "session_interface.open_session" instead.' + )) + return self.session_interface.open_session(self, request) + + def save_session(self, session, response): + """Saves the session if it needs updates. For the default + implementation, check :meth:`open_session`. Instead of overriding this + method we recommend replacing the :class:`session_interface`. + + .. deprecated: 1.0 + Will be removed in 1.1. Use ``session_interface.save_session`` + instead. + + :param session: the session to be saved (a + :class:`~werkzeug.contrib.securecookie.SecureCookie` + object) + :param response: an instance of :attr:`response_class` + """ + + warnings.warn(DeprecationWarning( + '"save_session" is deprecated and will be removed in 1.1. Use' + ' "session_interface.save_session" instead.' + )) + return self.session_interface.save_session(self, session, response) + + def make_null_session(self): + """Creates a new instance of a missing session. Instead of overriding + this method we recommend replacing the :class:`session_interface`. + + .. deprecated: 1.0 + Will be removed in 1.1. Use ``session_interface.make_null_session`` + instead. + + .. versionadded:: 0.7 + """ + + warnings.warn(DeprecationWarning( + '"make_null_session" is deprecated and will be removed in 1.1. Use' + ' "session_interface.make_null_session" instead.' + )) + return self.session_interface.make_null_session(self) + + @setupmethod + def register_blueprint(self, blueprint, **options): + """Register a :class:`~flask.Blueprint` on the application. Keyword + arguments passed to this method will override the defaults set on the + blueprint. + + Calls the blueprint's :meth:`~flask.Blueprint.register` method after + recording the blueprint in the application's :attr:`blueprints`. + + :param blueprint: The blueprint to register. + :param url_prefix: Blueprint routes will be prefixed with this. + :param subdomain: Blueprint routes will match on this subdomain. + :param url_defaults: Blueprint routes will use these default values for + view arguments. + :param options: Additional keyword arguments are passed to + :class:`~flask.blueprints.BlueprintSetupState`. They can be + accessed in :meth:`~flask.Blueprint.record` callbacks. + + .. versionadded:: 0.7 + """ + first_registration = False + + if blueprint.name in self.blueprints: + assert self.blueprints[blueprint.name] is blueprint, ( + 'A name collision occurred between blueprints %r and %r. Both' + ' share the same name "%s". Blueprints that are created on the' + ' fly need unique names.' % ( + blueprint, self.blueprints[blueprint.name], blueprint.name + ) + ) + else: + self.blueprints[blueprint.name] = blueprint + self._blueprint_order.append(blueprint) + first_registration = True + + blueprint.register(self, options, first_registration) + + def iter_blueprints(self): + """Iterates over all blueprints by the order they were registered. + + .. versionadded:: 0.11 + """ + return iter(self._blueprint_order) + + @setupmethod + def add_url_rule(self, rule, endpoint=None, view_func=None, + provide_automatic_options=None, **options): + """Connects a URL rule. Works exactly like the :meth:`route` + decorator. If a view_func is provided it will be registered with the + endpoint. + + Basically this example:: + + @app.route('/') + def index(): + pass + + Is equivalent to the following:: + + def index(): + pass + app.add_url_rule('/', 'index', index) + + If the view_func is not provided you will need to connect the endpoint + to a view function like so:: + + app.view_functions['index'] = index + + Internally :meth:`route` invokes :meth:`add_url_rule` so if you want + to customize the behavior via subclassing you only need to change + this method. + + For more information refer to :ref:`url-route-registrations`. + + .. versionchanged:: 0.2 + `view_func` parameter added. + + .. versionchanged:: 0.6 + ``OPTIONS`` is added automatically as method. + + :param rule: the URL rule as string + :param endpoint: the endpoint for the registered URL rule. Flask + itself assumes the name of the view function as + endpoint + :param view_func: the function to call when serving a request to the + provided endpoint + :param provide_automatic_options: controls whether the ``OPTIONS`` + method should be added automatically. This can also be controlled + by setting the ``view_func.provide_automatic_options = False`` + before adding the rule. + :param options: the options to be forwarded to the underlying + :class:`~werkzeug.routing.Rule` object. A change + to Werkzeug is handling of method options. methods + is a list of methods this rule should be limited + to (``GET``, ``POST`` etc.). By default a rule + just listens for ``GET`` (and implicitly ``HEAD``). + Starting with Flask 0.6, ``OPTIONS`` is implicitly + added and handled by the standard request handling. + """ + if endpoint is None: + endpoint = _endpoint_from_view_func(view_func) + options['endpoint'] = endpoint + methods = options.pop('methods', None) + + # if the methods are not given and the view_func object knows its + # methods we can use that instead. If neither exists, we go with + # a tuple of only ``GET`` as default. + if methods is None: + methods = getattr(view_func, 'methods', None) or ('GET',) + if isinstance(methods, string_types): + raise TypeError('Allowed methods have to be iterables of strings, ' + 'for example: @app.route(..., methods=["POST"])') + methods = set(item.upper() for item in methods) + + # Methods that should always be added + required_methods = set(getattr(view_func, 'required_methods', ())) + + # starting with Flask 0.8 the view_func object can disable and + # force-enable the automatic options handling. + if provide_automatic_options is None: + provide_automatic_options = getattr(view_func, + 'provide_automatic_options', None) + + if provide_automatic_options is None: + if 'OPTIONS' not in methods: + provide_automatic_options = True + required_methods.add('OPTIONS') + else: + provide_automatic_options = False + + # Add the required methods now. + methods |= required_methods + + rule = self.url_rule_class(rule, methods=methods, **options) + rule.provide_automatic_options = provide_automatic_options + + self.url_map.add(rule) + if view_func is not None: + old_func = self.view_functions.get(endpoint) + if old_func is not None and old_func != view_func: + raise AssertionError('View function mapping is overwriting an ' + 'existing endpoint function: %s' % endpoint) + self.view_functions[endpoint] = view_func + + def route(self, rule, **options): + """A decorator that is used to register a view function for a + given URL rule. This does the same thing as :meth:`add_url_rule` + but is intended for decorator usage:: + + @app.route('/') + def index(): + return 'Hello World' + + For more information refer to :ref:`url-route-registrations`. + + :param rule: the URL rule as string + :param endpoint: the endpoint for the registered URL rule. Flask + itself assumes the name of the view function as + endpoint + :param options: the options to be forwarded to the underlying + :class:`~werkzeug.routing.Rule` object. A change + to Werkzeug is handling of method options. methods + is a list of methods this rule should be limited + to (``GET``, ``POST`` etc.). By default a rule + just listens for ``GET`` (and implicitly ``HEAD``). + Starting with Flask 0.6, ``OPTIONS`` is implicitly + added and handled by the standard request handling. + """ + def decorator(f): + endpoint = options.pop('endpoint', None) + self.add_url_rule(rule, endpoint, f, **options) + return f + return decorator + + @setupmethod + def endpoint(self, endpoint): + """A decorator to register a function as an endpoint. + Example:: + + @app.endpoint('example.endpoint') + def example(): + return "example" + + :param endpoint: the name of the endpoint + """ + def decorator(f): + self.view_functions[endpoint] = f + return f + return decorator + + @staticmethod + def _get_exc_class_and_code(exc_class_or_code): + """Ensure that we register only exceptions as handler keys""" + if isinstance(exc_class_or_code, integer_types): + exc_class = default_exceptions[exc_class_or_code] + else: + exc_class = exc_class_or_code + + assert issubclass(exc_class, Exception) + + if issubclass(exc_class, HTTPException): + return exc_class, exc_class.code + else: + return exc_class, None + + @setupmethod + def errorhandler(self, code_or_exception): + """Register a function to handle errors by code or exception class. + + A decorator that is used to register a function given an + error code. Example:: + + @app.errorhandler(404) + def page_not_found(error): + return 'This page does not exist', 404 + + You can also register handlers for arbitrary exceptions:: + + @app.errorhandler(DatabaseError) + def special_exception_handler(error): + return 'Database connection failed', 500 + + .. versionadded:: 0.7 + Use :meth:`register_error_handler` instead of modifying + :attr:`error_handler_spec` directly, for application wide error + handlers. + + .. versionadded:: 0.7 + One can now additionally also register custom exception types + that do not necessarily have to be a subclass of the + :class:`~werkzeug.exceptions.HTTPException` class. + + :param code_or_exception: the code as integer for the handler, or + an arbitrary exception + """ + def decorator(f): + self._register_error_handler(None, code_or_exception, f) + return f + return decorator + + @setupmethod + def register_error_handler(self, code_or_exception, f): + """Alternative error attach function to the :meth:`errorhandler` + decorator that is more straightforward to use for non decorator + usage. + + .. versionadded:: 0.7 + """ + self._register_error_handler(None, code_or_exception, f) + + @setupmethod + def _register_error_handler(self, key, code_or_exception, f): + """ + :type key: None|str + :type code_or_exception: int|T<=Exception + :type f: callable + """ + if isinstance(code_or_exception, HTTPException): # old broken behavior + raise ValueError( + 'Tried to register a handler for an exception instance {0!r}.' + ' Handlers can only be registered for exception classes or' + ' HTTP error codes.'.format(code_or_exception) + ) + + try: + exc_class, code = self._get_exc_class_and_code(code_or_exception) + except KeyError: + raise KeyError( + "'{0}' is not a recognized HTTP error code. Use a subclass of" + " HTTPException with that code instead.".format(code_or_exception) + ) + + handlers = self.error_handler_spec.setdefault(key, {}).setdefault(code, {}) + handlers[exc_class] = f + + @setupmethod + def template_filter(self, name=None): + """A decorator that is used to register custom template filter. + You can specify a name for the filter, otherwise the function + name will be used. Example:: + + @app.template_filter() + def reverse(s): + return s[::-1] + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + def decorator(f): + self.add_template_filter(f, name=name) + return f + return decorator + + @setupmethod + def add_template_filter(self, f, name=None): + """Register a custom template filter. Works exactly like the + :meth:`template_filter` decorator. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + self.jinja_env.filters[name or f.__name__] = f + + @setupmethod + def template_test(self, name=None): + """A decorator that is used to register custom template test. + You can specify a name for the test, otherwise the function + name will be used. Example:: + + @app.template_test() + def is_prime(n): + if n == 2: + return True + for i in range(2, int(math.ceil(math.sqrt(n))) + 1): + if n % i == 0: + return False + return True + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + def decorator(f): + self.add_template_test(f, name=name) + return f + return decorator + + @setupmethod + def add_template_test(self, f, name=None): + """Register a custom template test. Works exactly like the + :meth:`template_test` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + self.jinja_env.tests[name or f.__name__] = f + + @setupmethod + def template_global(self, name=None): + """A decorator that is used to register a custom template global function. + You can specify a name for the global function, otherwise the function + name will be used. Example:: + + @app.template_global() + def double(n): + return 2 * n + + .. versionadded:: 0.10 + + :param name: the optional name of the global function, otherwise the + function name will be used. + """ + def decorator(f): + self.add_template_global(f, name=name) + return f + return decorator + + @setupmethod + def add_template_global(self, f, name=None): + """Register a custom template global function. Works exactly like the + :meth:`template_global` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the global function, otherwise the + function name will be used. + """ + self.jinja_env.globals[name or f.__name__] = f + + @setupmethod + def before_request(self, f): + """Registers a function to run before each request. + + For example, this can be used to open a database connection, or to load + the logged in user from the session. + + The function will be called without any arguments. If it returns a + non-None value, the value is handled as if it was the return value from + the view, and further request handling is stopped. + """ + self.before_request_funcs.setdefault(None, []).append(f) + return f + + @setupmethod + def before_first_request(self, f): + """Registers a function to be run before the first request to this + instance of the application. + + The function will be called without any arguments and its return + value is ignored. + + .. versionadded:: 0.8 + """ + self.before_first_request_funcs.append(f) + return f + + @setupmethod + def after_request(self, f): + """Register a function to be run after each request. + + Your function must take one parameter, an instance of + :attr:`response_class` and return a new response object or the + same (see :meth:`process_response`). + + As of Flask 0.7 this function might not be executed at the end of the + request in case an unhandled exception occurred. + """ + self.after_request_funcs.setdefault(None, []).append(f) + return f + + @setupmethod + def teardown_request(self, f): + """Register a function to be run at the end of each request, + regardless of whether there was an exception or not. These functions + are executed when the request context is popped, even if not an + actual request was performed. + + Example:: + + ctx = app.test_request_context() + ctx.push() + ... + ctx.pop() + + When ``ctx.pop()`` is executed in the above example, the teardown + functions are called just before the request context moves from the + stack of active contexts. This becomes relevant if you are using + such constructs in tests. + + Generally teardown functions must take every necessary step to avoid + that they will fail. If they do execute code that might fail they + will have to surround the execution of these code by try/except + statements and log occurring errors. + + When a teardown function was called because of an exception it will + be passed an error object. + + The return values of teardown functions are ignored. + + .. admonition:: Debug Note + + In debug mode Flask will not tear down a request on an exception + immediately. Instead it will keep it alive so that the interactive + debugger can still access it. This behavior can be controlled + by the ``PRESERVE_CONTEXT_ON_EXCEPTION`` configuration variable. + """ + self.teardown_request_funcs.setdefault(None, []).append(f) + return f + + @setupmethod + def teardown_appcontext(self, f): + """Registers a function to be called when the application context + ends. These functions are typically also called when the request + context is popped. + + Example:: + + ctx = app.app_context() + ctx.push() + ... + ctx.pop() + + When ``ctx.pop()`` is executed in the above example, the teardown + functions are called just before the app context moves from the + stack of active contexts. This becomes relevant if you are using + such constructs in tests. + + Since a request context typically also manages an application + context it would also be called when you pop a request context. + + When a teardown function was called because of an unhandled exception + it will be passed an error object. If an :meth:`errorhandler` is + registered, it will handle the exception and the teardown will not + receive it. + + The return values of teardown functions are ignored. + + .. versionadded:: 0.9 + """ + self.teardown_appcontext_funcs.append(f) + return f + + @setupmethod + def context_processor(self, f): + """Registers a template context processor function.""" + self.template_context_processors[None].append(f) + return f + + @setupmethod + def shell_context_processor(self, f): + """Registers a shell context processor function. + + .. versionadded:: 0.11 + """ + self.shell_context_processors.append(f) + return f + + @setupmethod + def url_value_preprocessor(self, f): + """Register a URL value preprocessor function for all view + functions in the application. These functions will be called before the + :meth:`before_request` functions. + + The function can modify the values captured from the matched url before + they are passed to the view. For example, this can be used to pop a + common language code value and place it in ``g`` rather than pass it to + every view. + + The function is passed the endpoint name and values dict. The return + value is ignored. + """ + self.url_value_preprocessors.setdefault(None, []).append(f) + return f + + @setupmethod + def url_defaults(self, f): + """Callback function for URL defaults for all view functions of the + application. It's called with the endpoint and values and should + update the values passed in place. + """ + self.url_default_functions.setdefault(None, []).append(f) + return f + + def _find_error_handler(self, e): + """Return a registered error handler for an exception in this order: + blueprint handler for a specific code, app handler for a specific code, + blueprint handler for an exception class, app handler for an exception + class, or ``None`` if a suitable handler is not found. + """ + exc_class, code = self._get_exc_class_and_code(type(e)) + + for name, c in ( + (request.blueprint, code), (None, code), + (request.blueprint, None), (None, None) + ): + handler_map = self.error_handler_spec.setdefault(name, {}).get(c) + + if not handler_map: + continue + + for cls in exc_class.__mro__: + handler = handler_map.get(cls) + + if handler is not None: + return handler + + def handle_http_exception(self, e): + """Handles an HTTP exception. By default this will invoke the + registered error handlers and fall back to returning the + exception as response. + + .. versionadded:: 0.3 + """ + # Proxy exceptions don't have error codes. We want to always return + # those unchanged as errors + if e.code is None: + return e + + handler = self._find_error_handler(e) + if handler is None: + return e + return handler(e) + + def trap_http_exception(self, e): + """Checks if an HTTP exception should be trapped or not. By default + this will return ``False`` for all exceptions except for a bad request + key error if ``TRAP_BAD_REQUEST_ERRORS`` is set to ``True``. It + also returns ``True`` if ``TRAP_HTTP_EXCEPTIONS`` is set to ``True``. + + This is called for all HTTP exceptions raised by a view function. + If it returns ``True`` for any exception the error handler for this + exception is not called and it shows up as regular exception in the + traceback. This is helpful for debugging implicitly raised HTTP + exceptions. + + .. versionchanged:: 1.0 + Bad request errors are not trapped by default in debug mode. + + .. versionadded:: 0.8 + """ + if self.config['TRAP_HTTP_EXCEPTIONS']: + return True + + trap_bad_request = self.config['TRAP_BAD_REQUEST_ERRORS'] + + # if unset, trap key errors in debug mode + if ( + trap_bad_request is None and self.debug + and isinstance(e, BadRequestKeyError) + ): + return True + + if trap_bad_request: + return isinstance(e, BadRequest) + + return False + + def handle_user_exception(self, e): + """This method is called whenever an exception occurs that should be + handled. A special case are + :class:`~werkzeug.exception.HTTPException`\s which are forwarded by + this function to the :meth:`handle_http_exception` method. This + function will either return a response value or reraise the + exception with the same traceback. + + .. versionchanged:: 1.0 + Key errors raised from request data like ``form`` show the the bad + key in debug mode rather than a generic bad request message. + + .. versionadded:: 0.7 + """ + exc_type, exc_value, tb = sys.exc_info() + assert exc_value is e + # ensure not to trash sys.exc_info() at that point in case someone + # wants the traceback preserved in handle_http_exception. Of course + # we cannot prevent users from trashing it themselves in a custom + # trap_http_exception method so that's their fault then. + + # MultiDict passes the key to the exception, but that's ignored + # when generating the response message. Set an informative + # description for key errors in debug mode or when trapping errors. + if ( + (self.debug or self.config['TRAP_BAD_REQUEST_ERRORS']) + and isinstance(e, BadRequestKeyError) + # only set it if it's still the default description + and e.description is BadRequestKeyError.description + ): + e.description = "KeyError: '{0}'".format(*e.args) + + if isinstance(e, HTTPException) and not self.trap_http_exception(e): + return self.handle_http_exception(e) + + handler = self._find_error_handler(e) + + if handler is None: + reraise(exc_type, exc_value, tb) + return handler(e) + + def handle_exception(self, e): + """Default exception handling that kicks in when an exception + occurs that is not caught. In debug mode the exception will + be re-raised immediately, otherwise it is logged and the handler + for a 500 internal server error is used. If no such handler + exists, a default 500 internal server error message is displayed. + + .. versionadded:: 0.3 + """ + exc_type, exc_value, tb = sys.exc_info() + + got_request_exception.send(self, exception=e) + handler = self._find_error_handler(InternalServerError()) + + if self.propagate_exceptions: + # if we want to repropagate the exception, we can attempt to + # raise it with the whole traceback in case we can do that + # (the function was actually called from the except part) + # otherwise, we just raise the error again + if exc_value is e: + reraise(exc_type, exc_value, tb) + else: + raise e + + self.log_exception((exc_type, exc_value, tb)) + if handler is None: + return InternalServerError() + return self.finalize_request(handler(e), from_error_handler=True) + + def log_exception(self, exc_info): + """Logs an exception. This is called by :meth:`handle_exception` + if debugging is disabled and right before the handler is called. + The default implementation logs the exception as error on the + :attr:`logger`. + + .. versionadded:: 0.8 + """ + self.logger.error('Exception on %s [%s]' % ( + request.path, + request.method + ), exc_info=exc_info) + + def raise_routing_exception(self, request): + """Exceptions that are recording during routing are reraised with + this method. During debug we are not reraising redirect requests + for non ``GET``, ``HEAD``, or ``OPTIONS`` requests and we're raising + a different error instead to help debug situations. + + :internal: + """ + if not self.debug \ + or not isinstance(request.routing_exception, RequestRedirect) \ + or request.method in ('GET', 'HEAD', 'OPTIONS'): + raise request.routing_exception + + from .debughelpers import FormDataRoutingRedirect + raise FormDataRoutingRedirect(request) + + def dispatch_request(self): + """Does the request dispatching. Matches the URL and returns the + return value of the view or error handler. This does not have to + be a response object. In order to convert the return value to a + proper response object, call :func:`make_response`. + + .. versionchanged:: 0.7 + This no longer does the exception handling, this code was + moved to the new :meth:`full_dispatch_request`. + """ + req = _request_ctx_stack.top.request + if req.routing_exception is not None: + self.raise_routing_exception(req) + rule = req.url_rule + # if we provide automatic options for this URL and the + # request came with the OPTIONS method, reply automatically + if getattr(rule, 'provide_automatic_options', False) \ + and req.method == 'OPTIONS': + return self.make_default_options_response() + # otherwise dispatch to the handler for that endpoint + return self.view_functions[rule.endpoint](**req.view_args) + + def full_dispatch_request(self): + """Dispatches the request and on top of that performs request + pre and postprocessing as well as HTTP exception catching and + error handling. + + .. versionadded:: 0.7 + """ + self.try_trigger_before_first_request_functions() + try: + request_started.send(self) + rv = self.preprocess_request() + if rv is None: + rv = self.dispatch_request() + except Exception as e: + rv = self.handle_user_exception(e) + return self.finalize_request(rv) + + def finalize_request(self, rv, from_error_handler=False): + """Given the return value from a view function this finalizes + the request by converting it into a response and invoking the + postprocessing functions. This is invoked for both normal + request dispatching as well as error handlers. + + Because this means that it might be called as a result of a + failure a special safe mode is available which can be enabled + with the `from_error_handler` flag. If enabled, failures in + response processing will be logged and otherwise ignored. + + :internal: + """ + response = self.make_response(rv) + try: + response = self.process_response(response) + request_finished.send(self, response=response) + except Exception: + if not from_error_handler: + raise + self.logger.exception('Request finalizing failed with an ' + 'error while handling an error') + return response + + def try_trigger_before_first_request_functions(self): + """Called before each request and will ensure that it triggers + the :attr:`before_first_request_funcs` and only exactly once per + application instance (which means process usually). + + :internal: + """ + if self._got_first_request: + return + with self._before_request_lock: + if self._got_first_request: + return + for func in self.before_first_request_funcs: + func() + self._got_first_request = True + + def make_default_options_response(self): + """This method is called to create the default ``OPTIONS`` response. + This can be changed through subclassing to change the default + behavior of ``OPTIONS`` responses. + + .. versionadded:: 0.7 + """ + adapter = _request_ctx_stack.top.url_adapter + if hasattr(adapter, 'allowed_methods'): + methods = adapter.allowed_methods() + else: + # fallback for Werkzeug < 0.7 + methods = [] + try: + adapter.match(method='--') + except MethodNotAllowed as e: + methods = e.valid_methods + except HTTPException as e: + pass + rv = self.response_class() + rv.allow.update(methods) + return rv + + def should_ignore_error(self, error): + """This is called to figure out if an error should be ignored + or not as far as the teardown system is concerned. If this + function returns ``True`` then the teardown handlers will not be + passed the error. + + .. versionadded:: 0.10 + """ + return False + + def make_response(self, rv): + """Convert the return value from a view function to an instance of + :attr:`response_class`. + + :param rv: the return value from the view function. The view function + must return a response. Returning ``None``, or the view ending + without returning, is not allowed. The following types are allowed + for ``view_rv``: + + ``str`` (``unicode`` in Python 2) + A response object is created with the string encoded to UTF-8 + as the body. + + ``bytes`` (``str`` in Python 2) + A response object is created with the bytes as the body. + + ``tuple`` + Either ``(body, status, headers)``, ``(body, status)``, or + ``(body, headers)``, where ``body`` is any of the other types + allowed here, ``status`` is a string or an integer, and + ``headers`` is a dictionary or a list of ``(key, value)`` + tuples. If ``body`` is a :attr:`response_class` instance, + ``status`` overwrites the exiting value and ``headers`` are + extended. + + :attr:`response_class` + The object is returned unchanged. + + other :class:`~werkzeug.wrappers.Response` class + The object is coerced to :attr:`response_class`. + + :func:`callable` + The function is called as a WSGI application. The result is + used to create a response object. + + .. versionchanged:: 0.9 + Previously a tuple was interpreted as the arguments for the + response object. + """ + + status = headers = None + + # unpack tuple returns + if isinstance(rv, tuple): + len_rv = len(rv) + + # a 3-tuple is unpacked directly + if len_rv == 3: + rv, status, headers = rv + # decide if a 2-tuple has status or headers + elif len_rv == 2: + if isinstance(rv[1], (Headers, dict, tuple, list)): + rv, headers = rv + else: + rv, status = rv + # other sized tuples are not allowed + else: + raise TypeError( + 'The view function did not return a valid response tuple.' + ' The tuple must have the form (body, status, headers),' + ' (body, status), or (body, headers).' + ) + + # the body must not be None + if rv is None: + raise TypeError( + 'The view function did not return a valid response. The' + ' function either returned None or ended without a return' + ' statement.' + ) + + # make sure the body is an instance of the response class + if not isinstance(rv, self.response_class): + if isinstance(rv, (text_type, bytes, bytearray)): + # let the response class set the status and headers instead of + # waiting to do it manually, so that the class can handle any + # special logic + rv = self.response_class(rv, status=status, headers=headers) + status = headers = None + else: + # evaluate a WSGI callable, or coerce a different response + # class to the correct type + try: + rv = self.response_class.force_type(rv, request.environ) + except TypeError as e: + new_error = TypeError( + '{e}\nThe view function did not return a valid' + ' response. The return type must be a string, tuple,' + ' Response instance, or WSGI callable, but it was a' + ' {rv.__class__.__name__}.'.format(e=e, rv=rv) + ) + reraise(TypeError, new_error, sys.exc_info()[2]) + + # prefer the status if it was provided + if status is not None: + if isinstance(status, (text_type, bytes, bytearray)): + rv.status = status + else: + rv.status_code = status + + # extend existing headers with provided headers + if headers: + rv.headers.extend(headers) + + return rv + + def create_url_adapter(self, request): + """Creates a URL adapter for the given request. The URL adapter + is created at a point where the request context is not yet set + up so the request is passed explicitly. + + .. versionadded:: 0.6 + + .. versionchanged:: 0.9 + This can now also be called without a request object when the + URL adapter is created for the application context. + + .. versionchanged:: 1.0 + :data:`SERVER_NAME` no longer implicitly enables subdomain + matching. Use :attr:`subdomain_matching` instead. + """ + if request is not None: + # If subdomain matching is disabled (the default), use the + # default subdomain in all cases. This should be the default + # in Werkzeug but it currently does not have that feature. + subdomain = ((self.url_map.default_subdomain or None) + if not self.subdomain_matching else None) + return self.url_map.bind_to_environ( + request.environ, + server_name=self.config['SERVER_NAME'], + subdomain=subdomain) + # We need at the very least the server name to be set for this + # to work. + if self.config['SERVER_NAME'] is not None: + return self.url_map.bind( + self.config['SERVER_NAME'], + script_name=self.config['APPLICATION_ROOT'], + url_scheme=self.config['PREFERRED_URL_SCHEME']) + + def inject_url_defaults(self, endpoint, values): + """Injects the URL defaults for the given endpoint directly into + the values dictionary passed. This is used internally and + automatically called on URL building. + + .. versionadded:: 0.7 + """ + funcs = self.url_default_functions.get(None, ()) + if '.' in endpoint: + bp = endpoint.rsplit('.', 1)[0] + funcs = chain(funcs, self.url_default_functions.get(bp, ())) + for func in funcs: + func(endpoint, values) + + def handle_url_build_error(self, error, endpoint, values): + """Handle :class:`~werkzeug.routing.BuildError` on :meth:`url_for`. + """ + exc_type, exc_value, tb = sys.exc_info() + for handler in self.url_build_error_handlers: + try: + rv = handler(error, endpoint, values) + if rv is not None: + return rv + except BuildError as e: + # make error available outside except block (py3) + error = e + + # At this point we want to reraise the exception. If the error is + # still the same one we can reraise it with the original traceback, + # otherwise we raise it from here. + if error is exc_value: + reraise(exc_type, exc_value, tb) + raise error + + def preprocess_request(self): + """Called before the request is dispatched. Calls + :attr:`url_value_preprocessors` registered with the app and the + current blueprint (if any). Then calls :attr:`before_request_funcs` + registered with the app and the blueprint. + + If any :meth:`before_request` handler returns a non-None value, the + value is handled as if it was the return value from the view, and + further request handling is stopped. + """ + + bp = _request_ctx_stack.top.request.blueprint + + funcs = self.url_value_preprocessors.get(None, ()) + if bp is not None and bp in self.url_value_preprocessors: + funcs = chain(funcs, self.url_value_preprocessors[bp]) + for func in funcs: + func(request.endpoint, request.view_args) + + funcs = self.before_request_funcs.get(None, ()) + if bp is not None and bp in self.before_request_funcs: + funcs = chain(funcs, self.before_request_funcs[bp]) + for func in funcs: + rv = func() + if rv is not None: + return rv + + def process_response(self, response): + """Can be overridden in order to modify the response object + before it's sent to the WSGI server. By default this will + call all the :meth:`after_request` decorated functions. + + .. versionchanged:: 0.5 + As of Flask 0.5 the functions registered for after request + execution are called in reverse order of registration. + + :param response: a :attr:`response_class` object. + :return: a new response object or the same, has to be an + instance of :attr:`response_class`. + """ + ctx = _request_ctx_stack.top + bp = ctx.request.blueprint + funcs = ctx._after_request_functions + if bp is not None and bp in self.after_request_funcs: + funcs = chain(funcs, reversed(self.after_request_funcs[bp])) + if None in self.after_request_funcs: + funcs = chain(funcs, reversed(self.after_request_funcs[None])) + for handler in funcs: + response = handler(response) + if not self.session_interface.is_null_session(ctx.session): + self.session_interface.save_session(self, ctx.session, response) + return response + + def do_teardown_request(self, exc=_sentinel): + """Called after the request is dispatched and the response is + returned, right before the request context is popped. + + This calls all functions decorated with + :meth:`teardown_request`, and :meth:`Blueprint.teardown_request` + if a blueprint handled the request. Finally, the + :data:`request_tearing_down` signal is sent. + + This is called by + :meth:`RequestContext.pop() `, + which may be delayed during testing to maintain access to + resources. + + :param exc: An unhandled exception raised while dispatching the + request. Detected from the current exception information if + not passed. Passed to each teardown function. + + .. versionchanged:: 0.9 + Added the ``exc`` argument. + """ + if exc is _sentinel: + exc = sys.exc_info()[1] + funcs = reversed(self.teardown_request_funcs.get(None, ())) + bp = _request_ctx_stack.top.request.blueprint + if bp is not None and bp in self.teardown_request_funcs: + funcs = chain(funcs, reversed(self.teardown_request_funcs[bp])) + for func in funcs: + func(exc) + request_tearing_down.send(self, exc=exc) + + def do_teardown_appcontext(self, exc=_sentinel): + """Called right before the application context is popped. + + When handling a request, the application context is popped + after the request context. See :meth:`do_teardown_request`. + + This calls all functions decorated with + :meth:`teardown_appcontext`. Then the + :data:`appcontext_tearing_down` signal is sent. + + This is called by + :meth:`AppContext.pop() `. + + .. versionadded:: 0.9 + """ + if exc is _sentinel: + exc = sys.exc_info()[1] + for func in reversed(self.teardown_appcontext_funcs): + func(exc) + appcontext_tearing_down.send(self, exc=exc) + + def app_context(self): + """Create an :class:`~flask.ctx.AppContext`. Use as a ``with`` + block to push the context, which will make :data:`current_app` + point at this application. + + An application context is automatically pushed by + :meth:`RequestContext.push() ` + when handling a request, and when running a CLI command. Use + this to manually create a context outside of these situations. + + :: + + with app.app_context(): + init_db() + + See :doc:`/appcontext`. + + .. versionadded:: 0.9 + """ + return AppContext(self) + + def request_context(self, environ): + """Create a :class:`~flask.ctx.RequestContext` representing a + WSGI environment. Use a ``with`` block to push the context, + which will make :data:`request` point at this request. + + See :doc:`/reqcontext`. + + Typically you should not call this from your own code. A request + context is automatically pushed by the :meth:`wsgi_app` when + handling a request. Use :meth:`test_request_context` to create + an environment and context instead of this method. + + :param environ: a WSGI environment + """ + return RequestContext(self, environ) + + def test_request_context(self, *args, **kwargs): + """Create a :class:`~flask.ctx.RequestContext` for a WSGI + environment created from the given values. This is mostly useful + during testing, where you may want to run a function that uses + request data without dispatching a full request. + + See :doc:`/reqcontext`. + + Use a ``with`` block to push the context, which will make + :data:`request` point at the request for the created + environment. :: + + with test_request_context(...): + generate_report() + + When using the shell, it may be easier to push and pop the + context manually to avoid indentation. :: + + ctx = app.test_request_context(...) + ctx.push() + ... + ctx.pop() + + Takes the same arguments as Werkzeug's + :class:`~werkzeug.test.EnvironBuilder`, with some defaults from + the application. See the linked Werkzeug docs for most of the + available arguments. Flask-specific behavior is listed here. + + :param path: URL path being requested. + :param base_url: Base URL where the app is being served, which + ``path`` is relative to. If not given, built from + :data:`PREFERRED_URL_SCHEME`, ``subdomain``, + :data:`SERVER_NAME`, and :data:`APPLICATION_ROOT`. + :param subdomain: Subdomain name to append to + :data:`SERVER_NAME`. + :param url_scheme: Scheme to use instead of + :data:`PREFERRED_URL_SCHEME`. + :param data: The request body, either as a string or a dict of + form keys and values. + :param json: If given, this is serialized as JSON and passed as + ``data``. Also defaults ``content_type`` to + ``application/json``. + :param args: other positional arguments passed to + :class:`~werkzeug.test.EnvironBuilder`. + :param kwargs: other keyword arguments passed to + :class:`~werkzeug.test.EnvironBuilder`. + """ + from flask.testing import make_test_environ_builder + + builder = make_test_environ_builder(self, *args, **kwargs) + + try: + return self.request_context(builder.get_environ()) + finally: + builder.close() + + def wsgi_app(self, environ, start_response): + """The actual WSGI application. This is not implemented in + :meth:`__call__` so that middlewares can be applied without + losing a reference to the app object. Instead of doing this:: + + app = MyMiddleware(app) + + It's a better idea to do this instead:: + + app.wsgi_app = MyMiddleware(app.wsgi_app) + + Then you still have the original application object around and + can continue to call methods on it. + + .. versionchanged:: 0.7 + Teardown events for the request and app contexts are called + even if an unhandled error occurs. Other events may not be + called depending on when an error occurs during dispatch. + See :ref:`callbacks-and-errors`. + + :param environ: A WSGI environment. + :param start_response: A callable accepting a status code, + a list of headers, and an optional exception context to + start the response. + """ + ctx = self.request_context(environ) + error = None + try: + try: + ctx.push() + response = self.full_dispatch_request() + except Exception as e: + error = e + response = self.handle_exception(e) + except: + error = sys.exc_info()[1] + raise + return response(environ, start_response) + finally: + if self.should_ignore_error(error): + error = None + ctx.auto_pop(error) + + def __call__(self, environ, start_response): + """The WSGI server calls the Flask application object as the + WSGI application. This calls :meth:`wsgi_app` which can be + wrapped to applying middleware.""" + return self.wsgi_app(environ, start_response) + + def __repr__(self): + return '<%s %r>' % ( + self.__class__.__name__, + self.name, + ) diff --git a/venv/lib/python2.7/site-packages/flask/blueprints.py b/venv/lib/python2.7/site-packages/flask/blueprints.py new file mode 100644 index 0000000..5ce5561 --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/blueprints.py @@ -0,0 +1,448 @@ +# -*- coding: utf-8 -*- +""" + flask.blueprints + ~~~~~~~~~~~~~~~~ + + Blueprints are the recommended way to implement larger or more + pluggable applications in Flask 0.7 and later. + + :copyright: © 2010 by the Pallets team. + :license: BSD, see LICENSE for more details. +""" +from functools import update_wrapper +from werkzeug.urls import url_join + +from .helpers import _PackageBoundObject, _endpoint_from_view_func + + +class BlueprintSetupState(object): + """Temporary holder object for registering a blueprint with the + application. An instance of this class is created by the + :meth:`~flask.Blueprint.make_setup_state` method and later passed + to all register callback functions. + """ + + def __init__(self, blueprint, app, options, first_registration): + #: a reference to the current application + self.app = app + + #: a reference to the blueprint that created this setup state. + self.blueprint = blueprint + + #: a dictionary with all options that were passed to the + #: :meth:`~flask.Flask.register_blueprint` method. + self.options = options + + #: as blueprints can be registered multiple times with the + #: application and not everything wants to be registered + #: multiple times on it, this attribute can be used to figure + #: out if the blueprint was registered in the past already. + self.first_registration = first_registration + + subdomain = self.options.get('subdomain') + if subdomain is None: + subdomain = self.blueprint.subdomain + + #: The subdomain that the blueprint should be active for, ``None`` + #: otherwise. + self.subdomain = subdomain + + url_prefix = self.options.get('url_prefix') + if url_prefix is None: + url_prefix = self.blueprint.url_prefix + #: The prefix that should be used for all URLs defined on the + #: blueprint. + self.url_prefix = url_prefix + + #: A dictionary with URL defaults that is added to each and every + #: URL that was defined with the blueprint. + self.url_defaults = dict(self.blueprint.url_values_defaults) + self.url_defaults.update(self.options.get('url_defaults', ())) + + def add_url_rule(self, rule, endpoint=None, view_func=None, **options): + """A helper method to register a rule (and optionally a view function) + to the application. The endpoint is automatically prefixed with the + blueprint's name. + """ + if self.url_prefix is not None: + if rule: + rule = '/'.join(( + self.url_prefix.rstrip('/'), rule.lstrip('/'))) + else: + rule = self.url_prefix + options.setdefault('subdomain', self.subdomain) + if endpoint is None: + endpoint = _endpoint_from_view_func(view_func) + defaults = self.url_defaults + if 'defaults' in options: + defaults = dict(defaults, **options.pop('defaults')) + self.app.add_url_rule(rule, '%s.%s' % (self.blueprint.name, endpoint), + view_func, defaults=defaults, **options) + + +class Blueprint(_PackageBoundObject): + """Represents a blueprint. A blueprint is an object that records + functions that will be called with the + :class:`~flask.blueprints.BlueprintSetupState` later to register functions + or other things on the main application. See :ref:`blueprints` for more + information. + + .. versionadded:: 0.7 + """ + + warn_on_modifications = False + _got_registered_once = False + + #: Blueprint local JSON decoder class to use. + #: Set to ``None`` to use the app's :class:`~flask.app.Flask.json_encoder`. + json_encoder = None + #: Blueprint local JSON decoder class to use. + #: Set to ``None`` to use the app's :class:`~flask.app.Flask.json_decoder`. + json_decoder = None + + # TODO remove the next three attrs when Sphinx :inherited-members: works + # https://github.com/sphinx-doc/sphinx/issues/741 + + #: The name of the package or module that this app belongs to. Do not + #: change this once it is set by the constructor. + import_name = None + + #: Location of the template files to be added to the template lookup. + #: ``None`` if templates should not be added. + template_folder = None + + #: Absolute path to the package on the filesystem. Used to look up + #: resources contained in the package. + root_path = None + + def __init__(self, name, import_name, static_folder=None, + static_url_path=None, template_folder=None, + url_prefix=None, subdomain=None, url_defaults=None, + root_path=None): + _PackageBoundObject.__init__(self, import_name, template_folder, + root_path=root_path) + self.name = name + self.url_prefix = url_prefix + self.subdomain = subdomain + self.static_folder = static_folder + self.static_url_path = static_url_path + self.deferred_functions = [] + if url_defaults is None: + url_defaults = {} + self.url_values_defaults = url_defaults + + def record(self, func): + """Registers a function that is called when the blueprint is + registered on the application. This function is called with the + state as argument as returned by the :meth:`make_setup_state` + method. + """ + if self._got_registered_once and self.warn_on_modifications: + from warnings import warn + warn(Warning('The blueprint was already registered once ' + 'but is getting modified now. These changes ' + 'will not show up.')) + self.deferred_functions.append(func) + + def record_once(self, func): + """Works like :meth:`record` but wraps the function in another + function that will ensure the function is only called once. If the + blueprint is registered a second time on the application, the + function passed is not called. + """ + def wrapper(state): + if state.first_registration: + func(state) + return self.record(update_wrapper(wrapper, func)) + + def make_setup_state(self, app, options, first_registration=False): + """Creates an instance of :meth:`~flask.blueprints.BlueprintSetupState` + object that is later passed to the register callback functions. + Subclasses can override this to return a subclass of the setup state. + """ + return BlueprintSetupState(self, app, options, first_registration) + + def register(self, app, options, first_registration=False): + """Called by :meth:`Flask.register_blueprint` to register all views + and callbacks registered on the blueprint with the application. Creates + a :class:`.BlueprintSetupState` and calls each :meth:`record` callback + with it. + + :param app: The application this blueprint is being registered with. + :param options: Keyword arguments forwarded from + :meth:`~Flask.register_blueprint`. + :param first_registration: Whether this is the first time this + blueprint has been registered on the application. + """ + self._got_registered_once = True + state = self.make_setup_state(app, options, first_registration) + + if self.has_static_folder: + state.add_url_rule( + self.static_url_path + '/', + view_func=self.send_static_file, endpoint='static' + ) + + for deferred in self.deferred_functions: + deferred(state) + + def route(self, rule, **options): + """Like :meth:`Flask.route` but for a blueprint. The endpoint for the + :func:`url_for` function is prefixed with the name of the blueprint. + """ + def decorator(f): + endpoint = options.pop("endpoint", f.__name__) + self.add_url_rule(rule, endpoint, f, **options) + return f + return decorator + + def add_url_rule(self, rule, endpoint=None, view_func=None, **options): + """Like :meth:`Flask.add_url_rule` but for a blueprint. The endpoint for + the :func:`url_for` function is prefixed with the name of the blueprint. + """ + if endpoint: + assert '.' not in endpoint, "Blueprint endpoints should not contain dots" + if view_func and hasattr(view_func, '__name__'): + assert '.' not in view_func.__name__, "Blueprint view function name should not contain dots" + self.record(lambda s: + s.add_url_rule(rule, endpoint, view_func, **options)) + + def endpoint(self, endpoint): + """Like :meth:`Flask.endpoint` but for a blueprint. This does not + prefix the endpoint with the blueprint name, this has to be done + explicitly by the user of this method. If the endpoint is prefixed + with a `.` it will be registered to the current blueprint, otherwise + it's an application independent endpoint. + """ + def decorator(f): + def register_endpoint(state): + state.app.view_functions[endpoint] = f + self.record_once(register_endpoint) + return f + return decorator + + def app_template_filter(self, name=None): + """Register a custom template filter, available application wide. Like + :meth:`Flask.template_filter` but for a blueprint. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + def decorator(f): + self.add_app_template_filter(f, name=name) + return f + return decorator + + def add_app_template_filter(self, f, name=None): + """Register a custom template filter, available application wide. Like + :meth:`Flask.add_template_filter` but for a blueprint. Works exactly + like the :meth:`app_template_filter` decorator. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + def register_template(state): + state.app.jinja_env.filters[name or f.__name__] = f + self.record_once(register_template) + + def app_template_test(self, name=None): + """Register a custom template test, available application wide. Like + :meth:`Flask.template_test` but for a blueprint. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + def decorator(f): + self.add_app_template_test(f, name=name) + return f + return decorator + + def add_app_template_test(self, f, name=None): + """Register a custom template test, available application wide. Like + :meth:`Flask.add_template_test` but for a blueprint. Works exactly + like the :meth:`app_template_test` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + def register_template(state): + state.app.jinja_env.tests[name or f.__name__] = f + self.record_once(register_template) + + def app_template_global(self, name=None): + """Register a custom template global, available application wide. Like + :meth:`Flask.template_global` but for a blueprint. + + .. versionadded:: 0.10 + + :param name: the optional name of the global, otherwise the + function name will be used. + """ + def decorator(f): + self.add_app_template_global(f, name=name) + return f + return decorator + + def add_app_template_global(self, f, name=None): + """Register a custom template global, available application wide. Like + :meth:`Flask.add_template_global` but for a blueprint. Works exactly + like the :meth:`app_template_global` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the global, otherwise the + function name will be used. + """ + def register_template(state): + state.app.jinja_env.globals[name or f.__name__] = f + self.record_once(register_template) + + def before_request(self, f): + """Like :meth:`Flask.before_request` but for a blueprint. This function + is only executed before each request that is handled by a function of + that blueprint. + """ + self.record_once(lambda s: s.app.before_request_funcs + .setdefault(self.name, []).append(f)) + return f + + def before_app_request(self, f): + """Like :meth:`Flask.before_request`. Such a function is executed + before each request, even if outside of a blueprint. + """ + self.record_once(lambda s: s.app.before_request_funcs + .setdefault(None, []).append(f)) + return f + + def before_app_first_request(self, f): + """Like :meth:`Flask.before_first_request`. Such a function is + executed before the first request to the application. + """ + self.record_once(lambda s: s.app.before_first_request_funcs.append(f)) + return f + + def after_request(self, f): + """Like :meth:`Flask.after_request` but for a blueprint. This function + is only executed after each request that is handled by a function of + that blueprint. + """ + self.record_once(lambda s: s.app.after_request_funcs + .setdefault(self.name, []).append(f)) + return f + + def after_app_request(self, f): + """Like :meth:`Flask.after_request` but for a blueprint. Such a function + is executed after each request, even if outside of the blueprint. + """ + self.record_once(lambda s: s.app.after_request_funcs + .setdefault(None, []).append(f)) + return f + + def teardown_request(self, f): + """Like :meth:`Flask.teardown_request` but for a blueprint. This + function is only executed when tearing down requests handled by a + function of that blueprint. Teardown request functions are executed + when the request context is popped, even when no actual request was + performed. + """ + self.record_once(lambda s: s.app.teardown_request_funcs + .setdefault(self.name, []).append(f)) + return f + + def teardown_app_request(self, f): + """Like :meth:`Flask.teardown_request` but for a blueprint. Such a + function is executed when tearing down each request, even if outside of + the blueprint. + """ + self.record_once(lambda s: s.app.teardown_request_funcs + .setdefault(None, []).append(f)) + return f + + def context_processor(self, f): + """Like :meth:`Flask.context_processor` but for a blueprint. This + function is only executed for requests handled by a blueprint. + """ + self.record_once(lambda s: s.app.template_context_processors + .setdefault(self.name, []).append(f)) + return f + + def app_context_processor(self, f): + """Like :meth:`Flask.context_processor` but for a blueprint. Such a + function is executed each request, even if outside of the blueprint. + """ + self.record_once(lambda s: s.app.template_context_processors + .setdefault(None, []).append(f)) + return f + + def app_errorhandler(self, code): + """Like :meth:`Flask.errorhandler` but for a blueprint. This + handler is used for all requests, even if outside of the blueprint. + """ + def decorator(f): + self.record_once(lambda s: s.app.errorhandler(code)(f)) + return f + return decorator + + def url_value_preprocessor(self, f): + """Registers a function as URL value preprocessor for this + blueprint. It's called before the view functions are called and + can modify the url values provided. + """ + self.record_once(lambda s: s.app.url_value_preprocessors + .setdefault(self.name, []).append(f)) + return f + + def url_defaults(self, f): + """Callback function for URL defaults for this blueprint. It's called + with the endpoint and values and should update the values passed + in place. + """ + self.record_once(lambda s: s.app.url_default_functions + .setdefault(self.name, []).append(f)) + return f + + def app_url_value_preprocessor(self, f): + """Same as :meth:`url_value_preprocessor` but application wide. + """ + self.record_once(lambda s: s.app.url_value_preprocessors + .setdefault(None, []).append(f)) + return f + + def app_url_defaults(self, f): + """Same as :meth:`url_defaults` but application wide. + """ + self.record_once(lambda s: s.app.url_default_functions + .setdefault(None, []).append(f)) + return f + + def errorhandler(self, code_or_exception): + """Registers an error handler that becomes active for this blueprint + only. Please be aware that routing does not happen local to a + blueprint so an error handler for 404 usually is not handled by + a blueprint unless it is caused inside a view function. Another + special case is the 500 internal server error which is always looked + up from the application. + + Otherwise works as the :meth:`~flask.Flask.errorhandler` decorator + of the :class:`~flask.Flask` object. + """ + def decorator(f): + self.record_once(lambda s: s.app._register_error_handler( + self.name, code_or_exception, f)) + return f + return decorator + + def register_error_handler(self, code_or_exception, f): + """Non-decorator version of the :meth:`errorhandler` error attach + function, akin to the :meth:`~flask.Flask.register_error_handler` + application-wide function of the :class:`~flask.Flask` object but + for error handlers limited to this blueprint. + + .. versionadded:: 0.11 + """ + self.record_once(lambda s: s.app._register_error_handler( + self.name, code_or_exception, f)) diff --git a/venv/lib/python2.7/site-packages/flask/cli.py b/venv/lib/python2.7/site-packages/flask/cli.py new file mode 100644 index 0000000..efc1733 --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/cli.py @@ -0,0 +1,898 @@ +# -*- coding: utf-8 -*- +""" + flask.cli + ~~~~~~~~~ + + A simple command line application to run flask apps. + + :copyright: © 2010 by the Pallets team. + :license: BSD, see LICENSE for more details. +""" + +from __future__ import print_function + +import ast +import inspect +import os +import re +import ssl +import sys +import traceback +from functools import update_wrapper +from operator import attrgetter +from threading import Lock, Thread + +import click +from werkzeug.utils import import_string + +from . import __version__ +from ._compat import getargspec, iteritems, reraise, text_type +from .globals import current_app +from .helpers import get_debug_flag, get_env, get_load_dotenv + +try: + import dotenv +except ImportError: + dotenv = None + + +class NoAppException(click.UsageError): + """Raised if an application cannot be found or loaded.""" + + +def find_best_app(script_info, module): + """Given a module instance this tries to find the best possible + application in the module or raises an exception. + """ + from . import Flask + + # Search for the most common names first. + for attr_name in ('app', 'application'): + app = getattr(module, attr_name, None) + + if isinstance(app, Flask): + return app + + # Otherwise find the only object that is a Flask instance. + matches = [ + v for k, v in iteritems(module.__dict__) if isinstance(v, Flask) + ] + + if len(matches) == 1: + return matches[0] + elif len(matches) > 1: + raise NoAppException( + 'Detected multiple Flask applications in module "{module}". Use ' + '"FLASK_APP={module}:name" to specify the correct ' + 'one.'.format(module=module.__name__) + ) + + # Search for app factory functions. + for attr_name in ('create_app', 'make_app'): + app_factory = getattr(module, attr_name, None) + + if inspect.isfunction(app_factory): + try: + app = call_factory(script_info, app_factory) + + if isinstance(app, Flask): + return app + except TypeError: + if not _called_with_wrong_args(app_factory): + raise + raise NoAppException( + 'Detected factory "{factory}" in module "{module}", but ' + 'could not call it without arguments. Use ' + '"FLASK_APP=\'{module}:{factory}(args)\'" to specify ' + 'arguments.'.format( + factory=attr_name, module=module.__name__ + ) + ) + + raise NoAppException( + 'Failed to find Flask application or factory in module "{module}". ' + 'Use "FLASK_APP={module}:name to specify one.'.format( + module=module.__name__ + ) + ) + + +def call_factory(script_info, app_factory, arguments=()): + """Takes an app factory, a ``script_info` object and optionally a tuple + of arguments. Checks for the existence of a script_info argument and calls + the app_factory depending on that and the arguments provided. + """ + args_spec = getargspec(app_factory) + arg_names = args_spec.args + arg_defaults = args_spec.defaults + + if 'script_info' in arg_names: + return app_factory(*arguments, script_info=script_info) + elif arguments: + return app_factory(*arguments) + elif not arguments and len(arg_names) == 1 and arg_defaults is None: + return app_factory(script_info) + + return app_factory() + + +def _called_with_wrong_args(factory): + """Check whether calling a function raised a ``TypeError`` because + the call failed or because something in the factory raised the + error. + + :param factory: the factory function that was called + :return: true if the call failed + """ + tb = sys.exc_info()[2] + + try: + while tb is not None: + if tb.tb_frame.f_code is factory.__code__: + # in the factory, it was called successfully + return False + + tb = tb.tb_next + + # didn't reach the factory + return True + finally: + del tb + + +def find_app_by_string(script_info, module, app_name): + """Checks if the given string is a variable name or a function. If it is a + function, it checks for specified arguments and whether it takes a + ``script_info`` argument and calls the function with the appropriate + arguments. + """ + from flask import Flask + match = re.match(r'^ *([^ ()]+) *(?:\((.*?) *,? *\))? *$', app_name) + + if not match: + raise NoAppException( + '"{name}" is not a valid variable name or function ' + 'expression.'.format(name=app_name) + ) + + name, args = match.groups() + + try: + attr = getattr(module, name) + except AttributeError as e: + raise NoAppException(e.args[0]) + + if inspect.isfunction(attr): + if args: + try: + args = ast.literal_eval('({args},)'.format(args=args)) + except (ValueError, SyntaxError)as e: + raise NoAppException( + 'Could not parse the arguments in ' + '"{app_name}".'.format(e=e, app_name=app_name) + ) + else: + args = () + + try: + app = call_factory(script_info, attr, args) + except TypeError as e: + if not _called_with_wrong_args(attr): + raise + + raise NoAppException( + '{e}\nThe factory "{app_name}" in module "{module}" could not ' + 'be called with the specified arguments.'.format( + e=e, app_name=app_name, module=module.__name__ + ) + ) + else: + app = attr + + if isinstance(app, Flask): + return app + + raise NoAppException( + 'A valid Flask application was not obtained from ' + '"{module}:{app_name}".'.format( + module=module.__name__, app_name=app_name + ) + ) + + +def prepare_import(path): + """Given a filename this will try to calculate the python path, add it + to the search path and return the actual module name that is expected. + """ + path = os.path.realpath(path) + + if os.path.splitext(path)[1] == '.py': + path = os.path.splitext(path)[0] + + if os.path.basename(path) == '__init__': + path = os.path.dirname(path) + + module_name = [] + + # move up until outside package structure (no __init__.py) + while True: + path, name = os.path.split(path) + module_name.append(name) + + if not os.path.exists(os.path.join(path, '__init__.py')): + break + + if sys.path[0] != path: + sys.path.insert(0, path) + + return '.'.join(module_name[::-1]) + + +def locate_app(script_info, module_name, app_name, raise_if_not_found=True): + __traceback_hide__ = True + + try: + __import__(module_name) + except ImportError: + # Reraise the ImportError if it occurred within the imported module. + # Determine this by checking whether the trace has a depth > 1. + if sys.exc_info()[-1].tb_next: + raise NoAppException( + 'While importing "{name}", an ImportError was raised:' + '\n\n{tb}'.format(name=module_name, tb=traceback.format_exc()) + ) + elif raise_if_not_found: + raise NoAppException( + 'Could not import "{name}".'.format(name=module_name) + ) + else: + return + + module = sys.modules[module_name] + + if app_name is None: + return find_best_app(script_info, module) + else: + return find_app_by_string(script_info, module, app_name) + + +def get_version(ctx, param, value): + if not value or ctx.resilient_parsing: + return + message = 'Flask %(version)s\nPython %(python_version)s' + click.echo(message % { + 'version': __version__, + 'python_version': sys.version, + }, color=ctx.color) + ctx.exit() + + +version_option = click.Option( + ['--version'], + help='Show the flask version', + expose_value=False, + callback=get_version, + is_flag=True, + is_eager=True +) + + +class DispatchingApp(object): + """Special application that dispatches to a Flask application which + is imported by name in a background thread. If an error happens + it is recorded and shown as part of the WSGI handling which in case + of the Werkzeug debugger means that it shows up in the browser. + """ + + def __init__(self, loader, use_eager_loading=False): + self.loader = loader + self._app = None + self._lock = Lock() + self._bg_loading_exc_info = None + if use_eager_loading: + self._load_unlocked() + else: + self._load_in_background() + + def _load_in_background(self): + def _load_app(): + __traceback_hide__ = True + with self._lock: + try: + self._load_unlocked() + except Exception: + self._bg_loading_exc_info = sys.exc_info() + t = Thread(target=_load_app, args=()) + t.start() + + def _flush_bg_loading_exception(self): + __traceback_hide__ = True + exc_info = self._bg_loading_exc_info + if exc_info is not None: + self._bg_loading_exc_info = None + reraise(*exc_info) + + def _load_unlocked(self): + __traceback_hide__ = True + self._app = rv = self.loader() + self._bg_loading_exc_info = None + return rv + + def __call__(self, environ, start_response): + __traceback_hide__ = True + if self._app is not None: + return self._app(environ, start_response) + self._flush_bg_loading_exception() + with self._lock: + if self._app is not None: + rv = self._app + else: + rv = self._load_unlocked() + return rv(environ, start_response) + + +class ScriptInfo(object): + """Help object to deal with Flask applications. This is usually not + necessary to interface with as it's used internally in the dispatching + to click. In future versions of Flask this object will most likely play + a bigger role. Typically it's created automatically by the + :class:`FlaskGroup` but you can also manually create it and pass it + onwards as click object. + """ + + def __init__(self, app_import_path=None, create_app=None): + #: Optionally the import path for the Flask application. + self.app_import_path = app_import_path or os.environ.get('FLASK_APP') + #: Optionally a function that is passed the script info to create + #: the instance of the application. + self.create_app = create_app + #: A dictionary with arbitrary data that can be associated with + #: this script info. + self.data = {} + self._loaded_app = None + + def load_app(self): + """Loads the Flask app (if not yet loaded) and returns it. Calling + this multiple times will just result in the already loaded app to + be returned. + """ + __traceback_hide__ = True + + if self._loaded_app is not None: + return self._loaded_app + + app = None + + if self.create_app is not None: + app = call_factory(self, self.create_app) + else: + if self.app_import_path: + path, name = (self.app_import_path.split(':', 1) + [None])[:2] + import_name = prepare_import(path) + app = locate_app(self, import_name, name) + else: + for path in ('wsgi.py', 'app.py'): + import_name = prepare_import(path) + app = locate_app(self, import_name, None, + raise_if_not_found=False) + + if app: + break + + if not app: + raise NoAppException( + 'Could not locate a Flask application. You did not provide ' + 'the "FLASK_APP" environment variable, and a "wsgi.py" or ' + '"app.py" module was not found in the current directory.' + ) + + debug = get_debug_flag() + + # Update the app's debug flag through the descriptor so that other + # values repopulate as well. + if debug is not None: + app.debug = debug + + self._loaded_app = app + return app + + +pass_script_info = click.make_pass_decorator(ScriptInfo, ensure=True) + + +def with_appcontext(f): + """Wraps a callback so that it's guaranteed to be executed with the + script's application context. If callbacks are registered directly + to the ``app.cli`` object then they are wrapped with this function + by default unless it's disabled. + """ + @click.pass_context + def decorator(__ctx, *args, **kwargs): + with __ctx.ensure_object(ScriptInfo).load_app().app_context(): + return __ctx.invoke(f, *args, **kwargs) + return update_wrapper(decorator, f) + + +class AppGroup(click.Group): + """This works similar to a regular click :class:`~click.Group` but it + changes the behavior of the :meth:`command` decorator so that it + automatically wraps the functions in :func:`with_appcontext`. + + Not to be confused with :class:`FlaskGroup`. + """ + + def command(self, *args, **kwargs): + """This works exactly like the method of the same name on a regular + :class:`click.Group` but it wraps callbacks in :func:`with_appcontext` + unless it's disabled by passing ``with_appcontext=False``. + """ + wrap_for_ctx = kwargs.pop('with_appcontext', True) + def decorator(f): + if wrap_for_ctx: + f = with_appcontext(f) + return click.Group.command(self, *args, **kwargs)(f) + return decorator + + def group(self, *args, **kwargs): + """This works exactly like the method of the same name on a regular + :class:`click.Group` but it defaults the group class to + :class:`AppGroup`. + """ + kwargs.setdefault('cls', AppGroup) + return click.Group.group(self, *args, **kwargs) + + +class FlaskGroup(AppGroup): + """Special subclass of the :class:`AppGroup` group that supports + loading more commands from the configured Flask app. Normally a + developer does not have to interface with this class but there are + some very advanced use cases for which it makes sense to create an + instance of this. + + For information as of why this is useful see :ref:`custom-scripts`. + + :param add_default_commands: if this is True then the default run and + shell commands wil be added. + :param add_version_option: adds the ``--version`` option. + :param create_app: an optional callback that is passed the script info and + returns the loaded app. + :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv` + files to set environment variables. Will also change the working + directory to the directory containing the first file found. + + .. versionchanged:: 1.0 + If installed, python-dotenv will be used to load environment variables + from :file:`.env` and :file:`.flaskenv` files. + """ + + def __init__(self, add_default_commands=True, create_app=None, + add_version_option=True, load_dotenv=True, **extra): + params = list(extra.pop('params', None) or ()) + + if add_version_option: + params.append(version_option) + + AppGroup.__init__(self, params=params, **extra) + self.create_app = create_app + self.load_dotenv = load_dotenv + + if add_default_commands: + self.add_command(run_command) + self.add_command(shell_command) + self.add_command(routes_command) + + self._loaded_plugin_commands = False + + def _load_plugin_commands(self): + if self._loaded_plugin_commands: + return + try: + import pkg_resources + except ImportError: + self._loaded_plugin_commands = True + return + + for ep in pkg_resources.iter_entry_points('flask.commands'): + self.add_command(ep.load(), ep.name) + self._loaded_plugin_commands = True + + def get_command(self, ctx, name): + self._load_plugin_commands() + + # We load built-in commands first as these should always be the + # same no matter what the app does. If the app does want to + # override this it needs to make a custom instance of this group + # and not attach the default commands. + # + # This also means that the script stays functional in case the + # application completely fails. + rv = AppGroup.get_command(self, ctx, name) + if rv is not None: + return rv + + info = ctx.ensure_object(ScriptInfo) + try: + rv = info.load_app().cli.get_command(ctx, name) + if rv is not None: + return rv + except NoAppException: + pass + + def list_commands(self, ctx): + self._load_plugin_commands() + + # The commands available is the list of both the application (if + # available) plus the builtin commands. + rv = set(click.Group.list_commands(self, ctx)) + info = ctx.ensure_object(ScriptInfo) + try: + rv.update(info.load_app().cli.list_commands(ctx)) + except Exception: + # Here we intentionally swallow all exceptions as we don't + # want the help page to break if the app does not exist. + # If someone attempts to use the command we try to create + # the app again and this will give us the error. + # However, we will not do so silently because that would confuse + # users. + traceback.print_exc() + return sorted(rv) + + def main(self, *args, **kwargs): + # Set a global flag that indicates that we were invoked from the + # command line interface. This is detected by Flask.run to make the + # call into a no-op. This is necessary to avoid ugly errors when the + # script that is loaded here also attempts to start a server. + os.environ['FLASK_RUN_FROM_CLI'] = 'true' + + if get_load_dotenv(self.load_dotenv): + load_dotenv() + + obj = kwargs.get('obj') + + if obj is None: + obj = ScriptInfo(create_app=self.create_app) + + kwargs['obj'] = obj + kwargs.setdefault('auto_envvar_prefix', 'FLASK') + return super(FlaskGroup, self).main(*args, **kwargs) + + +def _path_is_ancestor(path, other): + """Take ``other`` and remove the length of ``path`` from it. Then join it + to ``path``. If it is the original value, ``path`` is an ancestor of + ``other``.""" + return os.path.join(path, other[len(path):].lstrip(os.sep)) == other + + +def load_dotenv(path=None): + """Load "dotenv" files in order of precedence to set environment variables. + + If an env var is already set it is not overwritten, so earlier files in the + list are preferred over later files. + + Changes the current working directory to the location of the first file + found, with the assumption that it is in the top level project directory + and will be where the Python path should import local packages from. + + This is a no-op if `python-dotenv`_ is not installed. + + .. _python-dotenv: https://github.com/theskumar/python-dotenv#readme + + :param path: Load the file at this location instead of searching. + :return: ``True`` if a file was loaded. + + .. versionadded:: 1.0 + """ + if dotenv is None: + if path or os.path.exists('.env') or os.path.exists('.flaskenv'): + click.secho( + ' * Tip: There are .env files present.' + ' Do "pip install python-dotenv" to use them.', + fg='yellow') + return + + if path is not None: + return dotenv.load_dotenv(path) + + new_dir = None + + for name in ('.env', '.flaskenv'): + path = dotenv.find_dotenv(name, usecwd=True) + + if not path: + continue + + if new_dir is None: + new_dir = os.path.dirname(path) + + dotenv.load_dotenv(path) + + if new_dir and os.getcwd() != new_dir: + os.chdir(new_dir) + + return new_dir is not None # at least one file was located and loaded + + +def show_server_banner(env, debug, app_import_path, eager_loading): + """Show extra startup messages the first time the server is run, + ignoring the reloader. + """ + if os.environ.get('WERKZEUG_RUN_MAIN') == 'true': + return + + if app_import_path is not None: + message = ' * Serving Flask app "{0}"'.format(app_import_path) + + if not eager_loading: + message += ' (lazy loading)' + + click.echo(message) + + click.echo(' * Environment: {0}'.format(env)) + + if env == 'production': + click.secho( + ' WARNING: Do not use the development server in a production' + ' environment.', fg='red') + click.secho(' Use a production WSGI server instead.', dim=True) + + if debug is not None: + click.echo(' * Debug mode: {0}'.format('on' if debug else 'off')) + + +class CertParamType(click.ParamType): + """Click option type for the ``--cert`` option. Allows either an + existing file, the string ``'adhoc'``, or an import for a + :class:`~ssl.SSLContext` object. + """ + + name = 'path' + + def __init__(self): + self.path_type = click.Path( + exists=True, dir_okay=False, resolve_path=True) + + def convert(self, value, param, ctx): + try: + return self.path_type(value, param, ctx) + except click.BadParameter: + value = click.STRING(value, param, ctx).lower() + + if value == 'adhoc': + try: + import OpenSSL + except ImportError: + raise click.BadParameter( + 'Using ad-hoc certificates requires pyOpenSSL.', + ctx, param) + + return value + + obj = import_string(value, silent=True) + + if sys.version_info < (2, 7): + if obj: + return obj + else: + if isinstance(obj, ssl.SSLContext): + return obj + + raise + + +def _validate_key(ctx, param, value): + """The ``--key`` option must be specified when ``--cert`` is a file. + Modifies the ``cert`` param to be a ``(cert, key)`` pair if needed. + """ + cert = ctx.params.get('cert') + is_adhoc = cert == 'adhoc' + + if sys.version_info < (2, 7): + is_context = cert and not isinstance(cert, (text_type, bytes)) + else: + is_context = isinstance(cert, ssl.SSLContext) + + if value is not None: + if is_adhoc: + raise click.BadParameter( + 'When "--cert" is "adhoc", "--key" is not used.', + ctx, param) + + if is_context: + raise click.BadParameter( + 'When "--cert" is an SSLContext object, "--key is not used.', + ctx, param) + + if not cert: + raise click.BadParameter( + '"--cert" must also be specified.', + ctx, param) + + ctx.params['cert'] = cert, value + + else: + if cert and not (is_adhoc or is_context): + raise click.BadParameter( + 'Required when using "--cert".', + ctx, param) + + return value + + +@click.command('run', short_help='Runs a development server.') +@click.option('--host', '-h', default='127.0.0.1', + help='The interface to bind to.') +@click.option('--port', '-p', default=5000, + help='The port to bind to.') +@click.option('--cert', type=CertParamType(), + help='Specify a certificate file to use HTTPS.') +@click.option('--key', + type=click.Path(exists=True, dir_okay=False, resolve_path=True), + callback=_validate_key, expose_value=False, + help='The key file to use when specifying a certificate.') +@click.option('--reload/--no-reload', default=None, + help='Enable or disable the reloader. By default the reloader ' + 'is active if debug is enabled.') +@click.option('--debugger/--no-debugger', default=None, + help='Enable or disable the debugger. By default the debugger ' + 'is active if debug is enabled.') +@click.option('--eager-loading/--lazy-loader', default=None, + help='Enable or disable eager loading. By default eager ' + 'loading is enabled if the reloader is disabled.') +@click.option('--with-threads/--without-threads', default=True, + help='Enable or disable multithreading.') +@pass_script_info +def run_command(info, host, port, reload, debugger, eager_loading, + with_threads, cert): + """Run a local development server. + + This server is for development purposes only. It does not provide + the stability, security, or performance of production WSGI servers. + + The reloader and debugger are enabled by default if + FLASK_ENV=development or FLASK_DEBUG=1. + """ + debug = get_debug_flag() + + if reload is None: + reload = debug + + if debugger is None: + debugger = debug + + if eager_loading is None: + eager_loading = not reload + + show_server_banner(get_env(), debug, info.app_import_path, eager_loading) + app = DispatchingApp(info.load_app, use_eager_loading=eager_loading) + + from werkzeug.serving import run_simple + run_simple(host, port, app, use_reloader=reload, use_debugger=debugger, + threaded=with_threads, ssl_context=cert) + + +@click.command('shell', short_help='Runs a shell in the app context.') +@with_appcontext +def shell_command(): + """Runs an interactive Python shell in the context of a given + Flask application. The application will populate the default + namespace of this shell according to it's configuration. + + This is useful for executing small snippets of management code + without having to manually configure the application. + """ + import code + from flask.globals import _app_ctx_stack + app = _app_ctx_stack.top.app + banner = 'Python %s on %s\nApp: %s [%s]\nInstance: %s' % ( + sys.version, + sys.platform, + app.import_name, + app.env, + app.instance_path, + ) + ctx = {} + + # Support the regular Python interpreter startup script if someone + # is using it. + startup = os.environ.get('PYTHONSTARTUP') + if startup and os.path.isfile(startup): + with open(startup, 'r') as f: + eval(compile(f.read(), startup, 'exec'), ctx) + + ctx.update(app.make_shell_context()) + + code.interact(banner=banner, local=ctx) + + +@click.command('routes', short_help='Show the routes for the app.') +@click.option( + '--sort', '-s', + type=click.Choice(('endpoint', 'methods', 'rule', 'match')), + default='endpoint', + help=( + 'Method to sort routes by. "match" is the order that Flask will match ' + 'routes when dispatching a request.' + ) +) +@click.option( + '--all-methods', + is_flag=True, + help="Show HEAD and OPTIONS methods." +) +@with_appcontext +def routes_command(sort, all_methods): + """Show all registered routes with endpoints and methods.""" + + rules = list(current_app.url_map.iter_rules()) + if not rules: + click.echo('No routes were registered.') + return + + ignored_methods = set(() if all_methods else ('HEAD', 'OPTIONS')) + + if sort in ('endpoint', 'rule'): + rules = sorted(rules, key=attrgetter(sort)) + elif sort == 'methods': + rules = sorted(rules, key=lambda rule: sorted(rule.methods)) + + rule_methods = [ + ', '.join(sorted(rule.methods - ignored_methods)) for rule in rules + ] + + headers = ('Endpoint', 'Methods', 'Rule') + widths = ( + max(len(rule.endpoint) for rule in rules), + max(len(methods) for methods in rule_methods), + max(len(rule.rule) for rule in rules), + ) + widths = [max(len(h), w) for h, w in zip(headers, widths)] + row = '{{0:<{0}}} {{1:<{1}}} {{2:<{2}}}'.format(*widths) + + click.echo(row.format(*headers).strip()) + click.echo(row.format(*('-' * width for width in widths))) + + for rule, methods in zip(rules, rule_methods): + click.echo(row.format(rule.endpoint, methods, rule.rule).rstrip()) + + +cli = FlaskGroup(help="""\ +A general utility script for Flask applications. + +Provides commands from Flask, extensions, and the application. Loads the +application defined in the FLASK_APP environment variable, or from a wsgi.py +file. Setting the FLASK_ENV environment variable to 'development' will enable +debug mode. + +\b + {prefix}{cmd} FLASK_APP=hello.py + {prefix}{cmd} FLASK_ENV=development + {prefix}flask run +""".format( + cmd='export' if os.name == 'posix' else 'set', + prefix='$ ' if os.name == 'posix' else '> ' +)) + + +def main(as_module=False): + args = sys.argv[1:] + + if as_module: + this_module = 'flask' + + if sys.version_info < (2, 7): + this_module += '.cli' + + name = 'python -m ' + this_module + + # Python rewrites "python -m flask" to the path to the file in argv. + # Restore the original command so that the reloader works. + sys.argv = ['-m', this_module] + args + else: + name = None + + cli.main(args=args, prog_name=name) + + +if __name__ == '__main__': + main(as_module=True) diff --git a/venv/lib/python2.7/site-packages/flask/config.py b/venv/lib/python2.7/site-packages/flask/config.py new file mode 100644 index 0000000..d6074ba --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/config.py @@ -0,0 +1,265 @@ +# -*- coding: utf-8 -*- +""" + flask.config + ~~~~~~~~~~~~ + + Implements the configuration related objects. + + :copyright: © 2010 by the Pallets team. + :license: BSD, see LICENSE for more details. +""" + +import os +import types +import errno + +from werkzeug.utils import import_string +from ._compat import string_types, iteritems +from . import json + + +class ConfigAttribute(object): + """Makes an attribute forward to the config""" + + def __init__(self, name, get_converter=None): + self.__name__ = name + self.get_converter = get_converter + + def __get__(self, obj, type=None): + if obj is None: + return self + rv = obj.config[self.__name__] + if self.get_converter is not None: + rv = self.get_converter(rv) + return rv + + def __set__(self, obj, value): + obj.config[self.__name__] = value + + +class Config(dict): + """Works exactly like a dict but provides ways to fill it from files + or special dictionaries. There are two common patterns to populate the + config. + + Either you can fill the config from a config file:: + + app.config.from_pyfile('yourconfig.cfg') + + Or alternatively you can define the configuration options in the + module that calls :meth:`from_object` or provide an import path to + a module that should be loaded. It is also possible to tell it to + use the same module and with that provide the configuration values + just before the call:: + + DEBUG = True + SECRET_KEY = 'development key' + app.config.from_object(__name__) + + In both cases (loading from any Python file or loading from modules), + only uppercase keys are added to the config. This makes it possible to use + lowercase values in the config file for temporary values that are not added + to the config or to define the config keys in the same file that implements + the application. + + Probably the most interesting way to load configurations is from an + environment variable pointing to a file:: + + app.config.from_envvar('YOURAPPLICATION_SETTINGS') + + In this case before launching the application you have to set this + environment variable to the file you want to use. On Linux and OS X + use the export statement:: + + export YOURAPPLICATION_SETTINGS='/path/to/config/file' + + On windows use `set` instead. + + :param root_path: path to which files are read relative from. When the + config object is created by the application, this is + the application's :attr:`~flask.Flask.root_path`. + :param defaults: an optional dictionary of default values + """ + + def __init__(self, root_path, defaults=None): + dict.__init__(self, defaults or {}) + self.root_path = root_path + + def from_envvar(self, variable_name, silent=False): + """Loads a configuration from an environment variable pointing to + a configuration file. This is basically just a shortcut with nicer + error messages for this line of code:: + + app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS']) + + :param variable_name: name of the environment variable + :param silent: set to ``True`` if you want silent failure for missing + files. + :return: bool. ``True`` if able to load config, ``False`` otherwise. + """ + rv = os.environ.get(variable_name) + if not rv: + if silent: + return False + raise RuntimeError('The environment variable %r is not set ' + 'and as such configuration could not be ' + 'loaded. Set this variable and make it ' + 'point to a configuration file' % + variable_name) + return self.from_pyfile(rv, silent=silent) + + def from_pyfile(self, filename, silent=False): + """Updates the values in the config from a Python file. This function + behaves as if the file was imported as module with the + :meth:`from_object` function. + + :param filename: the filename of the config. This can either be an + absolute filename or a filename relative to the + root path. + :param silent: set to ``True`` if you want silent failure for missing + files. + + .. versionadded:: 0.7 + `silent` parameter. + """ + filename = os.path.join(self.root_path, filename) + d = types.ModuleType('config') + d.__file__ = filename + try: + with open(filename, mode='rb') as config_file: + exec(compile(config_file.read(), filename, 'exec'), d.__dict__) + except IOError as e: + if silent and e.errno in ( + errno.ENOENT, errno.EISDIR, errno.ENOTDIR + ): + return False + e.strerror = 'Unable to load configuration file (%s)' % e.strerror + raise + self.from_object(d) + return True + + def from_object(self, obj): + """Updates the values from the given object. An object can be of one + of the following two types: + + - a string: in this case the object with that name will be imported + - an actual object reference: that object is used directly + + Objects are usually either modules or classes. :meth:`from_object` + loads only the uppercase attributes of the module/class. A ``dict`` + object will not work with :meth:`from_object` because the keys of a + ``dict`` are not attributes of the ``dict`` class. + + Example of module-based configuration:: + + app.config.from_object('yourapplication.default_config') + from yourapplication import default_config + app.config.from_object(default_config) + + You should not use this function to load the actual configuration but + rather configuration defaults. The actual config should be loaded + with :meth:`from_pyfile` and ideally from a location not within the + package because the package might be installed system wide. + + See :ref:`config-dev-prod` for an example of class-based configuration + using :meth:`from_object`. + + :param obj: an import name or object + """ + if isinstance(obj, string_types): + obj = import_string(obj) + for key in dir(obj): + if key.isupper(): + self[key] = getattr(obj, key) + + def from_json(self, filename, silent=False): + """Updates the values in the config from a JSON file. This function + behaves as if the JSON object was a dictionary and passed to the + :meth:`from_mapping` function. + + :param filename: the filename of the JSON file. This can either be an + absolute filename or a filename relative to the + root path. + :param silent: set to ``True`` if you want silent failure for missing + files. + + .. versionadded:: 0.11 + """ + filename = os.path.join(self.root_path, filename) + + try: + with open(filename) as json_file: + obj = json.loads(json_file.read()) + except IOError as e: + if silent and e.errno in (errno.ENOENT, errno.EISDIR): + return False + e.strerror = 'Unable to load configuration file (%s)' % e.strerror + raise + return self.from_mapping(obj) + + def from_mapping(self, *mapping, **kwargs): + """Updates the config like :meth:`update` ignoring items with non-upper + keys. + + .. versionadded:: 0.11 + """ + mappings = [] + if len(mapping) == 1: + if hasattr(mapping[0], 'items'): + mappings.append(mapping[0].items()) + else: + mappings.append(mapping[0]) + elif len(mapping) > 1: + raise TypeError( + 'expected at most 1 positional argument, got %d' % len(mapping) + ) + mappings.append(kwargs.items()) + for mapping in mappings: + for (key, value) in mapping: + if key.isupper(): + self[key] = value + return True + + def get_namespace(self, namespace, lowercase=True, trim_namespace=True): + """Returns a dictionary containing a subset of configuration options + that match the specified namespace/prefix. Example usage:: + + app.config['IMAGE_STORE_TYPE'] = 'fs' + app.config['IMAGE_STORE_PATH'] = '/var/app/images' + app.config['IMAGE_STORE_BASE_URL'] = 'http://img.website.com' + image_store_config = app.config.get_namespace('IMAGE_STORE_') + + The resulting dictionary `image_store_config` would look like:: + + { + 'type': 'fs', + 'path': '/var/app/images', + 'base_url': 'http://img.website.com' + } + + This is often useful when configuration options map directly to + keyword arguments in functions or class constructors. + + :param namespace: a configuration namespace + :param lowercase: a flag indicating if the keys of the resulting + dictionary should be lowercase + :param trim_namespace: a flag indicating if the keys of the resulting + dictionary should not include the namespace + + .. versionadded:: 0.11 + """ + rv = {} + for k, v in iteritems(self): + if not k.startswith(namespace): + continue + if trim_namespace: + key = k[len(namespace):] + else: + key = k + if lowercase: + key = key.lower() + rv[key] = v + return rv + + def __repr__(self): + return '<%s %s>' % (self.__class__.__name__, dict.__repr__(self)) diff --git a/venv/lib/python2.7/site-packages/flask/ctx.py b/venv/lib/python2.7/site-packages/flask/ctx.py new file mode 100644 index 0000000..8472c92 --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/ctx.py @@ -0,0 +1,457 @@ +# -*- coding: utf-8 -*- +""" + flask.ctx + ~~~~~~~~~ + + Implements the objects required to keep the context. + + :copyright: © 2010 by the Pallets team. + :license: BSD, see LICENSE for more details. +""" + +import sys +from functools import update_wrapper + +from werkzeug.exceptions import HTTPException + +from .globals import _request_ctx_stack, _app_ctx_stack +from .signals import appcontext_pushed, appcontext_popped +from ._compat import BROKEN_PYPY_CTXMGR_EXIT, reraise + + +# a singleton sentinel value for parameter defaults +_sentinel = object() + + +class _AppCtxGlobals(object): + """A plain object. Used as a namespace for storing data during an + application context. + + Creating an app context automatically creates this object, which is + made available as the :data:`g` proxy. + + .. describe:: 'key' in g + + Check whether an attribute is present. + + .. versionadded:: 0.10 + + .. describe:: iter(g) + + Return an iterator over the attribute names. + + .. versionadded:: 0.10 + """ + + def get(self, name, default=None): + """Get an attribute by name, or a default value. Like + :meth:`dict.get`. + + :param name: Name of attribute to get. + :param default: Value to return if the attribute is not present. + + .. versionadded:: 0.10 + """ + return self.__dict__.get(name, default) + + def pop(self, name, default=_sentinel): + """Get and remove an attribute by name. Like :meth:`dict.pop`. + + :param name: Name of attribute to pop. + :param default: Value to return if the attribute is not present, + instead of raise a ``KeyError``. + + .. versionadded:: 0.11 + """ + if default is _sentinel: + return self.__dict__.pop(name) + else: + return self.__dict__.pop(name, default) + + def setdefault(self, name, default=None): + """Get the value of an attribute if it is present, otherwise + set and return a default value. Like :meth:`dict.setdefault`. + + :param name: Name of attribute to get. + :param: default: Value to set and return if the attribute is not + present. + + .. versionadded:: 0.11 + """ + return self.__dict__.setdefault(name, default) + + def __contains__(self, item): + return item in self.__dict__ + + def __iter__(self): + return iter(self.__dict__) + + def __repr__(self): + top = _app_ctx_stack.top + if top is not None: + return '' % top.app.name + return object.__repr__(self) + + +def after_this_request(f): + """Executes a function after this request. This is useful to modify + response objects. The function is passed the response object and has + to return the same or a new one. + + Example:: + + @app.route('/') + def index(): + @after_this_request + def add_header(response): + response.headers['X-Foo'] = 'Parachute' + return response + return 'Hello World!' + + This is more useful if a function other than the view function wants to + modify a response. For instance think of a decorator that wants to add + some headers without converting the return value into a response object. + + .. versionadded:: 0.9 + """ + _request_ctx_stack.top._after_request_functions.append(f) + return f + + +def copy_current_request_context(f): + """A helper function that decorates a function to retain the current + request context. This is useful when working with greenlets. The moment + the function is decorated a copy of the request context is created and + then pushed when the function is called. + + Example:: + + import gevent + from flask import copy_current_request_context + + @app.route('/') + def index(): + @copy_current_request_context + def do_some_work(): + # do some work here, it can access flask.request like you + # would otherwise in the view function. + ... + gevent.spawn(do_some_work) + return 'Regular response' + + .. versionadded:: 0.10 + """ + top = _request_ctx_stack.top + if top is None: + raise RuntimeError('This decorator can only be used at local scopes ' + 'when a request context is on the stack. For instance within ' + 'view functions.') + reqctx = top.copy() + def wrapper(*args, **kwargs): + with reqctx: + return f(*args, **kwargs) + return update_wrapper(wrapper, f) + + +def has_request_context(): + """If you have code that wants to test if a request context is there or + not this function can be used. For instance, you may want to take advantage + of request information if the request object is available, but fail + silently if it is unavailable. + + :: + + class User(db.Model): + + def __init__(self, username, remote_addr=None): + self.username = username + if remote_addr is None and has_request_context(): + remote_addr = request.remote_addr + self.remote_addr = remote_addr + + Alternatively you can also just test any of the context bound objects + (such as :class:`request` or :class:`g` for truthness):: + + class User(db.Model): + + def __init__(self, username, remote_addr=None): + self.username = username + if remote_addr is None and request: + remote_addr = request.remote_addr + self.remote_addr = remote_addr + + .. versionadded:: 0.7 + """ + return _request_ctx_stack.top is not None + + +def has_app_context(): + """Works like :func:`has_request_context` but for the application + context. You can also just do a boolean check on the + :data:`current_app` object instead. + + .. versionadded:: 0.9 + """ + return _app_ctx_stack.top is not None + + +class AppContext(object): + """The application context binds an application object implicitly + to the current thread or greenlet, similar to how the + :class:`RequestContext` binds request information. The application + context is also implicitly created if a request context is created + but the application is not on top of the individual application + context. + """ + + def __init__(self, app): + self.app = app + self.url_adapter = app.create_url_adapter(None) + self.g = app.app_ctx_globals_class() + + # Like request context, app contexts can be pushed multiple times + # but there a basic "refcount" is enough to track them. + self._refcnt = 0 + + def push(self): + """Binds the app context to the current context.""" + self._refcnt += 1 + if hasattr(sys, 'exc_clear'): + sys.exc_clear() + _app_ctx_stack.push(self) + appcontext_pushed.send(self.app) + + def pop(self, exc=_sentinel): + """Pops the app context.""" + try: + self._refcnt -= 1 + if self._refcnt <= 0: + if exc is _sentinel: + exc = sys.exc_info()[1] + self.app.do_teardown_appcontext(exc) + finally: + rv = _app_ctx_stack.pop() + assert rv is self, 'Popped wrong app context. (%r instead of %r)' \ + % (rv, self) + appcontext_popped.send(self.app) + + def __enter__(self): + self.push() + return self + + def __exit__(self, exc_type, exc_value, tb): + self.pop(exc_value) + + if BROKEN_PYPY_CTXMGR_EXIT and exc_type is not None: + reraise(exc_type, exc_value, tb) + + +class RequestContext(object): + """The request context contains all request relevant information. It is + created at the beginning of the request and pushed to the + `_request_ctx_stack` and removed at the end of it. It will create the + URL adapter and request object for the WSGI environment provided. + + Do not attempt to use this class directly, instead use + :meth:`~flask.Flask.test_request_context` and + :meth:`~flask.Flask.request_context` to create this object. + + When the request context is popped, it will evaluate all the + functions registered on the application for teardown execution + (:meth:`~flask.Flask.teardown_request`). + + The request context is automatically popped at the end of the request + for you. In debug mode the request context is kept around if + exceptions happen so that interactive debuggers have a chance to + introspect the data. With 0.4 this can also be forced for requests + that did not fail and outside of ``DEBUG`` mode. By setting + ``'flask._preserve_context'`` to ``True`` on the WSGI environment the + context will not pop itself at the end of the request. This is used by + the :meth:`~flask.Flask.test_client` for example to implement the + deferred cleanup functionality. + + You might find this helpful for unittests where you need the + information from the context local around for a little longer. Make + sure to properly :meth:`~werkzeug.LocalStack.pop` the stack yourself in + that situation, otherwise your unittests will leak memory. + """ + + def __init__(self, app, environ, request=None): + self.app = app + if request is None: + request = app.request_class(environ) + self.request = request + self.url_adapter = app.create_url_adapter(self.request) + self.flashes = None + self.session = None + + # Request contexts can be pushed multiple times and interleaved with + # other request contexts. Now only if the last level is popped we + # get rid of them. Additionally if an application context is missing + # one is created implicitly so for each level we add this information + self._implicit_app_ctx_stack = [] + + # indicator if the context was preserved. Next time another context + # is pushed the preserved context is popped. + self.preserved = False + + # remembers the exception for pop if there is one in case the context + # preservation kicks in. + self._preserved_exc = None + + # Functions that should be executed after the request on the response + # object. These will be called before the regular "after_request" + # functions. + self._after_request_functions = [] + + self.match_request() + + def _get_g(self): + return _app_ctx_stack.top.g + def _set_g(self, value): + _app_ctx_stack.top.g = value + g = property(_get_g, _set_g) + del _get_g, _set_g + + def copy(self): + """Creates a copy of this request context with the same request object. + This can be used to move a request context to a different greenlet. + Because the actual request object is the same this cannot be used to + move a request context to a different thread unless access to the + request object is locked. + + .. versionadded:: 0.10 + """ + return self.__class__(self.app, + environ=self.request.environ, + request=self.request + ) + + def match_request(self): + """Can be overridden by a subclass to hook into the matching + of the request. + """ + try: + url_rule, self.request.view_args = \ + self.url_adapter.match(return_rule=True) + self.request.url_rule = url_rule + except HTTPException as e: + self.request.routing_exception = e + + def push(self): + """Binds the request context to the current context.""" + # If an exception occurs in debug mode or if context preservation is + # activated under exception situations exactly one context stays + # on the stack. The rationale is that you want to access that + # information under debug situations. However if someone forgets to + # pop that context again we want to make sure that on the next push + # it's invalidated, otherwise we run at risk that something leaks + # memory. This is usually only a problem in test suite since this + # functionality is not active in production environments. + top = _request_ctx_stack.top + if top is not None and top.preserved: + top.pop(top._preserved_exc) + + # Before we push the request context we have to ensure that there + # is an application context. + app_ctx = _app_ctx_stack.top + if app_ctx is None or app_ctx.app != self.app: + app_ctx = self.app.app_context() + app_ctx.push() + self._implicit_app_ctx_stack.append(app_ctx) + else: + self._implicit_app_ctx_stack.append(None) + + if hasattr(sys, 'exc_clear'): + sys.exc_clear() + + _request_ctx_stack.push(self) + + # Open the session at the moment that the request context is available. + # This allows a custom open_session method to use the request context. + # Only open a new session if this is the first time the request was + # pushed, otherwise stream_with_context loses the session. + if self.session is None: + session_interface = self.app.session_interface + self.session = session_interface.open_session( + self.app, self.request + ) + + if self.session is None: + self.session = session_interface.make_null_session(self.app) + + def pop(self, exc=_sentinel): + """Pops the request context and unbinds it by doing that. This will + also trigger the execution of functions registered by the + :meth:`~flask.Flask.teardown_request` decorator. + + .. versionchanged:: 0.9 + Added the `exc` argument. + """ + app_ctx = self._implicit_app_ctx_stack.pop() + + try: + clear_request = False + if not self._implicit_app_ctx_stack: + self.preserved = False + self._preserved_exc = None + if exc is _sentinel: + exc = sys.exc_info()[1] + self.app.do_teardown_request(exc) + + # If this interpreter supports clearing the exception information + # we do that now. This will only go into effect on Python 2.x, + # on 3.x it disappears automatically at the end of the exception + # stack. + if hasattr(sys, 'exc_clear'): + sys.exc_clear() + + request_close = getattr(self.request, 'close', None) + if request_close is not None: + request_close() + clear_request = True + finally: + rv = _request_ctx_stack.pop() + + # get rid of circular dependencies at the end of the request + # so that we don't require the GC to be active. + if clear_request: + rv.request.environ['werkzeug.request'] = None + + # Get rid of the app as well if necessary. + if app_ctx is not None: + app_ctx.pop(exc) + + assert rv is self, 'Popped wrong request context. ' \ + '(%r instead of %r)' % (rv, self) + + def auto_pop(self, exc): + if self.request.environ.get('flask._preserve_context') or \ + (exc is not None and self.app.preserve_context_on_exception): + self.preserved = True + self._preserved_exc = exc + else: + self.pop(exc) + + def __enter__(self): + self.push() + return self + + def __exit__(self, exc_type, exc_value, tb): + # do not pop the request stack if we are in debug mode and an + # exception happened. This will allow the debugger to still + # access the request object in the interactive shell. Furthermore + # the context can be force kept alive for the test client. + # See flask.testing for how this works. + self.auto_pop(exc_value) + + if BROKEN_PYPY_CTXMGR_EXIT and exc_type is not None: + reraise(exc_type, exc_value, tb) + + def __repr__(self): + return '<%s \'%s\' [%s] of %s>' % ( + self.__class__.__name__, + self.request.url, + self.request.method, + self.app.name, + ) diff --git a/venv/lib/python2.7/site-packages/flask/debughelpers.py b/venv/lib/python2.7/site-packages/flask/debughelpers.py new file mode 100644 index 0000000..e9765f2 --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/debughelpers.py @@ -0,0 +1,168 @@ +# -*- coding: utf-8 -*- +""" + flask.debughelpers + ~~~~~~~~~~~~~~~~~~ + + Various helpers to make the development experience better. + + :copyright: © 2010 by the Pallets team. + :license: BSD, see LICENSE for more details. +""" + +import os +from warnings import warn + +from ._compat import implements_to_string, text_type +from .app import Flask +from .blueprints import Blueprint +from .globals import _request_ctx_stack + + +class UnexpectedUnicodeError(AssertionError, UnicodeError): + """Raised in places where we want some better error reporting for + unexpected unicode or binary data. + """ + + +@implements_to_string +class DebugFilesKeyError(KeyError, AssertionError): + """Raised from request.files during debugging. The idea is that it can + provide a better error message than just a generic KeyError/BadRequest. + """ + + def __init__(self, request, key): + form_matches = request.form.getlist(key) + buf = ['You tried to access the file "%s" in the request.files ' + 'dictionary but it does not exist. The mimetype for the request ' + 'is "%s" instead of "multipart/form-data" which means that no ' + 'file contents were transmitted. To fix this error you should ' + 'provide enctype="multipart/form-data" in your form.' % + (key, request.mimetype)] + if form_matches: + buf.append('\n\nThe browser instead transmitted some file names. ' + 'This was submitted: %s' % ', '.join('"%s"' % x + for x in form_matches)) + self.msg = ''.join(buf) + + def __str__(self): + return self.msg + + +class FormDataRoutingRedirect(AssertionError): + """This exception is raised by Flask in debug mode if it detects a + redirect caused by the routing system when the request method is not + GET, HEAD or OPTIONS. Reasoning: form data will be dropped. + """ + + def __init__(self, request): + exc = request.routing_exception + buf = ['A request was sent to this URL (%s) but a redirect was ' + 'issued automatically by the routing system to "%s".' + % (request.url, exc.new_url)] + + # In case just a slash was appended we can be extra helpful + if request.base_url + '/' == exc.new_url.split('?')[0]: + buf.append(' The URL was defined with a trailing slash so ' + 'Flask will automatically redirect to the URL ' + 'with the trailing slash if it was accessed ' + 'without one.') + + buf.append(' Make sure to directly send your %s-request to this URL ' + 'since we can\'t make browsers or HTTP clients redirect ' + 'with form data reliably or without user interaction.' % + request.method) + buf.append('\n\nNote: this exception is only raised in debug mode') + AssertionError.__init__(self, ''.join(buf).encode('utf-8')) + + +def attach_enctype_error_multidict(request): + """Since Flask 0.8 we're monkeypatching the files object in case a + request is detected that does not use multipart form data but the files + object is accessed. + """ + oldcls = request.files.__class__ + class newcls(oldcls): + def __getitem__(self, key): + try: + return oldcls.__getitem__(self, key) + except KeyError: + if key not in request.form: + raise + raise DebugFilesKeyError(request, key) + newcls.__name__ = oldcls.__name__ + newcls.__module__ = oldcls.__module__ + request.files.__class__ = newcls + + +def _dump_loader_info(loader): + yield 'class: %s.%s' % (type(loader).__module__, type(loader).__name__) + for key, value in sorted(loader.__dict__.items()): + if key.startswith('_'): + continue + if isinstance(value, (tuple, list)): + if not all(isinstance(x, (str, text_type)) for x in value): + continue + yield '%s:' % key + for item in value: + yield ' - %s' % item + continue + elif not isinstance(value, (str, text_type, int, float, bool)): + continue + yield '%s: %r' % (key, value) + + +def explain_template_loading_attempts(app, template, attempts): + """This should help developers understand what failed""" + info = ['Locating template "%s":' % template] + total_found = 0 + blueprint = None + reqctx = _request_ctx_stack.top + if reqctx is not None and reqctx.request.blueprint is not None: + blueprint = reqctx.request.blueprint + + for idx, (loader, srcobj, triple) in enumerate(attempts): + if isinstance(srcobj, Flask): + src_info = 'application "%s"' % srcobj.import_name + elif isinstance(srcobj, Blueprint): + src_info = 'blueprint "%s" (%s)' % (srcobj.name, + srcobj.import_name) + else: + src_info = repr(srcobj) + + info.append('% 5d: trying loader of %s' % ( + idx + 1, src_info)) + + for line in _dump_loader_info(loader): + info.append(' %s' % line) + + if triple is None: + detail = 'no match' + else: + detail = 'found (%r)' % (triple[1] or '') + total_found += 1 + info.append(' -> %s' % detail) + + seems_fishy = False + if total_found == 0: + info.append('Error: the template could not be found.') + seems_fishy = True + elif total_found > 1: + info.append('Warning: multiple loaders returned a match for the template.') + seems_fishy = True + + if blueprint is not None and seems_fishy: + info.append(' The template was looked up from an endpoint that ' + 'belongs to the blueprint "%s".' % blueprint) + info.append(' Maybe you did not place a template in the right folder?') + info.append(' See http://flask.pocoo.org/docs/blueprints/#templates') + + app.logger.info('\n'.join(info)) + + +def explain_ignored_app_run(): + if os.environ.get('WERKZEUG_RUN_MAIN') != 'true': + warn(Warning('Silently ignoring app.run() because the ' + 'application is run from the flask command line ' + 'executable. Consider putting app.run() behind an ' + 'if __name__ == "__main__" guard to silence this ' + 'warning.'), stacklevel=3) diff --git a/venv/lib/python2.7/site-packages/flask/globals.py b/venv/lib/python2.7/site-packages/flask/globals.py new file mode 100644 index 0000000..7d50a6f --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/globals.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +""" + flask.globals + ~~~~~~~~~~~~~ + + Defines all the global objects that are proxies to the current + active context. + + :copyright: © 2010 by the Pallets team. + :license: BSD, see LICENSE for more details. +""" + +from functools import partial +from werkzeug.local import LocalStack, LocalProxy + + +_request_ctx_err_msg = '''\ +Working outside of request context. + +This typically means that you attempted to use functionality that needed +an active HTTP request. Consult the documentation on testing for +information about how to avoid this problem.\ +''' +_app_ctx_err_msg = '''\ +Working outside of application context. + +This typically means that you attempted to use functionality that needed +to interface with the current application object in some way. To solve +this, set up an application context with app.app_context(). See the +documentation for more information.\ +''' + + +def _lookup_req_object(name): + top = _request_ctx_stack.top + if top is None: + raise RuntimeError(_request_ctx_err_msg) + return getattr(top, name) + + +def _lookup_app_object(name): + top = _app_ctx_stack.top + if top is None: + raise RuntimeError(_app_ctx_err_msg) + return getattr(top, name) + + +def _find_app(): + top = _app_ctx_stack.top + if top is None: + raise RuntimeError(_app_ctx_err_msg) + return top.app + + +# context locals +_request_ctx_stack = LocalStack() +_app_ctx_stack = LocalStack() +current_app = LocalProxy(_find_app) +request = LocalProxy(partial(_lookup_req_object, 'request')) +session = LocalProxy(partial(_lookup_req_object, 'session')) +g = LocalProxy(partial(_lookup_app_object, 'g')) diff --git a/venv/lib/python2.7/site-packages/flask/helpers.py b/venv/lib/python2.7/site-packages/flask/helpers.py new file mode 100644 index 0000000..df0b91f --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/helpers.py @@ -0,0 +1,1044 @@ +# -*- coding: utf-8 -*- +""" + flask.helpers + ~~~~~~~~~~~~~ + + Implements various helpers. + + :copyright: © 2010 by the Pallets team. + :license: BSD, see LICENSE for more details. +""" + +import os +import socket +import sys +import pkgutil +import posixpath +import mimetypes +from time import time +from zlib import adler32 +from threading import RLock +import unicodedata +from werkzeug.routing import BuildError +from functools import update_wrapper + +from werkzeug.urls import url_quote +from werkzeug.datastructures import Headers, Range +from werkzeug.exceptions import BadRequest, NotFound, \ + RequestedRangeNotSatisfiable + +from werkzeug.wsgi import wrap_file +from jinja2 import FileSystemLoader + +from .signals import message_flashed +from .globals import session, _request_ctx_stack, _app_ctx_stack, \ + current_app, request +from ._compat import string_types, text_type, PY2 + +# sentinel +_missing = object() + + +# what separators does this operating system provide that are not a slash? +# this is used by the send_from_directory function to ensure that nobody is +# able to access files from outside the filesystem. +_os_alt_seps = list(sep for sep in [os.path.sep, os.path.altsep] + if sep not in (None, '/')) + + +def get_env(): + """Get the environment the app is running in, indicated by the + :envvar:`FLASK_ENV` environment variable. The default is + ``'production'``. + """ + return os.environ.get('FLASK_ENV') or 'production' + + +def get_debug_flag(): + """Get whether debug mode should be enabled for the app, indicated + by the :envvar:`FLASK_DEBUG` environment variable. The default is + ``True`` if :func:`.get_env` returns ``'development'``, or ``False`` + otherwise. + """ + val = os.environ.get('FLASK_DEBUG') + + if not val: + return get_env() == 'development' + + return val.lower() not in ('0', 'false', 'no') + + +def get_load_dotenv(default=True): + """Get whether the user has disabled loading dotenv files by setting + :envvar:`FLASK_SKIP_DOTENV`. The default is ``True``, load the + files. + + :param default: What to return if the env var isn't set. + """ + val = os.environ.get('FLASK_SKIP_DOTENV') + + if not val: + return default + + return val.lower() in ('0', 'false', 'no') + + +def _endpoint_from_view_func(view_func): + """Internal helper that returns the default endpoint for a given + function. This always is the function name. + """ + assert view_func is not None, 'expected view func if endpoint ' \ + 'is not provided.' + return view_func.__name__ + + +def stream_with_context(generator_or_function): + """Request contexts disappear when the response is started on the server. + This is done for efficiency reasons and to make it less likely to encounter + memory leaks with badly written WSGI middlewares. The downside is that if + you are using streamed responses, the generator cannot access request bound + information any more. + + This function however can help you keep the context around for longer:: + + from flask import stream_with_context, request, Response + + @app.route('/stream') + def streamed_response(): + @stream_with_context + def generate(): + yield 'Hello ' + yield request.args['name'] + yield '!' + return Response(generate()) + + Alternatively it can also be used around a specific generator:: + + from flask import stream_with_context, request, Response + + @app.route('/stream') + def streamed_response(): + def generate(): + yield 'Hello ' + yield request.args['name'] + yield '!' + return Response(stream_with_context(generate())) + + .. versionadded:: 0.9 + """ + try: + gen = iter(generator_or_function) + except TypeError: + def decorator(*args, **kwargs): + gen = generator_or_function(*args, **kwargs) + return stream_with_context(gen) + return update_wrapper(decorator, generator_or_function) + + def generator(): + ctx = _request_ctx_stack.top + if ctx is None: + raise RuntimeError('Attempted to stream with context but ' + 'there was no context in the first place to keep around.') + with ctx: + # Dummy sentinel. Has to be inside the context block or we're + # not actually keeping the context around. + yield None + + # The try/finally is here so that if someone passes a WSGI level + # iterator in we're still running the cleanup logic. Generators + # don't need that because they are closed on their destruction + # automatically. + try: + for item in gen: + yield item + finally: + if hasattr(gen, 'close'): + gen.close() + + # The trick is to start the generator. Then the code execution runs until + # the first dummy None is yielded at which point the context was already + # pushed. This item is discarded. Then when the iteration continues the + # real generator is executed. + wrapped_g = generator() + next(wrapped_g) + return wrapped_g + + +def make_response(*args): + """Sometimes it is necessary to set additional headers in a view. Because + views do not have to return response objects but can return a value that + is converted into a response object by Flask itself, it becomes tricky to + add headers to it. This function can be called instead of using a return + and you will get a response object which you can use to attach headers. + + If view looked like this and you want to add a new header:: + + def index(): + return render_template('index.html', foo=42) + + You can now do something like this:: + + def index(): + response = make_response(render_template('index.html', foo=42)) + response.headers['X-Parachutes'] = 'parachutes are cool' + return response + + This function accepts the very same arguments you can return from a + view function. This for example creates a response with a 404 error + code:: + + response = make_response(render_template('not_found.html'), 404) + + The other use case of this function is to force the return value of a + view function into a response which is helpful with view + decorators:: + + response = make_response(view_function()) + response.headers['X-Parachutes'] = 'parachutes are cool' + + Internally this function does the following things: + + - if no arguments are passed, it creates a new response argument + - if one argument is passed, :meth:`flask.Flask.make_response` + is invoked with it. + - if more than one argument is passed, the arguments are passed + to the :meth:`flask.Flask.make_response` function as tuple. + + .. versionadded:: 0.6 + """ + if not args: + return current_app.response_class() + if len(args) == 1: + args = args[0] + return current_app.make_response(args) + + +def url_for(endpoint, **values): + """Generates a URL to the given endpoint with the method provided. + + Variable arguments that are unknown to the target endpoint are appended + to the generated URL as query arguments. If the value of a query argument + is ``None``, the whole pair is skipped. In case blueprints are active + you can shortcut references to the same blueprint by prefixing the + local endpoint with a dot (``.``). + + This will reference the index function local to the current blueprint:: + + url_for('.index') + + For more information, head over to the :ref:`Quickstart `. + + To integrate applications, :class:`Flask` has a hook to intercept URL build + errors through :attr:`Flask.url_build_error_handlers`. The `url_for` + function results in a :exc:`~werkzeug.routing.BuildError` when the current + app does not have a URL for the given endpoint and values. When it does, the + :data:`~flask.current_app` calls its :attr:`~Flask.url_build_error_handlers` if + it is not ``None``, which can return a string to use as the result of + `url_for` (instead of `url_for`'s default to raise the + :exc:`~werkzeug.routing.BuildError` exception) or re-raise the exception. + An example:: + + def external_url_handler(error, endpoint, values): + "Looks up an external URL when `url_for` cannot build a URL." + # This is an example of hooking the build_error_handler. + # Here, lookup_url is some utility function you've built + # which looks up the endpoint in some external URL registry. + url = lookup_url(endpoint, **values) + if url is None: + # External lookup did not have a URL. + # Re-raise the BuildError, in context of original traceback. + exc_type, exc_value, tb = sys.exc_info() + if exc_value is error: + raise exc_type, exc_value, tb + else: + raise error + # url_for will use this result, instead of raising BuildError. + return url + + app.url_build_error_handlers.append(external_url_handler) + + Here, `error` is the instance of :exc:`~werkzeug.routing.BuildError`, and + `endpoint` and `values` are the arguments passed into `url_for`. Note + that this is for building URLs outside the current application, and not for + handling 404 NotFound errors. + + .. versionadded:: 0.10 + The `_scheme` parameter was added. + + .. versionadded:: 0.9 + The `_anchor` and `_method` parameters were added. + + .. versionadded:: 0.9 + Calls :meth:`Flask.handle_build_error` on + :exc:`~werkzeug.routing.BuildError`. + + :param endpoint: the endpoint of the URL (name of the function) + :param values: the variable arguments of the URL rule + :param _external: if set to ``True``, an absolute URL is generated. Server + address can be changed via ``SERVER_NAME`` configuration variable which + defaults to `localhost`. + :param _scheme: a string specifying the desired URL scheme. The `_external` + parameter must be set to ``True`` or a :exc:`ValueError` is raised. The default + behavior uses the same scheme as the current request, or + ``PREFERRED_URL_SCHEME`` from the :ref:`app configuration ` if no + request context is available. As of Werkzeug 0.10, this also can be set + to an empty string to build protocol-relative URLs. + :param _anchor: if provided this is added as anchor to the URL. + :param _method: if provided this explicitly specifies an HTTP method. + """ + appctx = _app_ctx_stack.top + reqctx = _request_ctx_stack.top + + if appctx is None: + raise RuntimeError( + 'Attempted to generate a URL without the application context being' + ' pushed. This has to be executed when application context is' + ' available.' + ) + + # If request specific information is available we have some extra + # features that support "relative" URLs. + if reqctx is not None: + url_adapter = reqctx.url_adapter + blueprint_name = request.blueprint + + if endpoint[:1] == '.': + if blueprint_name is not None: + endpoint = blueprint_name + endpoint + else: + endpoint = endpoint[1:] + + external = values.pop('_external', False) + + # Otherwise go with the url adapter from the appctx and make + # the URLs external by default. + else: + url_adapter = appctx.url_adapter + + if url_adapter is None: + raise RuntimeError( + 'Application was not able to create a URL adapter for request' + ' independent URL generation. You might be able to fix this by' + ' setting the SERVER_NAME config variable.' + ) + + external = values.pop('_external', True) + + anchor = values.pop('_anchor', None) + method = values.pop('_method', None) + scheme = values.pop('_scheme', None) + appctx.app.inject_url_defaults(endpoint, values) + + # This is not the best way to deal with this but currently the + # underlying Werkzeug router does not support overriding the scheme on + # a per build call basis. + old_scheme = None + if scheme is not None: + if not external: + raise ValueError('When specifying _scheme, _external must be True') + old_scheme = url_adapter.url_scheme + url_adapter.url_scheme = scheme + + try: + try: + rv = url_adapter.build(endpoint, values, method=method, + force_external=external) + finally: + if old_scheme is not None: + url_adapter.url_scheme = old_scheme + except BuildError as error: + # We need to inject the values again so that the app callback can + # deal with that sort of stuff. + values['_external'] = external + values['_anchor'] = anchor + values['_method'] = method + values['_scheme'] = scheme + return appctx.app.handle_url_build_error(error, endpoint, values) + + if anchor is not None: + rv += '#' + url_quote(anchor) + return rv + + +def get_template_attribute(template_name, attribute): + """Loads a macro (or variable) a template exports. This can be used to + invoke a macro from within Python code. If you for example have a + template named :file:`_cider.html` with the following contents: + + .. sourcecode:: html+jinja + + {% macro hello(name) %}Hello {{ name }}!{% endmacro %} + + You can access this from Python code like this:: + + hello = get_template_attribute('_cider.html', 'hello') + return hello('World') + + .. versionadded:: 0.2 + + :param template_name: the name of the template + :param attribute: the name of the variable of macro to access + """ + return getattr(current_app.jinja_env.get_template(template_name).module, + attribute) + + +def flash(message, category='message'): + """Flashes a message to the next request. In order to remove the + flashed message from the session and to display it to the user, + the template has to call :func:`get_flashed_messages`. + + .. versionchanged:: 0.3 + `category` parameter added. + + :param message: the message to be flashed. + :param category: the category for the message. The following values + are recommended: ``'message'`` for any kind of message, + ``'error'`` for errors, ``'info'`` for information + messages and ``'warning'`` for warnings. However any + kind of string can be used as category. + """ + # Original implementation: + # + # session.setdefault('_flashes', []).append((category, message)) + # + # This assumed that changes made to mutable structures in the session are + # always in sync with the session object, which is not true for session + # implementations that use external storage for keeping their keys/values. + flashes = session.get('_flashes', []) + flashes.append((category, message)) + session['_flashes'] = flashes + message_flashed.send(current_app._get_current_object(), + message=message, category=category) + + +def get_flashed_messages(with_categories=False, category_filter=[]): + """Pulls all flashed messages from the session and returns them. + Further calls in the same request to the function will return + the same messages. By default just the messages are returned, + but when `with_categories` is set to ``True``, the return value will + be a list of tuples in the form ``(category, message)`` instead. + + Filter the flashed messages to one or more categories by providing those + categories in `category_filter`. This allows rendering categories in + separate html blocks. The `with_categories` and `category_filter` + arguments are distinct: + + * `with_categories` controls whether categories are returned with message + text (``True`` gives a tuple, where ``False`` gives just the message text). + * `category_filter` filters the messages down to only those matching the + provided categories. + + See :ref:`message-flashing-pattern` for examples. + + .. versionchanged:: 0.3 + `with_categories` parameter added. + + .. versionchanged:: 0.9 + `category_filter` parameter added. + + :param with_categories: set to ``True`` to also receive categories. + :param category_filter: whitelist of categories to limit return values + """ + flashes = _request_ctx_stack.top.flashes + if flashes is None: + _request_ctx_stack.top.flashes = flashes = session.pop('_flashes') \ + if '_flashes' in session else [] + if category_filter: + flashes = list(filter(lambda f: f[0] in category_filter, flashes)) + if not with_categories: + return [x[1] for x in flashes] + return flashes + + +def send_file(filename_or_fp, mimetype=None, as_attachment=False, + attachment_filename=None, add_etags=True, + cache_timeout=None, conditional=False, last_modified=None): + """Sends the contents of a file to the client. This will use the + most efficient method available and configured. By default it will + try to use the WSGI server's file_wrapper support. Alternatively + you can set the application's :attr:`~Flask.use_x_sendfile` attribute + to ``True`` to directly emit an ``X-Sendfile`` header. This however + requires support of the underlying webserver for ``X-Sendfile``. + + By default it will try to guess the mimetype for you, but you can + also explicitly provide one. For extra security you probably want + to send certain files as attachment (HTML for instance). The mimetype + guessing requires a `filename` or an `attachment_filename` to be + provided. + + ETags will also be attached automatically if a `filename` is provided. You + can turn this off by setting `add_etags=False`. + + If `conditional=True` and `filename` is provided, this method will try to + upgrade the response stream to support range requests. This will allow + the request to be answered with partial content response. + + Please never pass filenames to this function from user sources; + you should use :func:`send_from_directory` instead. + + .. versionadded:: 0.2 + + .. versionadded:: 0.5 + The `add_etags`, `cache_timeout` and `conditional` parameters were + added. The default behavior is now to attach etags. + + .. versionchanged:: 0.7 + mimetype guessing and etag support for file objects was + deprecated because it was unreliable. Pass a filename if you are + able to, otherwise attach an etag yourself. This functionality + will be removed in Flask 1.0 + + .. versionchanged:: 0.9 + cache_timeout pulls its default from application config, when None. + + .. versionchanged:: 0.12 + The filename is no longer automatically inferred from file objects. If + you want to use automatic mimetype and etag support, pass a filepath via + `filename_or_fp` or `attachment_filename`. + + .. versionchanged:: 0.12 + The `attachment_filename` is preferred over `filename` for MIME-type + detection. + + .. versionchanged:: 1.0 + UTF-8 filenames, as specified in `RFC 2231`_, are supported. + + .. _RFC 2231: https://tools.ietf.org/html/rfc2231#section-4 + + :param filename_or_fp: the filename of the file to send. + This is relative to the :attr:`~Flask.root_path` + if a relative path is specified. + Alternatively a file object might be provided in + which case ``X-Sendfile`` might not work and fall + back to the traditional method. Make sure that the + file pointer is positioned at the start of data to + send before calling :func:`send_file`. + :param mimetype: the mimetype of the file if provided. If a file path is + given, auto detection happens as fallback, otherwise an + error will be raised. + :param as_attachment: set to ``True`` if you want to send this file with + a ``Content-Disposition: attachment`` header. + :param attachment_filename: the filename for the attachment if it + differs from the file's filename. + :param add_etags: set to ``False`` to disable attaching of etags. + :param conditional: set to ``True`` to enable conditional responses. + + :param cache_timeout: the timeout in seconds for the headers. When ``None`` + (default), this value is set by + :meth:`~Flask.get_send_file_max_age` of + :data:`~flask.current_app`. + :param last_modified: set the ``Last-Modified`` header to this value, + a :class:`~datetime.datetime` or timestamp. + If a file was passed, this overrides its mtime. + """ + mtime = None + fsize = None + if isinstance(filename_or_fp, string_types): + filename = filename_or_fp + if not os.path.isabs(filename): + filename = os.path.join(current_app.root_path, filename) + file = None + if attachment_filename is None: + attachment_filename = os.path.basename(filename) + else: + file = filename_or_fp + filename = None + + if mimetype is None: + if attachment_filename is not None: + mimetype = mimetypes.guess_type(attachment_filename)[0] \ + or 'application/octet-stream' + + if mimetype is None: + raise ValueError( + 'Unable to infer MIME-type because no filename is available. ' + 'Please set either `attachment_filename`, pass a filepath to ' + '`filename_or_fp` or set your own MIME-type via `mimetype`.' + ) + + headers = Headers() + if as_attachment: + if attachment_filename is None: + raise TypeError('filename unavailable, required for ' + 'sending as attachment') + + try: + attachment_filename = attachment_filename.encode('latin-1') + except UnicodeEncodeError: + filenames = { + 'filename': unicodedata.normalize( + 'NFKD', attachment_filename).encode('latin-1', 'ignore'), + 'filename*': "UTF-8''%s" % url_quote(attachment_filename), + } + else: + filenames = {'filename': attachment_filename} + + headers.add('Content-Disposition', 'attachment', **filenames) + + if current_app.use_x_sendfile and filename: + if file is not None: + file.close() + headers['X-Sendfile'] = filename + fsize = os.path.getsize(filename) + headers['Content-Length'] = fsize + data = None + else: + if file is None: + file = open(filename, 'rb') + mtime = os.path.getmtime(filename) + fsize = os.path.getsize(filename) + headers['Content-Length'] = fsize + data = wrap_file(request.environ, file) + + rv = current_app.response_class(data, mimetype=mimetype, headers=headers, + direct_passthrough=True) + + if last_modified is not None: + rv.last_modified = last_modified + elif mtime is not None: + rv.last_modified = mtime + + rv.cache_control.public = True + if cache_timeout is None: + cache_timeout = current_app.get_send_file_max_age(filename) + if cache_timeout is not None: + rv.cache_control.max_age = cache_timeout + rv.expires = int(time() + cache_timeout) + + if add_etags and filename is not None: + from warnings import warn + + try: + rv.set_etag('%s-%s-%s' % ( + os.path.getmtime(filename), + os.path.getsize(filename), + adler32( + filename.encode('utf-8') if isinstance(filename, text_type) + else filename + ) & 0xffffffff + )) + except OSError: + warn('Access %s failed, maybe it does not exist, so ignore etags in ' + 'headers' % filename, stacklevel=2) + + if conditional: + try: + rv = rv.make_conditional(request, accept_ranges=True, + complete_length=fsize) + except RequestedRangeNotSatisfiable: + if file is not None: + file.close() + raise + # make sure we don't send x-sendfile for servers that + # ignore the 304 status code for x-sendfile. + if rv.status_code == 304: + rv.headers.pop('x-sendfile', None) + return rv + + +def safe_join(directory, *pathnames): + """Safely join `directory` and zero or more untrusted `pathnames` + components. + + Example usage:: + + @app.route('/wiki/') + def wiki_page(filename): + filename = safe_join(app.config['WIKI_FOLDER'], filename) + with open(filename, 'rb') as fd: + content = fd.read() # Read and process the file content... + + :param directory: the trusted base directory. + :param pathnames: the untrusted pathnames relative to that directory. + :raises: :class:`~werkzeug.exceptions.NotFound` if one or more passed + paths fall out of its boundaries. + """ + + parts = [directory] + + for filename in pathnames: + if filename != '': + filename = posixpath.normpath(filename) + + if ( + any(sep in filename for sep in _os_alt_seps) + or os.path.isabs(filename) + or filename == '..' + or filename.startswith('../') + ): + raise NotFound() + + parts.append(filename) + + return posixpath.join(*parts) + + +def send_from_directory(directory, filename, **options): + """Send a file from a given directory with :func:`send_file`. This + is a secure way to quickly expose static files from an upload folder + or something similar. + + Example usage:: + + @app.route('/uploads/') + def download_file(filename): + return send_from_directory(app.config['UPLOAD_FOLDER'], + filename, as_attachment=True) + + .. admonition:: Sending files and Performance + + It is strongly recommended to activate either ``X-Sendfile`` support in + your webserver or (if no authentication happens) to tell the webserver + to serve files for the given path on its own without calling into the + web application for improved performance. + + .. versionadded:: 0.5 + + :param directory: the directory where all the files are stored. + :param filename: the filename relative to that directory to + download. + :param options: optional keyword arguments that are directly + forwarded to :func:`send_file`. + """ + filename = safe_join(directory, filename) + if not os.path.isabs(filename): + filename = os.path.join(current_app.root_path, filename) + try: + if not os.path.isfile(filename): + raise NotFound() + except (TypeError, ValueError): + raise BadRequest() + options.setdefault('conditional', True) + return send_file(filename, **options) + + +def get_root_path(import_name): + """Returns the path to a package or cwd if that cannot be found. This + returns the path of a package or the folder that contains a module. + + Not to be confused with the package path returned by :func:`find_package`. + """ + # Module already imported and has a file attribute. Use that first. + mod = sys.modules.get(import_name) + if mod is not None and hasattr(mod, '__file__'): + return os.path.dirname(os.path.abspath(mod.__file__)) + + # Next attempt: check the loader. + loader = pkgutil.get_loader(import_name) + + # Loader does not exist or we're referring to an unloaded main module + # or a main module without path (interactive sessions), go with the + # current working directory. + if loader is None or import_name == '__main__': + return os.getcwd() + + # For .egg, zipimporter does not have get_filename until Python 2.7. + # Some other loaders might exhibit the same behavior. + if hasattr(loader, 'get_filename'): + filepath = loader.get_filename(import_name) + else: + # Fall back to imports. + __import__(import_name) + mod = sys.modules[import_name] + filepath = getattr(mod, '__file__', None) + + # If we don't have a filepath it might be because we are a + # namespace package. In this case we pick the root path from the + # first module that is contained in our package. + if filepath is None: + raise RuntimeError('No root path can be found for the provided ' + 'module "%s". This can happen because the ' + 'module came from an import hook that does ' + 'not provide file name information or because ' + 'it\'s a namespace package. In this case ' + 'the root path needs to be explicitly ' + 'provided.' % import_name) + + # filepath is import_name.py for a module, or __init__.py for a package. + return os.path.dirname(os.path.abspath(filepath)) + + +def _matching_loader_thinks_module_is_package(loader, mod_name): + """Given the loader that loaded a module and the module this function + attempts to figure out if the given module is actually a package. + """ + # If the loader can tell us if something is a package, we can + # directly ask the loader. + if hasattr(loader, 'is_package'): + return loader.is_package(mod_name) + # importlib's namespace loaders do not have this functionality but + # all the modules it loads are packages, so we can take advantage of + # this information. + elif (loader.__class__.__module__ == '_frozen_importlib' and + loader.__class__.__name__ == 'NamespaceLoader'): + return True + # Otherwise we need to fail with an error that explains what went + # wrong. + raise AttributeError( + ('%s.is_package() method is missing but is required by Flask of ' + 'PEP 302 import hooks. If you do not use import hooks and ' + 'you encounter this error please file a bug against Flask.') % + loader.__class__.__name__) + + +def find_package(import_name): + """Finds a package and returns the prefix (or None if the package is + not installed) as well as the folder that contains the package or + module as a tuple. The package path returned is the module that would + have to be added to the pythonpath in order to make it possible to + import the module. The prefix is the path below which a UNIX like + folder structure exists (lib, share etc.). + """ + root_mod_name = import_name.split('.')[0] + loader = pkgutil.get_loader(root_mod_name) + if loader is None or import_name == '__main__': + # import name is not found, or interactive/main module + package_path = os.getcwd() + else: + # For .egg, zipimporter does not have get_filename until Python 2.7. + if hasattr(loader, 'get_filename'): + filename = loader.get_filename(root_mod_name) + elif hasattr(loader, 'archive'): + # zipimporter's loader.archive points to the .egg or .zip + # archive filename is dropped in call to dirname below. + filename = loader.archive + else: + # At least one loader is missing both get_filename and archive: + # Google App Engine's HardenedModulesHook + # + # Fall back to imports. + __import__(import_name) + filename = sys.modules[import_name].__file__ + package_path = os.path.abspath(os.path.dirname(filename)) + + # In case the root module is a package we need to chop of the + # rightmost part. This needs to go through a helper function + # because of python 3.3 namespace packages. + if _matching_loader_thinks_module_is_package( + loader, root_mod_name): + package_path = os.path.dirname(package_path) + + site_parent, site_folder = os.path.split(package_path) + py_prefix = os.path.abspath(sys.prefix) + if package_path.startswith(py_prefix): + return py_prefix, package_path + elif site_folder.lower() == 'site-packages': + parent, folder = os.path.split(site_parent) + # Windows like installations + if folder.lower() == 'lib': + base_dir = parent + # UNIX like installations + elif os.path.basename(parent).lower() == 'lib': + base_dir = os.path.dirname(parent) + else: + base_dir = site_parent + return base_dir, package_path + return None, package_path + + +class locked_cached_property(object): + """A decorator that converts a function into a lazy property. The + function wrapped is called the first time to retrieve the result + and then that calculated result is used the next time you access + the value. Works like the one in Werkzeug but has a lock for + thread safety. + """ + + def __init__(self, func, name=None, doc=None): + self.__name__ = name or func.__name__ + self.__module__ = func.__module__ + self.__doc__ = doc or func.__doc__ + self.func = func + self.lock = RLock() + + def __get__(self, obj, type=None): + if obj is None: + return self + with self.lock: + value = obj.__dict__.get(self.__name__, _missing) + if value is _missing: + value = self.func(obj) + obj.__dict__[self.__name__] = value + return value + + +class _PackageBoundObject(object): + #: The name of the package or module that this app belongs to. Do not + #: change this once it is set by the constructor. + import_name = None + + #: Location of the template files to be added to the template lookup. + #: ``None`` if templates should not be added. + template_folder = None + + #: Absolute path to the package on the filesystem. Used to look up + #: resources contained in the package. + root_path = None + + def __init__(self, import_name, template_folder=None, root_path=None): + self.import_name = import_name + self.template_folder = template_folder + + if root_path is None: + root_path = get_root_path(self.import_name) + + self.root_path = root_path + self._static_folder = None + self._static_url_path = None + + def _get_static_folder(self): + if self._static_folder is not None: + return os.path.join(self.root_path, self._static_folder) + + def _set_static_folder(self, value): + self._static_folder = value + + static_folder = property( + _get_static_folder, _set_static_folder, + doc='The absolute path to the configured static folder.' + ) + del _get_static_folder, _set_static_folder + + def _get_static_url_path(self): + if self._static_url_path is not None: + return self._static_url_path + + if self.static_folder is not None: + return '/' + os.path.basename(self.static_folder) + + def _set_static_url_path(self, value): + self._static_url_path = value + + static_url_path = property( + _get_static_url_path, _set_static_url_path, + doc='The URL prefix that the static route will be registered for.' + ) + del _get_static_url_path, _set_static_url_path + + @property + def has_static_folder(self): + """This is ``True`` if the package bound object's container has a + folder for static files. + + .. versionadded:: 0.5 + """ + return self.static_folder is not None + + @locked_cached_property + def jinja_loader(self): + """The Jinja loader for this package bound object. + + .. versionadded:: 0.5 + """ + if self.template_folder is not None: + return FileSystemLoader(os.path.join(self.root_path, + self.template_folder)) + + def get_send_file_max_age(self, filename): + """Provides default cache_timeout for the :func:`send_file` functions. + + By default, this function returns ``SEND_FILE_MAX_AGE_DEFAULT`` from + the configuration of :data:`~flask.current_app`. + + Static file functions such as :func:`send_from_directory` use this + function, and :func:`send_file` calls this function on + :data:`~flask.current_app` when the given cache_timeout is ``None``. If a + cache_timeout is given in :func:`send_file`, that timeout is used; + otherwise, this method is called. + + This allows subclasses to change the behavior when sending files based + on the filename. For example, to set the cache timeout for .js files + to 60 seconds:: + + class MyFlask(flask.Flask): + def get_send_file_max_age(self, name): + if name.lower().endswith('.js'): + return 60 + return flask.Flask.get_send_file_max_age(self, name) + + .. versionadded:: 0.9 + """ + return total_seconds(current_app.send_file_max_age_default) + + def send_static_file(self, filename): + """Function used internally to send static files from the static + folder to the browser. + + .. versionadded:: 0.5 + """ + if not self.has_static_folder: + raise RuntimeError('No static folder for this object') + # Ensure get_send_file_max_age is called in all cases. + # Here, we ensure get_send_file_max_age is called for Blueprints. + cache_timeout = self.get_send_file_max_age(filename) + return send_from_directory(self.static_folder, filename, + cache_timeout=cache_timeout) + + def open_resource(self, resource, mode='rb'): + """Opens a resource from the application's resource folder. To see + how this works, consider the following folder structure:: + + /myapplication.py + /schema.sql + /static + /style.css + /templates + /layout.html + /index.html + + If you want to open the :file:`schema.sql` file you would do the + following:: + + with app.open_resource('schema.sql') as f: + contents = f.read() + do_something_with(contents) + + :param resource: the name of the resource. To access resources within + subfolders use forward slashes as separator. + :param mode: resource file opening mode, default is 'rb'. + """ + if mode not in ('r', 'rb'): + raise ValueError('Resources can only be opened for reading') + return open(os.path.join(self.root_path, resource), mode) + + +def total_seconds(td): + """Returns the total seconds from a timedelta object. + + :param timedelta td: the timedelta to be converted in seconds + + :returns: number of seconds + :rtype: int + """ + return td.days * 60 * 60 * 24 + td.seconds + + +def is_ip(value): + """Determine if the given string is an IP address. + + Python 2 on Windows doesn't provide ``inet_pton``, so this only + checks IPv4 addresses in that environment. + + :param value: value to check + :type value: str + + :return: True if string is an IP address + :rtype: bool + """ + if PY2 and os.name == 'nt': + try: + socket.inet_aton(value) + return True + except socket.error: + return False + + for family in (socket.AF_INET, socket.AF_INET6): + try: + socket.inet_pton(family, value) + except socket.error: + pass + else: + return True + + return False diff --git a/venv/lib/python2.7/site-packages/flask/json/__init__.py b/venv/lib/python2.7/site-packages/flask/json/__init__.py new file mode 100644 index 0000000..fbe6b92 --- /dev/null +++ b/venv/lib/python2.7/site-packages/flask/json/__init__.py @@ -0,0 +1,327 @@ +# -*- coding: utf-8 -*- +""" +flask.json +~~~~~~~~~~ + +:copyright: © 2010 by the Pallets team. +:license: BSD, see LICENSE for more details. +""" +import codecs +import io +import uuid +from datetime import date, datetime +from flask.globals import current_app, request +from flask._compat import text_type, PY2 + +from werkzeug.http import http_date +from jinja2 import Markup + +# Use the same json implementation as itsdangerous on which we +# depend anyways. +from itsdangerous import json as _json + + +# Figure out if simplejson escapes slashes. This behavior was changed +# from one version to another without reason. +_slash_escape = '\\/' not in _json.dumps('/') + + +__all__ = ['dump', 'dumps', 'load', 'loads', 'htmlsafe_dump', + 'htmlsafe_dumps', 'JSONDecoder', 'JSONEncoder', + 'jsonify'] + + +def _wrap_reader_for_text(fp, encoding): + if isinstance(fp.read(0), bytes): + fp = io.TextIOWrapper(io.BufferedReader(fp), encoding) + return fp + + +def _wrap_writer_for_text(fp, encoding): + try: + fp.write('') + except TypeError: + fp = io.TextIOWrapper(fp, encoding) + return fp + + +class JSONEncoder(_json.JSONEncoder): + """The default Flask JSON encoder. This one extends the default simplejson + encoder by also supporting ``datetime`` objects, ``UUID`` as well as + ``Markup`` objects which are serialized as RFC 822 datetime strings (same + as the HTTP date format). In order to support more data types override the + :meth:`default` method. + """ + + def default(self, o): + """Implement this method in a subclass such that it returns a + serializable object for ``o``, or calls the base implementation (to + raise a :exc:`TypeError`). + + For example, to support arbitrary iterators, you could implement + default like this:: + + def default(self, o): + try: + iterable = iter(o) + except TypeError: + pass + else: + return list(iterable) + return JSONEncoder.default(self, o) + """ + if isinstance(o, datetime): + return http_date(o.utctimetuple()) + if isinstance(o, date): + return http_date(o.timetuple()) + if isinstance(o, uuid.UUID): + return str(o) + if hasattr(o, '__html__'): + return text_type(o.__html__()) + return _json.JSONEncoder.default(self, o) + + +class JSONDecoder(_json.JSONDecoder): + """The default JSON decoder. This one does not change the behavior from + the default simplejson decoder. Consult the :mod:`json` documentation + for more information. This decoder is not only used for the load + functions of this module but also :attr:`~flask.Request`. + """ + + +def _dump_arg_defaults(kwargs): + """Inject default arguments for dump functions.""" + if current_app: + bp = current_app.blueprints.get(request.blueprint) if request else None + kwargs.setdefault( + 'cls', + bp.json_encoder if bp and bp.json_encoder + else current_app.json_encoder + ) + + if not current_app.config['JSON_AS_ASCII']: + kwargs.setdefault('ensure_ascii', False) + + kwargs.setdefault('sort_keys', current_app.config['JSON_SORT_KEYS']) + else: + kwargs.setdefault('sort_keys', True) + kwargs.setdefault('cls', JSONEncoder) + + +def _load_arg_defaults(kwargs): + """Inject default arguments for load functions.""" + if current_app: + bp = current_app.blueprints.get(request.blueprint) if request else None + kwargs.setdefault( + 'cls', + bp.json_decoder if bp and bp.json_decoder + else current_app.json_decoder + ) + else: + kwargs.setdefault('cls', JSONDecoder) + + +def detect_encoding(data): + """Detect which UTF codec was used to encode the given bytes. + + The latest JSON standard (:rfc:`8259`) suggests that only UTF-8 is + accepted. Older documents allowed 8, 16, or 32. 16 and 32 can be big + or little endian. Some editors or libraries may prepend a BOM. + + :param data: Bytes in unknown UTF encoding. + :return: UTF encoding name + """ + head = data[:4] + + if head[:3] == codecs.BOM_UTF8: + return 'utf-8-sig' + + if b'\x00' not in head: + return 'utf-8' + + if head in (codecs.BOM_UTF32_BE, codecs.BOM_UTF32_LE): + return 'utf-32' + + if head[:2] in (codecs.BOM_UTF16_BE, codecs.BOM_UTF16_LE): + return 'utf-16' + + if len(head) == 4: + if head[:3] == b'\x00\x00\x00': + return 'utf-32-be' + + if head[::2] == b'\x00\x00': + return 'utf-16-be' + + if head[1:] == b'\x00\x00\x00': + return 'utf-32-le' + + if head[1::2] == b'\x00\x00': + return 'utf-16-le' + + if len(head) == 2: + return 'utf-16-be' if head.startswith(b'\x00') else 'utf-16-le' + + return 'utf-8' + + +def dumps(obj, **kwargs): + """Serialize ``obj`` to a JSON formatted ``str`` by using the application's + configured encoder (:attr:`~flask.Flask.json_encoder`) if there is an + application on the stack. + + This function can return ``unicode`` strings or ascii-only bytestrings by + default which coerce into unicode strings automatically. That behavior by + default is controlled by the ``JSON_AS_ASCII`` configuration variable + and can be overridden by the simplejson ``ensure_ascii`` parameter. + """ + _dump_arg_defaults(kwargs) + encoding = kwargs.pop('encoding', None) + rv = _json.dumps(obj, **kwargs) + if encoding is not None and isinstance(rv, text_type): + rv = rv.encode(encoding) + return rv + + +def dump(obj, fp, **kwargs): + """Like :func:`dumps` but writes into a file object.""" + _dump_arg_defaults(kwargs) + encoding = kwargs.pop('encoding', None) + if encoding is not None: + fp = _wrap_writer_for_text(fp, encoding) + _json.dump(obj, fp, **kwargs) + + +def loads(s, **kwargs): + """Unserialize a JSON object from a string ``s`` by using the application's + configured decoder (:attr:`~flask.Flask.json_decoder`) if there is an + application on the stack. + """ + _load_arg_defaults(kwargs) + if isinstance(s, bytes): + encoding = kwargs.pop('encoding', None) + if encoding is None: + encoding = detect_encoding(s) + s = s.decode(encoding) + return _json.loads(s, **kwargs) + + +def load(fp, **kwargs): + """Like :func:`loads` but reads from a file object. + """ + _load_arg_defaults(kwargs) + if not PY2: + fp = _wrap_reader_for_text(fp, kwargs.pop('encoding', None) or 'utf-8') + return _json.load(fp, **kwargs) + + +def htmlsafe_dumps(obj, **kwargs): + """Works exactly like :func:`dumps` but is safe for use in `` + ''' % { + 'edit_url': edit_url, + } + + return BytesIO(contents + button.encode('utf-8')) + + +def send_file(filename): + mimetype = mimetypes.guess_type(filename)[0] + if mimetype is None: + mimetype = 'application/octet-stream' + + headers = Headers() + + try: + file = open(filename, 'rb') + mtime = os.path.getmtime(filename) + headers['Content-Length'] = os.path.getsize(filename) + except (IOError, OSError): + abort(404) + + rewritten = False + if mimetype == 'text/html': + rewritten = True + new_file = rewrite_html_for_editing(file, + edit_url=posixpath.join('/', request.script_root, 'admin/edit')) + file.close() + file = new_file + del headers['Content-Length'] + + headers['Cache-Control'] = 'no-cache, no-store' + + data = wrap_file(request.environ, file) + + rv = Response(data, mimetype=mimetype, headers=headers, + direct_passthrough=True) + + if not rewritten: + # if we know the file modification date, we can store it as + # the time of the last modification. + if mtime is not None: + rv.last_modified = int(mtime) + rv.cache_control.public = True + try: + rv.set_etag('lektor-%s-%s-%s' % ( + os.path.getmtime(filename), + os.path.getsize(filename), + adler32( + filename.encode('utf-8') if isinstance(filename, string_types) + else filename + ) & 0xffffffff, + )) + except OSError: + pass + + return rv + + +def handle_build_failure(failure): + return render_template('build-failure.html', **failure.data) + + +def serve_up_artifact(path): + li = current_app.lektor_info + pad = li.get_pad() + + artifact_name, filename = li.resolve_artifact('/' + path, pad) + if filename is None: + abort(404) + + if artifact_name is None: + artifact_name = path.strip('/') + + # If there was a build failure for the given artifact, we want + # to render this instead of sending the (most likely missing or + # corrupted) file. + ctrl = li.get_failure_controller(pad) + failure = ctrl.lookup_failure(artifact_name) + if failure is not None: + return handle_build_failure(failure) + + return send_file(filename) + + +@bp.route('/', defaults={'path': ''}) +@bp.route('/') +def serve_artifact(path): + return serve_up_artifact(path) + + +@bp.errorhandler(404) +def serve_error_page(error): + try: + return serve_up_artifact('404.html') + except NotFound as e: + return e diff --git a/venv/lib/python2.7/site-packages/lektor/admin/package-lock.json b/venv/lib/python2.7/site-packages/lektor/admin/package-lock.json new file mode 100644 index 0000000..91db3ab --- /dev/null +++ b/venv/lib/python2.7/site-packages/lektor/admin/package-lock.json @@ -0,0 +1,7186 @@ +{ + "name": "lektor", + "version": "0.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "abab": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.3.tgz", + "integrity": "sha1-uB3l9ydOxOdW15fNg08wNkJyTl0=", + "dev": true + }, + "acorn": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz", + "integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc=", + "dev": true + }, + "acorn-dynamic-import": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz", + "integrity": "sha1-x1K9IQvvZ5UBtsbLf8hPj0cVjMQ=", + "dev": true, + "requires": { + "acorn": "4.0.13" + }, + "dependencies": { + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", + "dev": true + } + } + }, + "acorn-globals": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz", + "integrity": "sha1-VbtemGkVB7dFedBRNBMhfDgMVM8=", + "dev": true, + "requires": { + "acorn": "2.7.0" + } + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "requires": { + "acorn": "3.3.0" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true + } + } + }, + "ajv": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.2.tgz", + "integrity": "sha1-R8aNaehvXZUxA7AHSpQw3GPaXjk=", + "dev": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.0.0", + "json-schema-traverse": "0.3.1", + "json-stable-stringify": "1.0.1" + } + }, + "ajv-keywords": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", + "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", + "dev": true + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "requires": { + "kind-of": "3.2.2", + "longest": "1.0.1", + "repeat-string": "1.6.1" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, + "ansi-escapes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dev": true, + "requires": { + "micromatch": "2.3.11", + "normalize-path": "2.1.1" + } + }, + "argparse": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "dev": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "1.1.0" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "1.0.3" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "array.prototype.find": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.0.4.tgz", + "integrity": "sha1-VWpcU2LAhkgyPdrrnenRS8GGTJA=", + "dev": true, + "requires": { + "define-properties": "1.1.2", + "es-abstract": "1.8.2" + } + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "dev": true + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "dev": true + }, + "asn1.js": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.1.tgz", + "integrity": "sha1-SLokC0WpKA6UdImQull9IWYX/UA=", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0" + } + }, + "assert": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", + "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", + "dev": true, + "requires": { + "util": "0.10.3" + } + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", + "dev": true + }, + "assertion-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz", + "integrity": "sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw=", + "dev": true + }, + "async": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz", + "integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==", + "dev": true, + "requires": { + "lodash": "4.17.4" + } + }, + "async-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", + "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", + "dev": true + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", + "dev": true + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + } + }, + "babel-core": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz", + "integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "babel-generator": "6.26.0", + "babel-helpers": "6.24.1", + "babel-messages": "6.23.0", + "babel-register": "6.26.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "convert-source-map": "1.5.0", + "debug": "2.6.8", + "json5": "0.5.1", + "lodash": "4.17.4", + "minimatch": "3.0.4", + "path-is-absolute": "1.0.1", + "private": "0.1.7", + "slash": "1.0.0", + "source-map": "0.5.7" + } + }, + "babel-generator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.0.tgz", + "integrity": "sha1-rBriAHC3n248odMmlhMFN3TyDcU=", + "dev": true, + "requires": { + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "detect-indent": "4.0.0", + "jsesc": "1.3.0", + "lodash": "4.17.4", + "source-map": "0.5.7", + "trim-right": "1.0.1" + } + }, + "babel-helper-builder-react-jsx": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz", + "integrity": "sha1-Of+DE7dci2Xc7/HzHTg+D/KkCKA=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "esutils": "2.0.2" + } + }, + "babel-helper-call-delegate": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", + "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", + "dev": true, + "requires": { + "babel-helper-hoist-variables": "6.24.1", + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-define-map": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", + "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", + "dev": true, + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.4" + } + }, + "babel-helper-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", + "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "dev": true, + "requires": { + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-get-function-arity": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", + "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-hoist-variables": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", + "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-optimise-call-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", + "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-regex": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", + "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.4" + } + }, + "babel-helper-replace-supers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", + "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", + "dev": true, + "requires": { + "babel-helper-optimise-call-expression": "6.24.1", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-loader": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-7.1.2.tgz", + "integrity": "sha512-jRwlFbINAeyDStqK6Dd5YuY0k5YuzQUvlz2ZamuXrXmxav3pNqe9vfJ402+2G+OmlJSXxCOpB6Uz0INM7RQe2A==", + "dev": true, + "requires": { + "find-cache-dir": "1.0.0", + "loader-utils": "1.1.0", + "mkdirp": "0.5.1" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-check-es2015-constants": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", + "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-istanbul": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.4.tgz", + "integrity": "sha1-GN3oS/POMp/d8/QQP66SFFbY5Yc=", + "dev": true, + "requires": { + "find-up": "2.1.0", + "istanbul-lib-instrument": "1.8.0", + "test-exclude": "4.1.1" + } + }, + "babel-plugin-syntax-flow": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz", + "integrity": "sha1-TDqyCiryaqIM0lmVw5jE63AxDI0=", + "dev": true + }, + "babel-plugin-syntax-jsx": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", + "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=", + "dev": true + }, + "babel-plugin-syntax-object-rest-spread": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", + "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", + "dev": true + }, + "babel-plugin-transform-es2015-arrow-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", + "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-block-scoped-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", + "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-block-scoping": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", + "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.4" + } + }, + "babel-plugin-transform-es2015-classes": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", + "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", + "dev": true, + "requires": { + "babel-helper-define-map": "6.26.0", + "babel-helper-function-name": "6.24.1", + "babel-helper-optimise-call-expression": "6.24.1", + "babel-helper-replace-supers": "6.24.1", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-computed-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", + "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-destructuring": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", + "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-duplicate-keys": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", + "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-for-of": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", + "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", + "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", + "dev": true, + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", + "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-amd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", + "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", + "dev": true, + "requires": { + "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-commonjs": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz", + "integrity": "sha1-DYOUApt9xqvhqX7xgeAHWN0uXYo=", + "dev": true, + "requires": { + "babel-plugin-transform-strict-mode": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-systemjs": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", + "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", + "dev": true, + "requires": { + "babel-helper-hoist-variables": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-umd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", + "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", + "dev": true, + "requires": { + "babel-plugin-transform-es2015-modules-amd": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-object-super": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", + "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "dev": true, + "requires": { + "babel-helper-replace-supers": "6.24.1", + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-parameters": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", + "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", + "dev": true, + "requires": { + "babel-helper-call-delegate": "6.24.1", + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-shorthand-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", + "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-spread": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", + "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-sticky-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", + "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "dev": true, + "requires": { + "babel-helper-regex": "6.26.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-template-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", + "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-typeof-symbol": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", + "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-unicode-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", + "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", + "dev": true, + "requires": { + "babel-helper-regex": "6.26.0", + "babel-runtime": "6.26.0", + "regexpu-core": "2.0.0" + } + }, + "babel-plugin-transform-flow-strip-types": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz", + "integrity": "sha1-hMtnKTXUNxT9wyvOhFaNh0Qc988=", + "dev": true, + "requires": { + "babel-plugin-syntax-flow": "6.18.0", + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-object-rest-spread": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", + "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=", + "dev": true, + "requires": { + "babel-plugin-syntax-object-rest-spread": "6.13.0", + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-react-display-name": { + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz", + "integrity": "sha1-Z+K/Hx6ck6sI25Z5LgU5K/LMKNE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-react-jsx": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz", + "integrity": "sha1-hAoCjn30YN/DotKfDA2R9jduZqM=", + "dev": true, + "requires": { + "babel-helper-builder-react-jsx": "6.26.0", + "babel-plugin-syntax-jsx": "6.18.0", + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-react-jsx-self": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz", + "integrity": "sha1-322AqdomEqEh5t3XVYvL7PBuY24=", + "dev": true, + "requires": { + "babel-plugin-syntax-jsx": "6.18.0", + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-react-jsx-source": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz", + "integrity": "sha1-ZqwSFT9c0tF7PBkmj0vwGX9E7NY=", + "dev": true, + "requires": { + "babel-plugin-syntax-jsx": "6.18.0", + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-regenerator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", + "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", + "dev": true, + "requires": { + "regenerator-transform": "0.10.1" + } + }, + "babel-plugin-transform-strict-mode": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", + "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-preset-es2015": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz", + "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=", + "dev": true, + "requires": { + "babel-plugin-check-es2015-constants": "6.22.0", + "babel-plugin-transform-es2015-arrow-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoping": "6.26.0", + "babel-plugin-transform-es2015-classes": "6.24.1", + "babel-plugin-transform-es2015-computed-properties": "6.24.1", + "babel-plugin-transform-es2015-destructuring": "6.23.0", + "babel-plugin-transform-es2015-duplicate-keys": "6.24.1", + "babel-plugin-transform-es2015-for-of": "6.23.0", + "babel-plugin-transform-es2015-function-name": "6.24.1", + "babel-plugin-transform-es2015-literals": "6.22.0", + "babel-plugin-transform-es2015-modules-amd": "6.24.1", + "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", + "babel-plugin-transform-es2015-modules-systemjs": "6.24.1", + "babel-plugin-transform-es2015-modules-umd": "6.24.1", + "babel-plugin-transform-es2015-object-super": "6.24.1", + "babel-plugin-transform-es2015-parameters": "6.24.1", + "babel-plugin-transform-es2015-shorthand-properties": "6.24.1", + "babel-plugin-transform-es2015-spread": "6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "6.24.1", + "babel-plugin-transform-es2015-template-literals": "6.22.0", + "babel-plugin-transform-es2015-typeof-symbol": "6.23.0", + "babel-plugin-transform-es2015-unicode-regex": "6.24.1", + "babel-plugin-transform-regenerator": "6.26.0" + } + }, + "babel-preset-flow": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz", + "integrity": "sha1-5xIYiHCFrpoktb5Baa/7WZgWxJ0=", + "dev": true, + "requires": { + "babel-plugin-transform-flow-strip-types": "6.22.0" + } + }, + "babel-preset-react": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-preset-react/-/babel-preset-react-6.24.1.tgz", + "integrity": "sha1-umnfrqRfw+xjm2pOzqbhdwLJE4A=", + "dev": true, + "requires": { + "babel-plugin-syntax-jsx": "6.18.0", + "babel-plugin-transform-react-display-name": "6.25.0", + "babel-plugin-transform-react-jsx": "6.24.1", + "babel-plugin-transform-react-jsx-self": "6.22.0", + "babel-plugin-transform-react-jsx-source": "6.22.0", + "babel-preset-flow": "6.23.0" + } + }, + "babel-register": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", + "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "dev": true, + "requires": { + "babel-core": "6.26.0", + "babel-runtime": "6.26.0", + "core-js": "2.5.1", + "home-or-tmp": "2.0.0", + "lodash": "4.17.4", + "mkdirp": "0.5.1", + "source-map-support": "0.4.18" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "2.5.1", + "regenerator-runtime": "0.11.0" + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "lodash": "4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.8", + "globals": "9.18.0", + "invariant": "2.2.2", + "lodash": "4.17.4" + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.4", + "to-fast-properties": "1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base64-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz", + "integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "big.js": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", + "dev": true + }, + "binary-extensions": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.10.0.tgz", + "integrity": "sha1-muuabF6IY4qtFx4Wf1kAq+JINdA=", + "dev": true + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "bootstrap": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.3.7.tgz", + "integrity": "sha1-WjiTlFSfIzMIdaOxUGVldPip63E=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "requires": { + "expand-range": "1.8.2", + "preserve": "0.2.0", + "repeat-element": "1.1.2" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browser-stdout": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "dev": true + }, + "browserify-aes": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.0.8.tgz", + "integrity": "sha512-WYCMOT/PtGTlpOKFht0YJFYcPy6pLCR98CtWfzK13zoynLlBMvAdEMSRGmgnJCw2M2j/5qxBkinZQFobieM8dQ==", + "dev": true, + "requires": { + "buffer-xor": "1.0.3", + "cipher-base": "1.0.4", + "create-hash": "1.1.3", + "evp_bytestokey": "1.0.3", + "inherits": "2.0.3", + "safe-buffer": "5.1.1" + } + }, + "browserify-cipher": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.0.tgz", + "integrity": "sha1-mYgkSHS/XtTijalWZtzWasj8Njo=", + "dev": true, + "requires": { + "browserify-aes": "1.0.8", + "browserify-des": "1.0.0", + "evp_bytestokey": "1.0.3" + } + }, + "browserify-des": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.0.tgz", + "integrity": "sha1-2qJ3cXRwki7S/hhZQRihdUOXId0=", + "dev": true, + "requires": { + "cipher-base": "1.0.4", + "des.js": "1.0.0", + "inherits": "2.0.3" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "randombytes": "2.0.5" + } + }, + "browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "browserify-rsa": "4.0.1", + "create-hash": "1.1.3", + "create-hmac": "1.1.6", + "elliptic": "6.4.0", + "inherits": "2.0.3", + "parse-asn1": "5.1.0" + } + }, + "browserify-zlib": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", + "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=", + "dev": true, + "requires": { + "pako": "0.2.9" + } + }, + "buffer": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "dev": true, + "requires": { + "base64-js": "1.2.1", + "ieee754": "1.1.8", + "isarray": "1.0.0" + } + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dev": true, + "requires": { + "callsites": "0.2.0" + } + }, + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true + }, + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "dev": true, + "requires": { + "align-text": "0.1.4", + "lazy-cache": "1.0.4" + } + }, + "chai": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", + "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", + "dev": true, + "requires": { + "assertion-error": "1.0.2", + "deep-eql": "0.1.3", + "type-detect": "1.0.0" + } + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "dev": true, + "requires": { + "anymatch": "1.3.2", + "async-each": "1.0.1", + "glob-parent": "2.0.0", + "inherits": "2.0.3", + "is-binary-path": "1.0.1", + "is-glob": "2.0.1", + "path-is-absolute": "1.0.1", + "readdirp": "2.1.0" + } + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "2.0.3", + "safe-buffer": "5.1.1" + } + }, + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "dev": true + }, + "clean-css": { + "version": "2.2.23", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-2.2.23.tgz", + "integrity": "sha1-BZC1R4tRbEkD7cLYm9P9vdKGMow=", + "dev": true, + "optional": true, + "requires": { + "commander": "2.2.0" + } + }, + "cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "dev": true, + "requires": { + "restore-cursor": "1.0.1" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "requires": { + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true + } + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "commander": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.2.0.tgz", + "integrity": "sha1-F1rUuTF/P/YV8gHB5XIk9Vo+kd8=", + "dev": true, + "optional": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", + "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "typedarray": "0.0.6" + } + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dev": true, + "requires": { + "date-now": "0.1.4" + } + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "convert-source-map": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz", + "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=", + "dev": true + }, + "core-js": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz", + "integrity": "sha1-rmh03GaTd4m4B1T/VCjfZoGcpQs=", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "create-ecdh": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz", + "integrity": "sha1-iIxyNZbN92EvZJgjPuvXo1MBc30=", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "elliptic": "6.4.0" + } + }, + "create-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz", + "integrity": "sha1-YGBCrIuSYnUPSDyt2rD1gZFy2P0=", + "dev": true, + "requires": { + "cipher-base": "1.0.4", + "inherits": "2.0.3", + "ripemd160": "2.0.1", + "sha.js": "2.4.8" + } + }, + "create-hmac": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.6.tgz", + "integrity": "sha1-rLniIaThe9sHbpBlfEK5PjcmzwY=", + "dev": true, + "requires": { + "cipher-base": "1.0.4", + "create-hash": "1.1.3", + "inherits": "2.0.3", + "ripemd160": "2.0.1", + "safe-buffer": "5.1.1", + "sha.js": "2.4.8" + } + }, + "create-react-class": { + "version": "15.6.0", + "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.6.0.tgz", + "integrity": "sha1-q0SEl8JlZuHilBPogyB9V8/nvtQ=", + "dev": true, + "requires": { + "fbjs": "0.8.15", + "loose-envify": "1.3.1", + "object-assign": "4.1.1" + } + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "4.1.1", + "shebang-command": "1.2.0", + "which": "1.3.0" + } + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "dev": true, + "requires": { + "boom": "2.10.1" + } + }, + "crypto-browserify": { + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.11.1.tgz", + "integrity": "sha512-Na7ZlwCOqoaW5RwUK1WpXws2kv8mNhWdTlzob0UXulk6G9BDbyiJaGTYBIX61Ozn9l1EPPJpICZb4DaOpT9NlQ==", + "dev": true, + "requires": { + "browserify-cipher": "1.0.0", + "browserify-sign": "4.0.4", + "create-ecdh": "4.0.0", + "create-hash": "1.1.3", + "create-hmac": "1.1.6", + "diffie-hellman": "5.0.2", + "inherits": "2.0.3", + "pbkdf2": "3.0.14", + "public-encrypt": "4.0.0", + "randombytes": "2.0.5" + } + }, + "css-loader": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.9.1.tgz", + "integrity": "sha1-LhqgDOfjDvLGp6SzAKCAp8l54Nw=", + "dev": true, + "requires": { + "csso": "1.3.12", + "loader-utils": "0.2.17", + "source-map": "0.1.43" + }, + "dependencies": { + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "3.2.0", + "emojis-list": "2.1.0", + "json5": "0.5.1", + "object-assign": "4.1.1" + } + }, + "source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "csso": { + "version": "1.3.12", + "resolved": "https://registry.npmjs.org/csso/-/csso-1.3.12.tgz", + "integrity": "sha1-/GKGlKLTiTiqrEmWdTIY/TEc254=", + "dev": true + }, + "cssom": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.2.tgz", + "integrity": "sha1-uANhcMefB6kP8vFuIihAJ6JDhIs=", + "dev": true + }, + "cssstyle": { + "version": "0.2.37", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz", + "integrity": "sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ=", + "dev": true, + "requires": { + "cssom": "0.3.2" + } + }, + "ctype": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz", + "integrity": "sha1-gsGMJGH3QRTvFsE1IkrQuRRMoS8=", + "dev": true, + "optional": true + }, + "d": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", + "dev": true, + "requires": { + "es5-ext": "0.10.30" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "dev": true + }, + "debug": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "debug-log": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", + "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=", + "dev": true + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "deep-eql": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", + "dev": true, + "requires": { + "type-detect": "0.1.1" + }, + "dependencies": { + "type-detect": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", + "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=", + "dev": true + } + } + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "define-properties": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", + "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", + "dev": true, + "requires": { + "foreach": "2.0.5", + "object-keys": "1.0.11" + } + }, + "deglob": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/deglob/-/deglob-2.1.0.tgz", + "integrity": "sha1-TUSr4W7zLHebSXK9FBqAMlApoUo=", + "dev": true, + "requires": { + "find-root": "1.1.0", + "glob": "7.1.1", + "ignore": "3.3.5", + "pkg-config": "1.1.1", + "run-parallel": "1.1.6", + "uniq": "1.0.1" + } + }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "requires": { + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.0", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.2" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "des.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", + "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0" + } + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true, + "requires": { + "repeating": "2.0.1" + } + }, + "diff": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", + "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz", + "integrity": "sha1-tYNXOScM/ias9jIJn97SoH8gnl4=", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "miller-rabin": "4.0.0", + "randombytes": "2.0.5" + } + }, + "doctrine": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.0.tgz", + "integrity": "sha1-xz2NKQnSIpHhoAejlYBNqLZl/mM=", + "dev": true, + "requires": { + "esutils": "2.0.2", + "isarray": "1.0.0" + } + }, + "domain-browser": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz", + "integrity": "sha1-hnqksJP6oF8d4IwG9NeyH9+GmLw=", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "elliptic": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", + "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "brorand": "1.1.0", + "hash.js": "1.1.3", + "hmac-drbg": "1.0.1", + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0", + "minimalistic-crypto-utils": "1.0.1" + } + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "dev": true, + "requires": { + "iconv-lite": "0.4.19" + } + }, + "enhanced-resolve": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz", + "integrity": "sha1-BCHjOf1xQZs9oT0Smzl5BAIwR24=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "memory-fs": "0.4.1", + "object-assign": "4.1.1", + "tapable": "0.2.8" + } + }, + "errno": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz", + "integrity": "sha1-uJbiOp5ei6M4cfyZar02NfyaHH0=", + "dev": true, + "requires": { + "prr": "0.0.0" + } + }, + "error-ex": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "dev": true, + "requires": { + "is-arrayish": "0.2.1" + } + }, + "es-abstract": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.8.2.tgz", + "integrity": "sha512-dvhwFL3yjQxNNsOWx6exMlaDrRHCRGMQlnx5lsXDCZ/J7G/frgIIl94zhZSp/galVAYp7VzPi1OrAHta89/yGQ==", + "dev": true, + "requires": { + "es-to-primitive": "1.1.1", + "function-bind": "1.1.1", + "has": "1.0.1", + "is-callable": "1.1.3", + "is-regex": "1.0.4" + } + }, + "es-to-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", + "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", + "dev": true, + "requires": { + "is-callable": "1.1.3", + "is-date-object": "1.0.1", + "is-symbol": "1.0.1" + } + }, + "es5-ext": { + "version": "0.10.30", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.30.tgz", + "integrity": "sha1-cUGhaDZpfbq/qq7uQUlc4p9SyTk=", + "dev": true, + "requires": { + "es6-iterator": "2.0.1", + "es6-symbol": "3.1.1" + } + }, + "es6-iterator": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", + "integrity": "sha1-jjGcnwRTv1ddN0lAplWSDlnKVRI=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.30", + "es6-symbol": "3.1.1" + } + }, + "es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.30", + "es6-iterator": "2.0.1", + "es6-set": "0.1.5", + "es6-symbol": "3.1.1", + "event-emitter": "0.3.5" + } + }, + "es6-set": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", + "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.30", + "es6-iterator": "2.0.1", + "es6-symbol": "3.1.1", + "event-emitter": "0.3.5" + } + }, + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.30" + } + }, + "es6-weak-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", + "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.30", + "es6-iterator": "2.0.1", + "es6-symbol": "3.1.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "escodegen": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.9.0.tgz", + "integrity": "sha512-v0MYvNQ32bzwoG2OSFzWAkuahDQHK92JBN0pTAALJ4RIxEZe766QJPDR8Hqy7XNUy5K3fnVL76OqYAdc4TZEIw==", + "dev": true, + "requires": { + "esprima": "3.1.3", + "estraverse": "4.2.0", + "esutils": "2.0.2", + "optionator": "0.8.2", + "source-map": "0.5.7" + } + }, + "escope": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", + "dev": true, + "requires": { + "es6-map": "0.1.5", + "es6-weak-map": "2.0.2", + "esrecurse": "4.2.0", + "estraverse": "4.2.0" + } + }, + "eslint": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", + "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "chalk": "1.1.3", + "concat-stream": "1.6.0", + "debug": "2.6.8", + "doctrine": "2.0.0", + "escope": "3.6.0", + "espree": "3.5.0", + "esquery": "1.0.0", + "estraverse": "4.2.0", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "glob": "7.1.1", + "globals": "9.18.0", + "ignore": "3.3.5", + "imurmurhash": "0.1.4", + "inquirer": "0.12.0", + "is-my-json-valid": "2.16.1", + "is-resolvable": "1.0.0", + "js-yaml": "3.10.0", + "json-stable-stringify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "1.2.1", + "progress": "1.1.8", + "require-uncached": "1.0.3", + "shelljs": "0.7.8", + "strip-bom": "3.0.0", + "strip-json-comments": "2.0.1", + "table": "3.8.3", + "text-table": "0.2.0", + "user-home": "2.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "eslint-config-standard": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz", + "integrity": "sha1-wGHk0GbzedwXzVYsZOgZtN1FRZE=", + "dev": true + }, + "eslint-config-standard-jsx": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-4.0.2.tgz", + "integrity": "sha512-F8fRh2WFnTek7dZH9ZaE0PCBwdVGkwVWZmizla/DDNOmg7Tx6B/IlK5+oYpiX29jpu73LszeJj5i1axEZv6VMw==", + "dev": true + }, + "eslint-import-resolver-node": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz", + "integrity": "sha1-Wt2BBujJKNssuiMrzZ76hG49oWw=", + "dev": true, + "requires": { + "debug": "2.6.8", + "object-assign": "4.1.1", + "resolve": "1.4.0" + } + }, + "eslint-module-utils": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz", + "integrity": "sha512-jDI/X5l/6D1rRD/3T43q8Qgbls2nq5km5KSqiwlyUbGo5+04fXhMKdCPhjwbqAa6HXWaMxj8Q4hQDIh7IadJQw==", + "dev": true, + "requires": { + "debug": "2.6.8", + "pkg-dir": "1.0.0" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "pkg-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "dev": true, + "requires": { + "find-up": "1.1.2" + } + } + } + }, + "eslint-plugin-import": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.2.0.tgz", + "integrity": "sha1-crowb60wXWfEgWNIpGmaQimsi04=", + "dev": true, + "requires": { + "builtin-modules": "1.1.1", + "contains-path": "0.1.0", + "debug": "2.6.8", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "0.2.3", + "eslint-module-utils": "2.1.1", + "has": "1.0.1", + "lodash.cond": "4.5.2", + "minimatch": "3.0.4", + "pkg-up": "1.0.0" + }, + "dependencies": { + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "2.0.2", + "isarray": "1.0.0" + } + } + } + }, + "eslint-plugin-node": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-4.2.3.tgz", + "integrity": "sha512-vIUQPuwbVYdz/CYnlTLsJrRy7iXHQjdEe5wz0XhhdTym3IInM/zZLlPf9nZ2mThsH0QcsieCOWs2vOeCy/22LQ==", + "dev": true, + "requires": { + "ignore": "3.3.5", + "minimatch": "3.0.4", + "object-assign": "4.1.1", + "resolve": "1.4.0", + "semver": "5.3.0" + }, + "dependencies": { + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true + } + } + }, + "eslint-plugin-promise": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.5.0.tgz", + "integrity": "sha1-ePu2/+BHIBYnVp6FpsU3OvKmj8o=", + "dev": true + }, + "eslint-plugin-react": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-6.10.3.tgz", + "integrity": "sha1-xUNb6wZ3ThLH2y9qut3L+QDNP3g=", + "dev": true, + "requires": { + "array.prototype.find": "2.0.4", + "doctrine": "1.5.0", + "has": "1.0.1", + "jsx-ast-utils": "1.4.1", + "object.assign": "4.0.4" + }, + "dependencies": { + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "2.0.2", + "isarray": "1.0.0" + } + } + } + }, + "eslint-plugin-standard": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz", + "integrity": "sha1-NNDJFbRe3G8BA5PH7vOCOwhWXPI=", + "dev": true + }, + "espree": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.0.tgz", + "integrity": "sha1-mDWGJb3QVYYeon4oZ+pyn69GPY0=", + "dev": true, + "requires": { + "acorn": "5.1.2", + "acorn-jsx": "3.0.1" + }, + "dependencies": { + "acorn": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.2.tgz", + "integrity": "sha512-o96FZLJBPY1lvTuJylGA9Bk3t/GKPPJG8H0ydQQl01crzwJgspa4AEIq/pVTXigmK0PHVQhiAtn8WMBLL9D2WA==", + "dev": true + } + } + }, + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true + }, + "esquery": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz", + "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", + "dev": true, + "requires": { + "estraverse": "4.2.0" + } + }, + "esrecurse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz", + "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", + "dev": true, + "requires": { + "estraverse": "4.2.0", + "object-assign": "4.1.1" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.30" + } + }, + "event-source-polyfill": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/event-source-polyfill/-/event-source-polyfill-0.0.5.tgz", + "integrity": "sha1-1jXwlXg9VBGX9OXWoeDeo6h60vY=", + "dev": true + }, + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "1.3.4", + "safe-buffer": "5.1.1" + } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + } + }, + "exit-hook": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", + "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", + "dev": true + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "0.1.1" + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "dev": true, + "requires": { + "fill-range": "2.2.3" + } + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "dev": true + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } + }, + "extract-text-webpack-plugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/extract-text-webpack-plugin/-/extract-text-webpack-plugin-3.0.0.tgz", + "integrity": "sha1-kMqnkHvESfM1AF46x1MrQbAN5hI=", + "dev": true, + "requires": { + "async": "2.5.0", + "loader-utils": "1.1.0", + "schema-utils": "0.3.0", + "webpack-sources": "1.0.1" + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", + "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fbjs": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.15.tgz", + "integrity": "sha1-TwaV/fzBbDfAsH+s7Iy0xAkWhbk=", + "dev": true, + "requires": { + "core-js": "1.2.7", + "isomorphic-fetch": "2.2.1", + "loose-envify": "1.3.1", + "object-assign": "4.1.1", + "promise": "7.3.1", + "setimmediate": "1.0.5", + "ua-parser-js": "0.7.14" + }, + "dependencies": { + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=", + "dev": true + } + } + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5", + "object-assign": "4.1.1" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "requires": { + "flat-cache": "1.2.2", + "object-assign": "4.1.1" + } + }, + "file-loader": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-0.11.2.tgz", + "integrity": "sha512-N+uhF3mswIFeziHQjGScJ/yHXYt3DiLBeC+9vWW+WjUBiClMSOlV1YrXQi+7KM2aA3Rn4Bybgv+uXFQbfkzpvg==", + "dev": true, + "requires": { + "loader-utils": "1.1.0" + } + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true + }, + "fill-range": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", + "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", + "dev": true, + "requires": { + "is-number": "2.1.0", + "isobject": "2.1.0", + "randomatic": "1.1.7", + "repeat-element": "1.1.2", + "repeat-string": "1.6.1" + } + }, + "find-cache-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", + "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", + "dev": true, + "requires": { + "commondir": "1.0.1", + "make-dir": "1.0.0", + "pkg-dir": "2.0.0" + } + }, + "find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "dev": true + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "2.0.0" + } + }, + "flat-cache": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz", + "integrity": "sha1-+oZxTnLCHbiGAXYezy9VXRq8a5Y=", + "dev": true, + "requires": { + "circular-json": "0.3.3", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" + } + }, + "font-awesome": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", + "integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=", + "dev": true + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "1.0.2" + } + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "generate-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", + "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", + "dev": true + }, + "generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "dev": true, + "requires": { + "is-property": "1.0.2" + } + }, + "get-caller-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", + "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", + "dev": true + }, + "get-stdin": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz", + "integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g=", + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, + "requires": { + "glob-parent": "2.0.0", + "is-glob": "2.0.1" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "2.0.1" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.1", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true + }, + "growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", + "dev": true + }, + "har-schema": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", + "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", + "dev": true + }, + "har-validator": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", + "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", + "dev": true, + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + }, + "dependencies": { + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "dev": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + } + } + }, + "has": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", + "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", + "dev": true, + "requires": { + "function-bind": "1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "hash-base": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", + "integrity": "sha1-ZuodhW206KVHDK32/OI65SRO8uE=", + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dev": true, + "requires": { + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0" + } + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "dev": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "history": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/history/-/history-1.17.0.tgz", + "integrity": "sha1-xUg8qlodH+oAoafY0ZuHQBZxHSk=", + "dev": true, + "requires": { + "deep-equal": "1.0.1", + "invariant": "2.2.2", + "query-string": "3.0.3", + "warning": "2.1.0" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "1.1.3", + "minimalistic-assert": "1.0.0", + "minimalistic-crypto-utils": "1.0.1" + } + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "dev": true + }, + "hoist-non-react-statics": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz", + "integrity": "sha1-qkSM8JhtVcxAdzsXF0t90GbLfPs=", + "dev": true + }, + "home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "dev": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "hosted-git-info": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", + "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", + "dev": true + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "dev": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.1", + "sshpk": "1.13.1" + } + }, + "https-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.1.tgz", + "integrity": "sha1-P5E2XKvmC3ftDruiS0VOPgnZWoI=", + "dev": true + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", + "dev": true + }, + "ieee754": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", + "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=", + "dev": true + }, + "ignore": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.5.tgz", + "integrity": "sha512-JLH93mL8amZQhh/p6mfQgVBH3M6epNq3DfsXsTSuSrInVjwyYlFE1nv2AgfRCC8PoOhM0jwQ5v8s9LgbK7yGDw==", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "inquirer": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", + "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", + "dev": true, + "requires": { + "ansi-escapes": "1.4.0", + "ansi-regex": "2.1.1", + "chalk": "1.1.3", + "cli-cursor": "1.0.2", + "cli-width": "2.2.0", + "figures": "1.7.0", + "lodash": "4.17.4", + "readline2": "1.0.1", + "run-async": "0.1.0", + "rx-lite": "3.1.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "through": "2.3.8" + } + }, + "interpret": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.4.tgz", + "integrity": "sha1-ggzdWIuGj/sZGoCVBtbJyPISsbA=", + "dev": true + }, + "invariant": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", + "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", + "dev": true, + "requires": { + "loose-envify": "1.3.1" + } + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "1.10.0" + } + }, + "is-buffer": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz", + "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=", + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true, + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-callable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz", + "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=", + "dev": true + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true, + "requires": { + "is-primitive": "2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } + }, + "is-my-json-valid": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz", + "integrity": "sha512-ochPsqWS1WXj8ZnMIV0vnNXooaMhp7cyL4FMSIPKTtnV0Ha/T19G2b9kkhcNsabV9bxYkze7/aLZJb/bYuFduQ==", + "dev": true, + "requires": { + "generate-function": "2.0.0", + "generate-object-property": "1.2.0", + "jsonpointer": "4.0.1", + "xtend": "4.0.1" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", + "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", + "dev": true, + "requires": { + "is-path-inside": "1.0.0" + } + }, + "is-path-inside": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", + "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", + "dev": true, + "requires": { + "path-is-inside": "1.0.2" + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", + "dev": true + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "1.0.1" + } + }, + "is-resolvable": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz", + "integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=", + "dev": true, + "requires": { + "tryit": "1.0.3" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", + "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + }, + "isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", + "dev": true, + "requires": { + "node-fetch": "1.7.3", + "whatwg-fetch": "2.0.3" + } + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.1.tgz", + "integrity": "sha512-0+1vDkmzxqJIn5rcoEqapSB4DmPxE31EtI2dF2aCkV5esN9EWHxZ0dwgDClivMXJqE7zaYQxq30hj5L0nlTN5Q==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.8.0.tgz", + "integrity": "sha1-ZvbJQhzJ7EcE928tsIS6kHiitTI=", + "dev": true, + "requires": { + "babel-generator": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "istanbul-lib-coverage": "1.1.1", + "semver": "5.4.1" + } + }, + "jquery": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-2.2.4.tgz", + "integrity": "sha1-LInWiJterFIqfuoywUUhVZxsvwI=", + "dev": true + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", + "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", + "dev": true, + "requires": { + "argparse": "1.0.9", + "esprima": "4.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", + "dev": true + } + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true + }, + "jsdom": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-8.5.0.tgz", + "integrity": "sha1-1Nj12/J2hjW2KmKCO5R89wcevJg=", + "dev": true, + "requires": { + "abab": "1.0.3", + "acorn": "2.7.0", + "acorn-globals": "1.0.9", + "array-equal": "1.0.0", + "cssom": "0.3.2", + "cssstyle": "0.2.37", + "escodegen": "1.9.0", + "iconv-lite": "0.4.19", + "nwmatcher": "1.4.1", + "parse5": "1.5.1", + "request": "2.81.0", + "sax": "1.2.4", + "symbol-tree": "3.2.2", + "tough-cookie": "2.3.2", + "webidl-conversions": "3.0.1", + "whatwg-url": "2.0.1", + "xml-name-validator": "2.0.1" + } + }, + "jsdomify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/jsdomify/-/jsdomify-2.2.0.tgz", + "integrity": "sha1-sprqmg0Vv5AuD+y4nMIVRgf3kXk=", + "dev": true, + "requires": { + "jsdom": "8.5.0" + } + }, + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true + }, + "json-loader": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz", + "integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, + "jsonpointer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "jsx-ast-utils": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz", + "integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE=", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "1.0.0" + } + }, + "less": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/less/-/less-1.7.5.tgz", + "integrity": "sha1-TyIM9yiKJ+rKc5325ICKLUwNV1Y=", + "dev": true, + "requires": { + "clean-css": "2.2.23", + "graceful-fs": "3.0.11", + "mime": "1.2.11", + "mkdirp": "0.5.1", + "request": "2.40.0", + "source-map": "0.1.43" + }, + "dependencies": { + "asn1": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz", + "integrity": "sha1-VZvhg3bQik7E2+gId9J4GGObLfc=", + "dev": true, + "optional": true + }, + "assert-plus": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz", + "integrity": "sha1-7nQAlBMALYTOxyGcasgRgS5yMWA=", + "dev": true, + "optional": true + }, + "async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", + "dev": true, + "optional": true + }, + "aws-sign2": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz", + "integrity": "sha1-xXED96F/wDfwLXwuZLYC6iI/fWM=", + "dev": true, + "optional": true + }, + "boom": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz", + "integrity": "sha1-emNune1O/O+xnO9JR6PGffrukRs=", + "dev": true, + "requires": { + "hoek": "0.9.1" + } + }, + "combined-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", + "integrity": "sha1-ATfmV7qlp1QcV6w3rF/AfXO03B8=", + "dev": true, + "optional": true, + "requires": { + "delayed-stream": "0.0.5" + } + }, + "cryptiles": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz", + "integrity": "sha1-7ZH/HxetE9N0gohZT4pIoNJvMlw=", + "dev": true, + "optional": true, + "requires": { + "boom": "0.4.2" + } + }, + "delayed-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz", + "integrity": "sha1-1LH0OpPoKW3+AmlPRoC8N6MTxz8=", + "dev": true, + "optional": true + }, + "forever-agent": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz", + "integrity": "sha1-bQ4JxJIflKJ/Y9O0nF/v8epMUTA=", + "dev": true, + "optional": true + }, + "form-data": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz", + "integrity": "sha1-kavXiKupcCsaq/qLwBAxoqyeOxI=", + "dev": true, + "optional": true, + "requires": { + "async": "0.9.2", + "combined-stream": "0.0.7", + "mime": "1.2.11" + } + }, + "graceful-fs": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz", + "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=", + "dev": true, + "optional": true, + "requires": { + "natives": "1.1.0" + } + }, + "hawk": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz", + "integrity": "sha1-h81JH5tG5OKurKM1QWdmiF0tHtk=", + "dev": true, + "optional": true, + "requires": { + "boom": "0.4.2", + "cryptiles": "0.2.2", + "hoek": "0.9.1", + "sntp": "0.2.4" + } + }, + "hoek": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz", + "integrity": "sha1-PTIkYrrfB3Fup+uFuviAec3c5QU=", + "dev": true + }, + "http-signature": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz", + "integrity": "sha1-T72sEyVZqoMjEh5UB3nAoBKyfmY=", + "dev": true, + "optional": true, + "requires": { + "asn1": "0.1.11", + "assert-plus": "0.1.5", + "ctype": "0.5.3" + } + }, + "mime-types": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz", + "integrity": "sha1-mVrhOSq4r/y/yyZB3QVOlDwNXc4=", + "dev": true, + "optional": true + }, + "node-uuid": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=", + "dev": true, + "optional": true + }, + "oauth-sign": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz", + "integrity": "sha1-y1QPk7srIqfVlBaRoojWDo6pOG4=", + "dev": true, + "optional": true + }, + "qs": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-1.0.2.tgz", + "integrity": "sha1-UKk+K1r2aRwxvOpdrnjubqGQN2g=", + "dev": true, + "optional": true + }, + "request": { + "version": "2.40.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.40.0.tgz", + "integrity": "sha1-TdZw9pbx5uhC5mtLXoOTAaub62c=", + "dev": true, + "optional": true, + "requires": { + "aws-sign2": "0.5.0", + "forever-agent": "0.5.2", + "form-data": "0.1.4", + "hawk": "1.1.1", + "http-signature": "0.10.1", + "json-stringify-safe": "5.0.1", + "mime-types": "1.0.2", + "node-uuid": "1.4.8", + "oauth-sign": "0.3.0", + "qs": "1.0.2", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.4.3" + } + }, + "sntp": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz", + "integrity": "sha1-+4hfGLDzqtGJ+CSGJTa87ux1CQA=", + "dev": true, + "optional": true, + "requires": { + "hoek": "0.9.1" + } + }, + "source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", + "dev": true, + "optional": true, + "requires": { + "amdefine": "1.0.1" + } + }, + "tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", + "dev": true, + "optional": true + } + } + }, + "less-loader": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-0.7.8.tgz", + "integrity": "sha1-jFNRo+4iwwtbwzH6DMP6sdri5EM=", + "dev": true, + "requires": { + "loader-utils": "0.2.17" + }, + "dependencies": { + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "3.2.0", + "emojis-list": "2.1.0", + "json5": "0.5.1", + "object-assign": "4.1.1" + } + } + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" + } + }, + "loader-runner": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.3.0.tgz", + "integrity": "sha1-9IKuqC1UPgeSFwDVpG7yb9rGuKI=", + "dev": true + }, + "loader-utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", + "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", + "dev": true, + "requires": { + "big.js": "3.2.0", + "emojis-list": "2.1.0", + "json5": "0.5.1" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + } + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + }, + "lodash._baseassign": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", + "dev": true, + "requires": { + "lodash._basecopy": "3.0.1", + "lodash.keys": "3.1.2" + } + }, + "lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "dev": true + }, + "lodash._basecreate": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", + "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", + "dev": true + }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "dev": true + }, + "lodash.cond": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz", + "integrity": "sha1-9HGh2khr5g9quVXRcRVSPdHSVdU=", + "dev": true + }, + "lodash.create": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", + "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", + "dev": true, + "requires": { + "lodash._baseassign": "3.2.0", + "lodash._basecreate": "3.0.3", + "lodash._isiterateecall": "3.0.9" + } + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "dev": true + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "3.9.1", + "lodash.isarguments": "3.1.0", + "lodash.isarray": "3.0.4" + } + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true + }, + "loose-envify": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", + "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", + "dev": true, + "requires": { + "js-tokens": "3.0.2" + } + }, + "lru-cache": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", + "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", + "dev": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "make-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.0.0.tgz", + "integrity": "sha1-l6ARdR6R3YfPre9Ygy67BJNt6Xg=", + "dev": true, + "requires": { + "pify": "2.3.0" + } + }, + "md5.js": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", + "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", + "dev": true, + "requires": { + "hash-base": "3.0.4", + "inherits": "2.0.3" + }, + "dependencies": { + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "safe-buffer": "5.1.1" + } + } + } + }, + "mem": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "dev": true, + "requires": { + "mimic-fn": "1.1.0" + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "0.1.4", + "readable-stream": "2.3.3" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "2.0.0", + "array-unique": "0.2.1", + "braces": "1.8.5", + "expand-brackets": "0.1.5", + "extglob": "0.3.2", + "filename-regex": "2.0.1", + "is-extglob": "1.0.0", + "is-glob": "2.0.1", + "kind-of": "3.2.2", + "normalize-path": "2.1.1", + "object.omit": "2.0.1", + "parse-glob": "3.0.4", + "regex-cache": "0.4.4" + } + }, + "miller-rabin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.0.tgz", + "integrity": "sha1-SmL7HUKTPAVYOYL0xxb2+55sbT0=", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "brorand": "1.1.0" + } + }, + "mime": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", + "integrity": "sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA=", + "dev": true, + "optional": true + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", + "dev": true + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "dev": true, + "requires": { + "mime-db": "1.30.0" + } + }, + "mimic-fn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", + "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=", + "dev": true + }, + "minimalistic-assert": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz", + "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.5.3.tgz", + "integrity": "sha512-/6na001MJWEtYxHOV1WLfsmR4YIynkUEhBwzsb+fk2qmQ3iqsi258l/Q2MWHJMImAcNpZ8DEdYAK72NHoIQ9Eg==", + "dev": true, + "requires": { + "browser-stdout": "1.3.0", + "commander": "2.9.0", + "debug": "2.6.8", + "diff": "3.2.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.1", + "growl": "1.9.2", + "he": "1.1.1", + "json3": "3.3.2", + "lodash.create": "3.1.1", + "mkdirp": "0.5.1", + "supports-color": "3.1.2" + }, + "dependencies": { + "commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, + "requires": { + "graceful-readlink": "1.0.1" + } + }, + "supports-color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", + "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", + "dev": true, + "requires": { + "has-flag": "1.0.0" + } + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "mute-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", + "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", + "dev": true + }, + "native-promise-only": { + "version": "0.7.6-a", + "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.7.6-a.tgz", + "integrity": "sha1-skvQRRQJzDRA91W/QNJAKHkgaNA=", + "dev": true + }, + "natives": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.0.tgz", + "integrity": "sha1-6f+EFBimsux6SV6TmYT3jxY+bjE=", + "dev": true, + "optional": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "dev": true, + "requires": { + "encoding": "0.1.12", + "is-stream": "1.1.0" + } + }, + "node-libs-browser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.0.0.tgz", + "integrity": "sha1-o6WeyXAkmFtG6Vg3lkb5bEthZkY=", + "dev": true, + "requires": { + "assert": "1.4.1", + "browserify-zlib": "0.1.4", + "buffer": "4.9.1", + "console-browserify": "1.1.0", + "constants-browserify": "1.0.0", + "crypto-browserify": "3.11.1", + "domain-browser": "1.1.7", + "events": "1.1.1", + "https-browserify": "0.0.1", + "os-browserify": "0.2.1", + "path-browserify": "0.0.0", + "process": "0.11.10", + "punycode": "1.4.1", + "querystring-es3": "0.2.1", + "readable-stream": "2.3.3", + "stream-browserify": "2.0.1", + "stream-http": "2.7.2", + "string_decoder": "0.10.31", + "timers-browserify": "2.0.4", + "tty-browserify": "0.0.0", + "url": "0.11.0", + "util": "0.10.3", + "vm-browserify": "0.0.4" + }, + "dependencies": { + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "dev": true, + "requires": { + "hosted-git-info": "2.5.0", + "is-builtin-module": "1.0.0", + "semver": "5.4.1", + "validate-npm-package-license": "3.0.1" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "1.1.0" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "2.0.1" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "nwmatcher": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.1.tgz", + "integrity": "sha1-eumwew6oBNt+JfBctf5Al9TklJ8=", + "dev": true + }, + "nyc": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-8.4.0.tgz", + "integrity": "sha1-ZgNxyAfK7wQn+5sJSPdBgGJOpuQ=", + "dev": true, + "requires": { + "archy": "1.0.0", + "arrify": "1.0.1", + "caching-transform": "1.0.1", + "convert-source-map": "1.3.0", + "default-require-extensions": "1.0.0", + "find-cache-dir": "0.1.1", + "find-up": "1.1.2", + "foreground-child": "1.5.3", + "glob": "7.1.1", + "istanbul-lib-coverage": "1.0.0", + "istanbul-lib-hook": "1.0.0-alpha.4", + "istanbul-lib-instrument": "1.2.0", + "istanbul-lib-report": "1.0.0-alpha.3", + "istanbul-lib-source-maps": "1.0.2", + "istanbul-reports": "1.0.0", + "md5-hex": "1.3.0", + "micromatch": "2.3.11", + "mkdirp": "0.5.1", + "resolve-from": "2.0.0", + "rimraf": "2.5.4", + "signal-exit": "3.0.1", + "spawn-wrap": "1.2.4", + "test-exclude": "2.1.3", + "yargs": "6.3.0", + "yargs-parser": "4.0.2" + }, + "dependencies": { + "align-text": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.0.4", + "longest": "1.0.1", + "repeat-string": "1.6.1" + } + }, + "amdefine": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "ansi-regex": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "bundled": true, + "dev": true + }, + "append-transform": { + "version": "0.3.0", + "bundled": true, + "dev": true + }, + "archy": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "arr-diff": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "arr-flatten": "1.0.1" + } + }, + "arr-flatten": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "array-unique": { + "version": "0.2.1", + "bundled": true, + "dev": true + }, + "arrify": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "async": { + "version": "1.5.2", + "bundled": true, + "dev": true + }, + "babel-code-frame": { + "version": "6.16.0", + "bundled": true, + "dev": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "2.0.0" + } + }, + "babel-generator": { + "version": "6.18.0", + "bundled": true, + "dev": true, + "requires": { + "babel-messages": "6.8.0", + "babel-runtime": "6.18.0", + "babel-types": "6.18.0", + "detect-indent": "4.0.0", + "jsesc": "1.3.0", + "lodash": "4.16.6", + "source-map": "0.5.6" + } + }, + "babel-messages": { + "version": "6.8.0", + "bundled": true, + "dev": true, + "requires": { + "babel-runtime": "6.18.0" + } + }, + "babel-runtime": { + "version": "6.18.0", + "bundled": true, + "dev": true, + "requires": { + "core-js": "2.4.1", + "regenerator-runtime": "0.9.5" + } + }, + "babel-template": { + "version": "6.16.0", + "bundled": true, + "dev": true, + "requires": { + "babel-runtime": "6.18.0", + "babel-traverse": "6.18.0", + "babel-types": "6.18.0", + "babylon": "6.13.1", + "lodash": "4.16.6" + } + }, + "babel-traverse": { + "version": "6.18.0", + "bundled": true, + "dev": true, + "requires": { + "babel-code-frame": "6.16.0", + "babel-messages": "6.8.0", + "babel-runtime": "6.18.0", + "babel-types": "6.18.0", + "babylon": "6.13.1", + "debug": "2.2.0", + "globals": "9.12.0", + "invariant": "2.2.1", + "lodash": "4.16.6" + } + }, + "babel-types": { + "version": "6.18.0", + "bundled": true, + "dev": true, + "requires": { + "babel-runtime": "6.18.0", + "esutils": "2.0.2", + "lodash": "4.16.6", + "to-fast-properties": "1.0.2" + } + }, + "babylon": { + "version": "6.13.1", + "bundled": true, + "dev": true + }, + "balanced-match": { + "version": "0.4.2", + "bundled": true, + "dev": true + }, + "brace-expansion": { + "version": "1.1.6", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "0.4.2", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "1.8.5", + "bundled": true, + "dev": true, + "requires": { + "expand-range": "1.8.2", + "preserve": "0.2.0", + "repeat-element": "1.1.2" + } + }, + "builtin-modules": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "caching-transform": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "md5-hex": "1.3.0", + "mkdirp": "0.5.1", + "write-file-atomic": "1.2.0" + } + }, + "camelcase": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true + }, + "center-align": { + "version": "0.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "align-text": "0.1.4", + "lazy-cache": "1.0.4" + } + }, + "chalk": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "cliui": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "code-point-at": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "commondir": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "convert-source-map": { + "version": "1.3.0", + "bundled": true, + "dev": true + }, + "core-js": { + "version": "2.4.1", + "bundled": true, + "dev": true + }, + "cross-spawn": { + "version": "4.0.2", + "bundled": true, + "dev": true, + "requires": { + "lru-cache": "4.0.1", + "which": "1.2.11" + } + }, + "debug": { + "version": "2.2.0", + "bundled": true, + "dev": true, + "requires": { + "ms": "0.7.1" + } + }, + "decamelize": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "default-require-extensions": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "strip-bom": "2.0.0" + } + }, + "detect-indent": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "repeating": "2.0.1" + } + }, + "error-ex": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "is-arrayish": "0.2.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true, + "dev": true + }, + "esutils": { + "version": "2.0.2", + "bundled": true, + "dev": true + }, + "expand-brackets": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "requires": { + "is-posix-bracket": "0.1.1" + } + }, + "expand-range": { + "version": "1.8.2", + "bundled": true, + "dev": true, + "requires": { + "fill-range": "2.2.3" + } + }, + "extglob": { + "version": "0.3.2", + "bundled": true, + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } + }, + "filename-regex": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "fill-range": { + "version": "2.2.3", + "bundled": true, + "dev": true, + "requires": { + "is-number": "2.1.0", + "isobject": "2.1.0", + "randomatic": "1.1.5", + "repeat-element": "1.1.2", + "repeat-string": "1.6.1" + } + }, + "find-cache-dir": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "requires": { + "commondir": "1.0.1", + "mkdirp": "0.5.1", + "pkg-dir": "1.0.0" + } + }, + "find-up": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "for-in": { + "version": "0.1.6", + "bundled": true, + "dev": true + }, + "for-own": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "requires": { + "for-in": "0.1.6" + } + }, + "foreground-child": { + "version": "1.5.3", + "bundled": true, + "dev": true, + "requires": { + "cross-spawn": "4.0.2", + "signal-exit": "3.0.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "get-caller-file": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "glob": { + "version": "7.1.1", + "bundled": true, + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.3", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "glob-base": { + "version": "0.3.0", + "bundled": true, + "dev": true, + "requires": { + "glob-parent": "2.0.0", + "is-glob": "2.0.1" + } + }, + "glob-parent": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-glob": "2.0.1" + } + }, + "globals": { + "version": "9.12.0", + "bundled": true, + "dev": true + }, + "graceful-fs": { + "version": "4.1.9", + "bundled": true, + "dev": true + }, + "handlebars": { + "version": "4.0.5", + "bundled": true, + "dev": true, + "requires": { + "async": "1.5.2", + "optimist": "0.6.1", + "source-map": "0.4.4", + "uglify-js": "2.7.4" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "bundled": true, + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "has-ansi": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "2.0.0" + } + }, + "has-flag": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "hosted-git-info": { + "version": "2.1.5", + "bundled": true, + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true, + "dev": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "invariant": { + "version": "2.2.1", + "bundled": true, + "dev": true, + "requires": { + "loose-envify": "1.3.0" + } + }, + "invert-kv": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "bundled": true, + "dev": true + }, + "is-buffer": { + "version": "1.1.4", + "bundled": true, + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-dotfile": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "bundled": true, + "dev": true, + "requires": { + "is-primitive": "2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "is-extglob": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-glob": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } + }, + "is-number": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.0.4" + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "is-primitive": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "bundled": true, + "dev": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "isexe": { + "version": "1.1.2", + "bundled": true, + "dev": true + }, + "isobject": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "isarray": "1.0.0" + } + }, + "istanbul-lib-coverage": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "istanbul-lib-hook": { + "version": "1.0.0-alpha.4", + "bundled": true, + "dev": true, + "requires": { + "append-transform": "0.3.0" + } + }, + "istanbul-lib-instrument": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "babel-generator": "6.18.0", + "babel-template": "6.16.0", + "babel-traverse": "6.18.0", + "babel-types": "6.18.0", + "babylon": "6.13.1", + "istanbul-lib-coverage": "1.0.0", + "semver": "5.3.0" + } + }, + "istanbul-lib-report": { + "version": "1.0.0-alpha.3", + "bundled": true, + "dev": true, + "requires": { + "async": "1.5.2", + "istanbul-lib-coverage": "1.0.0", + "mkdirp": "0.5.1", + "path-parse": "1.0.5", + "rimraf": "2.5.4", + "supports-color": "3.1.2" + }, + "dependencies": { + "supports-color": { + "version": "3.1.2", + "bundled": true, + "dev": true, + "requires": { + "has-flag": "1.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "istanbul-lib-coverage": "1.0.0", + "mkdirp": "0.5.1", + "rimraf": "2.5.4", + "source-map": "0.5.6" + } + }, + "istanbul-reports": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "handlebars": "4.0.5" + } + }, + "js-tokens": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "jsesc": { + "version": "1.3.0", + "bundled": true, + "dev": true + }, + "kind-of": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "is-buffer": "1.1.4" + } + }, + "lazy-cache": { + "version": "1.0.4", + "bundled": true, + "dev": true, + "optional": true + }, + "lcid": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "invert-kv": "1.0.0" + } + }, + "load-json-file": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "4.1.9", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" + } + }, + "lodash": { + "version": "4.16.6", + "bundled": true, + "dev": true + }, + "longest": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "loose-envify": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "js-tokens": "2.0.0" + } + }, + "lru-cache": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.0.0" + } + }, + "md5-hex": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "md5-o-matic": "0.1.1" + } + }, + "md5-o-matic": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "micromatch": { + "version": "2.3.11", + "bundled": true, + "dev": true, + "requires": { + "arr-diff": "2.0.0", + "array-unique": "0.2.1", + "braces": "1.8.5", + "expand-brackets": "0.1.5", + "extglob": "0.3.2", + "filename-regex": "2.0.0", + "is-extglob": "1.0.0", + "is-glob": "2.0.1", + "kind-of": "3.0.4", + "normalize-path": "2.0.1", + "object.omit": "2.0.1", + "parse-glob": "3.0.4", + "regex-cache": "0.4.3" + } + }, + "minimatch": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "1.1.6" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "0.7.1", + "bundled": true, + "dev": true + }, + "normalize-package-data": { + "version": "2.3.5", + "bundled": true, + "dev": true, + "requires": { + "hosted-git-info": "2.1.5", + "is-builtin-module": "1.0.0", + "semver": "5.3.0", + "validate-npm-package-license": "3.0.1" + } + }, + "normalize-path": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "object-assign": { + "version": "4.1.0", + "bundled": true, + "dev": true + }, + "object.omit": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "for-own": "0.1.4", + "is-extendable": "0.1.1" + } + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "optimist": { + "version": "0.6.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8", + "wordwrap": "0.0.3" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "os-locale": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "lcid": "1.0.0" + } + }, + "parse-glob": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "glob-base": "0.3.0", + "is-dotfile": "1.0.2", + "is-extglob": "1.0.0", + "is-glob": "2.0.1" + } + }, + "parse-json": { + "version": "2.2.0", + "bundled": true, + "dev": true, + "requires": { + "error-ex": "1.3.0" + } + }, + "path-exists": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "path-parse": { + "version": "1.0.5", + "bundled": true, + "dev": true + }, + "path-type": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "4.1.9", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "pify": { + "version": "2.3.0", + "bundled": true, + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "bundled": true, + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "pkg-dir": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "find-up": "1.1.2" + } + }, + "preserve": { + "version": "0.2.0", + "bundled": true, + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "randomatic": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "requires": { + "is-number": "2.1.0", + "kind-of": "3.0.4" + } + }, + "read-pkg": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "load-json-file": "1.1.0", + "normalize-package-data": "2.3.5", + "path-type": "1.1.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "find-up": "1.1.2", + "read-pkg": "1.1.0" + } + }, + "regenerator-runtime": { + "version": "0.9.5", + "bundled": true, + "dev": true + }, + "regex-cache": { + "version": "0.4.3", + "bundled": true, + "dev": true, + "requires": { + "is-equal-shallow": "0.1.3", + "is-primitive": "2.0.0" + } + }, + "repeat-element": { + "version": "1.1.2", + "bundled": true, + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "bundled": true, + "dev": true + }, + "repeating": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-finite": "1.0.2" + } + }, + "require-directory": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "resolve-from": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "right-align": { + "version": "0.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "align-text": "0.1.4" + } + }, + "rimraf": { + "version": "2.5.4", + "bundled": true, + "dev": true, + "requires": { + "glob": "7.1.1" + } + }, + "semver": { + "version": "5.3.0", + "bundled": true, + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "signal-exit": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "slide": { + "version": "1.1.6", + "bundled": true, + "dev": true + }, + "source-map": { + "version": "0.5.6", + "bundled": true, + "dev": true + }, + "spawn-wrap": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "requires": { + "foreground-child": "1.5.3", + "mkdirp": "0.5.1", + "os-homedir": "1.0.2", + "rimraf": "2.5.4", + "signal-exit": "2.1.2", + "which": "1.2.11" + }, + "dependencies": { + "signal-exit": { + "version": "2.1.2", + "bundled": true, + "dev": true + } + } + }, + "spdx-correct": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "spdx-license-ids": "1.2.2" + } + }, + "spdx-expression-parse": { + "version": "1.0.4", + "bundled": true, + "dev": true + }, + "spdx-license-ids": { + "version": "1.2.2", + "bundled": true, + "dev": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "1.0.1", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "2.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-utf8": "0.2.1" + } + }, + "supports-color": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "test-exclude": { + "version": "2.1.3", + "bundled": true, + "dev": true, + "requires": { + "arrify": "1.0.1", + "micromatch": "2.3.11", + "object-assign": "4.1.0", + "read-pkg-up": "1.0.1", + "require-main-filename": "1.0.1" + } + }, + "to-fast-properties": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "uglify-js": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "async": "0.2.10", + "source-map": "0.5.6", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + }, + "dependencies": { + "async": { + "version": "0.2.10", + "bundled": true, + "dev": true, + "optional": true + }, + "yargs": { + "version": "3.10.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + } + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "validate-npm-package-license": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "spdx-correct": "1.0.2", + "spdx-expression-parse": "1.0.4" + } + }, + "which": { + "version": "1.2.11", + "bundled": true, + "dev": true, + "requires": { + "isexe": "1.1.2" + } + }, + "which-module": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "window-size": { + "version": "0.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "wordwrap": { + "version": "0.0.3", + "bundled": true, + "dev": true + }, + "wrap-ansi": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "write-file-atomic": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "4.1.9", + "imurmurhash": "0.1.4", + "slide": "1.1.6" + } + }, + "y18n": { + "version": "3.2.1", + "bundled": true, + "dev": true + }, + "yallist": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "yargs": { + "version": "6.3.0", + "bundled": true, + "dev": true, + "requires": { + "camelcase": "3.0.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "os-locale": "1.4.0", + "read-pkg-up": "1.0.1", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "1.0.2", + "which-module": "1.0.0", + "window-size": "0.2.0", + "y18n": "3.2.1", + "yargs-parser": "4.0.2" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "cliui": { + "version": "3.2.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.0.0" + } + }, + "window-size": { + "version": "0.2.0", + "bundled": true, + "dev": true + } + } + }, + "yargs-parser": { + "version": "4.0.2", + "bundled": true, + "dev": true, + "requires": { + "camelcase": "3.0.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "bundled": true, + "dev": true + } + } + } + } + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-keys": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", + "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", + "dev": true + }, + "object.assign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.0.4.tgz", + "integrity": "sha1-scnMBE7xuf5jYG/BQau7MuFHMMw=", + "dev": true, + "requires": { + "define-properties": "1.1.2", + "function-bind": "1.1.1", + "object-keys": "1.0.11" + } + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true, + "requires": { + "for-own": "0.1.5", + "is-extendable": "0.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "onetime": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", + "dev": true + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + } + }, + "os-browserify": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.2.1.tgz", + "integrity": "sha1-Y/xMzuXS13Y9Jrv4YBB45sLgBE8=", + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "0.7.0", + "lcid": "1.0.0", + "mem": "1.1.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz", + "integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw=", + "dev": true + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "1.1.0" + } + }, + "pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=", + "dev": true + }, + "parse-asn1": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.0.tgz", + "integrity": "sha1-N8T5t+06tlx0gXtfJICTf7+XxxI=", + "dev": true, + "requires": { + "asn1.js": "4.9.1", + "browserify-aes": "1.0.8", + "create-hash": "1.1.3", + "evp_bytestokey": "1.0.3", + "pbkdf2": "3.0.14" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true, + "requires": { + "glob-base": "0.3.0", + "is-dotfile": "1.0.3", + "is-extglob": "1.0.0", + "is-glob": "2.0.1" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "1.3.1" + } + }, + "parse5": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz", + "integrity": "sha1-m387DeMr543CQBsXVzzK8Pb1nZQ=", + "dev": true + }, + "path-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", + "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "dev": true + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "pbkdf2": { + "version": "3.0.14", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.14.tgz", + "integrity": "sha512-gjsZW9O34fm0R7PaLHRJmLLVfSoesxztjPjE9o6R+qtVJij90ltg1joIovN9GKrRW3t1PzhDDG3UMEMFfZ+1wA==", + "dev": true, + "requires": { + "create-hash": "1.1.3", + "create-hmac": "1.1.6", + "ripemd160": "2.0.1", + "safe-buffer": "5.1.1", + "sha.js": "2.4.8" + } + }, + "performance-now": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", + "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "pkg-conf": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.0.0.tgz", + "integrity": "sha1-BxyHZQQDvM+5xif1h1G/5HwGcnk=", + "dev": true, + "requires": { + "find-up": "2.1.0", + "load-json-file": "2.0.0" + }, + "dependencies": { + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "pkg-config": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pkg-config/-/pkg-config-1.1.1.tgz", + "integrity": "sha1-VX7yLXPaPIg3EHdmxS6tq94pj+Q=", + "dev": true, + "requires": { + "debug-log": "1.0.1", + "find-root": "1.1.0", + "xtend": "4.0.1" + } + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "2.1.0" + } + }, + "pkg-up": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-1.0.0.tgz", + "integrity": "sha1-Pgj7RhUlxEIWJKM7n35tCvWwWiY=", + "dev": true, + "requires": { + "find-up": "1.1.2" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "2.0.1" + } + } + } + }, + "pluralize": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", + "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true + }, + "private": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.7.tgz", + "integrity": "sha1-aM5eih7woju1cMwoU3tTMqumPvE=", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "dev": true + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, + "requires": { + "asap": "2.0.6" + } + }, + "prop-types": { + "version": "15.5.10", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.5.10.tgz", + "integrity": "sha1-J5ffwxJhguOpXj37suiT3ddFYVQ=", + "dev": true, + "requires": { + "fbjs": "0.8.15", + "loose-envify": "1.3.1" + } + }, + "prr": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz", + "integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "public-encrypt": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.0.tgz", + "integrity": "sha1-OfaZ86RlYN1eusvKaTyvfGXBjMY=", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "browserify-rsa": "4.0.1", + "create-hash": "1.1.3", + "parse-asn1": "5.1.0", + "randombytes": "2.0.5" + } + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "qs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", + "dev": true + }, + "query-string": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-3.0.3.tgz", + "integrity": "sha1-ri4UtNBQcdTpuetIc8NbDc1C5jg=", + "dev": true, + "requires": { + "strict-uri-encode": "1.1.0" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "randomatic": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", + "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", + "dev": true, + "requires": { + "is-number": "3.0.0", + "kind-of": "4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "randombytes": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.5.tgz", + "integrity": "sha512-8T7Zn1AhMsQ/HI1SjcCfT/t4ii3eAqco3yOcSzS4mozsOz69lHLsoMXmF9nZgnFanYscnSlUSgs8uZyKzpE6kg==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "react": { + "version": "15.6.1", + "resolved": "https://registry.npmjs.org/react/-/react-15.6.1.tgz", + "integrity": "sha1-uqhDTsZ4C96ZfNw4C3nNM7ljk98=", + "dev": true, + "requires": { + "create-react-class": "15.6.0", + "fbjs": "0.8.15", + "loose-envify": "1.3.1", + "object-assign": "4.1.1", + "prop-types": "15.5.10" + } + }, + "react-addons-update": { + "version": "15.6.0", + "resolved": "https://registry.npmjs.org/react-addons-update/-/react-addons-update-15.6.0.tgz", + "integrity": "sha1-Z/jVo9PYrHzPpFJWWoMQBlF450g=", + "dev": true, + "requires": { + "fbjs": "0.8.15", + "object-assign": "4.1.1" + } + }, + "react-dom": { + "version": "15.6.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-15.6.1.tgz", + "integrity": "sha1-LLDtQZEDjlPCCes6eaI+Kkz5lHA=", + "dev": true, + "requires": { + "fbjs": "0.8.15", + "loose-envify": "1.3.1", + "object-assign": "4.1.1", + "prop-types": "15.5.10" + } + }, + "react-router": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-2.8.1.tgz", + "integrity": "sha1-c+lJH2zrMW0Pd5gpCBhj43juTtc=", + "dev": true, + "requires": { + "history": "2.1.2", + "hoist-non-react-statics": "1.2.0", + "invariant": "2.2.2", + "loose-envify": "1.3.1", + "warning": "3.0.0" + }, + "dependencies": { + "history": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/history/-/history-2.1.2.tgz", + "integrity": "sha1-SqLeiXoOSGfkU5hDvm7Nsphr/ew=", + "dev": true, + "requires": { + "deep-equal": "1.0.1", + "invariant": "2.2.2", + "query-string": "3.0.3", + "warning": "2.1.0" + }, + "dependencies": { + "warning": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/warning/-/warning-2.1.0.tgz", + "integrity": "sha1-ISINnGOvx3qMkhEeARr3Bc4MaQE=", + "dev": true, + "requires": { + "loose-envify": "1.3.1" + } + } + } + }, + "warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", + "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", + "dev": true, + "requires": { + "loose-envify": "1.3.1" + } + } + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "1.1.2", + "read-pkg": "1.1.0" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "2.0.1" + } + } + } + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "readdirp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", + "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "minimatch": "3.0.4", + "readable-stream": "2.3.3", + "set-immediate-shim": "1.0.1" + } + }, + "readline2": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", + "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "mute-stream": "0.0.5" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "1.4.0" + } + }, + "regenerate": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.2.tgz", + "integrity": "sha1-0ZQcZ7rUN+G+dkM63Vs4X5WxkmA=", + "dev": true + }, + "regenerator-runtime": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz", + "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==", + "dev": true + }, + "regenerator-transform": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", + "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "private": "0.1.7" + } + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "dev": true, + "requires": { + "is-equal-shallow": "0.1.3" + } + }, + "regexpu-core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", + "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "dev": true, + "requires": { + "regenerate": "1.3.2", + "regjsgen": "0.2.0", + "regjsparser": "0.1.5" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "dev": true + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "dev": true, + "requires": { + "jsesc": "0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "1.0.2" + } + }, + "request": { + "version": "2.81.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", + "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", + "dev": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dev": true, + "requires": { + "caller-path": "0.1.0", + "resolve-from": "1.0.1" + } + }, + "resolve": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz", + "integrity": "sha512-aW7sVKPufyHqOmyyLzg/J+8606v5nevBgaliIlV7nUpVMsDnoBGV/cbSLNjZAg9q0Cfd/+easKVKQ8vOu8fn1Q==", + "dev": true, + "requires": { + "path-parse": "1.0.5" + } + }, + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true + }, + "restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "dev": true, + "requires": { + "exit-hook": "1.1.1", + "onetime": "1.1.0" + } + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "dev": true, + "requires": { + "align-text": "0.1.4" + } + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "dev": true, + "requires": { + "glob": "7.1.1" + } + }, + "ripemd160": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz", + "integrity": "sha1-D0WEKVxTo2KK9+bXmsohzlfRxuc=", + "dev": true, + "requires": { + "hash-base": "2.0.2", + "inherits": "2.0.3" + } + }, + "run-async": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", + "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", + "dev": true, + "requires": { + "once": "1.4.0" + } + }, + "run-parallel": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.6.tgz", + "integrity": "sha1-KQA8miFj4B4tLfyQV18sbB1hoDk=", + "dev": true + }, + "rx-lite": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", + "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=", + "dev": true + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "schema-utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", + "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", + "dev": true, + "requires": { + "ajv": "5.2.2" + } + }, + "semver": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", + "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "dev": true + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "sha.js": { + "version": "2.4.8", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.8.tgz", + "integrity": "sha1-NwaMLEdra69ALRSknGf1l5IfY08=", + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "shelljs": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", + "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", + "dev": true, + "requires": { + "glob": "7.1.1", + "interpret": "1.0.4", + "rechoir": "0.6.2" + } + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", + "dev": true + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "source-list-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz", + "integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "0.5.7" + } + }, + "spdx-correct": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", + "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", + "dev": true, + "requires": { + "spdx-license-ids": "1.2.2" + } + }, + "spdx-expression-parse": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", + "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", + "dev": true + }, + "spdx-license-ids": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", + "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "dev": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "standard": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/standard/-/standard-10.0.3.tgz", + "integrity": "sha512-JURZ+85ExKLQULckDFijdX5WHzN6RC7fgiZNSV4jFQVo+3tPoQGHyBrGekye/yf0aOfb4210EM5qPNlc2cRh4w==", + "dev": true, + "requires": { + "eslint": "3.19.0", + "eslint-config-standard": "10.2.1", + "eslint-config-standard-jsx": "4.0.2", + "eslint-plugin-import": "2.2.0", + "eslint-plugin-node": "4.2.3", + "eslint-plugin-promise": "3.5.0", + "eslint-plugin-react": "6.10.3", + "eslint-plugin-standard": "3.0.1", + "standard-engine": "7.0.0" + } + }, + "standard-engine": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-7.0.0.tgz", + "integrity": "sha1-67d7nI/CyBZf+jU72Rug3/Qa9pA=", + "dev": true, + "requires": { + "deglob": "2.1.0", + "get-stdin": "5.0.1", + "minimist": "1.2.0", + "pkg-conf": "2.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "stream-browserify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", + "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3" + } + }, + "stream-http": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.7.2.tgz", + "integrity": "sha512-c0yTD2rbQzXtSsFSVhtpvY/vS6u066PcXOX9kBB3mSO76RiUQzL340uJkGBWnlBg4/HZzqiUXtaVA7wcRcJgEw==", + "dev": true, + "requires": { + "builtin-status-codes": "3.0.0", + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "to-arraybuffer": "1.0.1", + "xtend": "4.0.1" + } + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "0.2.1" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "style-loader": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.8.3.tgz", + "integrity": "sha1-9Pkut9tjdodI8VBlzWcA9aHIU1c=", + "dev": true, + "requires": { + "loader-utils": "0.2.17" + }, + "dependencies": { + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "3.2.0", + "emojis-list": "2.1.0", + "json5": "0.5.1", + "object-assign": "4.1.1" + } + } + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "symbol-tree": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", + "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=", + "dev": true + }, + "table": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", + "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", + "dev": true, + "requires": { + "ajv": "4.11.8", + "ajv-keywords": "1.5.1", + "chalk": "1.1.3", + "lodash": "4.17.4", + "slice-ansi": "0.0.4", + "string-width": "2.1.1" + }, + "dependencies": { + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "dev": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + } + } + }, + "tapable": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.8.tgz", + "integrity": "sha1-mTcqXJmb8t8WCvwNdL7U9HlIzSI=", + "dev": true + }, + "test-exclude": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.1.1.tgz", + "integrity": "sha512-35+Asrsk3XHJDBgf/VRFexPgh3UyETv8IAn/LRTiZjVy6rjPVqdEk8dJcJYBzl1w0XCJM48lvTy8SfEsCWS4nA==", + "dev": true, + "requires": { + "arrify": "1.0.1", + "micromatch": "2.3.11", + "object-assign": "4.1.1", + "read-pkg-up": "1.0.1", + "require-main-filename": "1.0.1" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "timers-browserify": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.4.tgz", + "integrity": "sha512-uZYhyU3EX8O7HQP+J9fTVYwsq90Vr68xPEFo7yrVImIxYvHgukBEgOB/SgGoorWVTzGM/3Z+wUNnboA4M8jWrg==", + "dev": true, + "requires": { + "setimmediate": "1.0.5" + } + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + }, + "tough-cookie": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", + "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", + "dev": true, + "requires": { + "punycode": "1.4.1" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "dev": true + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "tryit": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz", + "integrity": "sha1-OTvnMKlEb9Hq1tpZoBQwjzbCics=", + "dev": true + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2" + } + }, + "type-detect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", + "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=", + "dev": true + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "ua-parser-js": { + "version": "0.7.14", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.14.tgz", + "integrity": "sha1-EQ1T+kw/MmwSEpK76skE0uAzh8o=", + "dev": true + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "requires": { + "source-map": "0.5.7", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + }, + "dependencies": { + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + } + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true, + "optional": true + }, + "uglifyjs-webpack-plugin": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz", + "integrity": "sha1-uVH0q7a9YX5m9j64kUmOORdj4wk=", + "dev": true, + "requires": { + "source-map": "0.5.7", + "uglify-js": "2.8.29", + "webpack-sources": "1.0.1" + } + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "user-home": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", + "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", + "dev": true, + "requires": { + "os-homedir": "1.0.2" + } + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "uuid": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", + "dev": true, + "requires": { + "spdx-correct": "1.0.2", + "spdx-expression-parse": "1.0.4" + } + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "vm-browserify": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", + "dev": true, + "requires": { + "indexof": "0.0.1" + } + }, + "warning": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/warning/-/warning-2.1.0.tgz", + "integrity": "sha1-ISINnGOvx3qMkhEeARr3Bc4MaQE=", + "dev": true, + "requires": { + "loose-envify": "1.3.1" + } + }, + "watchpack": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.4.0.tgz", + "integrity": "sha1-ShRyvLuVK9Cpu0A2gB+VTfs5+qw=", + "dev": true, + "requires": { + "async": "2.5.0", + "chokidar": "1.7.0", + "graceful-fs": "4.1.11" + } + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "dev": true + }, + "webpack": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.6.0.tgz", + "integrity": "sha512-OsHT3D0W0KmPPh60tC7asNnOmST6bKTiR90UyEdT9QYoaJ4OYN4Gg7WK1k3VxHK07ZoiYWPsKvlS/gAjwL/vRA==", + "dev": true, + "requires": { + "acorn": "5.1.2", + "acorn-dynamic-import": "2.0.2", + "ajv": "5.2.2", + "ajv-keywords": "2.1.0", + "async": "2.5.0", + "enhanced-resolve": "3.4.1", + "escope": "3.6.0", + "interpret": "1.0.4", + "json-loader": "0.5.7", + "json5": "0.5.1", + "loader-runner": "2.3.0", + "loader-utils": "1.1.0", + "memory-fs": "0.4.1", + "mkdirp": "0.5.1", + "node-libs-browser": "2.0.0", + "source-map": "0.5.7", + "supports-color": "4.4.0", + "tapable": "0.2.8", + "uglifyjs-webpack-plugin": "0.4.6", + "watchpack": "1.4.0", + "webpack-sources": "1.0.1", + "yargs": "8.0.2" + }, + "dependencies": { + "acorn": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.2.tgz", + "integrity": "sha512-o96FZLJBPY1lvTuJylGA9Bk3t/GKPPJG8H0ydQQl01crzwJgspa4AEIq/pVTXigmK0PHVQhiAtn8WMBLL9D2WA==", + "dev": true + }, + "ajv-keywords": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.0.tgz", + "integrity": "sha1-opbhf3v658HOT34N5T0pyzIWLfA=", + "dev": true + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "webpack-sources": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.0.1.tgz", + "integrity": "sha512-05tMxipUCwHqYaVS8xc7sYPTly8PzXayRCB4dTxLhWTqlKUiwH6ezmEe0OSreL1c30LAuA3Zqmc+uEBUGFJDjw==", + "dev": true, + "requires": { + "source-list-map": "2.0.0", + "source-map": "0.5.7" + } + }, + "whatwg-fetch": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz", + "integrity": "sha1-nITsLc9oGH/wC8ZOEnS0QhduHIQ=", + "dev": true + }, + "whatwg-url": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-2.0.1.tgz", + "integrity": "sha1-U5ayBD8CDub3BNnEXqhRnnJN5lk=", + "dev": true, + "requires": { + "tr46": "0.0.3", + "webidl-conversions": "3.0.1" + } + }, + "which": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", + "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "dev": true, + "requires": { + "isexe": "2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "requires": { + "mkdirp": "0.5.1" + } + }, + "xml-name-validator": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz", + "integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU=", + "dev": true + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yargs": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz", + "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=", + "dev": true, + "requires": { + "camelcase": "4.1.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "os-locale": "2.1.0", + "read-pkg-up": "2.0.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" + }, + "dependencies": { + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + } + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "2.3.0" + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "2.1.0", + "read-pkg": "2.0.0" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + } + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "yargs-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", + "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", + "dev": true, + "requires": { + "camelcase": "4.1.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + } + } + } + } +} diff --git a/venv/lib/python2.7/site-packages/lektor/admin/package.json b/venv/lib/python2.7/site-packages/lektor/admin/package.json new file mode 100644 index 0000000..cb35b97 --- /dev/null +++ b/venv/lib/python2.7/site-packages/lektor/admin/package.json @@ -0,0 +1,80 @@ +{ + "name": "lektor", + "version": "0.0.0", + "private": true, + "dependencies": {}, + "devDependencies": { + "babel-core": "^6.26.0", + "babel-loader": "^7.1.2", + "babel-plugin-istanbul": "^4.1.4", + "babel-plugin-transform-object-rest-spread": "^6.26.0", + "babel-preset-es2015": "^6.24.1", + "babel-preset-react": "^6.24.1", + "babel-register": "^6.26.0", + "bootstrap": "~3.3.0", + "chai": "^3.5.0", + "css-loader": "^0.9.1", + "event-source-polyfill": "^0.0.5", + "extract-text-webpack-plugin": "^3.0.0", + "file-loader": "^0.11.2", + "font-awesome": "^4.3.0", + "history": "^1.17.0", + "jquery": "^2.1.3", + "jsdomify": "^2.1.0", + "json-loader": "^0.5.2", + "less": "^1.7.5", + "less-loader": "^0.7.8", + "mocha": "^3.1.2", + "native-promise-only": "^0.7.6-a", + "nyc": "^8.4.0", + "prop-types": "^15.5.10", + "querystring": "^0.2.0", + "react": "^15.3.0", + "react-addons-update": "^15.3.0", + "react-dom": "^15.3.0", + "react-router": "^2.6.0", + "standard": ">8.5.0", + "style-loader": "^0.8.3", + "webpack": "^3.6.0" + }, + "scripts": { + "lint": "standard", + "test": "nyc mocha static/js/**/*.test.js", + "report-coverage": "nyc report --reporter=lcov > coverage.lcov", + "webpack": "webpack --config ./static/webpack.config.js --context ./static" + }, + "babel": { + "presets": [ + "es2015", + "react" + ], + "plugins": [ + "transform-object-rest-spread" + ], + "env": { + "test": { + "plugins": [ + "istanbul" + ] + } + } + }, + "nyc": { + "extension": [ + ".jsx" + ], + "require": [ + "babel-register" + ] + }, + "standard": { + "ignore": [ + "static/gen/" + ], + "globals": [ + "$LEKTOR_CONFIG" + ] + }, + "author": "", + "license": "ISC" +} diff --git a/venv/lib/python2.7/site-packages/lektor/admin/static/fonts/LICENSE b/venv/lib/python2.7/site-packages/lektor/admin/static/fonts/LICENSE new file mode 100644 index 0000000..0ab5c8d --- /dev/null +++ b/venv/lib/python2.7/site-packages/lektor/admin/static/fonts/LICENSE @@ -0,0 +1,13 @@ +Copyright 2013 Christian Robertson + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/venv/lib/python2.7/site-packages/lektor/admin/static/fonts/RobotoSlab-Light-webfont.ttf b/venv/lib/python2.7/site-packages/lektor/admin/static/fonts/RobotoSlab-Light-webfont.ttf new file mode 100644 index 0000000..e3ababa Binary files /dev/null and b/venv/lib/python2.7/site-packages/lektor/admin/static/fonts/RobotoSlab-Light-webfont.ttf differ diff --git a/venv/lib/python2.7/site-packages/lektor/admin/static/fonts/RobotoSlab-Regular-webfont.ttf b/venv/lib/python2.7/site-packages/lektor/admin/static/fonts/RobotoSlab-Regular-webfont.ttf new file mode 100644 index 0000000..976440e Binary files /dev/null and b/venv/lib/python2.7/site-packages/lektor/admin/static/fonts/RobotoSlab-Regular-webfont.ttf differ diff --git a/venv/lib/python2.7/site-packages/lektor/admin/static/gen/478c97f5f24d794b1ce6b93cab5a4dad.ttf b/venv/lib/python2.7/site-packages/lektor/admin/static/gen/478c97f5f24d794b1ce6b93cab5a4dad.ttf new file mode 100644 index 0000000..976440e Binary files /dev/null and b/venv/lib/python2.7/site-packages/lektor/admin/static/gen/478c97f5f24d794b1ce6b93cab5a4dad.ttf differ diff --git a/venv/lib/python2.7/site-packages/lektor/admin/static/gen/674f50d287a8c48dc19ba404d20fe713.eot b/venv/lib/python2.7/site-packages/lektor/admin/static/gen/674f50d287a8c48dc19ba404d20fe713.eot new file mode 100644 index 0000000..e9f60ca Binary files /dev/null and b/venv/lib/python2.7/site-packages/lektor/admin/static/gen/674f50d287a8c48dc19ba404d20fe713.eot differ diff --git a/venv/lib/python2.7/site-packages/lektor/admin/static/gen/912ec66d7572ff821749319396470bde.svg b/venv/lib/python2.7/site-packages/lektor/admin/static/gen/912ec66d7572ff821749319396470bde.svg new file mode 100644 index 0000000..855c845 --- /dev/null +++ b/venv/lib/python2.7/site-packages/lektor/admin/static/gen/912ec66d7572ff821749319396470bde.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/venv/lib/python2.7/site-packages/lektor/admin/static/gen/af7ae505a9eed503f8b8e6982036873e.woff2 b/venv/lib/python2.7/site-packages/lektor/admin/static/gen/af7ae505a9eed503f8b8e6982036873e.woff2 new file mode 100644 index 0000000..4d13fc6 Binary files /dev/null and b/venv/lib/python2.7/site-packages/lektor/admin/static/gen/af7ae505a9eed503f8b8e6982036873e.woff2 differ diff --git a/venv/lib/python2.7/site-packages/lektor/admin/static/gen/app.js b/venv/lib/python2.7/site-packages/lektor/admin/static/gen/app.js new file mode 100644 index 0000000..f843613 --- /dev/null +++ b/venv/lib/python2.7/site-packages/lektor/admin/static/gen/app.js @@ -0,0 +1,9822 @@ +webpackJsonp([0],[ +/* 0 */, +/* 1 */, +/* 2 */, +/* 3 */, +/* 4 */, +/* 5 */, +/* 6 */, +/* 7 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var loadTranslations = function loadTranslations() { + var ctx = __webpack_require__(284); + var rv = {}; + ctx.keys().forEach(function (key) { + var langIdMatch = key.match(/([a-z]+)/); + rv[langIdMatch[1]] = ctx(key); + }); + return rv; +}; + +var i18n = { + translations: loadTranslations(), + + currentLanguage: 'en', + + setLanguageFromLocale: function setLanguageFromLocale(locale) { + if (locale) { + var lang = locale.split(/[-_]/)[0].toLowerCase(); + if (this.translations[lang] !== undefined) { + this.currentLanguage = lang; + } + } + }, + trans: function trans(key) { + var rv = void 0; + if ((typeof key === 'undefined' ? 'undefined' : _typeof(key)) === 'object') { + rv = key[i18n.currentLanguage]; + if (rv === undefined) { + rv = key.en; + } + return rv; + } + return i18n.translations[i18n.currentLanguage][key] || key; + } +}; + +exports.default = i18n; + +/***/ }), +/* 8 */, +/* 9 */, +/* 10 */, +/* 11 */, +/* 12 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _jquery = __webpack_require__(11); + +var _jquery2 = _interopRequireDefault(_jquery); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var slug = function slug(string, opts) { + opts = opts || {}; + string = string.toString(); + if (typeof opts === 'string') { + opts = { replacement: opts }; + } + opts.mode = opts.mode || slug.defaults.mode; + var defaults = slug.defaults.modes[opts.mode]; + ['replacement', 'multicharmap', 'charmap', 'remove'].forEach(function (key) { + opts[key] = opts[key] || defaults[key]; + }); + if (typeof opts.symbols === 'undefined') { + opts.symbols = defaults.symbols; + } + var lengths = []; + Object.keys(opts.multicharmap).forEach(function (key) { + var len = key.length; + if (lengths.indexOf(len) === -1) { + lengths.push(len); + } + }); + var result = ''; + + var _loop = function _loop(_char, _i, l) { + _char = string[_i]; + if (!lengths.some(function (len) { + var str = string.substr(_i, len); + if (opts.multicharmap[str]) { + _i += len - 1; + _char = opts.multicharmap[str]; + return true; + } else return false; + })) { + if (opts.charmap[_char]) { + _char = opts.charmap[_char]; + } + } + _char = _char.replace(/[^\w\s\-._~]/g, ''); // allowed + if (opts.remove) _char = _char.replace(opts.remove, ''); // add flavour + result += _char; + char = _char; + i = _i; + }; + + for (var char, i = 0, l = string.length; i < l; i++) { + _loop(char, i, l); + } + result = result.replace(/^\s+|\s+$/g, ''); // trim leading/trailing spaces + result = result.replace(/[-\s]+/g, opts.replacement); // convert spaces + return result.replace(opts.replacement + '$', ''); // remove trailing separator +}; + +slug.defaults = { + mode: 'pretty' +}; + +slug.multicharmap = slug.defaults.multicharmap = { + '<3': 'love', '&&': 'and', '||': 'or', 'w/': 'with' + + // https://code.djangoproject.com/browser/django/trunk/django/contrib/admin/media/js/urlify.js +};slug.charmap = slug.defaults.charmap = { + // latin + 'À': 'A', + 'Á': 'A', + 'Â': 'A', + 'Ã': 'A', + 'Ä': 'Ae', + 'Å': 'A', + 'Æ': 'AE', + 'Ç': 'C', + 'È': 'E', + 'É': 'E', + 'Ê': 'E', + 'Ë': 'E', + 'Ì': 'I', + 'Í': 'I', + 'Î': 'I', + 'Ï': 'I', + 'Ð': 'D', + 'Ñ': 'N', + 'Ò': 'O', + 'Ó': 'O', + 'Ô': 'O', + 'Õ': 'O', + 'Ö': 'Oe', + 'Ő': 'O', + 'Ø': 'O', + 'Ù': 'U', + 'Ú': 'U', + 'Û': 'U', + 'Ü': 'Ue', + 'Ű': 'U', + 'Ý': 'Y', + 'Þ': 'TH', + 'ß': 'ss', + 'à': 'a', + 'á': 'a', + 'â': 'a', + 'ã': 'a', + 'ä': 'ae', + 'å': 'a', + 'æ': 'ae', + 'ç': 'c', + 'è': 'e', + 'é': 'e', + 'ê': 'e', + 'ë': 'e', + 'ì': 'i', + 'í': 'i', + 'î': 'i', + 'ï': 'i', + 'ð': 'd', + 'ñ': 'n', + 'ò': 'o', + 'ó': 'o', + 'ô': 'o', + 'õ': 'o', + 'ö': 'oe', + 'ő': 'o', + 'ø': 'o', + 'ù': 'u', + 'ú': 'u', + 'û': 'u', + 'ü': 'ue', + 'ű': 'u', + 'ý': 'y', + 'þ': 'th', + 'ÿ': 'y', + 'ẞ': 'SS', + // greek + 'α': 'a', + 'β': 'b', + 'γ': 'g', + 'δ': 'd', + 'ε': 'e', + 'ζ': 'z', + 'η': 'h', + 'θ': '8', + 'ι': 'i', + 'κ': 'k', + 'λ': 'l', + 'μ': 'm', + 'ν': 'n', + 'ξ': '3', + 'ο': 'o', + 'π': 'p', + 'ρ': 'r', + 'σ': 's', + 'τ': 't', + 'υ': 'y', + 'φ': 'f', + 'χ': 'x', + 'ψ': 'ps', + 'ω': 'w', + 'ά': 'a', + 'έ': 'e', + 'ί': 'i', + 'ό': 'o', + 'ύ': 'y', + 'ή': 'h', + 'ώ': 'w', + 'ς': 's', + 'ϊ': 'i', + 'ΰ': 'y', + 'ϋ': 'y', + 'ΐ': 'i', + 'Α': 'A', + 'Β': 'B', + 'Γ': 'G', + 'Δ': 'D', + 'Ε': 'E', + 'Ζ': 'Z', + 'Η': 'H', + 'Θ': '8', + 'Ι': 'I', + 'Κ': 'K', + 'Λ': 'L', + 'Μ': 'M', + 'Ν': 'N', + 'Ξ': '3', + 'Ο': 'O', + 'Π': 'P', + 'Ρ': 'R', + 'Σ': 'S', + 'Τ': 'T', + 'Υ': 'Y', + 'Φ': 'F', + 'Χ': 'X', + 'Ψ': 'PS', + 'Ω': 'W', + 'Ά': 'A', + 'Έ': 'E', + 'Ί': 'I', + 'Ό': 'O', + 'Ύ': 'Y', + 'Ή': 'H', + 'Ώ': 'W', + 'Ϊ': 'I', + 'Ϋ': 'Y', + // turkish + 'ş': 's', + 'Ş': 'S', + 'ı': 'i', + 'İ': 'I', + 'ğ': 'g', + 'Ğ': 'G', + // russian + 'а': 'a', + 'б': 'b', + 'в': 'v', + 'г': 'g', + 'д': 'd', + 'е': 'e', + 'ё': 'yo', + 'ж': 'zh', + 'з': 'z', + 'и': 'i', + 'й': 'j', + 'к': 'k', + 'л': 'l', + 'м': 'm', + 'н': 'n', + 'о': 'o', + 'п': 'p', + 'р': 'r', + 'с': 's', + 'т': 't', + 'у': 'u', + 'ф': 'f', + 'х': 'h', + 'ц': 'c', + 'ч': 'ch', + 'ш': 'sh', + 'щ': 'sh', + 'ъ': 'u', + 'ы': 'y', + 'ь': '', + 'э': 'e', + 'ю': 'yu', + 'я': 'ya', + 'А': 'A', + 'Б': 'B', + 'В': 'V', + 'Г': 'G', + 'Д': 'D', + 'Е': 'E', + 'Ё': 'Yo', + 'Ж': 'Zh', + 'З': 'Z', + 'И': 'I', + 'Й': 'J', + 'К': 'K', + 'Л': 'L', + 'М': 'M', + 'Н': 'N', + 'О': 'O', + 'П': 'P', + 'Р': 'R', + 'С': 'S', + 'Т': 'T', + 'У': 'U', + 'Ф': 'F', + 'Х': 'H', + 'Ц': 'C', + 'Ч': 'Ch', + 'Ш': 'Sh', + 'Щ': 'Sh', + 'Ъ': 'U', + 'Ы': 'Y', + 'Ь': '', + 'Э': 'E', + 'Ю': 'Yu', + 'Я': 'Ya', + // ukranian + 'Є': 'Ye', + 'І': 'I', + 'Ї': 'Yi', + 'Ґ': 'G', + 'є': 'ye', + 'і': 'i', + 'ї': 'yi', + 'ґ': 'g', + // czech + 'č': 'c', + 'ď': 'd', + 'ě': 'e', + 'ň': 'n', + 'ř': 'r', + 'š': 's', + 'ť': 't', + 'ů': 'u', + 'ž': 'z', + 'Č': 'C', + 'Ď': 'D', + 'Ě': 'E', + 'Ň': 'N', + 'Ř': 'R', + 'Š': 'S', + 'Ť': 'T', + 'Ů': 'U', + 'Ž': 'Z', + // polish + 'ą': 'a', + 'ć': 'c', + 'ę': 'e', + 'ł': 'l', + 'ń': 'n', + 'ś': 's', + 'ź': 'z', + 'ż': 'z', + 'Ą': 'A', + 'Ć': 'C', + 'Ę': 'E', + 'Ł': 'L', + 'Ń': 'N', + 'Ś': 'S', + 'Ź': 'Z', + 'Ż': 'Z', + // latvian + 'ā': 'a', + 'ē': 'e', + 'ģ': 'g', + 'ī': 'i', + 'ķ': 'k', + 'ļ': 'l', + 'ņ': 'n', + 'ū': 'u', + 'Ā': 'A', + 'Ē': 'E', + 'Ģ': 'G', + 'Ī': 'I', + 'Ķ': 'K', + 'Ļ': 'L', + 'Ņ': 'N', + 'Ū': 'U', + // lithuanian + 'ė': 'e', + 'į': 'i', + 'ų': 'u', + 'Ė': 'E', + 'Į': 'I', + 'Ų': 'U', + // romanian + 'ț': 't', + 'Ț': 'T', + 'ţ': 't', + 'Ţ': 'T', + 'ș': 's', + 'Ș': 'S', + 'ă': 'a', + 'Ă': 'A', + // currency + '€': 'euro', + '₢': 'cruzeiro', + '₣': 'french franc', + '£': 'pound', + '₤': 'lira', + '₥': 'mill', + '₦': 'naira', + '₧': 'peseta', + '₨': 'rupee', + '₩': 'won', + '₪': 'new shequel', + '₫': 'dong', + '₭': 'kip', + '₮': 'tugrik', + '₯': 'drachma', + '₰': 'penny', + '₱': 'peso', + '₲': 'guarani', + '₳': 'austral', + '₴': 'hryvnia', + '₵': 'cedi', + '¢': 'cent', + '¥': 'yen', + '元': 'yuan', + '円': 'yen', + '﷼': 'rial', + '₠': 'ecu', + '¤': 'currency', + '฿': 'baht', + '$': 'dollar', + '₹': 'indian rupee', + // symbols + '©': '(c)', + 'œ': 'oe', + 'Œ': 'OE', + '∑': 'sum', + '®': '(r)', + '†': '+', + '“': '"', + '”': '"', + '‘': "'", + '’': "'", + '∂': 'd', + 'ƒ': 'f', + '™': 'tm', + '℠': 'sm', + '…': '...', + '˚': 'o', + 'º': 'o', + 'ª': 'a', + '•': '*', + '∆': 'delta', + '∞': 'infinity', + '♥': 'love', + '&': 'and', + '|': 'or', + '<': 'less', + '>': 'greater', + '=': 'equals' +}; + +slug.defaults.modes = { + pretty: { + replacement: '-', + symbols: true, + remove: /[.]/g, + charmap: slug.defaults.charmap, + multicharmap: slug.defaults.multicharmap + } +}; + +var utils = { + slugify: slug, + + getCanonicalUrl: function getCanonicalUrl(localPath) { + return $LEKTOR_CONFIG.site_root.match(/^(.*?)\/*$/)[1] + '/' + utils.stripLeadingSlash(localPath); + }, + isValidUrl: function isValidUrl(url) { + return !!url.match(/^(https?|ftp):\/\/\S+$/); + }, + stripLeadingSlash: function stripLeadingSlash(string) { + return string.match(/^\/*(.*?)$/)[1]; + }, + stripTrailingSlash: function stripTrailingSlash(string) { + return string.match(/^(.*?)\/*$/)[1]; + }, + joinFsPath: function joinFsPath(a, b) { + return utils.stripTrailingSlash(a) + '/' + utils.stripLeadingSlash(b); + }, + flipSetValue: function flipSetValue(originalSet, value, isActive) { + if (isActive) { + return utils.addToSet(originalSet || [], value); + } else { + return utils.removeFromSet(originalSet || [], value); + } + }, + addToSet: function addToSet(originalSet, value) { + for (var _i2 = 0; _i2 < originalSet.length; _i2++) { + if (originalSet[_i2] === value) { + return originalSet; + } + } + var rv = originalSet.slice(); + rv.push(value); + return rv; + }, + removeFromSet: function removeFromSet(originalSet, value) { + var rv = null; + var off = 0; + for (var _i3 = 0; _i3 < originalSet.length; _i3++) { + if (originalSet[_i3] === value) { + if (rv === null) { + rv = originalSet.slice(); + } + rv.splice(_i3 - off++, 1); + } + } + return rv === null ? originalSet : rv; + }, + urlPathsConsideredEqual: function urlPathsConsideredEqual(a, b) { + if (a == null || b == null) { + return false; + } + return utils.stripTrailingSlash(a) === utils.stripTrailingSlash(b); + }, + fsPathFromAdminObservedPath: function fsPathFromAdminObservedPath(adminPath) { + var base = $LEKTOR_CONFIG.site_root.match(/^(.*?)\/*$/)[1]; + if (adminPath.substr(0, base.length) !== base) { + return null; + } + return '/' + adminPath.substr(base.length).match(/^\/*(.*?)\/*$/)[1]; + }, + getParentFsPath: function getParentFsPath(fsPath) { + return fsPath.match(/^(.*?)\/([^/]*)$/)[1]; + }, + getApiUrl: function getApiUrl(url) { + return $LEKTOR_CONFIG.admin_root + '/api' + url; + }, + loadData: function loadData(url, params, options, createPromise) { + options = options || {}; + return createPromise(function (resolve, reject) { + _jquery2.default.ajax({ + url: utils.getApiUrl(url), + data: params, + method: options.method || 'GET' + }).done(function (data) { + resolve(data); + }).fail(function () { + reject({ + code: 'REQUEST_FAILED' + }); + }); + }); + }, + apiRequest: function apiRequest(url, options, createPromise) { + options = options || {}; + options.url = utils.getApiUrl(url); + if (options.json !== undefined) { + options.data = JSON.stringify(options.json); + options.contentType = 'application/json'; + delete options.json; + } + if (!options.method) { + options.method = 'GET'; + } + + return createPromise(function (resolve, reject) { + _jquery2.default.ajax(options).done(function (data) { + resolve(data); + }).fail(function () { + reject({ + code: 'REQUEST_FAILED' + }); + }); + }); + }, + fsToUrlPath: function fsToUrlPath(fsPath) { + var segments = fsPath.match(/^\/*(.*?)\/*$/)[1].split('/'); + if (segments.length === 1 && segments[0] === '') { + segments = []; + } + segments.unshift('root'); + return segments.join(':'); + }, + urlToFsPath: function urlToFsPath(urlPath) { + var segments = urlPath.match(/^:*(.*?):*$/)[1].split(':'); + if (segments.length < 1 || segments[0] !== 'root') { + return null; + } + segments[0] = ''; + return segments.join('/'); + }, + urlPathToSegments: function urlPathToSegments(urlPath) { + if (!urlPath) { + return null; + } + var rv = urlPath.match(/^:*(.*?):*$/)[1].split('/'); + if (rv.length >= 1 && rv[0] === 'root') { + return rv.slice(1); + } + return null; + }, + scrolledToBottom: function scrolledToBottom() { + return document.body.offsetHeight + document.body.scrollTop >= document.body.scrollHeight; + }, + getPlatform: function getPlatform() { + if (navigator.appVersion.indexOf('Win') !== -1) { + return 'windows'; + } else if (navigator.appVersion.indexOf('Mac') !== -1) { + return 'mac'; + } else if (navigator.appVersion.indexOf('X11') !== -1 || navigator.appVersion.indexOf('Linux') !== -1) { + return 'linux'; + } + return 'other'; + }, + isMetaKey: function isMetaKey(event) { + if (utils.getPlatform() === 'mac') { + return event.metaKey; + } else { + return event.ctrlKey; + } + } +}; + +exports.default = utils; + +/***/ }), +/* 13 */, +/* 14 */, +/* 15 */, +/* 16 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + +var _dialogSystem = __webpack_require__(22); + +var _dialogSystem2 = _interopRequireDefault(_dialogSystem); + +var _BaseComponent2 = __webpack_require__(283); + +var _BaseComponent3 = _interopRequireDefault(_BaseComponent2); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var Component = function (_BaseComponent) { + _inherits(Component, _BaseComponent); + + function Component(props) { + _classCallCheck(this, Component); + + var _this = _possibleConstructorReturn(this, (Component.__proto__ || Object.getPrototypeOf(Component)).call(this, props)); + + _this._unlistenBeforeLeavingRoute = null; + return _this; + } + + /* helper function for forwarding props down the tree */ + + + _createClass(Component, [{ + key: 'getRoutingProps', + value: function getRoutingProps() { + return { + history: this.props.history, + location: this.props.location, + params: this.props.params, + route: this.props.route, + routeParams: this.props.routeParams, + routes: this.props.routes + }; + } + + /* helper that can generate a path to a rule */ + + }, { + key: 'getPathToAdminPage', + value: function getPathToAdminPage(name, params) { + var _this2 = this; + + var parts = this.props.routes.map(function (x) { + return x.name; + }); + if (name !== null) { + if (name.substr(0, 1) === '.') { + parts[parts.length - 1] = name.substr(1); + } else { + parts = name.split('.'); + } + } + + var rv = []; + var node = this.props.routes[0]; + if (node.name !== parts.shift()) { + return null; + } + rv.push(node.path); + + parts.forEach(function (part) { + for (var i = 0; i < node.childRoutes.length; i++) { + if (node.childRoutes[i].name === part) { + node = node.childRoutes[i]; + rv.push(node.path); + return; + } + } + node = null; + }); + + return rv.join('/').replace(/:[a-zA-Z]+/g, function (m) { + var key = m.substr(1); + return params[key] || _this2.props.params[key]; + }); + } + + /* helper to transition to a specific page */ + + }, { + key: 'transitionToAdminPage', + value: function transitionToAdminPage(name, params) { + this.props.history.pushState(null, this.getPathToAdminPage(name, params)); + } + }, { + key: 'componentDidMount', + value: function componentDidMount() { + _get(Component.prototype.__proto__ || Object.getPrototypeOf(Component.prototype), 'componentDidMount', this).call(this); + if (this.props.history !== undefined) { + this._unlistenBeforeLeavingRoute = this.props.history.listenBeforeLeavingRoute(this.props.route, this.routerWillLeave.bind(this)); + } + } + }, { + key: 'componentWillUnmount', + value: function componentWillUnmount() { + _get(Component.prototype.__proto__ || Object.getPrototypeOf(Component.prototype), 'componentWillUnmount', this).call(this); + if (this._unlistenBeforeLeavingRoute) { + this._unlistenBeforeLeavingRoute(); + } + } + }, { + key: 'routerWillLeave', + value: function routerWillLeave(nextLocation) { + if (_dialogSystem2.default.preventNavigation()) { + return false; + } else { + _dialogSystem2.default.dismissDialog(); + } + } + }]); + + return Component; +}(_BaseComponent3.default); + +exports.default = Component; + +/***/ }), +/* 17 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _errorDialog = __webpack_require__(326); + +var _errorDialog2 = _interopRequireDefault(_errorDialog); + +var _dialogSystem = __webpack_require__(22); + +var _dialogSystem2 = _interopRequireDefault(_dialogSystem); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var bringUpDialog = function bringUpDialog(error) { + if (!_dialogSystem2.default.dialogIsOpen()) { + _dialogSystem2.default.showDialog(_errorDialog2.default, { + error: error + }); + } +}; + +var makeRichPromise = function makeRichPromise(callback) { + var fallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : bringUpDialog; + + var rv = new Promise(callback); + var then = rv.then; + var hasRejectionHandler = false; + + rv.then(null, function (value) { + if (!hasRejectionHandler) { + return fallback(value); + } + }); + + rv.then = function (onFulfilled, onRejected) { + if (onRejected) { + hasRejectionHandler = true; + } + return then.call(rv, onFulfilled, onRejected); + }; + + return rv; +}; + +exports.default = makeRichPromise; + +/***/ }), +/* 18 */, +/* 19 */, +/* 20 */, +/* 21 */, +/* 22 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _hub = __webpack_require__(45); + +var _hub2 = _interopRequireDefault(_hub); + +var _events = __webpack_require__(46); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var DialogSystem = function () { + function DialogSystem() { + _classCallCheck(this, DialogSystem); + + this._dialogInstance = null; + } + + // invoked by the application once the dialog has been created. + + + _createClass(DialogSystem, [{ + key: 'notifyDialogInstance', + value: function notifyDialogInstance(dialog) { + this._dialogInstance = dialog; + } + + // given a dialog class this will instruct the application to bring up + // the dialog and display it. + + }, { + key: 'showDialog', + value: function showDialog(dialog, options) { + // if the current dialog prevents navigation, then we just silently + // will not show the dialog. + if (!this.preventNavigation()) { + _hub2.default.emit(new _events.DialogChangedEvent({ + dialog: dialog, + dialogOptions: options || {} + })); + } + } + + // tells the application to dismiss the current dialog. + + }, { + key: 'dismissDialog', + value: function dismissDialog() { + if (!this.preventNavigation()) { + _hub2.default.emit(new _events.DialogChangedEvent({ + currentDialog: null + })); + } + } + + // indicates if a dialog is shown + + }, { + key: 'dialogIsOpen', + value: function dialogIsOpen() { + return !!this._dialogInstance; + } + + // returns true if the current dialog prevents navigation. + + }, { + key: 'preventNavigation', + value: function preventNavigation() { + return this._dialogInstance && this._dialogInstance.preventNavigation !== undefined && this._dialogInstance.preventNavigation(); + } + }]); + + return DialogSystem; +}(); + +var dialogSystem = new DialogSystem(); + +exports.default = dialogSystem; + +/***/ }), +/* 23 */ +/***/ (function(module, exports, __webpack_require__) { + +/* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +if (process.env.NODE_ENV !== 'production') { + var REACT_ELEMENT_TYPE = (typeof Symbol === 'function' && + Symbol.for && + Symbol.for('react.element')) || + 0xeac7; + + var isValidElement = function(object) { + return typeof object === 'object' && + object !== null && + object.$$typeof === REACT_ELEMENT_TYPE; + }; + + // By explicitly using `prop-types` you are opting into new development behavior. + // http://fb.me/prop-types-in-prod + var throwOnDirectAccess = true; + module.exports = __webpack_require__(91)(isValidElement, throwOnDirectAccess); +} else { + // By explicitly using `prop-types` you are opting into new production behavior. + // http://fb.me/prop-types-in-prod + module.exports = __webpack_require__(154)(); +} + +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) + +/***/ }), +/* 24 */, +/* 25 */, +/* 26 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _Component2 = __webpack_require__(16); + +var _Component3 = _interopRequireDefault(_Component2); + +var _utils = __webpack_require__(12); + +var _utils2 = _interopRequireDefault(_utils); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +/* a react component baseclass that has some basic knowledge about + the record it works with. */ +var RecordComponent = function (_Component) { + _inherits(RecordComponent, _Component); + + function RecordComponent() { + _classCallCheck(this, RecordComponent); + + return _possibleConstructorReturn(this, (RecordComponent.__proto__ || Object.getPrototypeOf(RecordComponent)).apply(this, arguments)); + } + + _createClass(RecordComponent, [{ + key: 'isRecordPreviewActive', + + /* checks if the record preview is active. */ + value: function isRecordPreviewActive() { + var routes = this.props.routes; + return routes.length > 0 && routes[routes.length - 1].component.name === 'PreviewPage'; + } + + /* this returns the current record path segments as array */ + + }, { + key: 'getRecordPathSegments', + value: function getRecordPathSegments() { + var path = this.props.params.path; + return path ? _utils2.default.urlPathToSegments(path) : []; + } + }, { + key: '_getRecordPathAndAlt', + value: function _getRecordPathAndAlt() { + var path = this.props.params.path; + if (!path) { + return [null, null]; + } + var items = path.split(/\+/, 2); + return [_utils2.default.urlToFsPath(items[0]), items[1]]; + } + + /* this returns the path of the current record. If the current page does + * not have a path component then null is returned. */ + + }, { + key: 'getRecordPath', + value: function getRecordPath() { + var _getRecordPathAndAlt2 = this._getRecordPathAndAlt(), + _getRecordPathAndAlt3 = _slicedToArray(_getRecordPathAndAlt2, 1), + path = _getRecordPathAndAlt3[0]; + + return path; + } + + /* returns the current alt */ + + }, { + key: 'getRecordAlt', + value: function getRecordAlt() { + var _getRecordPathAndAlt4 = this._getRecordPathAndAlt(), + _getRecordPathAndAlt5 = _slicedToArray(_getRecordPathAndAlt4, 2), + alt = _getRecordPathAndAlt5[1]; + + return !alt ? '_primary' : alt; + } + + /* return the url path for the current record path (or a modified one) + by preserving or overriding the alt */ + + }, { + key: 'getUrlRecordPathWithAlt', + value: function getUrlRecordPathWithAlt(newPath, newAlt) { + if (newPath === undefined || newPath === null) { + newPath = this.getRecordPath(); + } + if (newAlt === undefined || newAlt === null) { + newAlt = this.getRecordAlt(); + } + var rv = _utils2.default.fsToUrlPath(newPath); + if (newAlt !== '_primary') { + rv += '+' + newAlt; + } + return rv; + } + + /* returns the parent path if available */ + + }, { + key: 'getParentRecordPath', + value: function getParentRecordPath() { + return _utils2.default.getParentFsPath(this.getRecordPath()); + } + + /* returns true if this is the root record */ + + }, { + key: 'isRootRecord', + value: function isRootRecord() { + return this.getRecordPath() === ''; + } + + /* returns the breadcrumbs for the current record path */ + + }, { + key: 'getRecordCrumbs', + value: function getRecordCrumbs() { + var segments = this.getRecordPathSegments(); + if (segments === null) { + return []; + } + + segments.unshift('root'); + + var rv = []; + for (var i = 0; i < segments.length; i++) { + var curpath = segments.slice(0, i + 1).join(':'); + rv.push({ + id: 'path:' + curpath, + urlPath: curpath, + segments: segments.slice(1, i + 1), + title: segments[i] + }); + } + + return rv; + } + }]); + + return RecordComponent; +}(_Component3.default); + +exports.default = RecordComponent; + +/***/ }), +/* 27 */, +/* 28 */, +/* 29 */, +/* 30 */, +/* 31 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +//import warning from 'warning' + + + +exports.__esModule = true; +function deprecate(fn) { + return fn; + //return function () { + // warning(false, '[history] ' + message) + // return fn.apply(this, arguments) + //} +} + +exports["default"] = deprecate; +module.exports = exports["default"]; + +/***/ }), +/* 32 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(process) { + +exports.__esModule = true; + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +var _warning = __webpack_require__(33); + +var _warning2 = _interopRequireDefault(_warning); + +var _extractPath = __webpack_require__(139); + +var _extractPath2 = _interopRequireDefault(_extractPath); + +function parsePath(path) { + var pathname = _extractPath2['default'](path); + var search = ''; + var hash = ''; + + process.env.NODE_ENV !== 'production' ? _warning2['default'](path === pathname, 'A path must be pathname + search + hash only, not a fully qualified URL like "%s"', path) : undefined; + + var hashIndex = pathname.indexOf('#'); + if (hashIndex !== -1) { + hash = pathname.substring(hashIndex); + pathname = pathname.substring(0, hashIndex); + } + + var searchIndex = pathname.indexOf('?'); + if (searchIndex !== -1) { + search = pathname.substring(searchIndex); + pathname = pathname.substring(0, searchIndex); + } + + if (pathname === '') pathname = '/'; + + return { + pathname: pathname, + search: search, + hash: hash + }; +} + +exports['default'] = parsePath; +module.exports = exports['default']; +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) + +/***/ }), +/* 33 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2014-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + + + +/** + * Similar to invariant but only logs a warning if the condition is not met. + * This can be used to log issues in development environments in critical + * paths. Removing the logging code for production environments will keep the + * same logic and follow the same code paths. + */ + +var warning = function() {}; + +if (process.env.NODE_ENV !== 'production') { + warning = function(condition, format, args) { + var len = arguments.length; + args = new Array(len > 2 ? len - 2 : 0); + for (var key = 2; key < len; key++) { + args[key - 2] = arguments[key]; + } + if (format === undefined) { + throw new Error( + '`warning(condition, format, ...args)` requires a warning ' + + 'message argument' + ); + } + + if (format.length < 10 || (/^[s\W]*$/).test(format)) { + throw new Error( + 'The warning format should be able to uniquely identify this ' + + 'warning. Please, use a more descriptive format than: ' + format + ); + } + + if (!condition) { + var argIndex = 0; + var message = 'Warning: ' + + format.replace(/%s/g, function() { + return args[argIndex++]; + }); + if (typeof console !== 'undefined') { + console.error(message); + } + try { + // This error was thrown as a convenience so that you can use this stack + // to find the callsite that caused this warning to fire. + throw new Error(message); + } catch(x) {} + } + }; +} + +module.exports = warning; + +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) + +/***/ }), +/* 34 */, +/* 35 */, +/* 36 */, +/* 37 */, +/* 38 */, +/* 39 */, +/* 40 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/** + * Indicates that navigation was caused by a call to history.push. + */ + + +exports.__esModule = true; +var PUSH = 'PUSH'; + +exports.PUSH = PUSH; +/** + * Indicates that navigation was caused by a call to history.replace. + */ +var REPLACE = 'REPLACE'; + +exports.REPLACE = REPLACE; +/** + * Indicates that navigation was caused by some other action such + * as using a browser's back/forward buttons and/or manually manipulating + * the URL in a browser's location bar. This is the default. + * + * See https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate + * for more information. + */ +var POP = 'POP'; + +exports.POP = POP; +exports['default'] = { + PUSH: PUSH, + REPLACE: REPLACE, + POP: POP +}; + +/***/ }), +/* 41 */, +/* 42 */, +/* 43 */, +/* 44 */, +/* 45 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Hub = function () { + function Hub() { + _classCallCheck(this, Hub); + + this._subscriptions = {}; + } + + /* subscribes a callback to an event */ + + + _createClass(Hub, [{ + key: 'subscribe', + value: function subscribe(event, callback) { + if (typeof event !== 'string') { + event = event.getEventType(); + } + + var subs = this._subscriptions[event]; + if (subs === undefined) { + this._subscriptions[event] = subs = []; + } + + for (var i = 0; i < subs.length; i++) { + if (subs[i] === callback) { + return false; + } + } + + subs.push(callback); + return true; + } + + /* unsubscribes a callback from an event */ + + }, { + key: 'unsubscribe', + value: function unsubscribe(event, callback) { + if (typeof event !== 'string') { + event = event.getEventType(); + } + + var subs = this._subscriptions[event]; + if (subs === undefined) { + return false; + } + + for (var i = 0; i < subs.length; i++) { + if (subs[i] === callback) { + subs.splice(i, 1); + return true; + } + } + return false; + } + + /* emits an event with some parameters */ + + }, { + key: 'emit', + value: function emit(event) { + var subs = this._subscriptions[event.type]; + if (subs !== undefined) { + subs.forEach(function (callback) { + try { + callback(event); + } catch (e) { + console.log('Event callback failed: ', e, 'callback=', callback, 'event=', event); + } + }); + } + } + }]); + + return Hub; +}(); + +var hub = new Hub(); + +exports.default = hub; + +/***/ }), +/* 46 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Event = function () { + function Event() { + _classCallCheck(this, Event); + } + + _createClass(Event, [{ + key: 'toString', + value: function toString() { + return '[Event ' + this.type + ']'; + } + }, { + key: 'type', + get: function get() { + return Object.getPrototypeOf(this).constructor.getEventType(); + } + }]); + + return Event; +}(); + +Event.getEventType = function () { + return this.name; +}; + +var RecordEvent = function (_Event) { + _inherits(RecordEvent, _Event); + + function RecordEvent(options) { + _classCallCheck(this, RecordEvent); + + var _this = _possibleConstructorReturn(this, (RecordEvent.__proto__ || Object.getPrototypeOf(RecordEvent)).call(this, options = options || {})); + + _this.recordPath = options.recordPath; + return _this; + } + + return RecordEvent; +}(Event); + +var AttachmentsChangedEvent = function (_RecordEvent) { + _inherits(AttachmentsChangedEvent, _RecordEvent); + + function AttachmentsChangedEvent(options) { + _classCallCheck(this, AttachmentsChangedEvent); + + var _this2 = _possibleConstructorReturn(this, (AttachmentsChangedEvent.__proto__ || Object.getPrototypeOf(AttachmentsChangedEvent)).call(this, options = options || {})); + + _this2.attachmentsAdded = options.attachmentsAdded || []; + _this2.attachmentsRemoved = options.attachmentsRemoved || []; + return _this2; + } + + return AttachmentsChangedEvent; +}(RecordEvent); + +var DialogChangedEvent = function (_Event2) { + _inherits(DialogChangedEvent, _Event2); + + function DialogChangedEvent(options) { + _classCallCheck(this, DialogChangedEvent); + + var _this3 = _possibleConstructorReturn(this, (DialogChangedEvent.__proto__ || Object.getPrototypeOf(DialogChangedEvent)).call(this, options = options || {})); + + _this3.dialog = options.dialog; + _this3.dialogOptions = options.dialogOptions; + return _this3; + } + + return DialogChangedEvent; +}(Event); + +exports.Event = Event; +exports.RecordEvent = RecordEvent; +exports.AttachmentsChangedEvent = AttachmentsChangedEvent; +exports.DialogChangedEvent = DialogChangedEvent; + +/***/ }), +/* 47 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +exports.__esModule = true; +var canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement); +exports.canUseDOM = canUseDOM; + +/***/ }), +/* 48 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.BasicWidgetMixin = exports.ValidationFailure = undefined; + +var _propTypes = __webpack_require__(23); + +var _propTypes2 = _interopRequireDefault(_propTypes); + +var _i18n = __webpack_require__(7); + +var _i18n2 = _interopRequireDefault(_i18n); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function ValidationFailure(options) { + this.message = options.message || _i18n2.default.trans('INVALID_INPUT'); + this.type = options.type || 'error'; +} + +var BasicWidgetMixin = { + propTypes: { + value: _propTypes2.default.any, + type: _propTypes2.default.object, + placeholder: _propTypes2.default.any, + onChange: _propTypes2.default.func + }, + + getInputClass: function getInputClass() { + var rv = 'form-control'; + if (this.props.type.size === 'small') { + rv = 'input-sm ' + rv; + } else if (this.props.type.size === 'large') { + rv = 'input-lg ' + rv; + } + return rv; + }, + getValidationFailure: function getValidationFailure() { + if (this.getValidationFailureImpl) { + return this.getValidationFailureImpl(); + } + return null; + } +}; + +exports.ValidationFailure = ValidationFailure; +exports.BasicWidgetMixin = BasicWidgetMixin; + +/***/ }), +/* 49 */, +/* 50 */, +/* 51 */, +/* 52 */, +/* 53 */, +/* 54 */, +/* 55 */, +/* 56 */, +/* 57 */, +/* 58 */, +/* 59 */, +/* 60 */, +/* 61 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +exports.__esModule = true; +exports.addEventListener = addEventListener; +exports.removeEventListener = removeEventListener; +exports.getHashPath = getHashPath; +exports.replaceHashPath = replaceHashPath; +exports.getWindowPath = getWindowPath; +exports.go = go; +exports.getUserConfirmation = getUserConfirmation; +exports.supportsHistory = supportsHistory; +exports.supportsGoWithoutReloadUsingHash = supportsGoWithoutReloadUsingHash; + +function addEventListener(node, event, listener) { + if (node.addEventListener) { + node.addEventListener(event, listener, false); + } else { + node.attachEvent('on' + event, listener); + } +} + +function removeEventListener(node, event, listener) { + if (node.removeEventListener) { + node.removeEventListener(event, listener, false); + } else { + node.detachEvent('on' + event, listener); + } +} + +function getHashPath() { + // We can't use window.location.hash here because it's not + // consistent across browsers - Firefox will pre-decode it! + return window.location.href.split('#')[1] || ''; +} + +function replaceHashPath(path) { + window.location.replace(window.location.pathname + window.location.search + '#' + path); +} + +function getWindowPath() { + return window.location.pathname + window.location.search + window.location.hash; +} + +function go(n) { + if (n) window.history.go(n); +} + +function getUserConfirmation(message, callback) { + callback(window.confirm(message)); +} + +/** + * Returns true if the HTML5 history API is supported. Taken from Modernizr. + * + * https://github.com/Modernizr/Modernizr/blob/master/LICENSE + * https://github.com/Modernizr/Modernizr/blob/master/feature-detects/history.js + * changed to avoid false negatives for Windows Phones: https://github.com/rackt/react-router/issues/586 + */ + +function supportsHistory() { + var ua = navigator.userAgent; + if ((ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) && ua.indexOf('Mobile Safari') !== -1 && ua.indexOf('Chrome') === -1 && ua.indexOf('Windows Phone') === -1) { + return false; + } + // FIXME: Work around our browser history not working correctly on Chrome + // iOS: https://github.com/rackt/react-router/issues/2565 + if (ua.indexOf('CriOS') !== -1) { + return false; + } + return window.history && 'pushState' in window.history; +} + +/** + * Returns false if using go(n) with hash history causes a full page reload. + */ + +function supportsGoWithoutReloadUsingHash() { + var ua = navigator.userAgent; + return ua.indexOf('Firefox') === -1; +} + +/***/ }), +/* 62 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + +var _propTypes = __webpack_require__(23); + +var _propTypes2 = _interopRequireDefault(_propTypes); + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +var _Component2 = __webpack_require__(16); + +var _Component3 = _interopRequireDefault(_Component2); + +var _dialogSystem = __webpack_require__(22); + +var _dialogSystem2 = _interopRequireDefault(_dialogSystem); + +var _i18n = __webpack_require__(7); + +var _i18n2 = _interopRequireDefault(_i18n); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var SlideDialog = function (_Component) { + _inherits(SlideDialog, _Component); + + function SlideDialog(props) { + _classCallCheck(this, SlideDialog); + + var _this = _possibleConstructorReturn(this, (SlideDialog.__proto__ || Object.getPrototypeOf(SlideDialog)).call(this, props)); + + _this._onKeyPress = _this._onKeyPress.bind(_this); + return _this; + } + + _createClass(SlideDialog, [{ + key: 'componentDidMount', + value: function componentDidMount() { + _get(SlideDialog.prototype.__proto__ || Object.getPrototypeOf(SlideDialog.prototype), 'componentDidMount', this).call(this); + if (this.props.closeOnEscape) { + window.addEventListener('keydown', this._onKeyPress); + } + } + }, { + key: 'componentWillUnmount', + value: function componentWillUnmount() { + window.removeEventListener('keydown', this._onKeyPress); + _get(SlideDialog.prototype.__proto__ || Object.getPrototypeOf(SlideDialog.prototype), 'componentWillUnmount', this).call(this); + } + }, { + key: '_onKeyPress', + value: function _onKeyPress(event) { + if (event.which === 27 && this.props.closeOnEscape) { + event.preventDefault(); + _dialogSystem2.default.dismissDialog(); + } + } + }, { + key: '_onCloseClick', + value: function _onCloseClick(event) { + event.preventDefault(); + _dialogSystem2.default.dismissDialog(); + } + }, { + key: 'render', + value: function render() { + var _props = this.props, + children = _props.children, + title = _props.title, + hasCloseButton = _props.hasCloseButton, + className = _props.className, + props = _objectWithoutProperties(_props, ['children', 'title', 'hasCloseButton', 'className']); + + className = (className || '') + ' sliding-panel container'; + return _react2.default.createElement( + 'div', + _extends({ className: className }, props), + _react2.default.createElement( + 'div', + { className: 'col-md-6 col-md-offset-4' }, + hasCloseButton && _react2.default.createElement( + 'a', + { + href: '#', + className: 'close-btn', + onClick: this._onCloseClick.bind(this) + }, + _i18n2.default.trans('CLOSE') + ), + _react2.default.createElement( + 'h3', + null, + title + ), + children + ) + ); + } + }]); + + return SlideDialog; +}(_Component3.default); + +SlideDialog.propTypes = { + title: _propTypes2.default.string, + hasCloseButton: _propTypes2.default.bool, + closeOnEscape: _propTypes2.default.bool +}; + +exports.default = SlideDialog; + +/***/ }), +/* 63 */, +/* 64 */, +/* 65 */, +/* 66 */, +/* 67 */, +/* 68 */, +/* 69 */, +/* 70 */, +/* 71 */, +/* 72 */, +/* 73 */, +/* 74 */, +/* 75 */, +/* 76 */, +/* 77 */, +/* 78 */, +/* 79 */, +/* 80 */, +/* 81 */, +/* 82 */, +/* 83 */, +/* 84 */, +/* 85 */, +/* 86 */, +/* 87 */, +/* 88 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(process) { + +exports.__esModule = true; + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +var _warning = __webpack_require__(33); + +var _warning2 = _interopRequireDefault(_warning); + +function runTransitionHook(hook, location, callback) { + var result = hook(location, callback); + + if (hook.length < 2) { + // Assume the hook runs synchronously and automatically + // call the callback with the return value. + callback(result); + } else { + process.env.NODE_ENV !== 'production' ? _warning2['default'](result === undefined, 'You should not "return" in a transition hook with a callback argument; call the callback instead') : undefined; + } +} + +exports['default'] = runTransitionHook; +module.exports = exports['default']; +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) + +/***/ }), +/* 89 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _propTypes = __webpack_require__(23); + +var _propTypes2 = _interopRequireDefault(_propTypes); + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +var _primitiveWidgets = __webpack_require__(334); + +var _primitiveWidgets2 = _interopRequireDefault(_primitiveWidgets); + +var _multiWidgets = __webpack_require__(335); + +var _multiWidgets2 = _interopRequireDefault(_multiWidgets); + +var _flowWidget = __webpack_require__(336); + +var _flowWidget2 = _interopRequireDefault(_flowWidget); + +var _fakeWidgets = __webpack_require__(338); + +var _fakeWidgets2 = _interopRequireDefault(_fakeWidgets); + +var _mixins = __webpack_require__(48); + +var _Component2 = __webpack_require__(16); + +var _Component3 = _interopRequireDefault(_Component2); + +var _ToggleGroup = __webpack_require__(339); + +var _ToggleGroup2 = _interopRequireDefault(_ToggleGroup); + +var _i18n = __webpack_require__(7); + +var _i18n2 = _interopRequireDefault(_i18n); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var widgetComponents = { + 'singleline-text': _primitiveWidgets2.default.SingleLineTextInputWidget, + 'multiline-text': _primitiveWidgets2.default.MultiLineTextInputWidget, + 'datepicker': _primitiveWidgets2.default.DateInputWidget, + 'integer': _primitiveWidgets2.default.IntegerInputWidget, + 'float': _primitiveWidgets2.default.FloatInputWidget, + 'checkbox': _primitiveWidgets2.default.BooleanInputWidget, + 'url': _primitiveWidgets2.default.UrlInputWidget, + 'slug': _primitiveWidgets2.default.SlugInputWidget, + 'flow': _flowWidget2.default.FlowWidget, + 'checkboxes': _multiWidgets2.default.CheckboxesInputWidget, + 'select': _multiWidgets2.default.SelectInputWidget, + 'f-line': _fakeWidgets2.default.LineWidget, + 'f-spacing': _fakeWidgets2.default.SpacingWidget, + 'f-info': _fakeWidgets2.default.InfoWidget, + 'f-heading': _fakeWidgets2.default.HeadingWidget +}; + +var FallbackWidget = _react2.default.createClass({ + displayName: 'FallbackWidget', + + mixins: [_mixins.BasicWidgetMixin], + render: function render() { + return _react2.default.createElement( + 'div', + null, + _react2.default.createElement( + 'em', + null, + 'Widget "', + this.props.type.widget, + '" not implemented (used by type "', + this.props.type.name, + '")' + ) + ); + } +}); + +var FieldBox = function (_Component) { + _inherits(FieldBox, _Component); + + function FieldBox() { + _classCallCheck(this, FieldBox); + + return _possibleConstructorReturn(this, (FieldBox.__proto__ || Object.getPrototypeOf(FieldBox)).apply(this, arguments)); + } + + _createClass(FieldBox, [{ + key: 'render', + value: function render() { + var _props = this.props, + field = _props.field, + value = _props.value, + onChange = _props.onChange, + placeholder = _props.placeholder, + disabled = _props.disabled; + + var className = 'col-md-' + getFieldColumns(field) + ' field-box'; + var innerClassName = 'field'; + var inner = void 0; + + if (field.name.substr(0, 1) === '_') { + innerClassName += ' system-field'; + } + + var Widget = getWidgetComponentWithFallback(field.type); + if (Widget.isFakeWidget) { + inner = _react2.default.createElement(Widget, { key: field.name, type: field.type, field: field }); + } else { + var description = null; + if (field.description_i18n) { + description = _react2.default.createElement( + 'div', + { className: 'help-text' }, + _i18n2.default.trans(field.description_i18n) + ); + } + inner = _react2.default.createElement( + 'dl', + { className: innerClassName }, + !field.hide_label ? _react2.default.createElement( + 'dt', + null, + _i18n2.default.trans(field.label_i18n) + ) : null, + _react2.default.createElement( + 'dd', + null, + description, + _react2.default.createElement(Widget, { + value: value, + onChange: onChange, + type: field.type, + placeholder: placeholder, + disabled: disabled + }) + ) + ); + } + + return _react2.default.createElement( + 'div', + { className: className, key: field.name }, + inner + ); + } + }]); + + return FieldBox; +}(_Component3.default); + +FieldBox.propTypes = { + value: _propTypes2.default.any, + onChange: _propTypes2.default.func, + field: _propTypes2.default.any, + placeholder: _propTypes2.default.any +}; + +var getWidgetComponent = function getWidgetComponent(type) { + return widgetComponents[type.widget] || null; +}; + +var getWidgetComponentWithFallback = function getWidgetComponentWithFallback(type) { + return widgetComponents[type.widget] || FallbackWidget; +}; + +var getFieldColumns = function getFieldColumns(field) { + var widthSpec = (field.type.width || '1/1').split('/'); + return Math.min(12, Math.max(2, parseInt(12 * +widthSpec[0] / +widthSpec[1]))); +}; + +var getFieldRows = function getFieldRows(fields, isIllegalField) { + var normalFields = []; + var systemFields = []; + + if (!isIllegalField) { + isIllegalField = function isIllegalField(x) { + return false; + }; + } + + fields.forEach(function (field) { + if (!isIllegalField(field)) { + if (field.name.substr(0, 1) === '_') { + systemFields.push(field); + } else { + normalFields.push(field); + } + } + }); + + var processFields = function processFields(rv, rowType, fields) { + var currentColumns = 0; + var row = []; + + fields.forEach(function (field) { + var columns = getFieldColumns(field); + if (columns + currentColumns > 12) { + rv.push([rowType, row]); + currentColumns = 0; + row = []; + } + row.push(field); + currentColumns += columns; + }); + + if (row.length > 0) { + rv.push([rowType, row]); + } + }; + + var rv = []; + processFields(rv, 'normal', normalFields); + processFields(rv, 'system', systemFields); + return rv; +}; + +var renderFieldRows = function renderFieldRows(fields, isIllegalField, renderFunc) { + var rv = { + normal: [], + system: [] + }; + + var rows = getFieldRows(fields, isIllegalField); + + rows.forEach(function (item, idx) { + var _item = _slicedToArray(item, 2), + rowType = _item[0], + row = _item[1]; + + rv[rowType].push(_react2.default.createElement( + 'div', + { className: 'row field-row', key: rowType + '-' + idx }, + row.map(renderFunc) + )); + }); + + return [rv.normal, rv.system.length > 1 ? _react2.default.createElement( + _ToggleGroup2.default, + { + key: 'sys', + groupTitle: _i18n2.default.trans('SYSTEM_FIELDS'), + defaultVisibility: false }, + rv.system + ) : null]; +}; + +exports.default = { + getWidgetComponent: getWidgetComponent, + getWidgetComponentWithFallback: getWidgetComponentWithFallback, + getFieldRows: getFieldRows, + renderFieldRows: renderFieldRows, + getFieldColumns: getFieldColumns, + FallbackWidget: FallbackWidget, + FieldBox: FieldBox +}; + +/***/ }), +/* 90 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +var _i18n = __webpack_require__(7); + +var _i18n2 = _interopRequireDefault(_i18n); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var userLabel = { + + // formats a user label appropriately + format: function format(inputConfig) { + var label = null; + if (typeof inputConfig === 'string') { + label = inputConfig; + } else { + label = _i18n2.default.trans(inputConfig); + } + if (!label) { + return _react2.default.createElement('span', { className: '' }); + } + + var iconData = label.match(/^\[\[\s*(.*?)\s*(;\s*(.*?))?\s*\]\]$/); // eslint-disable-line no-useless-escape + if (iconData) { + var className = 'fa fa-' + iconData[1]; + if ((iconData[3] || '').match(/90|180|270/)) { + className += ' fa-rotate-' + iconData[3]; + } + return _react2.default.createElement('i', { className: className }); + } + + return _react2.default.createElement( + 'span', + null, + label + ); + } +}; + +exports.default = userLabel; + +/***/ }), +/* 91 */, +/* 92 */, +/* 93 */, +/* 94 */, +/* 95 */, +/* 96 */, +/* 97 */, +/* 98 */, +/* 99 */, +/* 100 */, +/* 101 */, +/* 102 */, +/* 103 */, +/* 104 */, +/* 105 */, +/* 106 */, +/* 107 */, +/* 108 */, +/* 109 */, +/* 110 */, +/* 111 */, +/* 112 */, +/* 113 */, +/* 114 */, +/* 115 */, +/* 116 */, +/* 117 */, +/* 118 */, +/* 119 */, +/* 120 */, +/* 121 */, +/* 122 */, +/* 123 */, +/* 124 */, +/* 125 */, +/* 126 */, +/* 127 */, +/* 128 */, +/* 129 */, +/* 130 */, +/* 131 */, +/* 132 */, +/* 133 */, +/* 134 */, +/* 135 */, +/* 136 */, +/* 137 */, +/* 138 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +//import warning from 'warning' + + +exports.__esModule = true; + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +var _Actions = __webpack_require__(40); + +var _parsePath = __webpack_require__(32); + +var _parsePath2 = _interopRequireDefault(_parsePath); + +function createLocation() { + var location = arguments.length <= 0 || arguments[0] === undefined ? '/' : arguments[0]; + var action = arguments.length <= 1 || arguments[1] === undefined ? _Actions.POP : arguments[1]; + var key = arguments.length <= 2 || arguments[2] === undefined ? null : arguments[2]; + + var _fourthArg = arguments.length <= 3 || arguments[3] === undefined ? null : arguments[3]; + + if (typeof location === 'string') location = _parsePath2['default'](location); + + if (typeof action === 'object') { + //warning( + // false, + // 'The state (2nd) argument to createLocation is deprecated; use a ' + + // 'location descriptor instead' + //) + + location = _extends({}, location, { state: action }); + + action = key || _Actions.POP; + key = _fourthArg; + } + + var pathname = location.pathname || '/'; + var search = location.search || ''; + var hash = location.hash || ''; + var state = location.state || null; + + return { + pathname: pathname, + search: search, + hash: hash, + state: state, + action: action, + key: key + }; +} + +exports['default'] = createLocation; +module.exports = exports['default']; + +/***/ }), +/* 139 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +exports.__esModule = true; +function extractPath(string) { + var match = string.match(/^https?:\/\/[^\/]*/); + + if (match == null) return string; + + return string.substring(match[0].length); +} + +exports["default"] = extractPath; +module.exports = exports["default"]; + +/***/ }), +/* 140 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(process) { + +exports.__esModule = true; + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +var _invariant = __webpack_require__(8); + +var _invariant2 = _interopRequireDefault(_invariant); + +var _Actions = __webpack_require__(40); + +var _ExecutionEnvironment = __webpack_require__(47); + +var _DOMUtils = __webpack_require__(61); + +var _DOMStateStorage = __webpack_require__(141); + +var _createDOMHistory = __webpack_require__(142); + +var _createDOMHistory2 = _interopRequireDefault(_createDOMHistory); + +var _parsePath = __webpack_require__(32); + +var _parsePath2 = _interopRequireDefault(_parsePath); + +/** + * Creates and returns a history object that uses HTML5's history API + * (pushState, replaceState, and the popstate event) to manage history. + * This is the recommended method of managing history in browsers because + * it provides the cleanest URLs. + * + * Note: In browsers that do not support the HTML5 history API full + * page reloads will be used to preserve URLs. + */ +function createBrowserHistory() { + var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; + + !_ExecutionEnvironment.canUseDOM ? process.env.NODE_ENV !== 'production' ? _invariant2['default'](false, 'Browser history needs a DOM') : _invariant2['default'](false) : undefined; + + var forceRefresh = options.forceRefresh; + + var isSupported = _DOMUtils.supportsHistory(); + var useRefresh = !isSupported || forceRefresh; + + function getCurrentLocation(historyState) { + historyState = historyState || window.history.state || {}; + + var path = _DOMUtils.getWindowPath(); + var _historyState = historyState; + var key = _historyState.key; + + var state = undefined; + if (key) { + state = _DOMStateStorage.readState(key); + } else { + state = null; + key = history.createKey(); + + if (isSupported) window.history.replaceState(_extends({}, historyState, { key: key }), null, path); + } + + var location = _parsePath2['default'](path); + + return history.createLocation(_extends({}, location, { state: state }), undefined, key); + } + + function startPopStateListener(_ref) { + var transitionTo = _ref.transitionTo; + + function popStateListener(event) { + if (event.state === undefined) return; // Ignore extraneous popstate events in WebKit. + + transitionTo(getCurrentLocation(event.state)); + } + + _DOMUtils.addEventListener(window, 'popstate', popStateListener); + + return function () { + _DOMUtils.removeEventListener(window, 'popstate', popStateListener); + }; + } + + function finishTransition(location) { + var basename = location.basename; + var pathname = location.pathname; + var search = location.search; + var hash = location.hash; + var state = location.state; + var action = location.action; + var key = location.key; + + if (action === _Actions.POP) return; // Nothing to do. + + _DOMStateStorage.saveState(key, state); + + var path = (basename || '') + pathname + search + hash; + var historyState = { + key: key + }; + + if (action === _Actions.PUSH) { + if (useRefresh) { + window.location.href = path; + return false; // Prevent location update. + } else { + window.history.pushState(historyState, null, path); + } + } else { + // REPLACE + if (useRefresh) { + window.location.replace(path); + return false; // Prevent location update. + } else { + window.history.replaceState(historyState, null, path); + } + } + } + + var history = _createDOMHistory2['default'](_extends({}, options, { + getCurrentLocation: getCurrentLocation, + finishTransition: finishTransition, + saveState: _DOMStateStorage.saveState + })); + + var listenerCount = 0, + stopPopStateListener = undefined; + + function listenBefore(listener) { + if (++listenerCount === 1) stopPopStateListener = startPopStateListener(history); + + var unlisten = history.listenBefore(listener); + + return function () { + unlisten(); + + if (--listenerCount === 0) stopPopStateListener(); + }; + } + + function listen(listener) { + if (++listenerCount === 1) stopPopStateListener = startPopStateListener(history); + + var unlisten = history.listen(listener); + + return function () { + unlisten(); + + if (--listenerCount === 0) stopPopStateListener(); + }; + } + + // deprecated + function registerTransitionHook(hook) { + if (++listenerCount === 1) stopPopStateListener = startPopStateListener(history); + + history.registerTransitionHook(hook); + } + + // deprecated + function unregisterTransitionHook(hook) { + history.unregisterTransitionHook(hook); + + if (--listenerCount === 0) stopPopStateListener(); + } + + return _extends({}, history, { + listenBefore: listenBefore, + listen: listen, + registerTransitionHook: registerTransitionHook, + unregisterTransitionHook: unregisterTransitionHook + }); +} + +exports['default'] = createBrowserHistory; +module.exports = exports['default']; +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) + +/***/ }), +/* 141 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(process) {/*eslint-disable no-empty */ + + +exports.__esModule = true; +exports.saveState = saveState; +exports.readState = readState; + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +var _warning = __webpack_require__(33); + +var _warning2 = _interopRequireDefault(_warning); + +var KeyPrefix = '@@History/'; +var QuotaExceededError = 'QuotaExceededError'; +var SecurityError = 'SecurityError'; + +function createKey(key) { + return KeyPrefix + key; +} + +function saveState(key, state) { + try { + window.sessionStorage.setItem(createKey(key), JSON.stringify(state)); + } catch (error) { + if (error.name === SecurityError) { + // Blocking cookies in Chrome/Firefox/Safari throws SecurityError on any + // attempt to access window.sessionStorage. + process.env.NODE_ENV !== 'production' ? _warning2['default'](false, '[history] Unable to save state; sessionStorage is not available due to security settings') : undefined; + + return; + } + + if (error.name === QuotaExceededError && window.sessionStorage.length === 0) { + // Safari "private mode" throws QuotaExceededError. + process.env.NODE_ENV !== 'production' ? _warning2['default'](false, '[history] Unable to save state; sessionStorage is not available in Safari private mode') : undefined; + + return; + } + + throw error; + } +} + +function readState(key) { + var json = undefined; + try { + json = window.sessionStorage.getItem(createKey(key)); + } catch (error) { + if (error.name === SecurityError) { + // Blocking cookies in Chrome/Firefox/Safari throws SecurityError on any + // attempt to access window.sessionStorage. + process.env.NODE_ENV !== 'production' ? _warning2['default'](false, '[history] Unable to read state; sessionStorage is not available due to security settings') : undefined; + + return null; + } + } + + if (json) { + try { + return JSON.parse(json); + } catch (error) { + // Ignore invalid JSON. + } + } + + return null; +} +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) + +/***/ }), +/* 142 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(process) { + +exports.__esModule = true; + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +var _invariant = __webpack_require__(8); + +var _invariant2 = _interopRequireDefault(_invariant); + +var _ExecutionEnvironment = __webpack_require__(47); + +var _DOMUtils = __webpack_require__(61); + +var _createHistory = __webpack_require__(143); + +var _createHistory2 = _interopRequireDefault(_createHistory); + +function createDOMHistory(options) { + var history = _createHistory2['default'](_extends({ + getUserConfirmation: _DOMUtils.getUserConfirmation + }, options, { + go: _DOMUtils.go + })); + + function listen(listener) { + !_ExecutionEnvironment.canUseDOM ? process.env.NODE_ENV !== 'production' ? _invariant2['default'](false, 'DOM history needs a DOM') : _invariant2['default'](false) : undefined; + + return history.listen(listener); + } + + return _extends({}, history, { + listen: listen + }); +} + +exports['default'] = createDOMHistory; +module.exports = exports['default']; +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) + +/***/ }), +/* 143 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +//import warning from 'warning' + + +exports.__esModule = true; + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +var _deepEqual = __webpack_require__(128); + +var _deepEqual2 = _interopRequireDefault(_deepEqual); + +var _AsyncUtils = __webpack_require__(299); + +var _Actions = __webpack_require__(40); + +var _createLocation2 = __webpack_require__(138); + +var _createLocation3 = _interopRequireDefault(_createLocation2); + +var _runTransitionHook = __webpack_require__(88); + +var _runTransitionHook2 = _interopRequireDefault(_runTransitionHook); + +var _parsePath = __webpack_require__(32); + +var _parsePath2 = _interopRequireDefault(_parsePath); + +var _deprecate = __webpack_require__(31); + +var _deprecate2 = _interopRequireDefault(_deprecate); + +function createRandomKey(length) { + return Math.random().toString(36).substr(2, length); +} + +function locationsAreEqual(a, b) { + return a.pathname === b.pathname && a.search === b.search && + //a.action === b.action && // Different action !== location change. + a.key === b.key && _deepEqual2['default'](a.state, b.state); +} + +var DefaultKeyLength = 6; + +function createHistory() { + var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; + var getCurrentLocation = options.getCurrentLocation; + var finishTransition = options.finishTransition; + var saveState = options.saveState; + var go = options.go; + var keyLength = options.keyLength; + var getUserConfirmation = options.getUserConfirmation; + + if (typeof keyLength !== 'number') keyLength = DefaultKeyLength; + + var transitionHooks = []; + + function listenBefore(hook) { + transitionHooks.push(hook); + + return function () { + transitionHooks = transitionHooks.filter(function (item) { + return item !== hook; + }); + }; + } + + var allKeys = []; + var changeListeners = []; + var location = undefined; + + function getCurrent() { + if (pendingLocation && pendingLocation.action === _Actions.POP) { + return allKeys.indexOf(pendingLocation.key); + } else if (location) { + return allKeys.indexOf(location.key); + } else { + return -1; + } + } + + function updateLocation(newLocation) { + var current = getCurrent(); + + location = newLocation; + + if (location.action === _Actions.PUSH) { + allKeys = [].concat(allKeys.slice(0, current + 1), [location.key]); + } else if (location.action === _Actions.REPLACE) { + allKeys[current] = location.key; + } + + changeListeners.forEach(function (listener) { + listener(location); + }); + } + + function listen(listener) { + changeListeners.push(listener); + + if (location) { + listener(location); + } else { + var _location = getCurrentLocation(); + allKeys = [_location.key]; + updateLocation(_location); + } + + return function () { + changeListeners = changeListeners.filter(function (item) { + return item !== listener; + }); + }; + } + + function confirmTransitionTo(location, callback) { + _AsyncUtils.loopAsync(transitionHooks.length, function (index, next, done) { + _runTransitionHook2['default'](transitionHooks[index], location, function (result) { + if (result != null) { + done(result); + } else { + next(); + } + }); + }, function (message) { + if (getUserConfirmation && typeof message === 'string') { + getUserConfirmation(message, function (ok) { + callback(ok !== false); + }); + } else { + callback(message !== false); + } + }); + } + + var pendingLocation = undefined; + + function transitionTo(nextLocation) { + if (location && locationsAreEqual(location, nextLocation)) return; // Nothing to do. + + pendingLocation = nextLocation; + + confirmTransitionTo(nextLocation, function (ok) { + if (pendingLocation !== nextLocation) return; // Transition was interrupted. + + if (ok) { + // treat PUSH to current path like REPLACE to be consistent with browsers + if (nextLocation.action === _Actions.PUSH) { + var prevPath = createPath(location); + var nextPath = createPath(nextLocation); + + if (nextPath === prevPath) nextLocation.action = _Actions.REPLACE; + } + + if (finishTransition(nextLocation) !== false) updateLocation(nextLocation); + } else if (location && nextLocation.action === _Actions.POP) { + var prevIndex = allKeys.indexOf(location.key); + var nextIndex = allKeys.indexOf(nextLocation.key); + + if (prevIndex !== -1 && nextIndex !== -1) go(prevIndex - nextIndex); // Restore the URL. + } + }); + } + + function push(location) { + transitionTo(createLocation(location, _Actions.PUSH, createKey())); + } + + function replace(location) { + transitionTo(createLocation(location, _Actions.REPLACE, createKey())); + } + + function goBack() { + go(-1); + } + + function goForward() { + go(1); + } + + function createKey() { + return createRandomKey(keyLength); + } + + function createPath(location) { + if (location == null || typeof location === 'string') return location; + + var pathname = location.pathname; + var search = location.search; + var hash = location.hash; + + var result = pathname; + + if (search) result += search; + + if (hash) result += hash; + + return result; + } + + function createHref(location) { + return createPath(location); + } + + function createLocation(location, action) { + var key = arguments.length <= 2 || arguments[2] === undefined ? createKey() : arguments[2]; + + if (typeof action === 'object') { + //warning( + // false, + // 'The state (2nd) argument to history.createLocation is deprecated; use a ' + + // 'location descriptor instead' + //) + + if (typeof location === 'string') location = _parsePath2['default'](location); + + location = _extends({}, location, { state: action }); + + action = key; + key = arguments[3] || createKey(); + } + + return _createLocation3['default'](location, action, key); + } + + // deprecated + function setState(state) { + if (location) { + updateLocationState(location, state); + updateLocation(location); + } else { + updateLocationState(getCurrentLocation(), state); + } + } + + function updateLocationState(location, state) { + location.state = _extends({}, location.state, state); + saveState(location.key, location.state); + } + + // deprecated + function registerTransitionHook(hook) { + if (transitionHooks.indexOf(hook) === -1) transitionHooks.push(hook); + } + + // deprecated + function unregisterTransitionHook(hook) { + transitionHooks = transitionHooks.filter(function (item) { + return item !== hook; + }); + } + + // deprecated + function pushState(state, path) { + if (typeof path === 'string') path = _parsePath2['default'](path); + + push(_extends({ state: state }, path)); + } + + // deprecated + function replaceState(state, path) { + if (typeof path === 'string') path = _parsePath2['default'](path); + + replace(_extends({ state: state }, path)); + } + + return { + listenBefore: listenBefore, + listen: listen, + transitionTo: transitionTo, + push: push, + replace: replace, + go: go, + goBack: goBack, + goForward: goForward, + createKey: createKey, + createPath: createPath, + createHref: createHref, + createLocation: createLocation, + + setState: _deprecate2['default'](setState, 'setState is deprecated; use location.key to save state instead'), + registerTransitionHook: _deprecate2['default'](registerTransitionHook, 'registerTransitionHook is deprecated; use listenBefore instead'), + unregisterTransitionHook: _deprecate2['default'](unregisterTransitionHook, 'unregisterTransitionHook is deprecated; use the callback returned from listenBefore instead'), + pushState: _deprecate2['default'](pushState, 'pushState is deprecated; use push instead'), + replaceState: _deprecate2['default'](replaceState, 'replaceState is deprecated; use replace instead') + }; +} + +exports['default'] = createHistory; +module.exports = exports['default']; + +/***/ }), +/* 144 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(process) { + +exports.__esModule = true; + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +var _warning = __webpack_require__(33); + +var _warning2 = _interopRequireDefault(_warning); + +var _ExecutionEnvironment = __webpack_require__(47); + +var _DOMUtils = __webpack_require__(61); + +var _deprecate = __webpack_require__(31); + +var _deprecate2 = _interopRequireDefault(_deprecate); + +function startBeforeUnloadListener(getBeforeUnloadPromptMessage) { + function listener(event) { + var message = getBeforeUnloadPromptMessage(); + + if (typeof message === 'string') { + (event || window.event).returnValue = message; + return message; + } + } + + _DOMUtils.addEventListener(window, 'beforeunload', listener); + + return function () { + _DOMUtils.removeEventListener(window, 'beforeunload', listener); + }; +} + +/** + * Returns a new createHistory function that can be used to create + * history objects that know how to use the beforeunload event in web + * browsers to cancel navigation. + */ +function useBeforeUnload(createHistory) { + return function (options) { + var history = createHistory(options); + + var stopBeforeUnloadListener = undefined; + var beforeUnloadHooks = []; + + function getBeforeUnloadPromptMessage() { + var message = undefined; + + for (var i = 0, len = beforeUnloadHooks.length; message == null && i < len; ++i) { + message = beforeUnloadHooks[i].call(); + }return message; + } + + function listenBeforeUnload(hook) { + beforeUnloadHooks.push(hook); + + if (beforeUnloadHooks.length === 1) { + if (_ExecutionEnvironment.canUseDOM) { + stopBeforeUnloadListener = startBeforeUnloadListener(getBeforeUnloadPromptMessage); + } else { + process.env.NODE_ENV !== 'production' ? _warning2['default'](false, 'listenBeforeUnload only works in DOM environments') : undefined; + } + } + + return function () { + beforeUnloadHooks = beforeUnloadHooks.filter(function (item) { + return item !== hook; + }); + + if (beforeUnloadHooks.length === 0 && stopBeforeUnloadListener) { + stopBeforeUnloadListener(); + stopBeforeUnloadListener = null; + } + }; + } + + // deprecated + function registerBeforeUnloadHook(hook) { + if (_ExecutionEnvironment.canUseDOM && beforeUnloadHooks.indexOf(hook) === -1) { + beforeUnloadHooks.push(hook); + + if (beforeUnloadHooks.length === 1) stopBeforeUnloadListener = startBeforeUnloadListener(getBeforeUnloadPromptMessage); + } + } + + // deprecated + function unregisterBeforeUnloadHook(hook) { + if (beforeUnloadHooks.length > 0) { + beforeUnloadHooks = beforeUnloadHooks.filter(function (item) { + return item !== hook; + }); + + if (beforeUnloadHooks.length === 0) stopBeforeUnloadListener(); + } + } + + return _extends({}, history, { + listenBeforeUnload: listenBeforeUnload, + + registerBeforeUnloadHook: _deprecate2['default'](registerBeforeUnloadHook, 'registerBeforeUnloadHook is deprecated; use listenBeforeUnload instead'), + unregisterBeforeUnloadHook: _deprecate2['default'](unregisterBeforeUnloadHook, 'unregisterBeforeUnloadHook is deprecated; use the callback returned from listenBeforeUnload instead') + }); + }; +} + +exports['default'] = useBeforeUnload; +module.exports = exports['default']; +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) + +/***/ }), +/* 145 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(process) { + +exports.__esModule = true; + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } + +var _warning = __webpack_require__(33); + +var _warning2 = _interopRequireDefault(_warning); + +var _queryString = __webpack_require__(129); + +var _runTransitionHook = __webpack_require__(88); + +var _runTransitionHook2 = _interopRequireDefault(_runTransitionHook); + +var _parsePath = __webpack_require__(32); + +var _parsePath2 = _interopRequireDefault(_parsePath); + +var _deprecate = __webpack_require__(31); + +var _deprecate2 = _interopRequireDefault(_deprecate); + +var SEARCH_BASE_KEY = '$searchBase'; + +function defaultStringifyQuery(query) { + return _queryString.stringify(query).replace(/%20/g, '+'); +} + +var defaultParseQueryString = _queryString.parse; + +function isNestedObject(object) { + for (var p in object) { + if (object.hasOwnProperty(p) && typeof object[p] === 'object' && !Array.isArray(object[p]) && object[p] !== null) return true; + }return false; +} + +/** + * Returns a new createHistory function that may be used to create + * history objects that know how to handle URL queries. + */ +function useQueries(createHistory) { + return function () { + var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; + var stringifyQuery = options.stringifyQuery; + var parseQueryString = options.parseQueryString; + + var historyOptions = _objectWithoutProperties(options, ['stringifyQuery', 'parseQueryString']); + + var history = createHistory(historyOptions); + + if (typeof stringifyQuery !== 'function') stringifyQuery = defaultStringifyQuery; + + if (typeof parseQueryString !== 'function') parseQueryString = defaultParseQueryString; + + function addQuery(location) { + if (location.query == null) { + var search = location.search; + + location.query = parseQueryString(search.substring(1)); + location[SEARCH_BASE_KEY] = { search: search, searchBase: '' }; + } + + // TODO: Instead of all the book-keeping here, this should just strip the + // stringified query from the search. + + return location; + } + + function appendQuery(location, query) { + var _extends2; + + var queryString = undefined; + if (!query || (queryString = stringifyQuery(query)) === '') return location; + + process.env.NODE_ENV !== 'production' ? _warning2['default'](stringifyQuery !== defaultStringifyQuery || !isNestedObject(query), 'useQueries does not stringify nested query objects by default; ' + 'use a custom stringifyQuery function') : undefined; + + if (typeof location === 'string') location = _parsePath2['default'](location); + + var searchBaseSpec = location[SEARCH_BASE_KEY]; + var searchBase = undefined; + if (searchBaseSpec && location.search === searchBaseSpec.search) { + searchBase = searchBaseSpec.searchBase; + } else { + searchBase = location.search || ''; + } + + var search = searchBase + (searchBase ? '&' : '?') + queryString; + + return _extends({}, location, (_extends2 = { + search: search + }, _extends2[SEARCH_BASE_KEY] = { search: search, searchBase: searchBase }, _extends2)); + } + + // Override all read methods with query-aware versions. + function listenBefore(hook) { + return history.listenBefore(function (location, callback) { + _runTransitionHook2['default'](hook, addQuery(location), callback); + }); + } + + function listen(listener) { + return history.listen(function (location) { + listener(addQuery(location)); + }); + } + + // Override all write methods with query-aware versions. + function push(location) { + history.push(appendQuery(location, location.query)); + } + + function replace(location) { + history.replace(appendQuery(location, location.query)); + } + + function createPath(location, query) { + //warning( + // !query, + // 'the query argument to createPath is deprecated; use a location descriptor instead' + //) + return history.createPath(appendQuery(location, query || location.query)); + } + + function createHref(location, query) { + //warning( + // !query, + // 'the query argument to createHref is deprecated; use a location descriptor instead' + //) + return history.createHref(appendQuery(location, query || location.query)); + } + + function createLocation() { + return addQuery(history.createLocation.apply(history, arguments)); + } + + // deprecated + function pushState(state, path, query) { + if (typeof path === 'string') path = _parsePath2['default'](path); + + push(_extends({ state: state }, path, { query: query })); + } + + // deprecated + function replaceState(state, path, query) { + if (typeof path === 'string') path = _parsePath2['default'](path); + + replace(_extends({ state: state }, path, { query: query })); + } + + return _extends({}, history, { + listenBefore: listenBefore, + listen: listen, + push: push, + replace: replace, + createPath: createPath, + createHref: createHref, + createLocation: createLocation, + + pushState: _deprecate2['default'](pushState, 'pushState is deprecated; use push instead'), + replaceState: _deprecate2['default'](replaceState, 'replaceState is deprecated; use replace instead') + }); + }; +} + +exports['default'] = useQueries; +module.exports = exports['default']; +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) + +/***/ }), +/* 146 */, +/* 147 */, +/* 148 */, +/* 149 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _propTypes = __webpack_require__(23); + +var _propTypes2 = _interopRequireDefault(_propTypes); + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +var _reactRouter = __webpack_require__(81); + +var _Component2 = __webpack_require__(16); + +var _Component3 = _interopRequireDefault(_Component2); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var LektorLink = function (_Component) { + _inherits(LektorLink, _Component); + + function LektorLink() { + _classCallCheck(this, LektorLink); + + return _possibleConstructorReturn(this, (LektorLink.__proto__ || Object.getPrototypeOf(LektorLink)).apply(this, arguments)); + } + + _createClass(LektorLink, [{ + key: 'render', + value: function render() { + var path = this.props.to; + if (path.substr(0, 1) !== '/') { + path = $LEKTOR_CONFIG.admin_root + '/' + path; + } + return _react2.default.createElement( + _reactRouter.Link, + { to: path, activeClassName: 'active' }, + this.props.children + ); + } + }]); + + return LektorLink; +}(_Component3.default); + +LektorLink.propTypes = { + to: _propTypes2.default.string +}; + +module.exports = LektorLink; + +/***/ }), +/* 150 */, +/* 151 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + +var _RecordComponent2 = __webpack_require__(26); + +var _RecordComponent3 = _interopRequireDefault(_RecordComponent2); + +var _i18n = __webpack_require__(7); + +var _i18n2 = _interopRequireDefault(_i18n); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var RecordEditComponent = function (_RecordComponent) { + _inherits(RecordEditComponent, _RecordComponent); + + function RecordEditComponent() { + _classCallCheck(this, RecordEditComponent); + + return _possibleConstructorReturn(this, (RecordEditComponent.__proto__ || Object.getPrototypeOf(RecordEditComponent)).apply(this, arguments)); + } + + _createClass(RecordEditComponent, [{ + key: 'hasPendingChanges', + value: function hasPendingChanges() { + return false; + } + }, { + key: 'routerWillLeave', + value: function routerWillLeave(nextLocation) { + var rv = _get(RecordEditComponent.prototype.__proto__ || Object.getPrototypeOf(RecordEditComponent.prototype), 'routerWillLeave', this).call(this, nextLocation); + if (rv !== undefined) { + return rv; + } + if (this.hasPendingChanges()) { + return _i18n2.default.trans('UNLOAD_ACTIVE_TAB'); + } + } + }]); + + return RecordEditComponent; +}(_RecordComponent3.default); + +exports.default = RecordEditComponent; + +/***/ }), +/* 152 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _propTypes = __webpack_require__(23); + +var _propTypes2 = _interopRequireDefault(_propTypes); + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +var _reactDom = __webpack_require__(98); + +var _reactDom2 = _interopRequireDefault(_reactDom); + +var _reactRouter = __webpack_require__(81); + +var _Component2 = __webpack_require__(16); + +var _Component3 = _interopRequireDefault(_Component2); + +var _i18n = __webpack_require__(7); + +var _i18n2 = _interopRequireDefault(_i18n); + +var _history = __webpack_require__(298); + +var _createBrowserHistory = __webpack_require__(140); + +var _createBrowserHistory2 = _interopRequireDefault(_createBrowserHistory); + +var _bootstrap = __webpack_require__(146); + +var _bootstrap2 = _interopRequireDefault(_bootstrap); + +var _bootstrapExtras = __webpack_require__(317); + +var _bootstrapExtras2 = _interopRequireDefault(_bootstrapExtras); + +var _fontAwesome = __webpack_require__(318); + +var _fontAwesome2 = _interopRequireDefault(_fontAwesome); + +var _nativePromiseOnly = __webpack_require__(147); + +var _nativePromiseOnly2 = _interopRequireDefault(_nativePromiseOnly); + +var _eventSourcePolyfill = __webpack_require__(322); + +var _eventSourcePolyfill2 = _interopRequireDefault(_eventSourcePolyfill); + +var _App = __webpack_require__(323); + +var _App2 = _interopRequireDefault(_App); + +var _Dash = __webpack_require__(332); + +var _Dash2 = _interopRequireDefault(_Dash); + +var _EditPage = __webpack_require__(333); + +var _EditPage2 = _interopRequireDefault(_EditPage); + +var _DeletePage = __webpack_require__(340); + +var _DeletePage2 = _interopRequireDefault(_DeletePage); + +var _PreviewPage = __webpack_require__(341); + +var _PreviewPage2 = _interopRequireDefault(_PreviewPage); + +var _AddChildPage = __webpack_require__(342); + +var _AddChildPage2 = _interopRequireDefault(_AddChildPage); + +var _AddAttachmentPage = __webpack_require__(343); + +var _AddAttachmentPage2 = _interopRequireDefault(_AddAttachmentPage); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +/* eslint-disable no-unused-vars */ + + +// polyfill for internet explorer + +/* eslint-enable no-unused-vars */ + +// route targets + + +_i18n2.default.currentLanguage = $LEKTOR_CONFIG.lang; + +var BadRoute = function (_Component) { + _inherits(BadRoute, _Component); + + function BadRoute() { + _classCallCheck(this, BadRoute); + + return _possibleConstructorReturn(this, (BadRoute.__proto__ || Object.getPrototypeOf(BadRoute)).apply(this, arguments)); + } + + _createClass(BadRoute, [{ + key: 'render', + value: function render() { + return _react2.default.createElement( + 'div', + null, + _react2.default.createElement( + 'h2', + null, + 'Nothing to see here' + ), + _react2.default.createElement( + 'p', + null, + 'There is really nothing to see here.' + ) + ); + } + }]); + + return BadRoute; +}(_Component3.default); + +BadRoute.contextTypes = { + router: _propTypes2.default.func +}; + +var routes = function () { + // route setup + return _react2.default.createElement( + _reactRouter.Route, + { name: 'app', path: $LEKTOR_CONFIG.admin_root, component: _App2.default }, + _react2.default.createElement(_reactRouter.Route, { name: 'edit', path: ':path/edit', component: _EditPage2.default }), + _react2.default.createElement(_reactRouter.Route, { name: 'delete', path: ':path/delete', component: _DeletePage2.default }), + _react2.default.createElement(_reactRouter.Route, { name: 'preview', path: ':path/preview', component: _PreviewPage2.default }), + _react2.default.createElement(_reactRouter.Route, { name: 'add-child', path: ':path/add-child', component: _AddChildPage2.default }), + _react2.default.createElement(_reactRouter.Route, { name: 'upload', path: ':path/upload', component: _AddAttachmentPage2.default }), + _react2.default.createElement(_reactRouter.IndexRoute, { component: _Dash2.default }), + _react2.default.createElement('route', { path: '*', component: BadRoute }) + ); +}(); + +var dash = document.getElementById('dash'); + +if (dash) { + _reactDom2.default.render(_react2.default.createElement( + _reactRouter.Router, + { history: (0, _history.useBeforeUnload)(_createBrowserHistory2.default)() }, + routes + ), dash); +} + +/***/ }), +/* 153 */, +/* 154 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + + + +var emptyFunction = __webpack_require__(14); +var invariant = __webpack_require__(1); +var ReactPropTypesSecret = __webpack_require__(63); + +module.exports = function() { + function shim(props, propName, componentName, location, propFullName, secret) { + if (secret === ReactPropTypesSecret) { + // It is still safe when called from React. + return; + } + invariant( + false, + 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' + + 'Use PropTypes.checkPropTypes() to call them. ' + + 'Read more at http://fb.me/use-check-prop-types' + ); + }; + shim.isRequired = shim; + function getShim() { + return shim; + }; + // Important! + // Keep this list in sync with production version in `./factoryWithTypeCheckers.js`. + var ReactPropTypes = { + array: shim, + bool: shim, + func: shim, + number: shim, + object: shim, + string: shim, + symbol: shim, + + any: shim, + arrayOf: getShim, + element: shim, + instanceOf: getShim, + node: shim, + objectOf: getShim, + oneOf: getShim, + oneOfType: getShim, + shape: getShim + }; + + ReactPropTypes.checkPropTypes = emptyFunction; + ReactPropTypes.PropTypes = ReactPropTypes; + + return ReactPropTypes; +}; + + +/***/ }), +/* 155 */, +/* 156 */, +/* 157 */, +/* 158 */, +/* 159 */, +/* 160 */, +/* 161 */, +/* 162 */, +/* 163 */, +/* 164 */, +/* 165 */, +/* 166 */, +/* 167 */, +/* 168 */, +/* 169 */, +/* 170 */, +/* 171 */, +/* 172 */, +/* 173 */, +/* 174 */, +/* 175 */, +/* 176 */, +/* 177 */, +/* 178 */, +/* 179 */, +/* 180 */, +/* 181 */, +/* 182 */, +/* 183 */, +/* 184 */, +/* 185 */, +/* 186 */, +/* 187 */, +/* 188 */, +/* 189 */, +/* 190 */, +/* 191 */, +/* 192 */, +/* 193 */, +/* 194 */, +/* 195 */, +/* 196 */, +/* 197 */, +/* 198 */, +/* 199 */, +/* 200 */, +/* 201 */, +/* 202 */, +/* 203 */, +/* 204 */, +/* 205 */, +/* 206 */, +/* 207 */, +/* 208 */, +/* 209 */, +/* 210 */, +/* 211 */, +/* 212 */, +/* 213 */, +/* 214 */, +/* 215 */, +/* 216 */, +/* 217 */, +/* 218 */, +/* 219 */, +/* 220 */, +/* 221 */, +/* 222 */, +/* 223 */, +/* 224 */, +/* 225 */, +/* 226 */, +/* 227 */, +/* 228 */, +/* 229 */, +/* 230 */, +/* 231 */, +/* 232 */, +/* 233 */, +/* 234 */, +/* 235 */, +/* 236 */, +/* 237 */, +/* 238 */, +/* 239 */, +/* 240 */, +/* 241 */, +/* 242 */, +/* 243 */, +/* 244 */, +/* 245 */, +/* 246 */, +/* 247 */, +/* 248 */, +/* 249 */, +/* 250 */, +/* 251 */, +/* 252 */, +/* 253 */, +/* 254 */, +/* 255 */, +/* 256 */, +/* 257 */, +/* 258 */, +/* 259 */, +/* 260 */, +/* 261 */, +/* 262 */, +/* 263 */, +/* 264 */, +/* 265 */, +/* 266 */, +/* 267 */, +/* 268 */, +/* 269 */, +/* 270 */, +/* 271 */, +/* 272 */, +/* 273 */, +/* 274 */, +/* 275 */, +/* 276 */, +/* 277 */, +/* 278 */, +/* 279 */, +/* 280 */, +/* 281 */, +/* 282 */, +/* 283 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +// the base component. This really should not exist in the first place +// but react is a bit meh when it comes to what's on the base component +// which breaks super. This is why we do this here. Note that this is +// also used by the standalone admin UI app. + + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var BaseComponent = function (_React$Component) { + _inherits(BaseComponent, _React$Component); + + function BaseComponent() { + _classCallCheck(this, BaseComponent); + + return _possibleConstructorReturn(this, (BaseComponent.__proto__ || Object.getPrototypeOf(BaseComponent)).apply(this, arguments)); + } + + _createClass(BaseComponent, [{ + key: 'componentDidMount', + value: function componentDidMount() {} + }, { + key: 'componentWillUnmount', + value: function componentWillUnmount() {} + }, { + key: 'componentDidUpdate', + value: function componentDidUpdate() {} + }, { + key: 'componentWillReceiveProps', + value: function componentWillReceiveProps(nextProps) {} + }]); + + return BaseComponent; +}(_react2.default.Component); + +exports.default = BaseComponent; + +/***/ }), +/* 284 */ +/***/ (function(module, exports, __webpack_require__) { + +var map = { + "./ca.json": 285, + "./de.json": 286, + "./en.json": 287, + "./es.json": 288, + "./fr.json": 289, + "./it.json": 290, + "./ja.json": 291, + "./ko.json": 292, + "./nl.json": 293, + "./pl.json": 294, + "./pt.json": 295, + "./ru.json": 296, + "./zh.json": 297 +}; +function webpackContext(req) { + return __webpack_require__(webpackContextResolve(req)); +}; +function webpackContextResolve(req) { + var id = map[req]; + if(!(id + 1)) // check for number or string + throw new Error("Cannot find module '" + req + "'."); + return id; +}; +webpackContext.keys = function webpackContextKeys() { + return Object.keys(map); +}; +webpackContext.resolve = webpackContextResolve; +module.exports = webpackContext; +webpackContext.id = 284; + +/***/ }), +/* 285 */ +/***/ (function(module, exports) { + +module.exports = {"RETURN_TO_WEBSITE":"Tornar al Lloc Web","UNLOAD_ACTIVE_TAB":"Hi ha informació sense desar, està segur que vol abandonar aquesta pàgina?","EDIT_METADATA":"Editar Metadades","EDIT":"Editar","DELETE":"Esborrar","PREVIEW":"Previsualitzar","ALTS":"Alternatives","PRIMARY_ALT":"Primària","PRIMARY_OVERLAY":"Overlaid","ADD_CHILD_PAGE":"Afegir Pàgina","ADD_ATTACHMENT":"Afegir Adjunt","ATTACHMENT_ACTIONS":"Accions sobre els Adjunts","PAGE_ACTIONS":"Accions sobre la Pàgina","NO_CHILD_PAGES":"Sense Subpàgines","CHILD_PAGES":"Subpàgines","NO_ATTACHMENTS":"Sense Adjunts","ATTACHMENTS":"Adjunts","ADD_ATTACHMENT_TO":"Afegir Adjunt a “%s”","ADD_ATTACHMENT_NOTE":"Pot pujar un nou adjunt aquí.","UPLOAD":"Pujar","PROGRESS":"Avenç","ERROR_PREFIX":"Error: ","ERROR_NO_ID_PROVIDED":"No s'ha proporcionat un ID.","ERROR_PAGE_ID_DUPLICATE":"Ja existeix una pàgina amb aquest ID (%s).","ERROR_INVALID_ID":"ID invàlid","ERROR_INVALID_DATE":"Data invàlida","ERROR_INVALID_NUMBER":"Número no vàlid","ERROR_INVALID_URL":"URL no vàlida","ERROR":"Error","ERROR_OCURRED":"Ha ocorregut un Error","ERROR_REQUEST_FAILED":"No s'ha pogut enviar la tasca al servidor. Potser el servidor està apagat o és inaccessible","ERROR_SERVER_UNAVAILABLE":"Servidor No Disponible","ERROR_SERVER_UNAVAILABLE_MESSAGE":"El servidor no respon. Ha estat apagat o hi ha hagut un error crític que ha fet que estigui inoperatiu i hagi de ser reiniciat.","MODEL":"Model","ADD_CHILD_PAGE_TO":"Afegir Subpàgina a “%s”","ADD_CHILD_PAGE_NOTE":"Pot afegir una nova subpàgina aquí. Tingui en compte que el model o el ID no podrà ser canviat fàcilment més endavant.","CREATE_CHILD_PAGE":"Afegir pàgina filla","DELETE_ATTACHMENT_PROMPT":"Realment vol esborrar aquest adjunt?","DELETE_ATTACHMENT_ALT_PROMPT":"Realment vol esborrar les metadades d'aquest adjunt alternatiu?","DELETE_PAGE_PROMPT":"Vol realment esborrar aquesta pàgina?","DELETE_PAGE_ALT_PROMPT":"Realment desitja esborrar aquesta alternativa?","DELETE_PAGE_CHILDREN_WARNING":"També s'esborraran les subpàgines que pengin d'aquesta pàgina.","DELETE_RECORD":"Esborrar “%s”","DELETE_ALL_PAGE_ALTS":"Esborrar també totes les alternatives i fitxers adjunts.","DELETE_ALL_ATTACHMENT_ALTS":"Esborrar totes les alternatives de l'annex i el fitxer adjunt.","DELETE_ONLY_PRIMARY_PAGE_ALT":"Esborrar només el registre principal. Els adjunts, les alternatives i les subpàgines no seran esborrades.","DELETE_ONLY_PRIMARY_ATTACHMENT_ALT":"Esborrar només les metadades del registre principal.","DELETE_PRIMARY_ALT_INFO":"Com aquest registre és una alternativa principal, pot ser esborrat per separat o conjuntament a la resta de continguts.","CHILD_PAGES_TO_BE_DELETED":"Subpàgines que seran esborrares:","ALTS_TO_BE_DELETED":"Alternatives que seran eliminades:","ATTACHMENTS_TO_BE_DELETED":"Adjunts que seran eliminats:","YES_DELETE":"Sí, esborrar","NO_CANCEL":"No, cancel·lar","SYSTEM_FIELDS":"Camps del Sistema","EDIT_ATTACHMENT_METADATA_OF":"Editar les Metadades de l'Adjunt “%s”","EDIT_PAGE_NAME":"Editar “%s”","SAVE_CHANGES":"Desar els canvis","BROWSE_FS":"Veure al Sistema de fitxers","BROWSE_FS_MAC":"Mostrar al Finder","BROWSE_FS_WINDOWS":"Mostrar a l'Explorador","ERROR_CANNOT_BROWSE_FS":"Error: el fitxer no existeix encara.","REMOVE_FLOWBLOCK_PROMPT":"¿Realment vol esborrar aquest block?","ADD_FLOWBLOCK":"Afegir Block","INVALID_INPUT":"Entrada invàlida","UP":"Amunt","DOWN":"Abaix","REMOVE":"Esborrar","ID":"ID","CLOSE":"Tancar","CANCEL":"Cancel·lar","BACK_TO_OVERVIEW":"Tornar a la Revisió","PUBLISH":"Publicar","PUBLISH_NOTE":"Des d'aquí pot publicar la versió actual del lloc web.","PUBLISH_SERVER":"Servidor Destinació","CURRENTLY_PUBLISHING":"Publicannt ...","STATE":"Estat","PUBLISH_DONE":"Publicat","PUBLISH_STATE_BUILDING":"Els canvis s'estan generant ...","PUBLISH_STATE_PUBLISH":"Els canvis s'estan publicant ...","PUBLISH_STATE_DONE":"Publicació finalitzada.","FIND_FILES":"Buscar Fitxers","FIND_FILES_PLACEHOLDER":"Introdueixi el nom de la pàgina ...","ATTACHMENT_TYPE":"Tipus d'adjunt","URL_SLUG":"URL personalitzada","TEMPLATE":"Plantilla","HIDE_PAGE":"Amagar pàgina","HIDE_PAGE_EXPLANATION":"Hauria d'estar oculta aquesta pàgina?","PAGE_IS_DISCOVERABLE":"La Pàgina és detectable","PAGE_IS_DISCOVERABLE_EXPLANATION":"Si s'habilita, la pàgina pot ser detectada, en cas contrari la URL del contingut ha de ser coneguda.","REFRESH_BUILD":"Regenerar Lloc Web","REFRESH_BUILD_NOTE":"Això esborra tots els resultats generats i llença una nova generació des de zero. Això és útil en algunes situacions on els errors de sincronització o a les plantilles han causat un resultat corrupte.","CURRENTLY_REFRESHING_BUILD":"Regenerant ...","REFRESHING_BUILD_DONE":"Actualització finalitzada!","FAILED_TO_LAUNCH_LEKTOR":"Ha fallat l'execució de Lektor.","PROJECT":"Projecte","CLOSE_PROJECT":"Tancar Projecte","OPEN_PROJECT":"Obrir Projecte","BROWSE_WEBSITE":"Anar al Lloc Web","VIEW_ADMIN_PANEL":"Anar al Panell d'Administració","QUIT":"Sortir","FAILED_TO_LOAD_PROJECT":"Ha fallat la càrrega del projecte :(","LOADING_PROJECT":"Carregant projecte ...","INITIALIZING_LEKTOR":"Inicialitzant Lektor ...","QUIT_LEKTOR":"Sortir de Lektor","FILE":"Arxiu","UNDO":"Desfer","REDO":"Tornar a fer","CUT":"Tallar","COPY":"Copiar","PASTE":"Enganxar","SELECT_ALL":"Seleccionar-ho Tot","HELP":"Ajuda","VISIT_WEBSITE":"Visitar Web","INSTALL_SHELL_COMMAND":"Instalar Eina","INSTALL_SHELL_COMMAND_QUESTION":"Vol instal·lar la eina 'lektor'? Es requereixen permisos d'administració.","FAILED_TO_INSTALL_SHELL_COMMANDS":"Ha fallat la instal·lació de l'eina.","INSTALL_SHELL_COMMAND_SUCCESS":"L'eina ha estat instal·lada amb èxit.","OPERATION_SUCCESS":"Amb èxit","YES":"Sí","NO":"No","OK":"OK","FAILED_TO_OPEN_CONTENT_FILE":"Error al intentar obrir el fitxer de contingut","OPEN_OTHER_PROJECT":"Obrir un altre Projecte","OPEN_OTHER_PROJECT_QUESTION":"Obrir aquest fitxer implica obrir un altre projecte (%s). El projecte actual serà tancat. Vol continuar?"} + +/***/ }), +/* 286 */ +/***/ (function(module, exports) { + +module.exports = {"RETURN_TO_WEBSITE":"Zur Webseite","UNLOAD_ACTIVE_TAB":"Du hast ungespeicherte Änderungen, willst du die Seite wirklich verlassen?","EDIT_METADATA":"Metadaten bearbeiten","EDIT":"Bearbeiten","DELETE":"Löschen","PREVIEW":"Vorschau","ALTS":"Alternativen","PRIMARY_ALT":"Primär","PRIMARY_OVERLAY":"Überlagert","ADD_CHILD_PAGE":"Seite hinzufügen","ADD_ATTACHMENT":"Anhang hinzufügen","ATTACHMENT_ACTIONS":"Anhang-Aktionen","PAGE_ACTIONS":"Seiten-Aktionen","NO_CHILD_PAGES":"Keine Unterseiten","CHILD_PAGES":"Unterseiten","NO_ATTACHMENTS":"Keine Anhänge","ATTACHMENTS":"Anhänge","ADD_ATTACHMENT_TO":"Anhang zu “%s” hinzufügen","ADD_ATTACHMENT_NOTE":"Hier kannst du neue Anhänge hochladen.","UPLOAD":"Hochladen","PROGRESS":"Fortschritt","ERROR_PREFIX":"Fehler: ","ERROR_NO_ID_PROVIDED":"Es wurde keine ID eingegeben.","ERROR_PAGE_ID_DUPLICATE":"Eine Seite mit dieser ID (%s) existiert bereits.","ERROR_INVALID_ID":"Ungültige ID","ERROR_INVALID_DATE":"Ungültiges Datum","ERROR_INVALID_NUMBER":"Ungültige Zahl","ERROR_INVALID_URL":"Ungültige URL","ERROR":"Fehler","ERROR_OCURRED":"Ein Fehler ist aufgetreten","ERROR_REQUEST_FAILED":"Ein Befehl konnte nicht an den Server gesendet werden. Eventuell reagiert der Server nicht oder wurde gestoppt.","ERROR_SERVER_UNAVAILABLE":"Server unerreichbar","ERROR_SERVER_UNAVAILABLE_MESSAGE":"Der Server reagiert nicht. Entweder er wurde gestoppt oder ein kritischer Fehler ist aufgetreten und er muss neu gestartet werden.","MODEL":"Modell","ADD_CHILD_PAGE_TO":"Unterseite zu “%s” hinzufügen","ADD_CHILD_PAGE_NOTE":"Du kannst hier eine neue Unterseite hinzufügen. Beachte, dass die ID und as Modell später nicht mehr verändert werden kann.","CREATE_CHILD_PAGE":"Unterseite hinzufügen","DELETE_ATTACHMENT_PROMPT":"Willst du den Anhang wirklich löschen?","DELETE_ATTACHMENT_ALT_PROMPT":"Willst du die Metadaten dieser Anhang-Alternative wirklich löschen?","DELETE_PAGE_PROMPT":"Willst du diese Seite wirklich löschen?","DELETE_PAGE_ALT_PROMPT":"Willst du diese Alternative wirklich löschen?","DELETE_PAGE_CHILDREN_WARNING":"Dies wird auch die Unterseiten der Seite löschen.","DELETE_RECORD":"“%s” Löschen","DELETE_ALL_PAGE_ALTS":"Alle Alternativen und angehängten Dateien mitlöschen.","DELETE_ALL_ATTACHMENT_ALTS":"Alle Alternativen und die angehängte Datei löschen.","DELETE_ONLY_PRIMARY_PAGE_ALT":"Nur den Primäreintrag löschen. Anhänge, andere Alternativen und Unterseiten werden nicht gelöscht.","DELETE_ONLY_PRIMARY_ATTACHMENT_ALT":"Nur die Metadaten des Primäreintrages löschen.","DELETE_PRIMARY_ALT_INFO":"Da dieser Eintrag eine Primäralternative ist, kann diese auch separat gelöscht werden oder zusammen mit allen anderen Inhalten.","CHILD_PAGES_TO_BE_DELETED":"Unterseiten, die gelöscht werden:","ALTS_TO_BE_DELETED":"Alternativen, die gelöscht werden:","ATTACHMENTS_TO_BE_DELETED":"Anhänge, die gelöscht werden:","YES_DELETE":"Ja, löschen","NO_CANCEL":"Nein, abbrechen","SYSTEM_FIELDS":"Systemfelder","EDIT_ATTACHMENT_METADATA_OF":"Bearbeite Metadaten von Anhang “%s”","EDIT_PAGE_NAME":"Bearbeite “%s”","SAVE_CHANGES":"Änderungen speichern","BROWSE_FS":"Im Dateisystem öffnen","BROWSE_FS_MAC":"In Finder anzeigen","BROWSE_FS_WINDOWS":"Im Explorer öffnen","ERROR_CANNOT_BROWSE_FS":"Fehler: Datei existiert noch nicht","REMOVE_FLOWBLOCK_PROMPT":"Willst du diesen Block wirklich entfernen?","ADD_FLOWBLOCK":"Block hinzufügen","INVALID_INPUT":"Ungültige Eingabe","UP":"Nach oben","DOWN":"Nach unten","REMOVE":"Entfernen","ID":"ID","CLOSE":"Schließen","CANCEL":"Abbrechen","BACK_TO_OVERVIEW":"Übersicht","PUBLISH":"Veröffentlichen","PUBLISH_NOTE":"Von hier aus kann der aktuelle Stand der Webseite publiziert werden.","PUBLISH_SERVER":"Ziel-Server","CURRENTLY_PUBLISHING":"Veröffentlichung …","STATE":"Status","PUBLISH_DONE":"Veröffentlicht","PUBLISH_STATE_BUILDING":"Änderungen werden gebaut ...","PUBLISH_STATE_PUBLISH":"Änderungen werden publiziert ...","PUBLISH_STATE_DONE":"Veröffentlichung fertiggestellt.","FIND_FILES":"Seiten Finden","FIND_FILES_PLACEHOLDER":"Seitenname eingeben ...","ATTACHMENT_TYPE":"Attachment type","URL_SLUG":"URL-Slug","TEMPLATE":"Vorlage","HIDE_PAGE":"Seite verstecken","HIDE_PAGE_EXPLANATION":"Soll diese Seite versteckt werden?","PAGE_IS_DISCOVERABLE":"Seite ist erkundbar","PAGE_IS_DISCOVERABLE_EXPLANATION":"Wenn dies aktiviert ist, wird Seite von Vorlagen verlinkt. Ansonsten muss die URL bekannt sein.","REFRESH_BUILD":"Änderungen regenerieren","REFRESH_BUILD_NOTE":"In machen Situationen kann es nützlich sein, alle Änderungen zu regenerieren. Zum Beispiel können Synchronisationsfehler und kaputte Vorlagen manchmal dazu führen, dass Seiten fehlerhaft gebaut wurden. Dies bringt Lektor dazu, alle Seiten neu zu bauen.","CURRENTLY_REFRESHING_BUILD":"Änderungen werden regeneriert ...","REFRESHING_BUILD_DONE":"Änderungen wurden regeneriert!","FAILED_TO_LAUNCH_LEKTOR":"Lektor konnte nicht gestartet werden.","PROJECT":"Projekt","CLOSE_PROJECT":"Projekt schließen","OPEN_PROJECT":"Projekt öffnen","BROWSE_WEBSITE":"Webseite anzeigen","VIEW_ADMIN_PANEL":"Admin-Panel öffnen","QUIT":"Beenden","FAILED_TO_LOAD_PROJECT":"Projekt konnte nicht geladen werden :(","LOADING_PROJECT":"Projekt wird geöffnet ...","INITIALIZING_LEKTOR":"Initialisiere Lektor ...","QUIT_LEKTOR":"Lektor beenden","FILE":"Datei","UNDO":"Rückgängig","REDO":"Wiederholen","CUT":"Ausschneiden","COPY":"Kopieren","PASTE":"Einfügen","SELECT_ALL":"Alles Markieren","HELP":"Hilfe","VISIT_WEBSITE":"Webseite öffnen","INSTALL_SHELL_COMMAND":"Shell-Befehl installieren","INSTALL_SHELL_COMMAND_QUESTION":"Möchtest du den 'lektor' Shell-Befehl installieren? Dies erfordert Admin-Rechte.","FAILED_TO_INSTALL_SHELL_COMMANDS":"Konnte Shell-Befehl nicht installieren.","INSTALL_SHELL_COMMAND_SUCCESS":"Shell-Befehl wurde erfolgreich installiert.","OPERATION_SUCCESS":"Operation erfolgreich","YES":"Ja","NO":"Nein","OK":"OK","FAILED_TO_OPEN_CONTENT_FILE":"Konnte Datei nicht öffnen","OPEN_OTHER_PROJECT":"Anderes Projekt öffnen","OPEN_OTHER_PROJECT_QUESTION":"Um diese Datei zu öffnen, muss ein anderes Projekt (%s) geöffnet werden. Das aktuelle Projekt wird dadurch geschlossen. Fortfahren?"} + +/***/ }), +/* 287 */ +/***/ (function(module, exports) { + +module.exports = {"RETURN_TO_WEBSITE":"Return to Website","UNLOAD_ACTIVE_TAB":"You have unsaved information, are you sure you want to leave this page?","EDIT_METADATA":"Edit Metadata","EDIT":"Edit","DELETE":"Delete","PREVIEW":"Preview","ALTS":"Alternatives","PRIMARY_ALT":"Primary","PRIMARY_OVERLAY":"Overlaid","ADD_CHILD_PAGE":"Add Page","ADD_ATTACHMENT":"Add Attachment","ATTACHMENT_ACTIONS":"Attachment Actions","PAGE_ACTIONS":"Page Actions","NO_CHILD_PAGES":"No Subpages","CHILD_PAGES":"Subpages","NO_ATTACHMENTS":"No attachments","ATTACHMENTS":"Attachments","ADD_ATTACHMENT_TO":"Add Attachment to “%s”","ADD_ATTACHMENT_NOTE":"You can upload a new attachment here.","UPLOAD":"Upload","PROGRESS":"Progress","ERROR_PREFIX":"Error: ","ERROR_NO_ID_PROVIDED":"No ID provided.","ERROR_PAGE_ID_DUPLICATE":"A page with this ID (%s) exists already.","ERROR_INVALID_ID":"Invalid ID","ERROR_INVALID_DATE":"Invalid date","ERROR_INVALID_NUMBER":"Not a valid number","ERROR_INVALID_URL":"Not a valid URL","ERROR":"Error","ERROR_OCURRED":"An Error ocurred","ERROR_REQUEST_FAILED":"Could not send command to server. Maybe the server was stopped or is unresponsive?","ERROR_SERVER_UNAVAILABLE":"Server Unavailable","ERROR_SERVER_UNAVAILABLE_MESSAGE":"The server is not responding. Either it was stopped or a critical error made it not operable and it needs to be restarted.","MODEL":"Model","ADD_CHILD_PAGE_TO":"Add Subpage to “%s”","ADD_CHILD_PAGE_NOTE":"You can add a new subpage to the page here. Note that the model or ID cannot be easily changed afterwards.","CREATE_CHILD_PAGE":"Add Child Page","DELETE_ATTACHMENT_PROMPT":"Do you really want to delete this attachment?","DELETE_ATTACHMENT_ALT_PROMPT":"Do you really want to delete the metadata of this attachment alternative?","DELETE_PAGE_PROMPT":"Do you really want to delete this page?","DELETE_PAGE_ALT_PROMPT":"Do you really want to delete this alternative?","DELETE_PAGE_CHILDREN_WARNING":"This will also delete the child subpages of this page.","DELETE_RECORD":"Delete “%s”","DELETE_ALL_PAGE_ALTS":"Also delete all alternatives and attached files.","DELETE_ALL_ATTACHMENT_ALTS":"Delete all alternatives and the attached file.","DELETE_ONLY_PRIMARY_PAGE_ALT":"Delete only the primary record. Attachments, alternatives and subpages will not be deleted.","DELETE_ONLY_PRIMARY_ATTACHMENT_ALT":"Only delete the Metadata of the primary record.","DELETE_PRIMARY_ALT_INFO":"Because this record is a primary alternative it can be deleted separately or together with all other contents.","CHILD_PAGES_TO_BE_DELETED":"Subpages that will be deleted:","ALTS_TO_BE_DELETED":"Alternatives that will be deleted:","ATTACHMENTS_TO_BE_DELETED":"Attachments that will be deleted:","YES_DELETE":"Yes, delete","NO_CANCEL":"No, cancel","SYSTEM_FIELDS":"System Fields","EDIT_ATTACHMENT_METADATA_OF":"Edit Metadata of Attachment “%s”","EDIT_PAGE_NAME":"Edit “%s”","SAVE_CHANGES":"Save Changes","BROWSE_FS":"Browse in Filesystem","BROWSE_FS_MAC":"Reveal in Finder","BROWSE_FS_WINDOWS":"Open in Explorer","ERROR_CANNOT_BROWSE_FS":"Error: File does not exist yet.","REMOVE_FLOWBLOCK_PROMPT":"Do you really want to remove this block?","ADD_FLOWBLOCK":"Add Block","INVALID_INPUT":"Invalid Input","UP":"Up","DOWN":"Down","REMOVE":"Remove","ID":"ID","CLOSE":"Close","CANCEL":"Cancel","BACK_TO_OVERVIEW":"Back to Overview","PUBLISH":"Publish","PUBLISH_NOTE":"From here you can publish the current version of the website.","PUBLISH_SERVER":"Target Server","CURRENTLY_PUBLISHING":"Publishing …","STATE":"Status","PUBLISH_DONE":"Published","PUBLISH_STATE_BUILDING":"Changes are being built ...","PUBLISH_STATE_PUBLISH":"Changes are being published ...","PUBLISH_STATE_DONE":"Publishing done.","FIND_FILES":"Find Files","FIND_FILES_PLACEHOLDER":"Enter page name ...","ATTACHMENT_TYPE":"Attachment type","URL_SLUG":"URL slug","TEMPLATE":"Template","HIDE_PAGE":"Hide page","HIDE_PAGE_EXPLANATION":"Should this page be hidden?","PAGE_IS_DISCOVERABLE":"Page is discoverable","PAGE_IS_DISCOVERABLE_EXPLANATION":"If this is enabled the page can be discovered, otherwise the URL has to be known.","REFRESH_BUILD":"Refresh Build","REFRESH_BUILD_NOTE":"This deletes all cached build results which triggers a rebuilt from scratch. This is useful in certain situations where sync errors or mistakes in templates caused corrupted output.","CURRENTLY_REFRESHING_BUILD":"Currently refreshing build ...","REFRESHING_BUILD_DONE":"Done refreshing build!","FAILED_TO_LAUNCH_LEKTOR":"Failed to launch Lektor.","PROJECT":"Project","CLOSE_PROJECT":"Close Project","OPEN_PROJECT":"Open Project","BROWSE_WEBSITE":"Browse Website","VIEW_ADMIN_PANEL":"View Admin Panel","QUIT":"Quit","FAILED_TO_LOAD_PROJECT":"Failed to load the project :(","LOADING_PROJECT":"Loading project ...","INITIALIZING_LEKTOR":"Initializing Lektor ...","QUIT_LEKTOR":"Quit Lektor","FILE":"File","UNDO":"Undo","REDO":"Redo","CUT":"Cut","COPY":"Copy","PASTE":"Paste","SELECT_ALL":"Select All","HELP":"Help","VISIT_WEBSITE":"Visit Website","INSTALL_SHELL_COMMAND":"Install Shell Command","INSTALL_SHELL_COMMAND_QUESTION":"Do you want to install the 'lektor' shell command? This requires admin rights.","FAILED_TO_INSTALL_SHELL_COMMANDS":"Failed to install shell commands.","INSTALL_SHELL_COMMAND_SUCCESS":"Shell command was successfully installed.","OPERATION_SUCCESS":"Success","YES":"Yes","NO":"No","OK":"OK","FAILED_TO_OPEN_CONTENT_FILE":"Failed to open content file","OPEN_OTHER_PROJECT":"Open other Project","OPEN_OTHER_PROJECT_QUESTION":"Opening this file requires opening another project (%s). The current project will be closed. Do you want to continue?"} + +/***/ }), +/* 288 */ +/***/ (function(module, exports) { + +module.exports = {"RETURN_TO_WEBSITE":"Volver al Sitio Web","UNLOAD_ACTIVE_TAB":"Tiene información sin guardar, está seguro de que quiere abandonar esta página?","EDIT_METADATA":"Editar Metadatos","EDIT":"Editar","DELETE":"Borrar","PREVIEW":"Previsualizar","ALTS":"Alternativas","PRIMARY_ALT":"Primaria","PRIMARY_OVERLAY":"Overlaid","ADD_CHILD_PAGE":"Añadir Página","ADD_ATTACHMENT":"Añadir Adjunto","ATTACHMENT_ACTIONS":"Acciones de Adjunto","PAGE_ACTIONS":"Acciones de Página","NO_CHILD_PAGES":"Sin Subpáginas","CHILD_PAGES":"Subpáginas","NO_ATTACHMENTS":"Sin Adjuntos","ATTACHMENTS":"Adjuntos","ADD_ATTACHMENT_TO":"Añadir Adjunto a “%s”","ADD_ATTACHMENT_NOTE":"Puede cargar un nuevo adjunto aquí.","UPLOAD":"Cargar","PROGRESS":"Avance","ERROR_PREFIX":"Error: ","ERROR_NO_ID_PROVIDED":"No se proporcionó un ID.","ERROR_PAGE_ID_DUPLICATE":"Ya existe una página con este ID (%s).","ERROR_INVALID_ID":"ID inválido","ERROR_INVALID_DATE":"Fecha inválida","ERROR_INVALID_NUMBER":"Número no válido","ERROR_INVALID_URL":"URL no válida","ERROR":"Error","ERROR_OCURRED":"Ocurrió un Error","ERROR_REQUEST_FAILED":"No se pudo enviar el comando al servidor. ¿Es posible que el servidor esté apagado o no responda?","ERROR_SERVER_UNAVAILABLE":"Servidor No Disponible","ERROR_SERVER_UNAVAILABLE_MESSAGE":"El servidor no responde. Fue apagado o hubo un error crítico que lo hace inoperativo y necesita ser reiniciado.","MODEL":"Modelo","ADD_CHILD_PAGE_TO":"Añada Subpágina a “%s”","ADD_CHILD_PAGE_NOTE":"Puede añadir una nueva subpágina aquí. Tenga en cuenta que el modelo o el ID no puede ser cambiado fácilmente más tarde.","CREATE_CHILD_PAGE":"Añada Página Hijo","DELETE_ATTACHMENT_PROMPT":"¿Quiere realmente borrar este anexo?","DELETE_ATTACHMENT_ALT_PROMPT":"¿Quiere realmente borrar los metadatos de esta alternativa de anexo?","DELETE_PAGE_PROMPT":"¿Quiere realmente borrar esta página?","DELETE_PAGE_ALT_PROMPT":"¿Quiere realmente borrar esta alternativa?","DELETE_PAGE_CHILDREN_WARNING":"Esto también borrará las subpáginas hijo de esta página.","DELETE_RECORD":"Borrar “%s”","DELETE_ALL_PAGE_ALTS":"Borrar también todas las alternativas y ficheros adjuntos.","DELETE_ALL_ATTACHMENT_ALTS":"Borrar todas las alternativas y el fichero adjunto.","DELETE_ONLY_PRIMARY_PAGE_ALT":"Borra sólo el registro principal. Los adjuntos, las alternativas y las subpáginas no serán borradas.","DELETE_ONLY_PRIMARY_ATTACHMENT_ALT":"Borra sólo los metadatos del registro principal.","DELETE_PRIMARY_ALT_INFO":"Como este registro es una alternativa principal, puede ser borrado por separado o junto al resto de contenidos.","CHILD_PAGES_TO_BE_DELETED":"Subpáginas que serán borradas:","ALTS_TO_BE_DELETED":"Alternativas que serán borradas:","ATTACHMENTS_TO_BE_DELETED":"Adjuntos que serán borrados:","YES_DELETE":"Sí, borrar","NO_CANCEL":"No, cancelar","SYSTEM_FIELDS":"Campos de Sistema","EDIT_ATTACHMENT_METADATA_OF":"Editar los Metadatos del Adjunto “%s”","EDIT_PAGE_NAME":"Editar “%s”","SAVE_CHANGES":"Guardar los cambios","BROWSE_FS":"Navegar en el Sistema de ficheros","BROWSE_FS_MAC":"Mostrar en el Finder","BROWSE_FS_WINDOWS":"Abrir en el Explorador","ERROR_CANNOT_BROWSE_FS":"Error: el fichero no existe todavía.","REMOVE_FLOWBLOCK_PROMPT":"¿Quiere realmente borrar este bloque?","ADD_FLOWBLOCK":"Añadir Bloque","INVALID_INPUT":"Entrada inválida","UP":"Arriba","DOWN":"Abajo","REMOVE":"Eliminar","ID":"ID","CLOSE":"Cerrar","CANCEL":"Cancelar","BACK_TO_OVERVIEW":"Vuelve a Revisión","PUBLISH":"Publicar","PUBLISH_NOTE":"Desde aquí puede publicar la versión actual del sitio web.","PUBLISH_SERVER":"Servidor Destino","CURRENTLY_PUBLISHING":"Publicando …","STATE":"Estado","PUBLISH_DONE":"Publicado","PUBLISH_STATE_BUILDING":"Los cambios se están generando ...","PUBLISH_STATE_PUBLISH":"Los cambios están siendo publicados ...","PUBLISH_STATE_DONE":"Publicación finalizada.","FIND_FILES":"Encontrar Ficheros","FIND_FILES_PLACEHOLDER":"Introduzca el nombre de la página ...","ATTACHMENT_TYPE":"Tipo de adjunto","URL_SLUG":"URL personalizada","TEMPLATE":"Plantilla","HIDE_PAGE":"Ocultar página","HIDE_PAGE_EXPLANATION":"¿Debería estar oculta esta página?","PAGE_IS_DISCOVERABLE":"La Página es detectable","PAGE_IS_DISCOVERABLE_EXPLANATION":"Si esto está habilitado la página puede ser detectada, en caso contrario la URL ha de ser conocida.","REFRESH_BUILD":"Refrescar la Generación","REFRESH_BUILD_NOTE":"Esto borra todos los resultados generados y lanza una nueva generación desde cero. Esto es útil en ciertas situaciones donde errores de sincronización o en las plantillas causaron un resultado corrupto.","CURRENTLY_REFRESHING_BUILD":"Regenerando ...","REFRESHING_BUILD_DONE":"¡Acabó la regeneración!","FAILED_TO_LAUNCH_LEKTOR":"Falló la ejecución de Lektor.","PROJECT":"Proyecto","CLOSE_PROJECT":"Cerrar Proyecto","OPEN_PROJECT":"Abrir Proyecto","BROWSE_WEBSITE":"Navegar Sitio Web","VIEW_ADMIN_PANEL":"Ver Panel de Administración","QUIT":"Salir","FAILED_TO_LOAD_PROJECT":"Falló la carga del proyecto :(","LOADING_PROJECT":"Cargando proyecto ...","INITIALIZING_LEKTOR":"Inicializando Lektor ...","QUIT_LEKTOR":"Salir de Lektor","FILE":"Archivo","UNDO":"Deshacer","REDO":"Rehacer","CUT":"Cortar","COPY":"Copiar","PASTE":"Pegar","SELECT_ALL":"Seleccionar Todo","HELP":"Ayuda","VISIT_WEBSITE":"Visitar Web","INSTALL_SHELL_COMMAND":"Instalar Comando","INSTALL_SHELL_COMMAND_QUESTION":"¿Quiere instalar el comando 'lektor'? Son necesarios privilegios de administrador.","FAILED_TO_INSTALL_SHELL_COMMANDS":"Falló la instalación de los comandos.","INSTALL_SHELL_COMMAND_SUCCESS":"El comando se instaló con éxito.","OPERATION_SUCCESS":"Con éxito","YES":"Sí","NO":"No","OK":"OK","FAILED_TO_OPEN_CONTENT_FILE":"Falló al abrir el fichero de contenido","OPEN_OTHER_PROJECT":"Abrir otro Proyecto","OPEN_OTHER_PROJECT_QUESTION":"Abrir este fichero requiere abrir otro proyecto (%s). El proyecto actual será cerrado. ¿Quiere continuar?"} + +/***/ }), +/* 289 */ +/***/ (function(module, exports) { + +module.exports = {"RETURN_TO_WEBSITE":"Retour au site Web","UNLOAD_ACTIVE_TAB":"Des informations ne sont pas enregistrées, voulez-vous vraiment quitter cette page ?","EDIT_METADATA":"Modifier les métadonnées","EDIT":"Modifier","DELETE":"Supprimer","PREVIEW":"Aperçu","ALTS":"Alternatives","PRIMARY_ALT":"Primaire","PRIMARY_OVERLAY":"Superposée","ADD_CHILD_PAGE":"Ajouter une page","ADD_ATTACHMENT":"Joindre un fichier","ATTACHMENT_ACTIONS":"Actions sur les fichiers joints","PAGE_ACTIONS":"Action sur les pages","NO_CHILD_PAGES":"Aucune sous-page","CHILD_PAGES":"Sous-pages","NO_ATTACHMENTS":"Aucun fichier joint","ATTACHMENTS":"Fichiers joints","ADD_ATTACHMENT_TO":"Joindre un fichier à « %s »","ADD_ATTACHMENT_NOTE":"Vous pouvez téléverser un nouveau fichier joint ici.","UPLOAD":"Téléverser","PROGRESS":"Progression","ERROR_PREFIX":"Erreur : ","ERROR_NO_ID_PROVIDED":"Erreur : aucun ID fourni.","ERROR_PAGE_ID_DUPLICATE":"Une page avec cet ID (%s) existe déjà.","ERROR_INVALID_ID":"ID non valide","ERROR_INVALID_DATE":"Date non valide","ERROR_INVALID_NUMBER":"Nombre non valide","ERROR_INVALID_URL":"URL non valide","ERROR":"Erreur","ERROR_OCURRED":"Une erreur a été rencontrée","ERROR_REQUEST_FAILED":"La commande n'a pas pu être envoyée au serveur. Le serveur a peut-être été arrêté ou ne répond plus ?","ERROR_SERVER_UNAVAILABLE":"Serveur indisponible","ERROR_SERVER_UNAVAILABLE_MESSAGE":"Le serveur ne répond pas. Il a dû être arrêté ou une erreur critique l'a rendu inopérant et il doit être redémarré.","MODEL":"Modèle","ADD_CHILD_PAGE_TO":"Ajouter une sous-page à « %s »","ADD_CHILD_PAGE_NOTE":"Vous pouvez ajouter une nouvelle sous-page à la page ici. Veuillez noter que le modèle ou l'ID ne peut pas être changé facilement ultérieurement.","CREATE_CHILD_PAGE":"Ajouter une sous-page","DELETE_ATTACHMENT_PROMPT":"Voulez-vous vraiment supprimer ce fichier joint ?","DELETE_ATTACHMENT_ALT_PROMPT":"Voulez-vous vraiment supprimer les métadonnées de ce fichier joint alternatif ?","DELETE_PAGE_PROMPT":"Voulez-vous vraiment supprimer cette page ?","DELETE_PAGE_ALT_PROMPT":"Voulez-vous vraiment supprimer cette version alternative ?","DELETE_PAGE_CHILDREN_WARNING":"Cela supprimera aussi les sous-pages de cette page.","DELETE_RECORD":"Supprimer « %s »","DELETE_ALL_PAGE_ALTS":"Supprimer aussi toutes les versions alternatives et les fichiers joints.","DELETE_ALL_ATTACHMENT_ALTS":"Supprimer toutes les versions alternatives et les fichiers joints.","DELETE_ONLY_PRIMARY_PAGE_ALT":"Supprimer seulement le premier enregistrement. Les fichiers joints, versions alternatives et sous-pages ne seront pas supprimées.","DELETE_ONLY_PRIMARY_ATTACHMENT_ALT":"Supprimer seulement les métadonnées de la pièce jointe primaire.","DELETE_PRIMARY_ALT_INFO":"Cet enregistrement étant l'alternative primaire, il peut être supprimé séparément ou avec tous les autres contenus.","CHILD_PAGES_TO_BE_DELETED":"Les sous-pages qui seront supprimées :","ALTS_TO_BE_DELETED":"Les versions alternatives qui seront supprimées :","ATTACHMENTS_TO_BE_DELETED":"Les fichiers joints qui seront supprimés :","YES_DELETE":"Oui, supprimer","NO_CANCEL":"Non, annuler","SYSTEM_FIELDS":"Champs système","EDIT_ATTACHMENT_METADATA_OF":"Modifier les métadonnées du fichier joint « %s »","EDIT_PAGE_NAME":"Modifier « %s »","SAVE_CHANGES":"Enregistrer les changements","BROWSE_FS":"Parcourir le système de fichiers","BROWSE_FS_MAC":"Révéler dans le Finder","BROWSE_FS_WINDOWS":"Ouvrir dans l'Explorateur","ERROR_CANNOT_BROWSE_FS":"Erreur : le fichier n'existe pas encore.","REMOVE_FLOWBLOCK_PROMPT":"Voulez-vous vraiment supprimer ce bloc ?","ADD_FLOWBLOCK":"Ajouter un bloc","INVALID_INPUT":"Saisie non valide","UP":"Haut","DOWN":"Bas","REMOVE":"Enlever","ID":"ID","CLOSE":"Fermer","CANCEL":"Annuler","BACK_TO_OVERVIEW":"Retour à l'aperçu","PUBLISH":"Publier","PUBLISH_NOTE":"À partir de maintenant, vous pouvez publier la version actuelle de votre site Web.","PUBLISH_SERVER":"Serveur cible","CURRENTLY_PUBLISHING":"Publication en cours…","STATE":"Statut","PUBLISH_DONE":"Publié","PUBLISH_STATE_BUILDING":"Les changements sont en cours de construction…","PUBLISH_STATE_PUBLISH":"Les changements sont en cours de publication…","PUBLISH_STATE_DONE":"Publication effectuée.","FIND_FILES":"Trouver les fichiers","FIND_FILES_PLACEHOLDER":"Saisir le nom de la page…","ATTACHMENT_TYPE":"Type de fichier joint","URL_SLUG":"Motif d'URL (slug)","TEMPLATE":"Modèle","HIDE_PAGE":"Masquer la page","HIDE_PAGE_EXPLANATION":"Est-ce que cette page devrait être masquée ?","PAGE_IS_DISCOVERABLE":"La page est « découvrable »","PAGE_IS_DISCOVERABLE_EXPLANATION":"Si activé, la page pourra être retrouvée car elle sera indexée, sinon l'URL devra être connue pour y accéder.","REFRESH_BUILD":"Actualiser la construction","REFRESH_BUILD_NOTE":"Cela supprime tous les résultats de la construction et entraîne une reconstruction complète. C'est utile dans certaines situations où le résultat est corrompu suite à des erreurs de synchronisation ou de modèles.","CURRENTLY_REFRESHING_BUILD":"Actualisation de la construction en cours…","REFRESHING_BUILD_DONE":"Actualisation de la construction terminée","FAILED_TO_LAUNCH_LEKTOR":"Impossible de lancer Lektor.","PROJECT":"Projet","CLOSE_PROJECT":"Fermer le projet","OPEN_PROJECT":"Ouvrir le projet","BROWSE_WEBSITE":"Ouvrir le site Web","VIEW_ADMIN_PANEL":"Voir le panneau administrateur","QUIT":"Quitter","FAILED_TO_LOAD_PROJECT":"Impossible de charger le projet :(","LOADING_PROJECT":"Chargement du projet…","INITIALIZING_LEKTOR":"Initialisation de Lektor…","QUIT_LEKTOR":"Quitter Lektor","FILE":"Fichier","UNDO":"Annuler","REDO":"Rétablir","CUT":"Couper","COPY":"Copier","PASTE":"Coller","SELECT_ALL":"Sélectionner tout","HELP":"Aide","VISIT_WEBSITE":"Visiter le site Web","INSTALL_SHELL_COMMAND":"Installer la commande shell","INSTALL_SHELL_COMMAND_QUESTION":"Voulez-vous installer la commande shell « lektor » ? Cela nécessite des droits administrateurs.","FAILED_TO_INSTALL_SHELL_COMMANDS":"Impossible d'installer les commandes shell.","INSTALL_SHELL_COMMAND_SUCCESS":"La commande shell a été correctement installée.","OPERATION_SUCCESS":"Succès","YES":"Oui","NO":"Non","OK":"OK","FAILED_TO_OPEN_CONTENT_FILE":"Impossible d'ouvir le contenu du fichier","OPEN_OTHER_PROJECT":"Ouvrir un autre projet","OPEN_OTHER_PROJECT_QUESTION":"Ouvrir ce fichier nécessite d'ouvrir un autre projet (%s). Le projet actuel sera fermé. Voulez-vous vraiment continuer ?"} + +/***/ }), +/* 290 */ +/***/ (function(module, exports) { + +module.exports = {"RETURN_TO_WEBSITE":"Torna al sito web","UNLOAD_ACTIVE_TAB":"Hai informazioni non salvate, sei sicuro di voler abbandonare questa pagina?","EDIT_METADATA":"Modifica metadati","EDIT":"Modifica","DELETE":"Cancella","PREVIEW":"Anteprima","ALTS":"Alternative","PRIMARY_ALT":"Primaria","PRIMARY_OVERLAY":"Sovrascritta","ADD_CHILD_PAGE":"Aggiungi pagina","ADD_ATTACHMENT":"Aggiungi allegato","ATTACHMENT_ACTIONS":"Azioni sull'allegato","PAGE_ACTIONS":"Azioni sulla pagina","NO_CHILD_PAGES":"Nessuna sottopagina","CHILD_PAGES":"Sottopagine","NO_ATTACHMENTS":"Nessun alleagto","ATTACHMENTS":"Allegati","ADD_ATTACHMENT_TO":"Aggiungi allegato a “%s”","ADD_ATTACHMENT_NOTE":"Puoi caricare un allegato qui.","UPLOAD":"Carica","PROGRESS":"Avanzamento","ERROR_PREFIX":"Errore: ","ERROR_NO_ID_PROVIDED":"Nessun ID fornito.","ERROR_PAGE_ID_DUPLICATE":"Una pagina con questo ID (%s) esiste già.","ERROR_INVALID_ID":"ID non valido","ERROR_INVALID_DATE":"Data non valida","ERROR_INVALID_NUMBER":"Non è un numero valido","ERROR_INVALID_URL":"Non è un indirizzo valido","ERROR":"Errore","ERROR_OCURRED":"È capitato un errore","ERROR_REQUEST_FAILED":"Impossibile inviare comandi al server. Magari il server è stato spento o è sovraccarico?","ERROR_SERVER_UNAVAILABLE":"Server non disponibile","ERROR_SERVER_UNAVAILABLE_MESSAGE":"Il server non risponde. Può essere spento o un errore critico l'ha reso non operativo ed è necessario riavviarlo.","MODEL":"Modello","ADD_CHILD_PAGE_TO":"Aggiungi sottopagina a “%s”","ADD_CHILD_PAGE_NOTE":"Puoi aggiungere una nuova sottopagina qui. Tieni presente che il modello o l'ID non potranno essere cambiati facilmente in futuro.","CREATE_CHILD_PAGE":"Aggiungi sottopagina","DELETE_ATTACHMENT_PROMPT":"Vuoi veramente cancellare questo allegato?","DELETE_ATTACHMENT_ALT_PROMPT":"Vuoi veramente cancellare i metadati di questa alternativa all'allegato?","DELETE_PAGE_PROMPT":"Vuoi veramente cancellare questa pagina?","DELETE_PAGE_ALT_PROMPT":"Vuoi veramente cancellare questa alternativa?","DELETE_PAGE_CHILDREN_WARNING":"Questo cancellerà anche le sottopagine di questa pagina.","DELETE_RECORD":"Cancella “%s”","DELETE_ALL_PAGE_ALTS":"Cancella anche tutte le alternative ed i file allegati.","DELETE_ALL_ATTACHMENT_ALTS":"Cancella tutte le alternative ed il file allegato.","DELETE_ONLY_PRIMARY_PAGE_ALT":"Cancella solo la pagina principale. Allegati, alternative e sottopagine nnon verranno cancellate.","DELETE_ONLY_PRIMARY_ATTACHMENT_ALT":"Cancella solo i metadati dell'allegato principale.","DELETE_PRIMARY_ALT_INFO":"Dato che questo oggetto è l'alternativa primaria, può essere cancellato separatamente o insieme al resto del contenuto.","CHILD_PAGES_TO_BE_DELETED":"Sottopagine che verranno cancellate:","ALTS_TO_BE_DELETED":"Alternative che verranno cancellate:","ATTACHMENTS_TO_BE_DELETED":"Allegati che verranno cancellati:","YES_DELETE":"Si, cancella","NO_CANCEL":"No, annulla","SYSTEM_FIELDS":"Campi di sistema","EDIT_ATTACHMENT_METADATA_OF":"Modifica i metadati dell'allegato “%s”","EDIT_PAGE_NAME":"Modifica “%s”","SAVE_CHANGES":"Salva modifiche","BROWSE_FS":"Apri nel filesystem","BROWSE_FS_MAC":"Apri in Finder","BROWSE_FS_WINDOWS":"Apri in Esplora risorse","ERROR_CANNOT_BROWSE_FS":"Errore: il file non esiste.","REMOVE_FLOWBLOCK_PROMPT":"Vuoi davvero cancellare questo blocco?","ADD_FLOWBLOCK":"Aggiungi blocco","INVALID_INPUT":"Input invalido","UP":"Su","DOWN":"Giù","REMOVE":"Rimuovi","ID":"ID","CLOSE":"Chiudi","CANCEL":"Annulla","BACK_TO_OVERVIEW":"Torna alla panoramica","PUBLISH":"Pubblica","PUBLISH_NOTE":"Da qui puoi pubblicare la versione corrente del sito web.","PUBLISH_SERVER":"Server di destinazione","CURRENTLY_PUBLISHING":"Pubblicazione in corso...","STATE":"Stato","PUBLISH_DONE":"Pubblicato","PUBLISH_STATE_BUILDING":"Costruendo le pagine modificate...","PUBLISH_STATE_PUBLISH":"Pubblicando le pagine modificate...","PUBLISH_STATE_DONE":"Pubblicazione completata.","FIND_FILES":"Trova i file","FIND_FILES_PLACEHOLDER":"Inserisci il nome della pagina...","ATTACHMENT_TYPE":"Tipo dell'allegato","URL_SLUG":"Alias della pagina","TEMPLATE":"Template","HIDE_PAGE":"Nascondi pagina","HIDE_PAGE_EXPLANATION":"Questa pagina deve essere nascosta?","PAGE_IS_DISCOVERABLE":"La pagina può essere scoperta?","PAGE_IS_DISCOVERABLE_EXPLANATION":"Se è abilitato la pagina può essere scoperta, altrimenti l'indirizzo deve essere noto.","REFRESH_BUILD":"Esegui build completa","REFRESH_BUILD_NOTE":"Questo cancella tutti i risultati precedenti, eseguendo una build completa. Questo è utile in casi in cui errori di sincronizzazione o errori nei template rendono il risultato corrotto.","CURRENTLY_REFRESHING_BUILD":"Eseguendo build completa...","REFRESHING_BUILD_DONE":"Build completa eseguita!","FAILED_TO_LAUNCH_LEKTOR":"Impossibile eseguire Lektor.","PROJECT":"Progetto","CLOSE_PROJECT":"Chiudi progetto","OPEN_PROJECT":"Apri progetto","BROWSE_WEBSITE":"Naviga nel sito web","VIEW_ADMIN_PANEL":"Mostra pannello di amministrazione","QUIT":"Esci","FAILED_TO_LOAD_PROJECT":"Impossibile caricare il progetto :(","LOADING_PROJECT":"Caricamento del progetto...","INITIALIZING_LEKTOR":"Preparazione di Lektor...","QUIT_LEKTOR":"Esci da Lektor","FILE":"File","UNDO":"Annulla","REDO":"Ripeti","CUT":"Taglia","COPY":"Copia","PASTE":"Incolla","SELECT_ALL":"Seleziona tutto","HELP":"Aiuto","VISIT_WEBSITE":"Visita il sito web","INSTALL_SHELL_COMMAND":"Installa comando shell","INSTALL_SHELL_COMMAND_QUESTION":"Vuoi installare il comando shell 'lektor'? Questo richiede privilegi di amministrazione.","FAILED_TO_INSTALL_SHELL_COMMANDS":"Impossibile installare il comando shell.","INSTALL_SHELL_COMMAND_SUCCESS":"Il comando shell è stato installato con successo.","OPERATION_SUCCESS":"Successo","YES":"Si","NO":"No","OK":"OK","FAILED_TO_OPEN_CONTENT_FILE":"Impossibile aprire il file di contenuto","OPEN_OTHER_PROJECT":"Apri un altro progetto","OPEN_OTHER_PROJECT_QUESTION":"Aprire questo file richiede l'apertura di un altro progetto (%s). Il progetto corrente verrà chiuso. Vuoi proseguire?"} + +/***/ }), +/* 291 */ +/***/ (function(module, exports) { + +module.exports = {"RETURN_TO_WEBSITE":"Websiteに戻る","UNLOAD_ACTIVE_TAB":"保存していない編集があります、本当にページを離れますか?","EDIT_METADATA":"メタデータの編集","EDIT":"編集","DELETE":"削除","PREVIEW":"プレビュー","ALTS":"代替","PRIMARY_ALT":"プライマリー","PRIMARY_OVERLAY":"上書き","ADD_CHILD_PAGE":"ページの追加","ADD_ATTACHMENT":"アタッチメントの追加","ATTACHMENT_ACTIONS":"アタッチメントのアクション","PAGE_ACTIONS":"ページアクション","NO_CHILD_PAGES":"サブページはありません","CHILD_PAGES":"サブページ","NO_ATTACHMENTS":"アタッチメントはありません","ATTACHMENTS":"アタッチメント","ADD_ATTACHMENT_TO":"“%s”にアタッチメントを追加する","ADD_ATTACHMENT_NOTE":"ここに新しいアタッチメントをアップロードできます","UPLOAD":"アップロード","PROGRESS":"プログレス","ERROR_PREFIX":"エラー: ","ERROR_NO_ID_PROVIDED":"IDがありません","ERROR_PAGE_ID_DUPLICATE":"このID (%s) のページはすでに存在します","ERROR_INVALID_ID":"IDが不正です","ERROR_INVALID_DATE":"日付が不正です","ERROR_INVALID_NUMBER":"不正な番号です","ERROR_INVALID_URL":"URLが不正です","ERROR":"エラー","ERROR_OCURRED":"エラーが発生しました","ERROR_REQUEST_FAILED":"サーバーにコマンドが送れませんでした、サーバーが止まっているか応答がないのかもしれません","ERROR_SERVER_UNAVAILABLE":"サーバーアンアベイラブル","ERROR_SERVER_UNAVAILABLE_MESSAGE":"サーバーが応答しません、中断されたかクリティカルなエラーが発生したたためオペレーションが完了しなかったためリスタートが必要です。","MODEL":"モデル","ADD_CHILD_PAGE_TO":"“%s”にサブページを追加する","ADD_CHILD_PAGE_NOTE":"このページにサブページが作れます。注意: モデルまたはIDはその後簡単には変更できません。","CREATE_CHILD_PAGE":"チャイルドページを作る","DELETE_ATTACHMENT_PROMPT":"本当にこの添付を削除しますか?","DELETE_ATTACHMENT_ALT_PROMPT":"本当にこの添付代替のメタデータを削除しますか?","DELETE_PAGE_PROMPT":"このページを本当に削除しますか?","DELETE_PAGE_ALT_PROMPT":"この代替を本能に削除しますか?","DELETE_PAGE_CHILDREN_WARNING":"このページのサブページも削除されます","DELETE_RECORD":"“%s”を削除","DELETE_ALL_PAGE_ALTS":"すべての代替と添付も削除","DELETE_ALL_ATTACHMENT_ALTS":"すべての代替と添付を削除","DELETE_ONLY_PRIMARY_PAGE_ALT":"プライマリレコードのメタデータのみ削除。添付、代替、サブページは削除されません。","DELETE_ONLY_PRIMARY_ATTACHMENT_ALT":"プライマリレコードのメタデータのみ削除","DELETE_PRIMARY_ALT_INFO":"このレコードはプライマリの代替のため、別に削除することも、他のすべてのコンポーネントともに削除することもできます。","CHILD_PAGES_TO_BE_DELETED":"サブページは削除されます:","ALTS_TO_BE_DELETED":"代替は削除されます:","ATTACHMENTS_TO_BE_DELETED":"添付は削除されます:","YES_DELETE":"はい、削除します","NO_CANCEL":"いいえ、キャンセルします","SYSTEM_FIELDS":"システムフィールド","EDIT_ATTACHMENT_METADATA_OF":"添付 “%s”のメタデータを編集","EDIT_PAGE_NAME":"“%s”を編集","SAVE_CHANGES":"編集を保存","BROWSE_FS":"ファイルシステムで閲覧する","BROWSE_FS_MAC":"ファインダーで開く","BROWSE_FS_WINDOWS":"エクスプローラで開く","ERROR_CANNOT_BROWSE_FS":"エラー: ファイルは存在しません","REMOVE_FLOWBLOCK_PROMPT":"このブロックを本当に削除しますか?","ADD_FLOWBLOCK":"ブロックを追加","INVALID_INPUT":"不正な入力","UP":"アップ","DOWN":"ダウン","REMOVE":"取り除く","ID":"ID","CLOSE":"閉じる","CANCEL":"キャンセル","BACK_TO_OVERVIEW":"オーバービューに戻る","PUBLISH":"公開","PUBLISH_NOTE":"ここから現行のウェブサイトを公開できます。","PUBLISH_SERVER":"ターゲットサーバー","CURRENTLY_PUBLISHING":"公開 …","STATE":"状態","PUBLISH_DONE":"公開中","PUBLISH_STATE_BUILDING":"変更がをビルドしています...","PUBLISH_STATE_PUBLISH":"変更が公開されました ...","PUBLISH_STATE_DONE":"公開完了","FIND_FILES":"ファイルを見つける","FIND_FILES_PLACEHOLDER":"ページ名を入力...","ATTACHMENT_TYPE":"添付タイプ","URL_SLUG":"URLストリング","TEMPLATE":"テンプレート","HIDE_PAGE":"ヘージを隠す","HIDE_PAGE_EXPLANATION":"このページを非表示にしますか?","PAGE_IS_DISCOVERABLE":"このページは外部から見ることが可能です","PAGE_IS_DISCOVERABLE_EXPLANATION":"有効にすることで、ページは発見可能になります、そうしない場合はアクセスするのにそのURLを知っている必要があります。","REFRESH_BUILD":"ビルドを更新","REFRESH_BUILD_NOTE":"これは、キャッシュ済みのビルド結果をすべて削除し、最初からの構築を開始します。同期のエラーやテンプレート内のミスにより出力が不正な場合に有効です。","CURRENTLY_REFRESHING_BUILD":"ビルドを更新中...","REFRESHING_BUILD_DONE":"ビルドを更新が完了しました!","FAILED_TO_LAUNCH_LEKTOR":"Lektorを開けるのに失敗しました","PROJECT":"プロジェクト","CLOSE_PROJECT":"プロジェクトを閉じる","OPEN_PROJECT":"プロジェクトを開ける","BROWSE_WEBSITE":"ブラウザで開く","VIEW_ADMIN_PANEL":"アドミンパネルを開く","QUIT":"終了","FAILED_TO_LOAD_PROJECT":"Failed to load the project :(","LOADING_PROJECT":"プロジェクトを読み込んでいます ...","INITIALIZING_LEKTOR":"Lektorを初期化しています ...","QUIT_LEKTOR":"Lektorを終了する","FILE":"ファイル","UNDO":"アンドゥー","REDO":"リドゥー","CUT":"カット","COPY":"コピー","PASTE":"ペースト","SELECT_ALL":"全てを選択","HELP":"ヘルプ","VISIT_WEBSITE":"Websiteを訪ねる","INSTALL_SHELL_COMMAND":"シェルコマンドをインストール","INSTALL_SHELL_COMMAND_QUESTION":"「lektor」のシェルコマンドをインストールしますか?。インストールするには管理権限が必要です。","FAILED_TO_INSTALL_SHELL_COMMANDS":"シェルコマンドのインストールに失敗しました。","INSTALL_SHELL_COMMAND_SUCCESS":"シェルコマンドのインストールに成功しました。","OPERATION_SUCCESS":"成功","YES":"はい","NO":"いいえ","OK":"了解","FAILED_TO_OPEN_CONTENT_FILE":"コンテンツファイルを開くのに失敗しました","OPEN_OTHER_PROJECT":"他のプロジェクトを開く","OPEN_OTHER_PROJECT_QUESTION":"このファイルを開くには、他のプロジェクト(%s)を開く必要があります。現在のプロジェクトは閉じられます、処理を継続しますか?"} + +/***/ }), +/* 292 */ +/***/ (function(module, exports) { + +module.exports = {"RETURN_TO_WEBSITE":"사이트로 되돌아가기","UNLOAD_ACTIVE_TAB":"저장되지 않은 정보가 있습니다. 페이지를 떠나시겠습니까?","EDIT_METADATA":"메타데이터 수정","EDIT":"수정","DELETE":"삭제","PREVIEW":"미리보기","ALTS":"다른 언어","PRIMARY_ALT":"기본","PRIMARY_OVERLAY":"겹친","ADD_CHILD_PAGE":"페이지 추가","ADD_ATTACHMENT":"첨부 파일 추가","ATTACHMENT_ACTIONS":"첨부 파일 작업","PAGE_ACTIONS":"페이지 작업","NO_CHILD_PAGES":"하위 페이지 없음","CHILD_PAGES":"하위 페이지","NO_ATTACHMENTS":"첨부 파일 없음","ATTACHMENTS":"첨부 파일","ADD_ATTACHMENT_TO":"“%s“에서 첨부 파일 추가","ADD_ATTACHMENT_NOTE":"여기서 새로운 첨부 파일을 업로드할 수 있습니다.","UPLOAD":"업로드","PROGRESS":"진행","ERROR_PREFIX":"에러: ","ERROR_NO_ID_PROVIDED":"제공된 ID가 없습니다.","ERROR_PAGE_ID_DUPLICATE":"이 ID (%s) 페이지는 이미 존재합니다.","ERROR_INVALID_ID":"잘못된 ID","ERROR_INVALID_DATE":"잘못된 날짜","ERROR_INVALID_NUMBER":"유효한 숫자 아님","ERROR_INVALID_URL":"유효한 URL 아님","ERROR":"에러","ERROR_OCURRED":"오류 발생","ERROR_REQUEST_FAILED":"서버에 명령을 보내지 못했습니다. 서버가 중지되었거나 응답하지 않을 수도 있네요?","ERROR_SERVER_UNAVAILABLE":"서버를 사용할 수 없음","ERROR_SERVER_UNAVAILABLE_MESSAGE":"서버가 응답하지 않습니다. 서버가 중지되었거나, 재시작을 필요로 하는 치명적인 오류가 발생했습니다.","MODEL":"모델","ADD_CHILD_PAGE_TO":"“%s”에 하위 페이지 추가","ADD_CHILD_PAGE_NOTE":"이 페이지에서 새로운 하위 페이지를 추가할 수 있습니다. 중요, 나중에 모델이나 ID를 변경하기 어렵습니다.","CREATE_CHILD_PAGE":"하위 페이지 추가","DELETE_ATTACHMENT_PROMPT":"정말로 첨부 파일을 삭제하실 건가요?","DELETE_ATTACHMENT_ALT_PROMPT":"정말로 첨부 파일의 다른 언어에 대한 메타데이터를 삭제하실 건가요?","DELETE_PAGE_PROMPT":"정말로 이 페이지를 삭제하실 건가요?","DELETE_PAGE_ALT_PROMPT":"정말로 이 다른 언어를 삭제하실 건가요?","DELETE_PAGE_CHILDREN_WARNING":"이 페이지의 하위 페이지 또한 삭제됩니다.","DELETE_RECORD":"“%s” 삭제","DELETE_ALL_PAGE_ALTS":"또한, 모든 다른 언어와 첨부 파일을 삭제합니다.","DELETE_ALL_ATTACHMENT_ALTS":"모든 다른 언어와 첨부 파일을 삭제합니다.","DELETE_ONLY_PRIMARY_PAGE_ALT":"오직 주 레코드만 삭제됩니다. 첨부 파일, 다른 언어, 하위 페이지는 삭제되지 않습니다.","DELETE_ONLY_PRIMARY_ATTACHMENT_ALT":"오직 주 레코드의 메타데이터만 삭제됩니다.","DELETE_PRIMARY_ALT_INFO":"이 레코드는 기본 언어이기 때문에 별도로 삭제하거나 다른 콘텐츠 전부와 같이 삭제할 수 있습니다.","CHILD_PAGES_TO_BE_DELETED":"하위 페이지를 삭제합니다:","ALTS_TO_BE_DELETED":"다른 언어를 삭제합니다:","ATTACHMENTS_TO_BE_DELETED":"첨부 파일을 삭제합니다:","YES_DELETE":"네, 삭제","NO_CANCEL":"아니요, 취소","SYSTEM_FIELDS":"시스템 필드","EDIT_ATTACHMENT_METADATA_OF":"첨부 파일 “%s”의 메타데이터 수정","EDIT_PAGE_NAME":"“%s” 수정","SAVE_CHANGES":"변경 저장","BROWSE_FS":"파일 시스템 검색","BROWSE_FS_MAC":"파인더에서 검색","BROWSE_FS_WINDOWS":"탐색기에서 열기","ERROR_CANNOT_BROWSE_FS":"오류: 파일이 존재하지 않습니다.","REMOVE_FLOWBLOCK_PROMPT":"이 블록을 제거하시겠습니까?","ADD_FLOWBLOCK":"블록 추가","INVALID_INPUT":"잘못된 입력","UP":"위로","DOWN":"아래로","REMOVE":"제거","ID":"ID","CLOSE":"닫기","CANCEL":"취소","BACK_TO_OVERVIEW":"개요로 되돌아가기","PUBLISH":"발행","PUBLISH_NOTE":"여기서 웹사이트 현재 버전을 발행할 수 있습니다.","PUBLISH_SERVER":"대상 서버","CURRENTLY_PUBLISHING":"발행 중 ...","STATE":"상태","PUBLISH_DONE":"발행됨","PUBLISH_STATE_BUILDING":"변경 사항 빌드 중 ...","PUBLISH_STATE_PUBLISH":"변경 사항 발행 중 ...","PUBLISH_STATE_DONE":"발행 완료.","FIND_FILES":"파일 찾기","FIND_FILES_PLACEHOLDER":"페이지 이름 입력 ...","ATTACHMENT_TYPE":"첨부 파일 형식","URL_SLUG":"URL slug","TEMPLATE":"템플릿","HIDE_PAGE":"페이지 숨기기","HIDE_PAGE_EXPLANATION":"이 페이지를 숨길까요?","PAGE_IS_DISCOVERABLE":"페이지 다시보이기","PAGE_IS_DISCOVERABLE_EXPLANATION":"이 설정이 활성화되어있으면 페이지를 확인할 수 있습니다. 그렇지 않으면 URL만 확인할 수 있습니다.","REFRESH_BUILD":"새로운 빌드","REFRESH_BUILD_NOTE":"이 트리거는 처음부터 다시 빌드합니다. 그러면서 이전 빌드하면서 캐시된 결과를 삭제합니다. 이 기능은 동기화 오류나 템플릿에서 잘못된 설정으로 출력물에 문제가 있을 때 유용합니다.","CURRENTLY_REFRESHING_BUILD":"지금 새롭게 빌드 중 ...","REFRESHING_BUILD_DONE":"새로운 빌드를 완료하였습니다!","FAILED_TO_LAUNCH_LEKTOR":"실행하지 못하였습니다.","PROJECT":"프로젝트","CLOSE_PROJECT":"프로젝트 닫기","OPEN_PROJECT":"프로젝트 열기","BROWSE_WEBSITE":"웹사이트 찾아보기","VIEW_ADMIN_PANEL":"관리자 판넬 보기","QUIT":"나가기","FAILED_TO_LOAD_PROJECT":"프로젝트를 불러오지 못하였습니다. :(","LOADING_PROJECT":"프로젝트 불러오는 중 ...","INITIALIZING_LEKTOR":"Lektor 초기화 중 ...","QUIT_LEKTOR":"Lektor 나가기","FILE":"파일","UNDO":"실행 취소","REDO":"다시 실행","CUT":"잘라내기","COPY":"복사","PASTE":"붙여넣기","SELECT_ALL":"전부 선택","HELP":"도움말","VISIT_WEBSITE":"웹사이트 방문","INSTALL_SHELL_COMMAND":"쉘 커멘드 설치","INSTALL_SHELL_COMMAND_QUESTION":"'lektor' 쉘 명령을 설치하시겠습니까? 관리자 권한이 필요합니다.","FAILED_TO_INSTALL_SHELL_COMMANDS":"쉘 명령을 설치하지 못하였습니다.","INSTALL_SHELL_COMMAND_SUCCESS":"쉘 명령이 성공적으로 설치되었습니다.","OPERATION_SUCCESS":"완료","YES":"예","NO":"아니오","OK":"OK","FAILED_TO_OPEN_CONTENT_FILE":"현재 파일을 열지 못하였습니다.","OPEN_OTHER_PROJECT":"다른 프로젝트 열기","OPEN_OTHER_PROJECT_QUESTION":"열려는 파일은 다른 프로젝트 (%s)를 열어야합니다. 현재 프로젝트는 종료됩니다. 계속 하시겠습니까?"} + +/***/ }), +/* 293 */ +/***/ (function(module, exports) { + +module.exports = {"RETURN_TO_WEBSITE":"Terug naar Website","UNLOAD_ACTIVE_TAB":"U hebt niet-opgeslagen data, weet je zeker dat je deze pagina wil verlaten?","EDIT_METADATA":"Bewerk Metadata","EDIT":"Bewerk","DELETE":"Verwijderen","PREVIEW":"Voorbeeld","ALTS":"Alternatieven","PRIMARY_ALT":"Primair","PRIMARY_OVERLAY":"Overlapt","ADD_CHILD_PAGE":"Pagina toevoegen","ADD_ATTACHMENT":"Bijlage toevoegen","ATTACHMENT_ACTIONS":"Bijlage Acties","PAGE_ACTIONS":"Pagina Acties","NO_CHILD_PAGES":"Geen Subpagina's","CHILD_PAGES":"Subpagina's","NO_ATTACHMENTS":"Geen bijlages","ATTACHMENTS":"Bijlages","ADD_ATTACHMENT_TO":"Voeg bijlage toe aan “%s”","ADD_ATTACHMENT_NOTE":"Je kan hier een nieuwe bijlage uploaden.","UPLOAD":"Upload","PROGRESS":"Vooruitgang","ERROR_PREFIX":"Fout: ","ERROR_NO_ID_PROVIDED":"Geen ID gegeven.","ERROR_PAGE_ID_DUPLICATE":"Een pagina met deze ID (%s) bestaat al.","ERROR_INVALID_ID":"Ongeldige ID","ERROR_INVALID_DATE":"Ongeldige datum","ERROR_INVALID_NUMBER":"Geen geldig getal","ERROR_INVALID_URL":"Geen geldige URL","ERROR":"Fout","ERROR_OCURRED":"Er is een fout opgetreden","ERROR_REQUEST_FAILED":"Kon het commando niet naar de server sturen. Misschien is de server gestopt of reageert deze niet?","ERROR_SERVER_UNAVAILABLE":"Server niet beschikbaar","ERROR_SERVER_UNAVAILABLE_MESSAGE":"De server reageert niet. Deze was gestopt of door een kritieke fout niet langer operationeel en moet worden herstart.","MODEL":"Model","ADD_CHILD_PAGE_TO":"Voeg Subpagina toe aan “%s”","ADD_CHILD_PAGE_NOTE":"U kan hier een nieuwe subpagina toevoegen. Merk op dat het model of de ID achteraf niet makkelijk gewijzigd kunnen worden.","CREATE_CHILD_PAGE":"Subpagina Toevoegen","DELETE_ATTACHMENT_PROMPT":"Weet je zeker dat je deze bijlage wilt verwijderen?","DELETE_ATTACHMENT_ALT_PROMPT":"Weet je zeker dat je de metadata van dit bijlage alternatief wilt verwijderen?","DELETE_PAGE_PROMPT":"Weet je zeker dat je deze pagina wilt verwijderen?","DELETE_PAGE_ALT_PROMPT":"Weet je zeker dat je dit alternatief wilt verwijderen?","DELETE_PAGE_CHILDREN_WARNING":"Dit zal ook de subpagina's van deze pagina verwijderen.","DELETE_RECORD":"Verwijder “%s”","DELETE_ALL_PAGE_ALTS":"Verwijder ook de alternatieven en bijlages.","DELETE_ALL_ATTACHMENT_ALTS":"Verwijder alle alternatieven en bijlages.","DELETE_ONLY_PRIMARY_PAGE_ALT":"Verwijder enkel de primaire record. Bijlages, alternatieven en subpagina's zullen niet verwijderd worden.","DELETE_ONLY_PRIMARY_ATTACHMENT_ALT":"Verwijder enkel de metadata van de primaire record.","DELETE_PRIMARY_ALT_INFO":"Omdat dit record een primair alternatief is, kan het apart verwijderd worden of samen met alle andere inhoud.","CHILD_PAGES_TO_BE_DELETED":"Subpagina's die verwijderd zullen worden:","ALTS_TO_BE_DELETED":"Alternatieven die verwijderd zullen worden:","ATTACHMENTS_TO_BE_DELETED":"Bijlages die verwijderd zullen worden:","YES_DELETE":"Ja, verwijder","NO_CANCEL":"Nee, annuleer","SYSTEM_FIELDS":"Systeem Velden","EDIT_ATTACHMENT_METADATA_OF":"Bewerk Metadata van Bijlage “%s”","EDIT_PAGE_NAME":"Bewerk “%s”","SAVE_CHANGES":"Wijzigingen opslaan","BROWSE_FS":"Blader in Bestandsysteem","BROWSE_FS_MAC":"Bekijk in Finder","BROWSE_FS_WINDOWS":"Open in Explorer","ERROR_CANNOT_BROWSE_FS":"Fout: Bestand bestaat nog niet.","REMOVE_FLOWBLOCK_PROMPT":"Weet je zeker dat je dit blok wilt verwijderen?","ADD_FLOWBLOCK":"Blok Toevoegen","INVALID_INPUT":"Ongeldige Invoer","UP":"Omhoog","DOWN":"Omlaag","REMOVE":"Verwijderen","ID":"ID","CLOSE":"Sluiten","CANCEL":"Annuleren","BACK_TO_OVERVIEW":"Terug naar Overzicht","PUBLISH":"Publiceren","PUBLISH_NOTE":"Van hieruit kan je de huidige versie van je website publiceren.","PUBLISH_SERVER":"Doelserver","CURRENTLY_PUBLISHING":"Publiceren …","STATE":"Status","PUBLISH_DONE":"Gepubliceerd","PUBLISH_STATE_BUILDING":"De wijzigingen worden gebouwd ...","PUBLISH_STATE_PUBLISH":"De wijzigingen worden gepuliceerd ...","PUBLISH_STATE_DONE":"Klaar met publiceren.","FIND_FILES":"Zoek bestanden","FIND_FILES_PLACEHOLDER":"Vul paginanaam in ...","ATTACHMENT_TYPE":"Type Bijlage","URL_SLUG":"URL slug","TEMPLATE":"Template","HIDE_PAGE":"Verberg pagina","HIDE_PAGE_EXPLANATION":"Moet deze pagina verborgen zijn?","PAGE_IS_DISCOVERABLE":"Deze pagina is vindbaar","PAGE_IS_DISCOVERABLE_EXPLANATION":"Als dit ingeschakeld is, is de pagina vindbaar. Anders moet de URL bekend zijn.","REFRESH_BUILD":"Ververs Build","REFRESH_BUILD_NOTE":"Dit verwijdert alle buildresultaten in de cache en veroorzaakt een volledige rebuild. Dit is nuttig in bepaalde situaties waar synchonisatiefouten of fouten in de templates de uitvoer corrupt hebben gemaakt.","CURRENTLY_REFRESHING_BUILD":"Bezig met verversen van de build ...","REFRESHING_BUILD_DONE":"Klaar met de build te verversen!","FAILED_TO_LAUNCH_LEKTOR":"Het starten van Lektor is mislukt.","PROJECT":"Project","CLOSE_PROJECT":"Sluit Project","OPEN_PROJECT":"Open Project","BROWSE_WEBSITE":"Bekijk Website","VIEW_ADMIN_PANEL":"Bekijk Admin Paneel","QUIT":"Afsluiten","FAILED_TO_LOAD_PROJECT":"Laden van het project is mislukt :(","LOADING_PROJECT":"Project laden ...","INITIALIZING_LEKTOR":"Lektor Initializeren ...","QUIT_LEKTOR":"Lektor Afsluiten","FILE":"Bestand","UNDO":"Ongedaan maken","REDO":"Opnieuw","CUT":"Knippen","COPY":"Kopiëren","PASTE":"Plakken","SELECT_ALL":"Selecteer alles","HELP":"Help","VISIT_WEBSITE":"Bezoek Website","INSTALL_SHELL_COMMAND":"Installeer Shell Commando","INSTALL_SHELL_COMMAND_QUESTION":"Weet je zeker dat je het 'lektor' shell commando wil installeren? Dit vereist admin rechten.","FAILED_TO_INSTALL_SHELL_COMMANDS":"Installeren van de shell commando's mislukt.","INSTALL_SHELL_COMMAND_SUCCESS":"Shell commando's zijn geïnstalleerd.","OPERATION_SUCCESS":"Success","YES":"Ja","NO":"Nee","OK":"OK","FAILED_TO_OPEN_CONTENT_FILE":"Kon het inhoudbestand niet openen","OPEN_OTHER_PROJECT":"Open ander Project","OPEN_OTHER_PROJECT_QUESTION":"Om deze file te openen moet een ander project geopend worden (%s). Het huidige project zal gesloten worden. Wil je verdergaan?"} + +/***/ }), +/* 294 */ +/***/ (function(module, exports) { + +module.exports = {"RETURN_TO_WEBSITE":"Wróć do strony","UNLOAD_ACTIVE_TAB":"Masz niezapisane dane, czy na pewno chcesz opuścić tą stronę ?","EDIT_METADATA":"Edytuj dane","EDIT":"Edycja","DELETE":"Usuń","PREVIEW":"Podgląd","ALTS":"Wersje językowe","PRIMARY_ALT":"Podstawowy język","PRIMARY_OVERLAY":"(Nałożony)","ADD_CHILD_PAGE":"Dodaj podstronę","ADD_ATTACHMENT":"Dodaj załącznik","ATTACHMENT_ACTIONS":"Operacje na załącznikach","PAGE_ACTIONS":"Operacje na stronach","NO_CHILD_PAGES":"Brak podstron","CHILD_PAGES":"Podstrony","NO_ATTACHMENTS":"Brak załączników","ATTACHMENTS":"Załączniki","ADD_ATTACHMENT_TO":"Dodaj załącznik do “%s”","ADD_ATTACHMENT_NOTE":"Możesz wgrać nowy załącznik tutaj.","UPLOAD":"Wgraj","PROGRESS":"Postęp","ERROR_PREFIX":"Błąd: ","ERROR_NO_ID_PROVIDED":"Nie podano ID.","ERROR_PAGE_ID_DUPLICATE":"Strona z ID: (%s) już istnieje.","ERROR_INVALID_ID":"Błędny ID","ERROR_INVALID_DATE":"Błędna data","ERROR_INVALID_NUMBER":"Błędny numer","ERROR_INVALID_URL":"Błędny adres URL","ERROR":"Błąd","ERROR_OCURRED":"Wystąpił błąd","ERROR_REQUEST_FAILED":"Nie można wysłać żądania do serwera. Może został zatrzymany, albo nie odpowiada?","ERROR_SERVER_UNAVAILABLE":"Serwer niedostępny","ERROR_SERVER_UNAVAILABLE_MESSAGE":"Serwer nie odpowiada. Został zatrzymany, albo wystąpił błąd krytyczny, który spowodował brak działania. Być może musi zostać zrestartowany.","MODEL":"Model","ADD_CHILD_PAGE_TO":"Dodaj podstronę do “%s”","ADD_CHILD_PAGE_NOTE":"Możesz dodać podstronę tutaj. Pamiętaj, że Model oraz ID nie mogą być zmienione później w prosty sposób.","CREATE_CHILD_PAGE":"Dodaj podstronę","DELETE_ATTACHMENT_PROMPT":"Czy na pewno chcesz usunąć ten załącznik?","DELETE_ATTACHMENT_ALT_PROMPT":"Czy na pewno chcesz usunąć dane załącznika dla tego języka?","DELETE_PAGE_PROMPT":"Czy na pewno chcesz usunąć tą stronę?","DELETE_PAGE_ALT_PROMPT":"Czy na pewno chcesz usunąć ten język?","DELETE_PAGE_CHILDREN_WARNING":"To spowoduje także usunięcie wszystkich podstron.","DELETE_RECORD":"Skasuj “%s”","DELETE_ALL_PAGE_ALTS":"Usuń również wszystkie wersje językowe oraz załączniki.","DELETE_ALL_ATTACHMENT_ALTS":"Usuń wszystkie wersje językowe oraz załączony plik.","DELETE_ONLY_PRIMARY_PAGE_ALT":"Usuń tylko podstawowy rekord. Załączniki, wersje językowe oraz podstrony nie będę usunięte.","DELETE_ONLY_PRIMARY_ATTACHMENT_ALT":"Usuń tylko dane podstawowego rekordu.","DELETE_PRIMARY_ALT_INFO":"Ponieważ ten rekord zawiera podstawową wersję językową może zostać usunięty osobno jak i razem z pozostałą zawartością.","CHILD_PAGES_TO_BE_DELETED":"Podstrony, które zostaną usunięte:","ALTS_TO_BE_DELETED":"Wersje językowe, które zostaną usunięte:","ATTACHMENTS_TO_BE_DELETED":"Załączniki, które zostaną usunięte:","YES_DELETE":"Tak, usuń","NO_CANCEL":"Nie, anuluj","SYSTEM_FIELDS":"Pola Systemowe","EDIT_ATTACHMENT_METADATA_OF":"Edytuj dane załącznika “%s”","EDIT_PAGE_NAME":"Edytuj “%s”","SAVE_CHANGES":"Zapisz zmiany","BROWSE_FS":"Otwórz w przeglądarce plików","BROWSE_FS_MAC":"Otwórz w Finderze","BROWSE_FS_WINDOWS":"Otwórz w eksploratorze plików","ERROR_CANNOT_BROWSE_FS":"Błąd: Plik jeszcze nie istnieje.","REMOVE_FLOWBLOCK_PROMPT":"Czy na pewno chcesz usunąć ten blok ?","ADD_FLOWBLOCK":"Dodaj blok","INVALID_INPUT":"Błędne dane wejściowe","UP":"W górę","DOWN":"W dół","REMOVE":"Usuń","ID":"ID","CLOSE":"Zamknij","CANCEL":"Anuluj","BACK_TO_OVERVIEW":"Powrót do przeglądu","PUBLISH":"Publikuj","PUBLISH_NOTE":"Stąd możesz opublikować aktualną wersję strony.","PUBLISH_SERVER":"Serwer Docelowy","CURRENTLY_PUBLISHING":"Publikowanie …","STATE":"Status","PUBLISH_DONE":"Opublikowany","PUBLISH_STATE_BUILDING":"Zmiany są wprowadzane ...","PUBLISH_STATE_PUBLISH":"Zmiany są publikowane ...","PUBLISH_STATE_DONE":"Publikowanie zakończone.","FIND_FILES":"Znadź Pliki","FIND_FILES_PLACEHOLDER":"Podaj nazwę strony ...","ATTACHMENT_TYPE":"Typ załącznika","URL_SLUG":"Przyjazny URL","TEMPLATE":"Szablon","HIDE_PAGE":"Ukryj stronę","HIDE_PAGE_EXPLANATION":"Czy ta strona powinna być ukryta?","PAGE_IS_DISCOVERABLE":"Strona jest 'widoczna'","PAGE_IS_DISCOVERABLE_EXPLANATION":"Jeśli włączone, strona jest widoczna na liście stron oraz w listingu dla danego rekordu. W przeciwnym razie, adres URL musi być znany","REFRESH_BUILD":"Zbuduj odświeżoną wersję","REFRESH_BUILD_NOTE":"To spowoduje usunięcie pamięci podręcznej i stworzenie wersji końcowej od nowa. Ta opcja jest przydatna w sytuacjach, gdzie błędy albo pomyłki synchronizacji w szablonach spowodowały uszkodzenie danych wyjściowych.","CURRENTLY_REFRESHING_BUILD":"Aktualnie odświeżam pakiet wyjściowy ...","REFRESHING_BUILD_DONE":"Zakończono odświeżanie pakietu wyjściowego!","FAILED_TO_LAUNCH_LEKTOR":"Nie udało się uruchomić Lektor.","PROJECT":"Projekt","CLOSE_PROJECT":"Zamknij projekt","OPEN_PROJECT":"Otwórz projekt","BROWSE_WEBSITE":"Przeglądaj stronę","VIEW_ADMIN_PANEL":"Przejdź do panelu administracyjnego","QUIT":"Wyjdź","FAILED_TO_LOAD_PROJECT":"Nie udało się załadować projektu :(","LOADING_PROJECT":"Ładowanie projektu ...","INITIALIZING_LEKTOR":"Inicjalizacja Lektor ...","QUIT_LEKTOR":"Opuść Lektor","FILE":"Plik","UNDO":"Cofnij","REDO":"Ponów","CUT":"Wytnij","COPY":"Kopiuj","PASTE":"Wklej","SELECT_ALL":"Zaznacz wszystko","HELP":"Pomoc","VISIT_WEBSITE":"Odwiedź stronę","INSTALL_SHELL_COMMAND":"Zainstaluj komendę powłoki","INSTALL_SHELL_COMMAND_QUESTION":"Czy chcesz zainstalować komendę 'lektor' w powłoce systemowej? Wygamane są uprawnienia administracyjne.","FAILED_TO_INSTALL_SHELL_COMMANDS":"Nie udało się zainstalować komend w powłoce systemowej.","INSTALL_SHELL_COMMAND_SUCCESS":"Komenda została pomyślnie zainstalowana w powłoce systemowej.","OPERATION_SUCCESS":"Sukces","YES":"Tak","NO":"Nie","OK":"OK","FAILED_TO_OPEN_CONTENT_FILE":"Nie udało się otworzyć zawartości pliku","OPEN_OTHER_PROJECT":"Otwórz inny projekt","OPEN_OTHER_PROJECT_QUESTION":"Otwarcie tego pliku wymaga otwarcia kolejnego projektu (%s). Obecny projekt zostanie zamknięty. Czy chcesz kontynuować?"} + +/***/ }), +/* 295 */ +/***/ (function(module, exports) { + +module.exports = {"RETURN_TO_WEBSITE":"Retornar ao Site","UNLOAD_ACTIVE_TAB":"Você tem modificações não salvas, tem certeza que deseja deixar a página?","EDIT_METADATA":"Editar Metadado","EDIT":"Editar","DELETE":"Deletar","PREVIEW":"Pré-visualizar","ALTS":"Alternativas","PRIMARY_ALT":"Primária","PRIMARY_OVERLAY":"Revestida","ADD_CHILD_PAGE":"Add Página","ADD_ATTACHMENT":"Add Anexo","ATTACHMENT_ACTIONS":"Ações de Anexos","PAGE_ACTIONS":"Ações de Páginas","NO_CHILD_PAGES":"Sem sub-páginas","CHILD_PAGES":"Sub-páginas","NO_ATTACHMENTS":"Sem anexos","ATTACHMENTS":"Anexos","ADD_ATTACHMENT_TO":"Add anexo para “%s”","ADD_ATTACHMENT_NOTE":"Você pode subir um novo anexo aqui.","UPLOAD":"Upload","PROGRESS":"Progresso","ERROR_PREFIX":"Erro: ","ERROR_NO_ID_PROVIDED":"Nenhuma ID fornecida.","ERROR_PAGE_ID_DUPLICATE":"Uma página com este ID (%s) já existe.","ERROR_INVALID_ID":"ID inválido","ERROR_INVALID_DATE":"Data inválida","ERROR_INVALID_NUMBER":"Não é um número válido","ERROR_INVALID_URL":"Não é uma URL válida","ERROR":"Erro","ERROR_OCURRED":"Ocorreu um Erro","ERROR_REQUEST_FAILED":"Não foi possível enviar o comando ao servidor. Talvez o servidor foi parado ou não está respondendo","ERROR_SERVER_UNAVAILABLE":"Servidor Não Disponível","ERROR_SERVER_UNAVAILABLE_MESSAGE":"O servidor não está respondendo. Ou foi parado ou um erro sério o fez parar e precisa ser reiniciado.","MODEL":"Modelo","ADD_CHILD_PAGE_TO":"Add Sub-página para “%s”","ADD_CHILD_PAGE_NOTE":"Você pode adicionar uma nova sub-página aqui. Note que o modelo ou o ID não podem ser mudados facilmente depois.","CREATE_CHILD_PAGE":"Add Página Filha","DELETE_ATTACHMENT_PROMPT":"Você tem certeza que deseja deletar este anexo?","DELETE_ATTACHMENT_ALT_PROMPT":"Você tem certeza que deseja deletar o metadado deste anexo alternativo?","DELETE_PAGE_PROMPT":"Você tem certeza que deseja deletar esta página","DELETE_PAGE_ALT_PROMPT":"Você tem certeza que deseja deletar esta alternativa?","DELETE_PAGE_CHILDREN_WARNING":"Isto também deletará as sub-páginas filhas desta página.","DELETE_RECORD":"Deletar “%s”","DELETE_ALL_PAGE_ALTS":"Também delete todas alternativas e arquivos de anexo.","DELETE_ALL_ATTACHMENT_ALTS":"Delete todas alternativas e arquivo de anexo","DELETE_ONLY_PRIMARY_PAGE_ALT":"Delete somente o registro primário. Anexos, alternativas e sub-páginas não serão deletadas.","DELETE_ONLY_PRIMARY_ATTACHMENT_ALT":"Delete somente o Metadado do registro primário.","DELETE_PRIMARY_ALT_INFO":"Porque este registro é uma alternativa primária ele pode ser deletado separadamente ou junto com todos os outros conteúdos.","CHILD_PAGES_TO_BE_DELETED":"Sub-páginas que serão deletadas:","ALTS_TO_BE_DELETED":"Alternativas que serão deletadas:","ATTACHMENTS_TO_BE_DELETED":"Anexos que serão deletados:","YES_DELETE":"Sim, deletar","NO_CANCEL":"Não, cancelar","SYSTEM_FIELDS":"Campos do Sistema","EDIT_ATTACHMENT_METADATA_OF":"Editar Metadado do Anexo “%s”","EDIT_PAGE_NAME":"Editar “%s”","SAVE_CHANGES":"Salvar Alterações","BROWSE_FS":"Navegar no Sistema","BROWSE_FS_MAC":"Mostrar no Finder","BROWSE_FS_WINDOWS":"Abrir no Explorer","ERROR_CANNOT_BROWSE_FS":"Erro: Arquivo não existe ainda.","REMOVE_FLOWBLOCK_PROMPT":"Você realmente deseja remover este bloco?","ADD_FLOWBLOCK":"Add Bloco","INVALID_INPUT":"Entrada Inválida","UP":"Cima","DOWN":"Baixo","REMOVE":"Remover","ID":"ID","CLOSE":"Fechar","CANCEL":"Cancelar","BACK_TO_OVERVIEW":"Voltar para Overview","PUBLISH":"Publicar","PUBLISH_NOTE":"Daqui você pode publicar a versão atual do website.","PUBLISH_SERVER":"Servidor Alvo","CURRENTLY_PUBLISHING":"Publicando …","STATE":"Status","PUBLISH_DONE":"Publicado","PUBLISH_STATE_BUILDING":"Mudanças estão sendo construídas ...","PUBLISH_STATE_PUBLISH":"Mudanças estão sendo publicadas ...","PUBLISH_STATE_DONE":"Publicação feita.","FIND_FILES":"Procurar Arquivos","FIND_FILES_PLACEHOLDER":"Entrar com o nome da página ...","ATTACHMENT_TYPE":"Tipo de anexo","URL_SLUG":"URL slug","TEMPLATE":"Template","HIDE_PAGE":"Esconder página","HIDE_PAGE_EXPLANATION":"Isto deveria ser escondido?","PAGE_IS_DISCOVERABLE":"Página é descobrível","PAGE_IS_DISCOVERABLE_EXPLANATION":"Se isto estiver ativo a página pode ser descoberta, caso contrário será necessário saber a URL.","REFRESH_BUILD":"Atualizar Build","REFRESH_BUILD_NOTE":"Isto deleta todos os resultados de builds em cache ativando uma build do zero. Isto é útil em situações onde erros de sincronização ou erros no template causam saídas corrompidas.","CURRENTLY_REFRESHING_BUILD":"No momento atualizando a build ...","REFRESHING_BUILD_DONE":"Atualização da build feita!","FAILED_TO_LAUNCH_LEKTOR":"Falha ao iniciar o Lektor.","PROJECT":"Projeto","CLOSE_PROJECT":"Fechar Projeto","OPEN_PROJECT":"Abrir Projeto","BROWSE_WEBSITE":"Navegar no Website","VIEW_ADMIN_PANEL":"Ver Admin Painel","QUIT":"Sair","FAILED_TO_LOAD_PROJECT":"Falha ao carregar o projeto :(","LOADING_PROJECT":"Carregando o projeto ...","INITIALIZING_LEKTOR":"Iniciando o Lektor ...","QUIT_LEKTOR":"Sair do Lektor","FILE":"Arquivo","UNDO":"Desfazer","REDO":"Refazer","CUT":"Cortar","COPY":"Copiar","PASTE":"Colar","SELECT_ALL":"Selecionar Todos","HELP":"Ajuda","VISIT_WEBSITE":"Visitar Website","INSTALL_SHELL_COMMAND":"Instalar Shell Command","INSTALL_SHELL_COMMAND_QUESTION":"Você deseja instalar 'lektor' shell command? Isto requer permissões de administrador.","FAILED_TO_INSTALL_SHELL_COMMANDS":"Falha ao instalar shell commands.","INSTALL_SHELL_COMMAND_SUCCESS":"Shell command foi instalado com sucesso.","OPERATION_SUCCESS":"Sucesso","YES":"Sim","NO":"Não","OK":"OK","FAILED_TO_OPEN_CONTENT_FILE":"Falha ao abrir o conteúdo do arquivo","OPEN_OTHER_PROJECT":"Abrir outro Projeto","OPEN_OTHER_PROJECT_QUESTION":"Abrir este arquivo requer abrir outro projeto (%s). O projeto atual será fechado. Deseja continuar?"} + +/***/ }), +/* 296 */ +/***/ (function(module, exports) { + +module.exports = {"RETURN_TO_WEBSITE":"Вернуться на вебсайт","UNLOAD_ACTIVE_TAB":"Ваши изменения не сохранены. Вы уверены, что хотите покинуть страницу?","EDIT_METADATA":"Редактировать метаданные","EDIT":"Редактировать","DELETE":"Удалить","PREVIEW":"Предпросмотр","ALTS":"Варианты","PRIMARY_ALT":"Основной","PRIMARY_OVERLAY":"Оверлей","ADD_CHILD_PAGE":"Добавить страницу","ADD_ATTACHMENT":"Приложить файл","ATTACHMENT_ACTIONS":"Действия с вложением","PAGE_ACTIONS":"Действия со страницей","NO_CHILD_PAGES":"Вложенные страницы отсутствуют","CHILD_PAGES":"Вложенные страницы","NO_ATTACHMENTS":"Вложенные файлы отсутствуют","ATTACHMENTS":"Вложенные файлы","ADD_ATTACHMENT_TO":"Приложить файл к странице “%s”","ADD_ATTACHMENT_NOTE":"Здесь вы можете загрузить новый файл.","UPLOAD":"Загрузить","PROGRESS":"Прогресс","ERROR_PREFIX":"Ошибка: ","ERROR_NO_ID_PROVIDED":"Ошибка: Отсутсует ID.","ERROR_PAGE_ID_DUPLICATE":"Страница с ID (%s) уже существует.","ERROR_INVALID_ID":"Некорректный ID","ERROR_INVALID_DATE":"Некорректная дата","ERROR_INVALID_NUMBER":"Некорректное число","ERROR_INVALID_URL":"Некорректный URL","ERROR":"Ошибка","ERROR_OCURRED":"Произошла ошибка","ERROR_REQUEST_FAILED":"Ошибка при отправке команды на сервер. Возможно, сервер остановлен или не отвечает.","ERROR_SERVER_UNAVAILABLE":"Сервер недоступен","ERROR_SERVER_UNAVAILABLE_MESSAGE":"Сервер не отвечает. Возможно, сервер остановлен или произошла критическая ошибка. Перезапустите сервер.","MODEL":"Модель","ADD_CHILD_PAGE_TO":"Создать вложенную страницу для “%s”","ADD_CHILD_PAGE_NOTE":"Здесь вы можете создать новую вложенную страницу. Имейте в виду, что вы не сможете легко изменить модель и ID после создания страницы.","CREATE_CHILD_PAGE":"Создать вложенную страницу","DELETE_ATTACHMENT_PROMPT":"Вы действительно хотите удалить это вложение?","DELETE_ATTACHMENT_ALT_PROMPT":"Вы действительно хотите удалить этот вариант вложения?","DELETE_PAGE_PROMPT":"Вы действительно хотите удалить эту страницу?","DELETE_PAGE_ALT_PROMPT":"Вы действительно хотите удалить этот вариант страницы?","DELETE_PAGE_CHILDREN_WARNING":"Страница будет удалена вместе со всеми вложенными страницами.","DELETE_RECORD":"Удалить “%s”","DELETE_ALL_PAGE_ALTS":"Удалить все варианты страницы и вложенные файлы.","DELETE_ALL_ATTACHMENT_ALTS":"Удалить все варианты вложенного файла","DELETE_ONLY_PRIMARY_PAGE_ALT":"Удалить только основную версию. Вложеннные страницы, файлы и другие варианты страницы не будут удалены.","DELETE_ONLY_PRIMARY_ATTACHMENT_ALT":"Удалить только основную версию.","DELETE_PRIMARY_ALT_INFO":"Данная версия является основной и может быть удалена как отдельно, так и вместе со всем содержимым.","CHILD_PAGES_TO_BE_DELETED":"Вложенные страницы, которые будут удалены:","ALTS_TO_BE_DELETED":"Версии, которые будут удалены:","ATTACHMENTS_TO_BE_DELETED":"Вложенные файлы, которые будут удалены:","YES_DELETE":"Да, удалить","NO_CANCEL":"Отмена","SYSTEM_FIELDS":"Системные поля","EDIT_ATTACHMENT_METADATA_OF":"Редактировать метаданные вложения “%s”","EDIT_PAGE_NAME":"Редактировать “%s”","SAVE_CHANGES":"Сохранить изменения","BROWSE_FS":"Посмотреть в файловой системе","BROWSE_FS_MAC":"Открыть в Finder","BROWSE_FS_WINDOWS":"Открыть в Обозревателе","ERROR_CANNOT_BROWSE_FS":"Ошибка: Файл не существует.","REMOVE_FLOWBLOCK_PROMPT":"Вы действительно хотите удалить этот блок?","ADD_FLOWBLOCK":"Добавить блок","INVALID_INPUT":"Некорректный ввод","UP":"Вверх","DOWN":"Вниз","REMOVE":"Удалить","ID":"Идентификатор (ID)","CLOSE":"Закрыть","CANCEL":"Отмена","BACK_TO_OVERVIEW":"На стартовую страницу","PUBLISH":"Опубликовать","PUBLISH_NOTE":"Здесь вы можете опубликовать текущую версию вебсайта.","PUBLISH_SERVER":"Сервер","CURRENTLY_PUBLISHING":"Публикация …","STATE":"Статус","PUBLISH_DONE":"Публикация завершена","PUBLISH_STATE_BUILDING":"Сборка изменений ...","PUBLISH_STATE_PUBLISH":"Публикация изменений ...","PUBLISH_STATE_DONE":"Публикация завершена.","FIND_FILES":"Поиск файла","FIND_FILES_PLACEHOLDER":"Введите имя страницы ...","ATTACHMENT_TYPE":"Тип вложения","URL_SLUG":"Краткий заголовок для URL","TEMPLATE":"Шаблон","HIDE_PAGE":"Скрыть страницу","HIDE_PAGE_EXPLANATION":"Скрыть данную страницу?","REFRESH_BUILD":"Обновить сборку","REFRESH_BUILD_NOTE":"В некоторых ситуациях бывает полезно заново пересобрать страницы вебсайта: например, когда произошёл сбой синхронизации или ошибка в шаблоне привела к некорректному отображению вебсайта.","CURRENTLY_REFRESHING_BUILD":"Обновление сборки ...","REFRESHING_BUILD_DONE":"Сборка обновлена!","FAILED_TO_LAUNCH_LEKTOR":"Не удалось запустить Lektor.","PROJECT":"Проект","CLOSE_PROJECT":"Закрыть проект","OPEN_PROJECT":"Открыть проект","BROWSE_WEBSITE":"Открыть вебсайт","VIEW_ADMIN_PANEL":"Открыть админ-панель","QUIT":"Выйти","FAILED_TO_LOAD_PROJECT":"Не удалось загрузить проект :(","LOADING_PROJECT":"Загрузка проекта ...","INITIALIZING_LEKTOR":"Инициализация Lektor ...","QUIT_LEKTOR":"Выйти из Lektor","FILE":"Файл","UNDO":"Отменить","REDO":"Повторить","CUT":"Вырезать","COPY":"Копировать","PASTE":"Вставить","SELECT_ALL":"Выделить всё","HELP":"Помощь","VISIT_WEBSITE":"Открыть вебсайт","INSTALL_SHELL_COMMAND":"Установить команду для терминала","INSTALL_SHELL_COMMAND_QUESTION":"Вы хотите установить команду 'lektor' для терминала? Для этого необходимы права администратора.","FAILED_TO_INSTALL_SHELL_COMMANDS":"Не удалось установить команду для терминала.","INSTALL_SHELL_COMMAND_SUCCESS":"Команда для терминала была успешно установлена.","OPERATION_SUCCESS":"Операция завершена успешно","YES":"Да","NO":"Нет","OK":"ОК"} + +/***/ }), +/* 297 */ +/***/ (function(module, exports) { + +module.exports = {"RETURN_TO_WEBSITE":"回到網頁","UNLOAD_ACTIVE_TAB":"你還有未儲存的資訊,確定要離開這個頁面?","EDIT_METADATA":"編輯元資料","EDIT":"編輯","DELETE":"刪除","PREVIEW":"預覽","ALTS":"副語","PRIMARY_ALT":"主語","PRIMARY_OVERLAY":"Overlaid","ADD_CHILD_PAGE":"新增頁面","ADD_ATTACHMENT":"新增附件","ATTACHMENT_ACTIONS":"附件行為","PAGE_ACTIONS":"頁面行為","NO_CHILD_PAGES":"沒有附件","CHILD_PAGES":"子頁面","NO_ATTACHMENTS":"沒有附件","ATTACHMENTS":"附件","ADD_ATTACHMENT_TO":"新增附件到「%s」","ADD_ATTACHMENT_NOTE":"你可以在這裡上傳新的附件。","UPLOAD":"上傳","PROGRESS":"進度","ERROR_PREFIX":"錯誤:","ERROR_NO_ID_PROVIDED":"錯誤:沒有提供ID。","ERROR_PAGE_ID_DUPLICATE":"已經有頁面的ID跟這個ID(%s)一樣了。","ERROR_INVALID_ID":"無效的ID","ERROR_INVALID_DATE":"無效的日期","ERROR_INVALID_NUMBER":"無效的數字","ERROR_INVALID_URL":"無效的URL","ERROR":"錯誤","ERROR_OCURRED":"發生錯誤","ERROR_REQUEST_FAILED":"無法傳送指令到伺服器,可能它被關了或沒回應?","ERROR_SERVER_UNAVAILABLE":"伺服器掛掉了","ERROR_SERVER_UNAVAILABLE_MESSAGE":"伺服器目前沒回應,它可能已被關閉或是遇到嚴重錯誤導致無法運作,伺服器需要重新啟動。","MODEL":"模型","ADD_CHILD_PAGE_TO":"新增子面頁到 「%s」","ADD_CHILD_PAGE_NOTE":"你可以在這裡加入新的子頁面,注意模型及ID之後無法輕易更改。","CREATE_CHILD_PAGE":"新增子頁面","DELETE_ATTACHMENT_PROMPT":"真的要刪除這個附件?","DELETE_ATTACHMENT_ALT_PROMPT":"你真的想刪除這個副語附件的元資料嗎?","DELETE_PAGE_PROMPT":"真的要刪除這個頁面?","DELETE_PAGE_ALT_PROMPT":"你真的想刪除這個分支嗎?","DELETE_PAGE_CHILDREN_WARNING":"這也會把這個頁面的子頁面刪除。","DELETE_RECORD":"刪除「%s」","DELETE_ALL_PAGE_ALTS":"順便刪除所有副語及附加檔案。","DELETE_ALL_ATTACHMENT_ALTS":"刪除所有副語及附加檔案。","DELETE_ONLY_PRIMARY_PAGE_ALT":"只刪除主語的紀錄,附件、副語、及子頁面不會被刪除。","DELETE_ONLY_PRIMARY_ATTACHMENT_ALT":"只刪除主語紀錄的元資料。","DELETE_PRIMARY_ALT_INFO":"主語可以被單獨刪除,或是連同副語一起刪除。","CHILD_PAGES_TO_BE_DELETED":"即將被刪除的子頁面:","ALTS_TO_BE_DELETED":"即將被刪除的副語:","ATTACHMENTS_TO_BE_DELETED":"即將被刪除的附件:","YES_DELETE":"對,就是要把它刪掉!","NO_CANCEL":"還是不要好了...","SYSTEM_FIELDS":"系統欄位","EDIT_ATTACHMENT_METADATA_OF":"編輯附件「%s」的元資料","EDIT_PAGE_NAME":"編輯「%s」","SAVE_CHANGES":"儲存變更","BROWSE_FS":"用文件系統開啟","BROWSE_FS_MAC":"用Finder開啟","BROWSE_FS_WINDOWS":"用檔案總管開啟","ERROR_CANNOT_BROWSE_FS":"錯誤:檔案還沒有存在。","REMOVE_FLOWBLOCK_PROMPT":"你真的要刪掉這個區塊?","ADD_FLOWBLOCK":"新增區塊","INVALID_INPUT":"無效的輸入","UP":"上","DOWN":"下","REMOVE":"移除","ID":"ID","CLOSE":"關閉","CANCEL":"取消","BACK_TO_OVERVIEW":"回到總覽","PUBLISH":"發佈","PUBLISH_NOTE":"你可以在這裡發佈網站目前的版本。","PUBLISH_SERVER":"目標伺服器","CURRENTLY_PUBLISHING":"發佈中...","STATE":"狀態","PUBLISH_DONE":"已發佈","PUBLISH_STATE_BUILDING":"正在建置變更...","PUBLISH_STATE_PUBLISH":"正在發佈變更...","PUBLISH_STATE_DONE":"發佈完成。","FIND_FILES":"搜尋檔案","FIND_FILES_PLACEHOLDER":"輸入頁面名稱...","ATTACHMENT_TYPE":"附件類型","URL_SLUG":"URL縮略名","TEMPLATE":"模板","HIDE_PAGE":"隱藏頁面","HIDE_PAGE_EXPLANATION":"要隱藏這個頁面嗎?","PAGE_IS_DISCOVERABLE":"網頁可以被發現","PAGE_IS_DISCOVERABLE_EXPLANATION":"若啟用則這個頁面可以被發現,否則必須知道URL才能連結到這裡。","REFRESH_BUILD":"重新整理建置","REFRESH_BUILD_NOTE":"這會刪掉所有緩存的建置結果並導致重新置建。這在特殊情況(如同步錯誤、模板出錯等)下會有用。","CURRENTLY_REFRESHING_BUILD":"刷新建置中...","REFRESHING_BUILD_DONE":"完成刷新建置!","FAILED_TO_LAUNCH_LEKTOR":"啟動Lektor失敗。","PROJECT":"專案","CLOSE_PROJECT":"關閉專案","OPEN_PROJECT":"開啟專案","BROWSE_WEBSITE":"瀏覽網站","VIEW_ADMIN_PANEL":"查看管理員面板","QUIT":"離開","FAILED_TO_LOAD_PROJECT":"讀取專案失敗 QAQ","LOADING_PROJECT":"讀取專案中...","INITIALIZING_LEKTOR":"初始化Lektor中...","QUIT_LEKTOR":"離開Lektor","FILE":"檔案","UNDO":"復原","REDO":"重做","CUT":"剪下","COPY":"複製","PASTE":"貼上","SELECT_ALL":"全選","HELP":"說明","VISIT_WEBSITE":"參觀網站","INSTALL_SHELL_COMMAND":"安裝命令列模式","INSTALL_SHELL_COMMAND_QUESTION":"你想安裝lektor命令列模式嗎? 這需要管理員權限。","FAILED_TO_INSTALL_SHELL_COMMANDS":"安裝命令列模式失敗。","INSTALL_SHELL_COMMAND_SUCCESS":"命令列模式安裝成功","OPERATION_SUCCESS":"成功","YES":"是","NO":"否","OK":"好","FAILED_TO_OPEN_CONTENT_FILE":"開啟檔案失敗","OPEN_OTHER_PROJECT":"開啟其它專案","OPEN_OTHER_PROJECT_QUESTION":"開啟這份檔案需要連同開啟另一個專案(%s),目前的專案將會被關閉,確定要繼續?"} + +/***/ }), +/* 298 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +exports.__esModule = true; + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +var _deprecate = __webpack_require__(31); + +var _deprecate2 = _interopRequireDefault(_deprecate); + +var _createLocation2 = __webpack_require__(138); + +var _createLocation3 = _interopRequireDefault(_createLocation2); + +var _createBrowserHistory = __webpack_require__(140); + +var _createBrowserHistory2 = _interopRequireDefault(_createBrowserHistory); + +exports.createHistory = _createBrowserHistory2['default']; + +var _createHashHistory2 = __webpack_require__(300); + +var _createHashHistory3 = _interopRequireDefault(_createHashHistory2); + +exports.createHashHistory = _createHashHistory3['default']; + +var _createMemoryHistory2 = __webpack_require__(301); + +var _createMemoryHistory3 = _interopRequireDefault(_createMemoryHistory2); + +exports.createMemoryHistory = _createMemoryHistory3['default']; + +var _useBasename2 = __webpack_require__(302); + +var _useBasename3 = _interopRequireDefault(_useBasename2); + +exports.useBasename = _useBasename3['default']; + +var _useBeforeUnload2 = __webpack_require__(144); + +var _useBeforeUnload3 = _interopRequireDefault(_useBeforeUnload2); + +exports.useBeforeUnload = _useBeforeUnload3['default']; + +var _useQueries2 = __webpack_require__(145); + +var _useQueries3 = _interopRequireDefault(_useQueries2); + +exports.useQueries = _useQueries3['default']; + +var _Actions2 = __webpack_require__(40); + +var _Actions3 = _interopRequireDefault(_Actions2); + +exports.Actions = _Actions3['default']; + +// deprecated + +var _enableBeforeUnload2 = __webpack_require__(303); + +var _enableBeforeUnload3 = _interopRequireDefault(_enableBeforeUnload2); + +exports.enableBeforeUnload = _enableBeforeUnload3['default']; + +var _enableQueries2 = __webpack_require__(304); + +var _enableQueries3 = _interopRequireDefault(_enableQueries2); + +exports.enableQueries = _enableQueries3['default']; +var createLocation = _deprecate2['default'](_createLocation3['default'], 'Using createLocation without a history instance is deprecated; please use history.createLocation instead'); +exports.createLocation = createLocation; + +/***/ }), +/* 299 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +exports.__esModule = true; +exports.loopAsync = loopAsync; + +function loopAsync(turns, work, callback) { + var currentTurn = 0; + var isDone = false; + + function done() { + isDone = true; + callback.apply(this, arguments); + } + + function next() { + if (isDone) return; + + if (currentTurn < turns) { + work.call(this, currentTurn++, next, done); + } else { + done.apply(this, arguments); + } + } + + next(); +} + +/***/ }), +/* 300 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(process) { + +exports.__esModule = true; + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +var _warning = __webpack_require__(33); + +var _warning2 = _interopRequireDefault(_warning); + +var _invariant = __webpack_require__(8); + +var _invariant2 = _interopRequireDefault(_invariant); + +var _Actions = __webpack_require__(40); + +var _ExecutionEnvironment = __webpack_require__(47); + +var _DOMUtils = __webpack_require__(61); + +var _DOMStateStorage = __webpack_require__(141); + +var _createDOMHistory = __webpack_require__(142); + +var _createDOMHistory2 = _interopRequireDefault(_createDOMHistory); + +var _parsePath = __webpack_require__(32); + +var _parsePath2 = _interopRequireDefault(_parsePath); + +function isAbsolutePath(path) { + return typeof path === 'string' && path.charAt(0) === '/'; +} + +function ensureSlash() { + var path = _DOMUtils.getHashPath(); + + if (isAbsolutePath(path)) return true; + + _DOMUtils.replaceHashPath('/' + path); + + return false; +} + +function addQueryStringValueToPath(path, key, value) { + return path + (path.indexOf('?') === -1 ? '?' : '&') + (key + '=' + value); +} + +function stripQueryStringValueFromPath(path, key) { + return path.replace(new RegExp('[?&]?' + key + '=[a-zA-Z0-9]+'), ''); +} + +function getQueryStringValueFromPath(path, key) { + var match = path.match(new RegExp('\\?.*?\\b' + key + '=(.+?)\\b')); + return match && match[1]; +} + +var DefaultQueryKey = '_k'; + +function createHashHistory() { + var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; + + !_ExecutionEnvironment.canUseDOM ? process.env.NODE_ENV !== 'production' ? _invariant2['default'](false, 'Hash history needs a DOM') : _invariant2['default'](false) : undefined; + + var queryKey = options.queryKey; + + if (queryKey === undefined || !!queryKey) queryKey = typeof queryKey === 'string' ? queryKey : DefaultQueryKey; + + function getCurrentLocation() { + var path = _DOMUtils.getHashPath(); + + var key = undefined, + state = undefined; + if (queryKey) { + key = getQueryStringValueFromPath(path, queryKey); + path = stripQueryStringValueFromPath(path, queryKey); + + if (key) { + state = _DOMStateStorage.readState(key); + } else { + state = null; + key = history.createKey(); + _DOMUtils.replaceHashPath(addQueryStringValueToPath(path, queryKey, key)); + } + } else { + key = state = null; + } + + var location = _parsePath2['default'](path); + + return history.createLocation(_extends({}, location, { state: state }), undefined, key); + } + + function startHashChangeListener(_ref) { + var transitionTo = _ref.transitionTo; + + function hashChangeListener() { + if (!ensureSlash()) return; // Always make sure hashes are preceeded with a /. + + transitionTo(getCurrentLocation()); + } + + ensureSlash(); + _DOMUtils.addEventListener(window, 'hashchange', hashChangeListener); + + return function () { + _DOMUtils.removeEventListener(window, 'hashchange', hashChangeListener); + }; + } + + function finishTransition(location) { + var basename = location.basename; + var pathname = location.pathname; + var search = location.search; + var state = location.state; + var action = location.action; + var key = location.key; + + if (action === _Actions.POP) return; // Nothing to do. + + var path = (basename || '') + pathname + search; + + if (queryKey) { + path = addQueryStringValueToPath(path, queryKey, key); + _DOMStateStorage.saveState(key, state); + } else { + // Drop key and state. + location.key = location.state = null; + } + + var currentHash = _DOMUtils.getHashPath(); + + if (action === _Actions.PUSH) { + if (currentHash !== path) { + window.location.hash = path; + } else { + process.env.NODE_ENV !== 'production' ? _warning2['default'](false, 'You cannot PUSH the same path using hash history') : undefined; + } + } else if (currentHash !== path) { + // REPLACE + _DOMUtils.replaceHashPath(path); + } + } + + var history = _createDOMHistory2['default'](_extends({}, options, { + getCurrentLocation: getCurrentLocation, + finishTransition: finishTransition, + saveState: _DOMStateStorage.saveState + })); + + var listenerCount = 0, + stopHashChangeListener = undefined; + + function listenBefore(listener) { + if (++listenerCount === 1) stopHashChangeListener = startHashChangeListener(history); + + var unlisten = history.listenBefore(listener); + + return function () { + unlisten(); + + if (--listenerCount === 0) stopHashChangeListener(); + }; + } + + function listen(listener) { + if (++listenerCount === 1) stopHashChangeListener = startHashChangeListener(history); + + var unlisten = history.listen(listener); + + return function () { + unlisten(); + + if (--listenerCount === 0) stopHashChangeListener(); + }; + } + + function push(location) { + process.env.NODE_ENV !== 'production' ? _warning2['default'](queryKey || location.state == null, 'You cannot use state without a queryKey it will be dropped') : undefined; + + history.push(location); + } + + function replace(location) { + process.env.NODE_ENV !== 'production' ? _warning2['default'](queryKey || location.state == null, 'You cannot use state without a queryKey it will be dropped') : undefined; + + history.replace(location); + } + + var goIsSupportedWithoutReload = _DOMUtils.supportsGoWithoutReloadUsingHash(); + + function go(n) { + process.env.NODE_ENV !== 'production' ? _warning2['default'](goIsSupportedWithoutReload, 'Hash history go(n) causes a full page reload in this browser') : undefined; + + history.go(n); + } + + function createHref(path) { + return '#' + history.createHref(path); + } + + // deprecated + function registerTransitionHook(hook) { + if (++listenerCount === 1) stopHashChangeListener = startHashChangeListener(history); + + history.registerTransitionHook(hook); + } + + // deprecated + function unregisterTransitionHook(hook) { + history.unregisterTransitionHook(hook); + + if (--listenerCount === 0) stopHashChangeListener(); + } + + // deprecated + function pushState(state, path) { + process.env.NODE_ENV !== 'production' ? _warning2['default'](queryKey || state == null, 'You cannot use state without a queryKey it will be dropped') : undefined; + + history.pushState(state, path); + } + + // deprecated + function replaceState(state, path) { + process.env.NODE_ENV !== 'production' ? _warning2['default'](queryKey || state == null, 'You cannot use state without a queryKey it will be dropped') : undefined; + + history.replaceState(state, path); + } + + return _extends({}, history, { + listenBefore: listenBefore, + listen: listen, + push: push, + replace: replace, + go: go, + createHref: createHref, + + registerTransitionHook: registerTransitionHook, // deprecated - warning is in createHistory + unregisterTransitionHook: unregisterTransitionHook, // deprecated - warning is in createHistory + pushState: pushState, // deprecated - warning is in createHistory + replaceState: replaceState // deprecated - warning is in createHistory + }); +} + +exports['default'] = createHashHistory; +module.exports = exports['default']; +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) + +/***/ }), +/* 301 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(process) { + +exports.__esModule = true; + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +var _warning = __webpack_require__(33); + +var _warning2 = _interopRequireDefault(_warning); + +var _invariant = __webpack_require__(8); + +var _invariant2 = _interopRequireDefault(_invariant); + +var _Actions = __webpack_require__(40); + +var _createHistory = __webpack_require__(143); + +var _createHistory2 = _interopRequireDefault(_createHistory); + +var _parsePath = __webpack_require__(32); + +var _parsePath2 = _interopRequireDefault(_parsePath); + +function createStateStorage(entries) { + return entries.filter(function (entry) { + return entry.state; + }).reduce(function (memo, entry) { + memo[entry.key] = entry.state; + return memo; + }, {}); +} + +function createMemoryHistory() { + var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; + + if (Array.isArray(options)) { + options = { entries: options }; + } else if (typeof options === 'string') { + options = { entries: [options] }; + } + + var history = _createHistory2['default'](_extends({}, options, { + getCurrentLocation: getCurrentLocation, + finishTransition: finishTransition, + saveState: saveState, + go: go + })); + + var _options = options; + var entries = _options.entries; + var current = _options.current; + + if (typeof entries === 'string') { + entries = [entries]; + } else if (!Array.isArray(entries)) { + entries = ['/']; + } + + entries = entries.map(function (entry) { + var key = history.createKey(); + + if (typeof entry === 'string') return { pathname: entry, key: key }; + + if (typeof entry === 'object' && entry) return _extends({}, entry, { key: key }); + + true ? process.env.NODE_ENV !== 'production' ? _invariant2['default'](false, 'Unable to create history entry from %s', entry) : _invariant2['default'](false) : undefined; + }); + + if (current == null) { + current = entries.length - 1; + } else { + !(current >= 0 && current < entries.length) ? process.env.NODE_ENV !== 'production' ? _invariant2['default'](false, 'Current index must be >= 0 and < %s, was %s', entries.length, current) : _invariant2['default'](false) : undefined; + } + + var storage = createStateStorage(entries); + + function saveState(key, state) { + storage[key] = state; + } + + function readState(key) { + return storage[key]; + } + + function getCurrentLocation() { + var entry = entries[current]; + var key = entry.key; + var basename = entry.basename; + var pathname = entry.pathname; + var search = entry.search; + + var path = (basename || '') + pathname + (search || ''); + + var state = undefined; + if (key) { + state = readState(key); + } else { + state = null; + key = history.createKey(); + entry.key = key; + } + + var location = _parsePath2['default'](path); + + return history.createLocation(_extends({}, location, { state: state }), undefined, key); + } + + function canGo(n) { + var index = current + n; + return index >= 0 && index < entries.length; + } + + function go(n) { + if (n) { + if (!canGo(n)) { + process.env.NODE_ENV !== 'production' ? _warning2['default'](false, 'Cannot go(%s) there is not enough history', n) : undefined; + return; + } + + current += n; + + var currentLocation = getCurrentLocation(); + + // change action to POP + history.transitionTo(_extends({}, currentLocation, { action: _Actions.POP })); + } + } + + function finishTransition(location) { + switch (location.action) { + case _Actions.PUSH: + current += 1; + + // if we are not on the top of stack + // remove rest and push new + if (current < entries.length) entries.splice(current); + + entries.push(location); + saveState(location.key, location.state); + break; + case _Actions.REPLACE: + entries[current] = location; + saveState(location.key, location.state); + break; + } + } + + return history; +} + +exports['default'] = createMemoryHistory; +module.exports = exports['default']; +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) + +/***/ }), +/* 302 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +exports.__esModule = true; + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } + +var _ExecutionEnvironment = __webpack_require__(47); + +var _runTransitionHook = __webpack_require__(88); + +var _runTransitionHook2 = _interopRequireDefault(_runTransitionHook); + +var _extractPath = __webpack_require__(139); + +var _extractPath2 = _interopRequireDefault(_extractPath); + +var _parsePath = __webpack_require__(32); + +var _parsePath2 = _interopRequireDefault(_parsePath); + +var _deprecate = __webpack_require__(31); + +var _deprecate2 = _interopRequireDefault(_deprecate); + +function useBasename(createHistory) { + return function () { + var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; + var basename = options.basename; + + var historyOptions = _objectWithoutProperties(options, ['basename']); + + var history = createHistory(historyOptions); + + // Automatically use the value of in HTML + // documents as basename if it's not explicitly given. + if (basename == null && _ExecutionEnvironment.canUseDOM) { + var base = document.getElementsByTagName('base')[0]; + + if (base) basename = _extractPath2['default'](base.href); + } + + function addBasename(location) { + if (basename && location.basename == null) { + if (location.pathname.indexOf(basename) === 0) { + location.pathname = location.pathname.substring(basename.length); + location.basename = basename; + + if (location.pathname === '') location.pathname = '/'; + } else { + location.basename = ''; + } + } + + return location; + } + + function prependBasename(location) { + if (!basename) return location; + + if (typeof location === 'string') location = _parsePath2['default'](location); + + var pname = location.pathname; + var normalizedBasename = basename.slice(-1) === '/' ? basename : basename + '/'; + var normalizedPathname = pname.charAt(0) === '/' ? pname.slice(1) : pname; + var pathname = normalizedBasename + normalizedPathname; + + return _extends({}, location, { + pathname: pathname + }); + } + + // Override all read methods with basename-aware versions. + function listenBefore(hook) { + return history.listenBefore(function (location, callback) { + _runTransitionHook2['default'](hook, addBasename(location), callback); + }); + } + + function listen(listener) { + return history.listen(function (location) { + listener(addBasename(location)); + }); + } + + // Override all write methods with basename-aware versions. + function push(location) { + history.push(prependBasename(location)); + } + + function replace(location) { + history.replace(prependBasename(location)); + } + + function createPath(location) { + return history.createPath(prependBasename(location)); + } + + function createHref(location) { + return history.createHref(prependBasename(location)); + } + + function createLocation() { + return addBasename(history.createLocation.apply(history, arguments)); + } + + // deprecated + function pushState(state, path) { + if (typeof path === 'string') path = _parsePath2['default'](path); + + push(_extends({ state: state }, path)); + } + + // deprecated + function replaceState(state, path) { + if (typeof path === 'string') path = _parsePath2['default'](path); + + replace(_extends({ state: state }, path)); + } + + return _extends({}, history, { + listenBefore: listenBefore, + listen: listen, + push: push, + replace: replace, + createPath: createPath, + createHref: createHref, + createLocation: createLocation, + + pushState: _deprecate2['default'](pushState, 'pushState is deprecated; use push instead'), + replaceState: _deprecate2['default'](replaceState, 'replaceState is deprecated; use replace instead') + }); + }; +} + +exports['default'] = useBasename; +module.exports = exports['default']; + +/***/ }), +/* 303 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +exports.__esModule = true; + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +var _deprecate = __webpack_require__(31); + +var _deprecate2 = _interopRequireDefault(_deprecate); + +var _useBeforeUnload = __webpack_require__(144); + +var _useBeforeUnload2 = _interopRequireDefault(_useBeforeUnload); + +exports['default'] = _deprecate2['default'](_useBeforeUnload2['default'], 'enableBeforeUnload is deprecated, use useBeforeUnload instead'); +module.exports = exports['default']; + +/***/ }), +/* 304 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +exports.__esModule = true; + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +var _deprecate = __webpack_require__(31); + +var _deprecate2 = _interopRequireDefault(_deprecate); + +var _useQueries = __webpack_require__(145); + +var _useQueries2 = _interopRequireDefault(_useQueries); + +exports['default'] = _deprecate2['default'](_useQueries2['default'], 'enableQueries is deprecated, use useQueries instead'); +module.exports = exports['default']; + +/***/ }), +/* 305 */, +/* 306 */, +/* 307 */, +/* 308 */, +/* 309 */, +/* 310 */, +/* 311 */, +/* 312 */, +/* 313 */, +/* 314 */, +/* 315 */, +/* 316 */, +/* 317 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _jquery = __webpack_require__(11); + +var _jquery2 = _interopRequireDefault(_jquery); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +(0, _jquery2.default)(document).ready(function () { + (0, _jquery2.default)('[data-toggle=offcanvas]').click(function () { + var target = (0, _jquery2.default)((0, _jquery2.default)(this).attr('data-target') || '.block-offcanvas'); + var isActive = target.is('.active'); + target.toggleClass('active', !isActive); + (0, _jquery2.default)(this).toggleClass('active', !isActive); + }); +}); + +/***/ }), +/* 318 */ +/***/ (function(module, exports) { + +// removed by extract-text-webpack-plugin + +/***/ }), +/* 319 */, +/* 320 */, +/* 321 */, +/* 322 */ +/***/ (function(module, exports) { + +/** @license + * eventsource.js + * Available under MIT License (MIT) + * https://github.com/Yaffle/EventSource/ + */ + +/*jslint indent: 2, vars: true, plusplus: true */ +/*global setTimeout, clearTimeout */ + +(function (global) { + "use strict"; + + function Map() { + this.data = {}; + } + + Map.prototype.get = function (key) { + return this.data[key + "~"]; + }; + Map.prototype.set = function (key, value) { + this.data[key + "~"] = value; + }; + Map.prototype["delete"] = function (key) { + delete this.data[key + "~"]; + }; + + function EventTarget() { + this.listeners = new Map(); + } + + function throwError(e) { + setTimeout(function () { + throw e; + }, 0); + } + + EventTarget.prototype.dispatchEvent = function (event) { + event.target = this; + var type = event.type.toString(); + var listeners = this.listeners; + var typeListeners = listeners.get(type); + if (typeListeners == undefined) { + return; + } + var length = typeListeners.length; + var i = -1; + var listener = undefined; + while (++i < length) { + listener = typeListeners[i]; + try { + listener.call(this, event); + } catch (e) { + throwError(e); + } + } + }; + EventTarget.prototype.addEventListener = function (type, callback) { + type = type.toString(); + var listeners = this.listeners; + var typeListeners = listeners.get(type); + if (typeListeners == undefined) { + typeListeners = []; + listeners.set(type, typeListeners); + } + var i = typeListeners.length; + while (--i >= 0) { + if (typeListeners[i] === callback) { + return; + } + } + typeListeners.push(callback); + }; + EventTarget.prototype.removeEventListener = function (type, callback) { + type = type.toString(); + var listeners = this.listeners; + var typeListeners = listeners.get(type); + if (typeListeners == undefined) { + return; + } + var length = typeListeners.length; + var filtered = []; + var i = -1; + while (++i < length) { + if (typeListeners[i] !== callback) { + filtered.push(typeListeners[i]); + } + } + if (filtered.length === 0) { + listeners["delete"](type); + } else { + listeners.set(type, filtered); + } + }; + + function Event(type) { + this.type = type; + this.target = undefined; + } + + function MessageEvent(type, options) { + Event.call(this, type); + this.data = options.data; + this.lastEventId = options.lastEventId; + } + + MessageEvent.prototype = Event.prototype; + + var XHR = global.XMLHttpRequest; + var XDR = global.XDomainRequest; + var isCORSSupported = XHR != undefined && (new XHR()).withCredentials != undefined; + var isXHR = isCORSSupported; + var Transport = isCORSSupported ? XHR : (XDR != undefined ? XDR : undefined); + var WAITING = -1; + var CONNECTING = 0; + var OPEN = 1; + var CLOSED = 2; + var AFTER_CR = 3; + var FIELD_START = 4; + var FIELD = 5; + var VALUE_START = 6; + var VALUE = 7; + var contentTypeRegExp = /^text\/event\-stream;?(\s*charset\=utf\-8)?$/i; + + var MINIMUM_DURATION = 1000; + var MAXIMUM_DURATION = 18000000; + + function getDuration(value, def) { + var n = value; + if (n !== n) { + n = def; + } + return (n < MINIMUM_DURATION ? MINIMUM_DURATION : (n > MAXIMUM_DURATION ? MAXIMUM_DURATION : n)); + } + + function fire(that, f, event) { + try { + if (typeof f === "function") { + f.call(that, event); + } + } catch (e) { + throwError(e); + } + } + + function EventSource(url, options) { + url = url.toString(); + + var withCredentials = isCORSSupported && options != undefined && Boolean(options.withCredentials); + var initialRetry = getDuration(1000, 0); + var heartbeatTimeout = getDuration(45000, 0); + + var lastEventId = ""; + var that = this; + var retry = initialRetry; + var wasActivity = false; + var xhr = options != undefined && options.Transport != undefined ? new options.Transport() : new Transport(); + var timeout = 0; + var timeout0 = 0; + var charOffset = 0; + var currentState = WAITING; + var dataBuffer = []; + var lastEventIdBuffer = ""; + var eventTypeBuffer = ""; + var onTimeout = undefined; + + var state = FIELD_START; + var field = ""; + var value = ""; + + function close() { + currentState = CLOSED; + if (xhr != undefined) { + xhr.abort(); + xhr = undefined; + } + if (timeout !== 0) { + clearTimeout(timeout); + timeout = 0; + } + if (timeout0 !== 0) { + clearTimeout(timeout0); + timeout0 = 0; + } + that.readyState = CLOSED; + } + + function onEvent(type) { + var responseText = currentState === OPEN || currentState === CONNECTING ? xhr.responseText : ""; + var event = undefined; + var isWrongStatusCodeOrContentType = false; + + if (currentState === CONNECTING) { + var status = 0; + var statusText = ""; + var contentType = undefined; + if (isXHR) { + try { + status = xhr.status; + statusText = xhr.statusText; + contentType = xhr.getResponseHeader("Content-Type"); + } catch (error) { + // https://bugs.webkit.org/show_bug.cgi?id=29121 + status = 0; + statusText = ""; + contentType = undefined; + // FF < 14, WebKit + // https://bugs.webkit.org/show_bug.cgi?id=29658 + // https://bugs.webkit.org/show_bug.cgi?id=77854 + } + } else if (type !== "" && type !== "error") { + status = 200; + statusText = "OK"; + contentType = xhr.contentType; + } + if (contentType == undefined) { + contentType = ""; + } + if (status === 0 && statusText === "" && type === "load" && responseText !== "") { + status = 200; + statusText = "OK"; + if (contentType === "") { // Opera 12 + var tmp = (/^data\:([^,]*?)(?:;base64)?,[\S]*$/).exec(url); + if (tmp != undefined) { + contentType = tmp[1]; + } + } + } + if (status === 200 && contentTypeRegExp.test(contentType)) { + currentState = OPEN; + wasActivity = true; + retry = initialRetry; + that.readyState = OPEN; + event = new Event("open"); + that.dispatchEvent(event); + fire(that, that.onopen, event); + if (currentState === CLOSED) { + return; + } + } else { + // Opera 12 + if (status !== 0 && (status !== 200 || contentType !== "")) { + var message = ""; + if (status !== 200) { + message = "EventSource's response has a status " + status + " " + statusText.replace(/\s+/g, " ") + " that is not 200. Aborting the connection."; + } else { + message = "EventSource's response has a Content-Type specifying an unsupported type: " + contentType.replace(/\s+/g, " ") + ". Aborting the connection."; + } + setTimeout(function () { + throw new Error(message); + }, 0); + isWrongStatusCodeOrContentType = true; + } + } + } + + if (currentState === OPEN) { + if (responseText.length > charOffset) { + wasActivity = true; + } + var i = charOffset - 1; + var length = responseText.length; + var c = "\n"; + while (++i < length) { + c = responseText.charAt(i); + if (state === AFTER_CR && c === "\n") { + state = FIELD_START; + } else { + if (state === AFTER_CR) { + state = FIELD_START; + } + if (c === "\r" || c === "\n") { + if (field === "data") { + dataBuffer.push(value); + } else if (field === "id") { + lastEventIdBuffer = value; + } else if (field === "event") { + eventTypeBuffer = value; + } else if (field === "retry") { + initialRetry = getDuration(Number(value), initialRetry); + retry = initialRetry; + } else if (field === "heartbeatTimeout") { + heartbeatTimeout = getDuration(Number(value), heartbeatTimeout); + if (timeout !== 0) { + clearTimeout(timeout); + timeout = setTimeout(onTimeout, heartbeatTimeout); + } + } + value = ""; + field = ""; + if (state === FIELD_START) { + if (dataBuffer.length !== 0) { + lastEventId = lastEventIdBuffer; + if (eventTypeBuffer === "") { + eventTypeBuffer = "message"; + } + event = new MessageEvent(eventTypeBuffer, { + data: dataBuffer.join("\n"), + lastEventId: lastEventIdBuffer + }); + that.dispatchEvent(event); + if (eventTypeBuffer === "message") { + fire(that, that.onmessage, event); + } + if (currentState === CLOSED) { + return; + } + } + dataBuffer.length = 0; + eventTypeBuffer = ""; + } + state = c === "\r" ? AFTER_CR : FIELD_START; + } else { + if (state === FIELD_START) { + state = FIELD; + } + if (state === FIELD) { + if (c === ":") { + state = VALUE_START; + } else { + field += c; + } + } else if (state === VALUE_START) { + if (c !== " ") { + value += c; + } + state = VALUE; + } else if (state === VALUE) { + value += c; + } + } + } + } + charOffset = length; + } + + if ((currentState === OPEN || currentState === CONNECTING) && + (type === "load" || type === "error" || isWrongStatusCodeOrContentType || (charOffset > 1024 * 1024) || (timeout === 0 && !wasActivity))) { + if (isWrongStatusCodeOrContentType) { + close(); + } else { + if (type === "" && timeout === 0 && !wasActivity) { + setTimeout(function () { + throw new Error("No activity within " + heartbeatTimeout + " milliseconds. Reconnecting."); + }, 0); + } + currentState = WAITING; + xhr.abort(); + if (timeout !== 0) { + clearTimeout(timeout); + timeout = 0; + } + if (retry > initialRetry * 16) { + retry = initialRetry * 16; + } + if (retry > MAXIMUM_DURATION) { + retry = MAXIMUM_DURATION; + } + timeout = setTimeout(onTimeout, retry); + retry = retry * 2 + 1; + + that.readyState = CONNECTING; + } + event = new Event("error"); + that.dispatchEvent(event); + fire(that, that.onerror, event); + } else { + if (timeout === 0) { + wasActivity = false; + timeout = setTimeout(onTimeout, heartbeatTimeout); + } + } + } + + function onProgress() { + onEvent("progress"); + } + + function onLoad() { + onEvent("load"); + } + + function onError() { + onEvent("error"); + } + + if (isXHR && global.opera != undefined) { + // workaround for Opera issue with "progress" events + timeout0 = setTimeout(function f() { + if (xhr.readyState === 3) { + onEvent("progress"); + } + timeout0 = setTimeout(f, 500); + }, 0); + } + + onTimeout = function () { + timeout = 0; + if (currentState !== WAITING) { + onEvent(""); + return; + } + + // loading indicator in Safari, Chrome < 14 + if (isXHR && !("onloadend" in xhr) && global.document != undefined && global.document.readyState != undefined && global.document.readyState !== "complete") { + timeout = setTimeout(onTimeout, 4); + return; + } + + // XDomainRequest#abort removes onprogress, onerror, onload + xhr.onload = onLoad; + xhr.onerror = onError; + + if (isXHR) { + // improper fix to match Firefox behaviour, but it is better than just ignore abort + // see https://bugzilla.mozilla.org/show_bug.cgi?id=768596 + // https://bugzilla.mozilla.org/show_bug.cgi?id=880200 + // https://code.google.com/p/chromium/issues/detail?id=153570 + xhr.onabort = onError; + + // Firefox 3.5 - 3.6 - ? < 9.0 + // onprogress is not fired sometimes or delayed + xhr.onreadystatechange = onProgress; + } + + // loading indicator in Firefox + // https://bugzilla.mozilla.org/show_bug.cgi?id=736723 + if (xhr.sendAsBinary == undefined) { + xhr.onprogress = onProgress; + } + + wasActivity = false; + timeout = setTimeout(onTimeout, heartbeatTimeout); + + charOffset = 0; + currentState = CONNECTING; + dataBuffer.length = 0; + eventTypeBuffer = ""; + lastEventIdBuffer = lastEventId; + value = ""; + field = ""; + state = FIELD_START; + + var s = url.slice(0, 5); + if (s !== "data:" && s !== "blob:") { + s = url + ((url.indexOf("?", 0) === -1 ? "?" : "&") + "lastEventId=" + encodeURIComponent(lastEventId) + "&r=" + (Math.random() + 1).toString().slice(2)); + } else { + s = url; + } + xhr.open("GET", s, true); + + if (isXHR) { + // withCredentials should be set after "open" for Safari and Chrome (< 19 ?) + xhr.withCredentials = withCredentials; + + xhr.responseType = "text"; + + // Request header field Cache-Control is not allowed by Access-Control-Allow-Headers. + // "Cache-control: no-cache" are not honored in Chrome and Firefox + // https://bugzilla.mozilla.org/show_bug.cgi?id=428916 + //xhr.setRequestHeader("Cache-Control", "no-cache"); + xhr.setRequestHeader("Accept", "text/event-stream"); + // Request header field Last-Event-ID is not allowed by Access-Control-Allow-Headers. + //xhr.setRequestHeader("Last-Event-ID", lastEventId); + } + + xhr.send(undefined); + }; + + EventTarget.call(this); + this.close = close; + this.url = url; + this.readyState = CONNECTING; + this.withCredentials = withCredentials; + + this.onopen = undefined; + this.onmessage = undefined; + this.onerror = undefined; + + onTimeout(); + } + + function F() { + this.CONNECTING = CONNECTING; + this.OPEN = OPEN; + this.CLOSED = CLOSED; + } + F.prototype = EventTarget.prototype; + + EventSource.prototype = new F(); + F.call(EventSource); + + var isEventSourceSupported = function () { + if (global.EventSource != undefined) { + try { + var es = new global.EventSource("data:text/event-stream;charset=utf-8,"); + es.close(); + return es.withCredentials === false && + es.url !== ""; // to filter out Opera 12 implementation + } catch (error) { + return false; + } + } + return false; + }; + + if (Transport != undefined && !isEventSourceSupported()) { + // Why replace a native EventSource ? + // https://bugzilla.mozilla.org/show_bug.cgi?id=444328 + // https://bugzilla.mozilla.org/show_bug.cgi?id=831392 + // https://code.google.com/p/chromium/issues/detail?id=260144 + // https://code.google.com/p/chromium/issues/detail?id=225654 + // ... + global.NativeEventSource = global.EventSource; + global.EventSource = EventSource; + } + +}(this)); + + +/***/ }), +/* 323 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +var _BreadCrumbs = __webpack_require__(324); + +var _BreadCrumbs2 = _interopRequireDefault(_BreadCrumbs); + +var _Sidebar = __webpack_require__(329); + +var _Sidebar2 = _interopRequireDefault(_Sidebar); + +var _Component2 = __webpack_require__(16); + +var _Component3 = _interopRequireDefault(_Component2); + +var _DialogSlot = __webpack_require__(330); + +var _DialogSlot2 = _interopRequireDefault(_DialogSlot); + +var _ServerStatus = __webpack_require__(331); + +var _ServerStatus2 = _interopRequireDefault(_ServerStatus); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var App = function (_Component) { + _inherits(App, _Component); + + function App() { + _classCallCheck(this, App); + + return _possibleConstructorReturn(this, (App.__proto__ || Object.getPrototypeOf(App)).apply(this, arguments)); + } + + _createClass(App, [{ + key: 'render', + value: function render() { + return _react2.default.createElement( + 'div', + { className: 'application' }, + _react2.default.createElement(_ServerStatus2.default, null), + _react2.default.createElement( + 'header', + null, + _react2.default.createElement( + _BreadCrumbs2.default, + this.getRoutingProps(), + _react2.default.createElement( + 'button', + { type: 'button', className: 'navbar-toggle', + 'data-toggle': 'offcanvas', + 'data-target': '.sidebar-block' }, + _react2.default.createElement( + 'span', + { className: 'sr-only' }, + 'Toggle navigation' + ), + _react2.default.createElement('span', { className: 'icon-list' }), + _react2.default.createElement('span', { className: 'icon-list' }), + _react2.default.createElement('span', { className: 'icon-list' }) + ) + ) + ), + _react2.default.createElement( + 'div', + { className: 'editor container' }, + _react2.default.createElement(_DialogSlot2.default, this.getRoutingProps()), + _react2.default.createElement( + 'div', + { className: 'sidebar-block block-offcanvas block-offcanvas-left' }, + _react2.default.createElement( + 'nav', + { className: 'sidebar col-md-2 col-sm-3 sidebar-offcanvas' }, + _react2.default.createElement(_Sidebar2.default, this.getRoutingProps()) + ), + _react2.default.createElement( + 'div', + { className: 'view col-md-10 col-sm-9' }, + this.props.children + ) + ) + ) + ); + } + }]); + + return App; +}(_Component3.default); + +exports.default = App; + +/***/ }), +/* 324 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +var _RecordComponent2 = __webpack_require__(26); + +var _RecordComponent3 = _interopRequireDefault(_RecordComponent2); + +var _Link = __webpack_require__(149); + +var _Link2 = _interopRequireDefault(_Link); + +var _utils = __webpack_require__(12); + +var _utils2 = _interopRequireDefault(_utils); + +var _i18n = __webpack_require__(7); + +var _i18n2 = _interopRequireDefault(_i18n); + +var _dialogSystem = __webpack_require__(22); + +var _dialogSystem2 = _interopRequireDefault(_dialogSystem); + +var _findFiles = __webpack_require__(325); + +var _findFiles2 = _interopRequireDefault(_findFiles); + +var _publish = __webpack_require__(327); + +var _publish2 = _interopRequireDefault(_publish); + +var _Refresh = __webpack_require__(328); + +var _Refresh2 = _interopRequireDefault(_Refresh); + +var _richPromise = __webpack_require__(17); + +var _richPromise2 = _interopRequireDefault(_richPromise); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var BreadCrumbs = function (_RecordComponent) { + _inherits(BreadCrumbs, _RecordComponent); + + function BreadCrumbs(props) { + _classCallCheck(this, BreadCrumbs); + + var _this = _possibleConstructorReturn(this, (BreadCrumbs.__proto__ || Object.getPrototypeOf(BreadCrumbs)).call(this, props)); + + _this.state = { + recordPathInfo: null + }; + _this._onKeyPress = _this._onKeyPress.bind(_this); + return _this; + } + + _createClass(BreadCrumbs, [{ + key: 'componentDidMount', + value: function componentDidMount() { + _get(BreadCrumbs.prototype.__proto__ || Object.getPrototypeOf(BreadCrumbs.prototype), 'componentDidMount', this).call(this); + this.updateCrumbs(); + window.addEventListener('keydown', this._onKeyPress); + } + }, { + key: 'componentDidUpdate', + value: function componentDidUpdate(prevProps, prevState) { + _get(BreadCrumbs.prototype.__proto__ || Object.getPrototypeOf(BreadCrumbs.prototype), 'componentDidUpdate', this).call(this, prevProps, prevState); + if (prevProps.params.path !== this.props.params.path) { + this.updateCrumbs(); + } + } + }, { + key: 'componentWillUnmount', + value: function componentWillUnmount() { + window.removeEventListener('keydown', this._onKeyPress); + } + }, { + key: 'updateCrumbs', + value: function updateCrumbs() { + var _this2 = this; + + var path = this.getRecordPath(); + if (path === null) { + this.setState({ + recordPathInfo: null + }); + return; + } + + _utils2.default.loadData('/pathinfo', { path: path }, null, _richPromise2.default).then(function (resp) { + _this2.setState({ + recordPathInfo: { + path: path, + segments: resp.segments + } + }); + }); + } + }, { + key: '_onKeyPress', + value: function _onKeyPress(event) { + // meta+g is open find files + if (event.which === 71 && _utils2.default.isMetaKey(event)) { + event.preventDefault(); + _dialogSystem2.default.showDialog(_findFiles2.default); + } + } + }, { + key: '_onCloseClick', + value: function _onCloseClick(e) { + _utils2.default.loadData('/previewinfo', { + path: this.getRecordPath(), + alt: this.getRecordAlt() + }, null, _richPromise2.default).then(function (resp) { + if (resp.url === null) { + window.location.href = _utils2.default.getCanonicalUrl('/'); + } else { + window.location.href = _utils2.default.getCanonicalUrl(resp.url); + } + }); + } + }, { + key: '_onFindFiles', + value: function _onFindFiles(e) { + _dialogSystem2.default.showDialog(_findFiles2.default); + } + }, { + key: '_onRefresh', + value: function _onRefresh(e) { + _dialogSystem2.default.showDialog(_Refresh2.default); + } + }, { + key: '_onPublish', + value: function _onPublish(e) { + _dialogSystem2.default.showDialog(_publish2.default); + } + }, { + key: 'renderGlobalActions', + value: function renderGlobalActions() { + return _react2.default.createElement( + 'div', + { className: 'btn-group' }, + _react2.default.createElement( + 'button', + { className: 'btn btn-default', onClick: this._onFindFiles.bind(this), title: _i18n2.default.trans('FIND_FILES') }, + _react2.default.createElement('i', { className: 'fa fa-search fa-fw' }) + ), + _react2.default.createElement( + 'button', + { className: 'btn btn-default', onClick: this._onPublish.bind(this), title: _i18n2.default.trans('PUBLISH') }, + _react2.default.createElement('i', { className: 'fa fa-cloud-upload fa-fw' }) + ), + _react2.default.createElement( + 'button', + { className: 'btn btn-default', onClick: this._onRefresh.bind(this), title: _i18n2.default.trans('REFRESH_BUILD') }, + _react2.default.createElement('i', { className: 'fa fa-refresh fa-fw' }) + ), + _react2.default.createElement( + 'button', + { className: 'btn btn-default', onClick: this._onCloseClick.bind(this), title: _i18n2.default.trans('RETURN_TO_WEBSITE') }, + _react2.default.createElement('i', { className: 'fa fa-eye fa-fw' }) + ) + ); + } + }, { + key: 'render', + value: function render() { + var _this3 = this; + + var crumbs = []; + var target = this.isRecordPreviewActive() ? '.preview' : '.edit'; + var lastItem = null; + + if (this.state.recordPathInfo != null) { + crumbs = this.state.recordPathInfo.segments.map(function (item) { + var urlPath = _this3.getUrlRecordPathWithAlt(item.path); + var label = item.label_i18n ? _i18n2.default.trans(item.label_i18n) : item.label; + var className = 'record-crumb'; + + if (!item.exists) { + label = item.id; + className += ' missing-record-crumb'; + } + lastItem = item; + + var adminPath = _this3.getPathToAdminPage(target, { path: urlPath }); + + return _react2.default.createElement( + 'li', + { key: item.path, className: className }, + _react2.default.createElement( + _Link2.default, + { to: adminPath }, + label + ) + ); + }); + } else { + crumbs = _react2.default.createElement( + 'li', + null, + _react2.default.createElement( + _Link2.default, + { to: this.getPathToAdminPage('.edit', { path: 'root' }) }, + _i18n2.default.trans('BACK_TO_OVERVIEW') + ) + ); + } + + return _react2.default.createElement( + 'div', + { className: 'breadcrumbs' }, + _react2.default.createElement( + 'ul', + { className: 'breadcrumb container' }, + this.props.children, + crumbs, + lastItem && lastItem.can_have_children ? _react2.default.createElement( + 'li', + { className: 'new-record-crumb' }, + _react2.default.createElement( + _Link2.default, + { to: this.getPathToAdminPage('.add-child', { + path: this.getUrlRecordPathWithAlt(lastItem.path) }) }, + '+' + ) + ) : null, + ' ' /* this space is needed for chrome ... */, + _react2.default.createElement( + 'li', + { className: 'meta' }, + this.renderGlobalActions() + ) + ) + ); + } + }]); + + return BreadCrumbs; +}(_RecordComponent3.default); + +exports.default = BreadCrumbs; + +/***/ }), +/* 325 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +var _RecordComponent2 = __webpack_require__(26); + +var _RecordComponent3 = _interopRequireDefault(_RecordComponent2); + +var _SlideDialog = __webpack_require__(62); + +var _SlideDialog2 = _interopRequireDefault(_SlideDialog); + +var _utils = __webpack_require__(12); + +var _utils2 = _interopRequireDefault(_utils); + +var _i18n = __webpack_require__(7); + +var _i18n2 = _interopRequireDefault(_i18n); + +var _dialogSystem = __webpack_require__(22); + +var _dialogSystem2 = _interopRequireDefault(_dialogSystem); + +var _richPromise = __webpack_require__(17); + +var _richPromise2 = _interopRequireDefault(_richPromise); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var FindFiles = function (_RecordComponent) { + _inherits(FindFiles, _RecordComponent); + + function FindFiles(props) { + _classCallCheck(this, FindFiles); + + var _this = _possibleConstructorReturn(this, (FindFiles.__proto__ || Object.getPrototypeOf(FindFiles)).call(this, props)); + + _this.state = { + query: '', + currentSelection: -1, + results: [] + }; + return _this; + } + + _createClass(FindFiles, [{ + key: 'componentDidMount', + value: function componentDidMount() { + _get(FindFiles.prototype.__proto__ || Object.getPrototypeOf(FindFiles.prototype), 'componentDidMount', this).call(this); + this.refs.q.focus(); + } + }, { + key: 'onInputChange', + value: function onInputChange(e) { + var _this2 = this; + + var q = e.target.value; + + if (q === '') { + this.setState({ + query: '', + results: [], + currentSelection: -1 + }); + } else { + this.setState({ + query: q + }); + + _utils2.default.apiRequest('/find', { + data: { + q: q, + alt: this.getRecordAlt(), + lang: _i18n2.default.currentLanguage + }, + method: 'POST' + }, _richPromise2.default).then(function (resp) { + _this2.setState({ + results: resp.results, + currentSelection: Math.min(_this2.state.currentSelection, resp.results.length - 1) + }); + }); + } + } + }, { + key: 'onInputKey', + value: function onInputKey(e) { + var sel = this.state.currentSelection; + var max = this.state.results.length; + if (e.which === 40) { + e.preventDefault(); + sel = (sel + 1) % max; + } else if (e.which === 38) { + e.preventDefault(); + sel = (sel - 1 + max) % max; + } else if (e.which === 13) { + this.onActiveItem(this.state.currentSelection); + } + this.setState({ + currentSelection: sel + }); + } + }, { + key: 'onActiveItem', + value: function onActiveItem(index) { + var item = this.state.results[index]; + if (item !== undefined) { + var target = this.isRecordPreviewActive() ? '.preview' : '.edit'; + var urlPath = this.getUrlRecordPathWithAlt(item.path); + _dialogSystem2.default.dismissDialog(); + this.transitionToAdminPage(target, { path: urlPath }); + } + } + }, { + key: 'selectItem', + value: function selectItem(index) { + this.setState({ + currentSelection: Math.min(index, this.state.results.length - 1) + }); + } + }, { + key: 'renderResults', + value: function renderResults() { + var _this3 = this; + + var rv = this.state.results.map(function (result, idx) { + var parents = result.parents.map(function (item, idx) { + return _react2.default.createElement( + 'span', + { className: 'parent', key: idx }, + item.title + ); + }); + + return _react2.default.createElement( + 'li', + { + key: idx, + className: idx === _this3.state.currentSelection ? 'active' : '', + onClick: _this3.onActiveItem.bind(_this3, idx), + onMouseEnter: _this3.selectItem.bind(_this3, idx) }, + parents, + _react2.default.createElement( + 'strong', + null, + result.title + ) + ); + }); + + return _react2.default.createElement( + 'ul', + { className: 'search-results' }, + rv + ); + } + }, { + key: 'render', + value: function render() { + return _react2.default.createElement( + _SlideDialog2.default, + { + hasCloseButton: true, + closeOnEscape: true, + title: _i18n2.default.trans('FIND_FILES') }, + _react2.default.createElement( + 'div', + { className: 'form-group' }, + _react2.default.createElement('input', { type: 'text', + ref: 'q', + className: 'form-control', + value: this.state.query, + onChange: this.onInputChange.bind(this), + onKeyDown: this.onInputKey.bind(this), + placeholder: _i18n2.default.trans('FIND_FILES_PLACEHOLDER') }) + ), + this.renderResults() + ); + } + }]); + + return FindFiles; +}(_RecordComponent3.default); + +exports.default = FindFiles; + +/***/ }), +/* 326 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _propTypes = __webpack_require__(23); + +var _propTypes2 = _interopRequireDefault(_propTypes); + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +var _RecordComponent2 = __webpack_require__(26); + +var _RecordComponent3 = _interopRequireDefault(_RecordComponent2); + +var _SlideDialog = __webpack_require__(62); + +var _SlideDialog2 = _interopRequireDefault(_SlideDialog); + +var _dialogSystem = __webpack_require__(22); + +var _dialogSystem2 = _interopRequireDefault(_dialogSystem); + +var _i18n = __webpack_require__(7); + +var _i18n2 = _interopRequireDefault(_i18n); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var ErrorDialog = function (_RecordComponent) { + _inherits(ErrorDialog, _RecordComponent); + + function ErrorDialog() { + _classCallCheck(this, ErrorDialog); + + return _possibleConstructorReturn(this, (ErrorDialog.__proto__ || Object.getPrototypeOf(ErrorDialog)).apply(this, arguments)); + } + + _createClass(ErrorDialog, [{ + key: 'onClose', + value: function onClose() { + _dialogSystem2.default.dismissDialog(); + } + }, { + key: 'render', + value: function render() { + return _react2.default.createElement( + _SlideDialog2.default, + { + hasCloseButton: true, + closeOnEscape: true, + title: _i18n2.default.trans('ERROR') }, + _react2.default.createElement( + 'p', + null, + _i18n2.default.trans('ERROR_OCURRED'), + ': ', + _i18n2.default.trans('ERROR_' + this.props.error.code) + ), + _react2.default.createElement( + 'div', + { className: 'actions' }, + _react2.default.createElement( + 'button', + { type: 'submit', className: 'btn btn-primary', + onClick: this.onClose.bind(this) }, + _i18n2.default.trans('CLOSE') + ) + ) + ); + } + }]); + + return ErrorDialog; +}(_RecordComponent3.default); + +ErrorDialog.propTypes = { + error: _propTypes2.default.object +}; + +exports.default = ErrorDialog; + +/***/ }), +/* 327 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* eslint-env browser */ + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +var _Component2 = __webpack_require__(16); + +var _Component3 = _interopRequireDefault(_Component2); + +var _SlideDialog = __webpack_require__(62); + +var _SlideDialog2 = _interopRequireDefault(_SlideDialog); + +var _utils = __webpack_require__(12); + +var _utils2 = _interopRequireDefault(_utils); + +var _i18n = __webpack_require__(7); + +var _i18n2 = _interopRequireDefault(_i18n); + +var _dialogSystem = __webpack_require__(22); + +var _dialogSystem2 = _interopRequireDefault(_dialogSystem); + +var _richPromise = __webpack_require__(17); + +var _richPromise2 = _interopRequireDefault(_richPromise); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var Publish = function (_Component) { + _inherits(Publish, _Component); + + function Publish(props) { + _classCallCheck(this, Publish); + + var _this = _possibleConstructorReturn(this, (Publish.__proto__ || Object.getPrototypeOf(Publish)).call(this, props)); + + _this.state = { + servers: [], + activeTarget: null, + log: [], + currentState: 'IDLE' + }; + return _this; + } + + _createClass(Publish, [{ + key: 'componentDidMount', + value: function componentDidMount() { + _get(Publish.prototype.__proto__ || Object.getPrototypeOf(Publish.prototype), 'componentDidMount', this).call(this); + this.syncDialog(); + } + }, { + key: 'componentWillUnmount', + value: function componentWillUnmount() { + _get(Publish.prototype.__proto__ || Object.getPrototypeOf(Publish.prototype), 'componentWillUnmount', this).call(this); + } + }, { + key: 'componentWillReceiveProps', + value: function componentWillReceiveProps(nextProps) { + this.syncDialog(); + } + }, { + key: 'preventNavigation', + value: function preventNavigation() { + return !this.isSafeToPublish(); + } + }, { + key: 'syncDialog', + value: function syncDialog() { + var _this2 = this; + + _utils2.default.loadData('/servers', {}, null, _richPromise2.default).then(function (_ref) { + var servers = _ref.servers; + + _this2.setState({ + servers: servers, + activeTarget: servers && servers.length ? servers[0].id : null + }); + }); + } + }, { + key: 'isSafeToPublish', + value: function isSafeToPublish() { + return this.state.currentState === 'IDLE' || this.state.currentState === 'DONE'; + } + }, { + key: 'onPublish', + value: function onPublish() { + if (this.isSafeToPublish()) { + this._beginBuild(); + } + } + }, { + key: 'onCancel', + value: function onCancel() { + _dialogSystem2.default.dismissDialog(); + } + }, { + key: '_beginBuild', + value: function _beginBuild() { + var _this3 = this; + + this.setState({ + log: [], + currentState: 'BUILDING' + }); + _utils2.default.apiRequest('/build', { + method: 'POST' + }, _richPromise2.default).then(function (resp) { + _this3._beginPublish(); + }); + } + }, { + key: '_beginPublish', + value: function _beginPublish() { + var _this4 = this; + + this.setState({ + currentState: 'PUBLISH' + }); + + var es = new EventSource(_utils2.default.getApiUrl('/publish') + '?server=' + encodeURIComponent(this.state.activeTarget)); + es.addEventListener('message', function (event) { + var data = JSON.parse(event.data); + if (data === null) { + _this4.setState({ + currentState: 'DONE' + }); + es.close(); + } else { + _this4.setState({ + log: _this4.state.log.concat(data.msg) + }); + } + }); + } + }, { + key: 'onSelectServer', + value: function onSelectServer(event) { + this.setState({ + activeTarget: event.target.value + }); + } + }, { + key: 'componentDidUpdate', + value: function componentDidUpdate() { + _get(Publish.prototype.__proto__ || Object.getPrototypeOf(Publish.prototype), 'componentDidUpdate', this).call(this); + var node = this.refs.log; + if (node) { + node.scrollTop = node.scrollHeight; + } + } + }, { + key: 'render', + value: function render() { + var servers = this.state.servers.map(function (server) { + return _react2.default.createElement( + 'option', + { value: server.id, key: server.id }, + _i18n2.default.trans(server.name_i18n) + ' (' + server.short_target + ')' + ); + }); + + var progress = null; + if (this.state.currentState !== 'IDLE') { + progress = _react2.default.createElement( + 'div', + null, + _react2.default.createElement( + 'h3', + null, + this.state.currentState !== 'DONE' ? _i18n2.default.trans('CURRENTLY_PUBLISHING') : _i18n2.default.trans('PUBLISH_DONE') + ), + _react2.default.createElement( + 'pre', + null, + _i18n2.default.trans('STATE') + ': ' + _i18n2.default.trans('PUBLISH_STATE_' + this.state.currentState) + ), + _react2.default.createElement( + 'pre', + { ref: 'log', className: 'build-log' }, + this.state.log.join('\n') + ) + ); + } + + return _react2.default.createElement( + _SlideDialog2.default, + { + hasCloseButton: false, + closeOnEscape: true, + title: _i18n2.default.trans('PUBLISH') }, + _react2.default.createElement( + 'p', + null, + _i18n2.default.trans('PUBLISH_NOTE') + ), + _react2.default.createElement( + 'dl', + null, + _react2.default.createElement( + 'dt', + null, + _i18n2.default.trans('PUBLISH_SERVER') + ), + _react2.default.createElement( + 'dd', + null, + _react2.default.createElement( + 'div', + { className: 'input-group' }, + _react2.default.createElement( + 'select', + { + value: this.state.activeTarget, + onChange: this.onSelectServer.bind(this), + className: 'form-control' }, + servers + ) + ) + ) + ), + _react2.default.createElement( + 'div', + { className: 'actions' }, + _react2.default.createElement( + 'button', + { type: 'submit', className: 'btn btn-primary', + disabled: !this.isSafeToPublish(), + onClick: this.onPublish.bind(this) }, + _i18n2.default.trans('PUBLISH') + ), + _react2.default.createElement( + 'button', + { type: 'submit', className: 'btn btn-default', + disabled: !this.isSafeToPublish(), + onClick: this.onCancel.bind(this) }, + _i18n2.default.trans(this.state.currentState === 'DONE' ? 'CLOSE' : 'CANCEL') + ) + ), + progress + ); + } + }]); + + return Publish; +}(_Component3.default); + +exports.default = Publish; + +/***/ }), +/* 328 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +var _Component2 = __webpack_require__(16); + +var _Component3 = _interopRequireDefault(_Component2); + +var _SlideDialog = __webpack_require__(62); + +var _SlideDialog2 = _interopRequireDefault(_SlideDialog); + +var _utils = __webpack_require__(12); + +var _utils2 = _interopRequireDefault(_utils); + +var _i18n = __webpack_require__(7); + +var _i18n2 = _interopRequireDefault(_i18n); + +var _dialogSystem = __webpack_require__(22); + +var _dialogSystem2 = _interopRequireDefault(_dialogSystem); + +var _richPromise = __webpack_require__(17); + +var _richPromise2 = _interopRequireDefault(_richPromise); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var Refresh = function (_Component) { + _inherits(Refresh, _Component); + + function Refresh(props) { + _classCallCheck(this, Refresh); + + var _this = _possibleConstructorReturn(this, (Refresh.__proto__ || Object.getPrototypeOf(Refresh)).call(this, props)); + + _this.state = { + currentState: 'IDLE' + }; + return _this; + } + + _createClass(Refresh, [{ + key: 'componentDidMount', + value: function componentDidMount() { + _get(Refresh.prototype.__proto__ || Object.getPrototypeOf(Refresh.prototype), 'componentDidMount', this).call(this); + this.syncDialog(); + } + }, { + key: 'preventNavigation', + value: function preventNavigation() { + return !this.isSafeToNavigate(); + } + }, { + key: 'isSafeToNavigate', + value: function isSafeToNavigate() { + return this.state.currentState === 'IDLE' || this.state.currentState === 'DONE'; + } + }, { + key: 'onRefresh', + value: function onRefresh() { + var _this2 = this; + + this.setState({ + currentState: 'CLEANING' + }); + _utils2.default.apiRequest('/clean', { + method: 'POST' + }, _richPromise2.default).then(function (resp) { + _this2.setState({ + currentState: 'DONE' + }); + }); + } + }, { + key: 'onCancel', + value: function onCancel() { + _dialogSystem2.default.dismissDialog(); + } + }, { + key: 'render', + value: function render() { + var progress = null; + if (this.state.currentState !== 'IDLE') { + progress = _react2.default.createElement( + 'div', + null, + _react2.default.createElement( + 'h3', + null, + this.state.currentState !== 'DONE' ? _i18n2.default.trans('CURRENTLY_REFRESHING_BUILD') : _i18n2.default.trans('REFRESHING_BUILD_DONE') + ) + ); + } + + return _react2.default.createElement( + _SlideDialog2.default, + { + hasCloseButton: false, + closeOnEscape: true, + title: _i18n2.default.trans('REFRESH_BUILD') }, + _react2.default.createElement( + 'p', + null, + _i18n2.default.trans('REFRESH_BUILD_NOTE') + ), + progress, + _react2.default.createElement( + 'div', + { className: 'actions' }, + _react2.default.createElement( + 'button', + { type: 'submit', className: 'btn btn-primary', + disabled: !this.isSafeToNavigate(), + onClick: this.onRefresh.bind(this) }, + _i18n2.default.trans('REFRESH_BUILD') + ), + _react2.default.createElement( + 'button', + { type: 'submit', className: 'btn btn-default', + disabled: !this.isSafeToNavigate(), + onClick: this.onCancel.bind(this) }, + _i18n2.default.trans(this.state.currentState === 'DONE' ? 'CLOSE' : 'CANCEL') + ) + ) + ); + } + }]); + + return Refresh; +}(_Component3.default); + +exports.default = Refresh; + +/***/ }), +/* 329 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* eslint-env browser */ + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +var _utils = __webpack_require__(12); + +var _utils2 = _interopRequireDefault(_utils); + +var _i18n = __webpack_require__(7); + +var _i18n2 = _interopRequireDefault(_i18n); + +var _hub = __webpack_require__(45); + +var _hub2 = _interopRequireDefault(_hub); + +var _events = __webpack_require__(46); + +var _RecordComponent2 = __webpack_require__(26); + +var _RecordComponent3 = _interopRequireDefault(_RecordComponent2); + +var _Link = __webpack_require__(149); + +var _Link2 = _interopRequireDefault(_Link); + +var _richPromise = __webpack_require__(17); + +var _richPromise2 = _interopRequireDefault(_richPromise); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var getBrowseButtonTitle = function getBrowseButtonTitle() { + var platform = _utils2.default.getPlatform(); + if (platform === 'mac') { + return _i18n2.default.trans('BROWSE_FS_MAC'); + } else if (platform === 'windows') { + return _i18n2.default.trans('BROWSE_FS_WINDOWS'); + } else { + return _i18n2.default.trans('BROWSE_FS'); + } +}; + +var CHILDREN_PER_PAGE = 15; + +var ChildPosCache = function () { + function ChildPosCache() { + _classCallCheck(this, ChildPosCache); + + this.memo = []; + } + + _createClass(ChildPosCache, [{ + key: 'rememberPosition', + value: function rememberPosition(record, page) { + for (var i = 0; i < this.memo.length; i++) { + if (this.memo[i][0] === record) { + this.memo[i][1] = page; + return; + } + } + this.memo.unshift([record, page]); + if (this.memo.length > 5) { + this.memo.length = 5; + } + } + }, { + key: 'getPosition', + value: function getPosition(record, childCount) { + for (var i = 0; i < this.memo.length; i++) { + if (this.memo[i][0] === record) { + var rv = this.memo[i][1]; + if (childCount !== undefined) { + rv = Math.min(rv, Math.ceil(childCount / CHILDREN_PER_PAGE)); + } + return rv; + } + } + return 1; + } + }]); + + return ChildPosCache; +}(); + +var Sidebar = function (_RecordComponent) { + _inherits(Sidebar, _RecordComponent); + + function Sidebar(props) { + _classCallCheck(this, Sidebar); + + var _this = _possibleConstructorReturn(this, (Sidebar.__proto__ || Object.getPrototypeOf(Sidebar)).call(this, props)); + + _this.state = _this._getInitialState(); + _this.childPosCache = new ChildPosCache(); + _this.onAttachmentsChanged = _this.onAttachmentsChanged.bind(_this); + return _this; + } + + _createClass(Sidebar, [{ + key: '_getInitialState', + value: function _getInitialState() { + return { + recordAttachments: [], + recordChildren: [], + recordAlts: [], + canHaveAttachments: false, + canHaveChildren: false, + isAttachment: false, + canBeDeleted: false, + recordExists: false, + lastRecordRequest: null, + childrenPage: 1 + }; + } + }, { + key: 'componentDidMount', + value: function componentDidMount() { + _get(Sidebar.prototype.__proto__ || Object.getPrototypeOf(Sidebar.prototype), 'componentDidMount', this).call(this); + this._updateRecordInfo(); + + _hub2.default.subscribe(_events.AttachmentsChangedEvent, this.onAttachmentsChanged); + } + }, { + key: 'componentDidUpdate', + value: function componentDidUpdate(prevProps, prevState) { + _get(Sidebar.prototype.__proto__ || Object.getPrototypeOf(Sidebar.prototype), 'componentDidUpdate', this).call(this, prevProps, prevState); + if (prevProps.params.path !== this.props.params.path) { + this._updateRecordInfo(); + } + } + }, { + key: 'componentWillUnmount', + value: function componentWillUnmount() { + _get(Sidebar.prototype.__proto__ || Object.getPrototypeOf(Sidebar.prototype), 'componentWillUnmount', this).call(this); + _hub2.default.unsubscribe(_events.AttachmentsChangedEvent, this.onAttachmentsChanged); + } + }, { + key: 'onAttachmentsChanged', + value: function onAttachmentsChanged(event) { + if (event.recordPath === this.getRecordPath()) { + this._updateRecordInfo(); + } + } + }, { + key: '_updateRecordInfo', + value: function _updateRecordInfo() { + var _this2 = this; + + var path = this.getRecordPath(); + if (path === null) { + this.setState(this._getInitialState()); + return; + } + + this.setState({ + lastRecordRequest: path + }, function () { + _utils2.default.loadData('/recordinfo', { path: path }, null, _richPromise2.default).then(function (resp) { + // we're already fetching something else. + if (path !== _this2.state.lastRecordRequest) { + return; + } + var alts = resp.alts; + alts.sort(function (a, b) { + var nameA = (a.is_primary ? 'A' : 'B') + _i18n2.default.trans(a.name_i18n); + var nameB = (b.is_primary ? 'A' : 'B') + _i18n2.default.trans(b.name_i18n); + return nameA === nameB ? 0 : nameA < nameB ? -1 : 1; + }); + _this2.setState({ + recordAttachments: resp.attachments, + recordChildren: resp.children, + recordAlts: alts, + canHaveAttachments: resp.can_have_attachments, + canHaveChildren: resp.can_have_children, + isAttachment: resp.is_attachment, + canBeDeleted: resp.can_be_deleted, + recordExists: resp.exists, + childrenPage: _this2.childPosCache.getPosition(path, resp.children.length) + }); + }); + }); + } + }, { + key: 'fsOpen', + value: function fsOpen(event) { + event.preventDefault(); + _utils2.default.apiRequest('/browsefs', { data: { + path: this.getRecordPath(), + alt: this.getRecordAlt() + }, + // eslint-disable-next-line indent + method: 'POST' }, _richPromise2.default).then(function (resp) { + if (!resp.okay) { + alert(_i18n2.default.trans('ERROR_CANNOT_BROWSE_FS')); + } + }); + } + }, { + key: 'renderPageActions', + value: function renderPageActions() { + var urlPath = this.getUrlRecordPathWithAlt(); + var links = []; + var deleteLink = null; + + links.push(_react2.default.createElement( + 'li', + { key: 'edit' }, + _react2.default.createElement( + _Link2.default, + { to: urlPath + '/edit' }, + this.state.isAttachment ? _i18n2.default.trans('EDIT_METADATA') : _i18n2.default.trans('EDIT') + ) + )); + + if (this.state.canBeDeleted) { + links.push(_react2.default.createElement( + 'li', + { key: 'delete' }, + _react2.default.createElement( + _Link2.default, + { to: urlPath + '/delete' }, + _i18n2.default.trans('DELETE') + ) + )); + } + + links.push(_react2.default.createElement( + 'li', + { key: 'preview' }, + _react2.default.createElement( + _Link2.default, + { to: urlPath + '/preview' }, + _i18n2.default.trans('PREVIEW') + ) + )); + + if (this.state.recordExists) { + links.push(_react2.default.createElement( + 'li', + { key: 'fs-open' }, + _react2.default.createElement( + 'a', + { href: '#', onClick: this.fsOpen.bind(this) }, + getBrowseButtonTitle() + ) + )); + } + + if (this.state.canHaveChildren) { + links.push(_react2.default.createElement( + 'li', + { key: 'add-child' }, + _react2.default.createElement( + _Link2.default, + { to: urlPath + '/add-child' }, + _i18n2.default.trans('ADD_CHILD_PAGE') + ) + )); + } + + if (this.state.canHaveAttachments) { + links.push(_react2.default.createElement( + 'li', + { key: 'add-attachment' }, + _react2.default.createElement( + _Link2.default, + { to: urlPath + '/upload' }, + _i18n2.default.trans('ADD_ATTACHMENT') + ) + )); + } + + var title = this.state.isAttachment ? _i18n2.default.trans('ATTACHMENT_ACTIONS') : _i18n2.default.trans('PAGE_ACTIONS'); + + return _react2.default.createElement( + 'div', + { key: 'actions', className: 'section' }, + _react2.default.createElement( + 'h3', + null, + title + ), + _react2.default.createElement( + 'ul', + { className: 'nav' }, + links, + deleteLink + ) + ); + } + }, { + key: 'renderAlts', + value: function renderAlts() { + var _this3 = this; + + if (this.state.recordAlts.length < 2) { + return null; + } + + var items = this.state.recordAlts.map(function (item) { + var title = _i18n2.default.trans(item.name_i18n); + var className = 'alt'; + if (item.is_primary) { + title += ' (' + _i18n2.default.trans('PRIMARY_ALT') + ')'; + } else if (item.primary_overlay) { + title += ' (' + _i18n2.default.trans('PRIMARY_OVERLAY') + ')'; + } + if (!item.exists) { + className += ' alt-missing'; + } + + var path = _this3.getPathToAdminPage(null, { + path: _this3.getUrlRecordPathWithAlt(null, item.alt) + }); + return _react2.default.createElement( + 'li', + { key: item.alt, className: className }, + _react2.default.createElement( + _Link2.default, + { to: path }, + title + ) + ); + }); + + return _react2.default.createElement( + 'div', + { key: 'alts', className: 'section' }, + _react2.default.createElement( + 'h3', + null, + _i18n2.default.trans('ALTS') + ), + _react2.default.createElement( + 'ul', + { className: 'nav' }, + items + ) + ); + } + }, { + key: 'renderChildPagination', + value: function renderChildPagination() { + var _this4 = this; + + var pages = Math.ceil(this.state.recordChildren.length / CHILDREN_PER_PAGE); + if (pages <= 1) { + return null; + } + var page = this.state.childrenPage; + var goToPage = function goToPage(diff, event) { + event.preventDefault(); + var newPage = page + diff; + _this4.childPosCache.rememberPosition(_this4.getRecordPath(), newPage); + _this4.setState({ + childrenPage: newPage + }); + }; + + return _react2.default.createElement( + 'li', + { className: 'pagination' }, + page > 1 ? _react2.default.createElement( + 'a', + { href: '#', onClick: goToPage.bind(this, -1) }, + '\xAB' + ) : _react2.default.createElement( + 'em', + null, + '\xAB' + ), + _react2.default.createElement( + 'span', + { className: 'page' }, + page + ' / ' + pages + ), + page < pages ? _react2.default.createElement( + 'a', + { href: '#', onClick: goToPage.bind(this, +1) }, + '\xBB' + ) : _react2.default.createElement( + 'em', + null, + '\xBB' + ) + ); + } + }, { + key: 'renderChildActions', + value: function renderChildActions() { + var _this5 = this; + + var target = this.isRecordPreviewActive() ? 'preview' : 'edit'; + + var children = this.state.recordChildren.slice((this.state.childrenPage - 1) * CHILDREN_PER_PAGE, this.state.childrenPage * CHILDREN_PER_PAGE); + + var items = children.map(function (child) { + var urlPath = _this5.getUrlRecordPathWithAlt(child.path); + return _react2.default.createElement( + 'li', + { key: child.id }, + _react2.default.createElement( + _Link2.default, + { to: urlPath + '/' + target }, + _i18n2.default.trans(child.label_i18n) + ) + ); + }); + + if (items.length === 0) { + items.push(_react2.default.createElement( + 'li', + { key: '_missing' }, + _react2.default.createElement( + 'em', + null, + _i18n2.default.trans('NO_CHILD_PAGES') + ) + )); + } + + return _react2.default.createElement( + 'div', + { key: 'children', className: 'section' }, + _react2.default.createElement( + 'h3', + null, + _i18n2.default.trans('CHILD_PAGES') + ), + _react2.default.createElement( + 'ul', + { className: 'nav record-children' }, + this.renderChildPagination(), + items + ) + ); + } + }, { + key: 'renderAttachmentActions', + value: function renderAttachmentActions() { + var _this6 = this; + + var items = this.state.recordAttachments.map(function (atch) { + var urlPath = _this6.getUrlRecordPathWithAlt(atch.path); + return _react2.default.createElement( + 'li', + { key: atch.id }, + _react2.default.createElement( + _Link2.default, + { to: urlPath + '/edit' }, + atch.id, + ' (', + atch.type, + ')' + ) + ); + }); + + if (items.length === 0) { + items.push(_react2.default.createElement( + 'li', + { key: '_missing' }, + _react2.default.createElement( + 'em', + null, + _i18n2.default.trans('NO_ATTACHMENTS') + ) + )); + } + + return _react2.default.createElement( + 'div', + { key: 'attachments', className: 'section' }, + _react2.default.createElement( + 'h3', + null, + _i18n2.default.trans('ATTACHMENTS') + ), + _react2.default.createElement( + 'ul', + { className: 'nav record-attachments' }, + items + ) + ); + } + }, { + key: 'render', + value: function render() { + var sections = []; + + if (this.getRecordPath() !== null) { + sections.push(this.renderPageActions()); + } + + sections.push(this.renderAlts()); + + if (this.state.canHaveChildren) { + sections.push(this.renderChildActions()); + } + + if (this.state.canHaveAttachments) { + sections.push(this.renderAttachmentActions()); + } + + return _react2.default.createElement( + 'div', + { className: 'sidebar-wrapper' }, + sections + ); + } + }]); + + return Sidebar; +}(_RecordComponent3.default); + +exports.default = Sidebar; + +/***/ }), +/* 330 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +var _Component2 = __webpack_require__(16); + +var _Component3 = _interopRequireDefault(_Component2); + +var _dialogSystem = __webpack_require__(22); + +var _dialogSystem2 = _interopRequireDefault(_dialogSystem); + +var _events = __webpack_require__(46); + +var _hub = __webpack_require__(45); + +var _hub2 = _interopRequireDefault(_hub); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var DialogSlot = function (_Component) { + _inherits(DialogSlot, _Component); + + function DialogSlot(props) { + _classCallCheck(this, DialogSlot); + + var _this = _possibleConstructorReturn(this, (DialogSlot.__proto__ || Object.getPrototypeOf(DialogSlot)).call(this, props)); + + _this.state = { + currentDialog: null, + currentDialogOptions: null + }; + _this.onDialogChanged = _this.onDialogChanged.bind(_this); + return _this; + } + + _createClass(DialogSlot, [{ + key: 'componentDidMount', + value: function componentDidMount() { + _get(DialogSlot.prototype.__proto__ || Object.getPrototypeOf(DialogSlot.prototype), 'componentDidMount', this).call(this); + _hub2.default.subscribe(_events.DialogChangedEvent, this.onDialogChanged); + } + }, { + key: 'componentWillUnmount', + value: function componentWillUnmount() { + _get(DialogSlot.prototype.__proto__ || Object.getPrototypeOf(DialogSlot.prototype), 'componentWillUnmount', this).call(this); + _hub2.default.unsubscribe(_events.DialogChangedEvent, this.onDialogChanged); + } + }, { + key: 'onDialogChanged', + value: function onDialogChanged(event) { + this.setState({ + currentDialog: event.dialog, + currentDialogOptions: event.dialogOptions || {} + }); + } + }, { + key: 'initDialogInstance', + value: function initDialogInstance(dialog) { + _dialogSystem2.default.notifyDialogInstance(dialog); + window.scrollTo(0, 0); + } + }, { + key: 'render', + value: function render() { + var _this2 = this; + + var dialog = null; + if (this.state.currentDialog) { + dialog = _react2.default.createElement(this.state.currentDialog, _extends({ + ref: function ref(_ref) { + return _this2.initDialogInstance(_ref); + } + }, this.getRoutingProps(), this.state.currentDialogOptions)); + } else { + _dialogSystem2.default.notifyDialogInstance(null); + } + + if (!dialog) { + return null; + } + + return _react2.default.createElement( + 'div', + { className: 'dialog-slot' }, + dialog, + _react2.default.createElement('div', { className: 'interface-protector' }) + ); + } + }]); + + return DialogSlot; +}(_Component3.default); + +exports.default = DialogSlot; + +/***/ }), +/* 331 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +var _Component2 = __webpack_require__(16); + +var _Component3 = _interopRequireDefault(_Component2); + +var _utils = __webpack_require__(12); + +var _utils2 = _interopRequireDefault(_utils); + +var _i18n = __webpack_require__(7); + +var _i18n2 = _interopRequireDefault(_i18n); + +var _richPromise = __webpack_require__(17); + +var _richPromise2 = _interopRequireDefault(_richPromise); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var ServerStatus = function (_Component) { + _inherits(ServerStatus, _Component); + + function ServerStatus(props) { + _classCallCheck(this, ServerStatus); + + var _this = _possibleConstructorReturn(this, (ServerStatus.__proto__ || Object.getPrototypeOf(ServerStatus)).call(this, props)); + + _this.state = { + serverIsUp: true, + projectId: null + }; + + _this.intervalId = null; + _this.onInterval = _this.onInterval.bind(_this); + return _this; + } + + _createClass(ServerStatus, [{ + key: 'componentDidMount', + value: function componentDidMount() { + _get(ServerStatus.prototype.__proto__ || Object.getPrototypeOf(ServerStatus.prototype), 'componentDidMount', this).call(this); + this.intervalId = window.setInterval(this.onInterval, 2000); + } + }, { + key: 'componentWillUnmount', + value: function componentWillUnmount() { + if (this.intervalId !== null) { + window.clearInterval(this.intervalId); + this.intervalId = null; + } + _get(ServerStatus.prototype.__proto__ || Object.getPrototypeOf(ServerStatus.prototype), 'componentWillUnmount', this).call(this); + } + }, { + key: 'onInterval', + value: function onInterval() { + var _this2 = this; + + _utils2.default.loadData('/ping', {}, null, _richPromise2.default).then(function (resp) { + if (_this2.state.projectId === null) { + _this2.setState({ + projectId: resp.project_id + }); + } + _this2.setState({ + serverIsUp: _this2.state.projectId === resp.project_id + }); + }, function () { + _this2.setState({ + serverIsUp: false + }); + }); + } + }, { + key: 'render', + value: function render() { + if (this.state.serverIsUp) { + return null; + } + return _react2.default.createElement( + 'div', + { className: 'server-down-panel' }, + _react2.default.createElement( + 'div', + { className: 'server-down-dialog' }, + _react2.default.createElement( + 'h3', + null, + _i18n2.default.trans('ERROR_SERVER_UNAVAILABLE') + ), + _react2.default.createElement( + 'p', + null, + _i18n2.default.trans('ERROR_SERVER_UNAVAILABLE_MESSAGE') + ) + ) + ); + } + }]); + + return ServerStatus; +}(_Component3.default); + +exports.default = ServerStatus; + +/***/ }), +/* 332 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + +var _Component2 = __webpack_require__(16); + +var _Component3 = _interopRequireDefault(_Component2); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var Dash = function (_Component) { + _inherits(Dash, _Component); + + function Dash() { + _classCallCheck(this, Dash); + + return _possibleConstructorReturn(this, (Dash.__proto__ || Object.getPrototypeOf(Dash)).apply(this, arguments)); + } + + _createClass(Dash, [{ + key: 'componentDidMount', + value: function componentDidMount() { + _get(Dash.prototype.__proto__ || Object.getPrototypeOf(Dash.prototype), 'componentDidMount', this).call(this); + var rootPreview = $LEKTOR_CONFIG.admin_root + '/root/preview'; + this.props.history.pushState(null, rootPreview); + } + }, { + key: 'render', + value: function render() { + return null; + } + }]); + + return Dash; +}(_Component3.default); + +exports.default = Dash; + +/***/ }), +/* 333 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +var _reactAddonsUpdate = __webpack_require__(150); + +var _reactAddonsUpdate2 = _interopRequireDefault(_reactAddonsUpdate); + +var _RecordEditComponent2 = __webpack_require__(151); + +var _RecordEditComponent3 = _interopRequireDefault(_RecordEditComponent2); + +var _utils = __webpack_require__(12); + +var _utils2 = _interopRequireDefault(_utils); + +var _i18n = __webpack_require__(7); + +var _i18n2 = _interopRequireDefault(_i18n); + +var _widgets = __webpack_require__(89); + +var _widgets2 = _interopRequireDefault(_widgets); + +var _richPromise = __webpack_require__(17); + +var _richPromise2 = _interopRequireDefault(_richPromise); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var EditPage = function (_RecordEditComponent) { + _inherits(EditPage, _RecordEditComponent); + + function EditPage(props) { + _classCallCheck(this, EditPage); + + var _this = _possibleConstructorReturn(this, (EditPage.__proto__ || Object.getPrototypeOf(EditPage)).call(this, props)); + + _this.state = { + recordInitialData: null, + recordData: null, + recordDataModel: null, + recordInfo: null, + hasPendingChanges: false + }; + _this._onKeyPress = _this._onKeyPress.bind(_this); + return _this; + } + + _createClass(EditPage, [{ + key: 'componentDidMount', + value: function componentDidMount() { + _get(EditPage.prototype.__proto__ || Object.getPrototypeOf(EditPage.prototype), 'componentDidMount', this).call(this); + this.syncEditor(); + window.addEventListener('keydown', this._onKeyPress); + } + }, { + key: 'componentWillReceiveProps', + value: function componentWillReceiveProps(nextProps) { + /* + if (nextProps.params.path !== this.props.params.path) { + this.syncEditor(); + } + */ + } + }, { + key: 'componentDidUpdate', + value: function componentDidUpdate(prevProps, prevState) { + if (prevProps.params.path !== this.props.params.path) { + this.syncEditor(); + } + } + }, { + key: 'componentWillUnmount', + value: function componentWillUnmount() { + window.removeEventListener('keydown', this._onKeyPress); + } + }, { + key: 'hasPendingChanges', + value: function hasPendingChanges() { + return this.state.hasPendingChanges; + } + }, { + key: '_onKeyPress', + value: function _onKeyPress(event) { + // meta+s is open find files + if (event.which === 83 && _utils2.default.isMetaKey(event)) { + event.preventDefault(); + this.saveChanges(); + } + } + }, { + key: 'isIllegalField', + value: function isIllegalField(field) { + switch (field.name) { + case '_id': + case '_path': + case '_gid': + case '_alt': + case '_source_alt': + case '_model': + case '_attachment_for': + return true; + case '_attachment_type': + return !this.state.recordInfo.is_attachment; + } + return false; + } + }, { + key: 'syncEditor', + value: function syncEditor() { + var _this2 = this; + + _utils2.default.loadData('/rawrecord', { + path: this.getRecordPath(), + alt: this.getRecordAlt() + }, null, _richPromise2.default).then(function (resp) { + _this2.setState({ + recordInitialData: resp.data, + recordData: {}, + recordDataModel: resp.datamodel, + recordInfo: resp.record_info, + hasPendingChanges: false + }); + }); + } + }, { + key: 'onValueChange', + value: function onValueChange(field, value) { + var updates = {}; + updates[field.name] = { $set: value || '' }; + var rd = (0, _reactAddonsUpdate2.default)(this.state.recordData, updates); + this.setState({ + recordData: rd, + hasPendingChanges: true + }); + } + }, { + key: 'getValues', + value: function getValues() { + var _this3 = this; + + var rv = {}; + this.state.recordDataModel.fields.forEach(function (field) { + if (_this3.isIllegalField(field)) { + return; + } + + var value = _this3.state.recordData[field.name]; + + if (value !== undefined) { + var Widget = _widgets2.default.getWidgetComponentWithFallback(field.type); + if (Widget.serializeValue) { + value = Widget.serializeValue(value, field.type); + } + } else { + value = _this3.state.recordInitialData[field.name]; + if (value === undefined) { + value = null; + } + } + + rv[field.name] = value; + }); + + return rv; + } + }, { + key: 'saveChanges', + value: function saveChanges() { + var _this4 = this; + + var path = this.getRecordPath(); + var alt = this.getRecordAlt(); + var newData = this.getValues(); + _utils2.default.apiRequest('/rawrecord', { json: { + data: newData, path: path, alt: alt }, + // eslint-disable-next-line indent + method: 'PUT' }, _richPromise2.default).then(function (resp) { + _this4.setState({ + hasPendingChanges: false + }, function () { + _this4.transitionToAdminPage('.preview', { + path: _this4.getUrlRecordPathWithAlt(path) + }); + }); + }); + } + }, { + key: 'deleteRecord', + value: function deleteRecord(event) { + this.transitionToAdminPage('.delete', { + path: this.getUrlRecordPathWithAlt() + }); + } + }, { + key: 'getValueForField', + value: function getValueForField(widget, field) { + var value = this.state.recordData[field.name]; + if (value === undefined) { + value = this.state.recordInitialData[field.name] || ''; + if (widget.deserializeValue) { + value = widget.deserializeValue(value, field.type); + } + } + return value; + } + }, { + key: 'getPlaceholderForField', + value: function getPlaceholderForField(widget, field) { + if (field['default'] !== null) { + if (widget.deserializeValue) { + return widget.deserializeValue(field['default'], field.type); + } + return field['default']; + } else if (field.name === '_slug') { + return this.state.recordInfo.slug_format; + } else if (field.name === '_template') { + return this.state.recordInfo.default_template; + } else if (field.name === '_attachment_type') { + return this.state.recordInfo.implied_attachment_type; + } + return null; + } + }, { + key: 'renderFormField', + value: function renderFormField(field, idx) { + var widget = _widgets2.default.getWidgetComponentWithFallback(field.type); + return _react2.default.createElement(_widgets2.default.FieldBox, { + key: idx, + value: this.getValueForField(widget, field), + placeholder: this.getPlaceholderForField(widget, field), + field: field, + onChange: this.onValueChange.bind(this, field), + disabled: !(field.alts_enabled == null || field.alts_enabled ^ this.state.recordInfo.alt === '_primary') + }); + } + }, { + key: 'renderFormFields', + value: function renderFormFields() { + return _widgets2.default.renderFieldRows(this.state.recordDataModel.fields, this.isIllegalField.bind(this), this.renderFormField.bind(this)); + } + }, { + key: 'render', + value: function render() { + // we have not loaded anything yet. + if (this.state.recordInfo === null) { + return null; + } + + var deleteButton = null; + if (this.state.recordInfo.can_be_deleted) { + deleteButton = _react2.default.createElement( + 'button', + { type: 'submit', className: 'btn btn-default', + onClick: this.deleteRecord.bind(this) }, + _i18n2.default.trans('DELETE') + ); + } + + var title = this.state.recordInfo.is_attachment ? _i18n2.default.trans('EDIT_ATTACHMENT_METADATA_OF') : _i18n2.default.trans('EDIT_PAGE_NAME'); + + var label = this.state.recordInfo.label_i18n ? _i18n2.default.trans(this.state.recordInfo.label_i18n) : this.state.recordInfo.label; + + return _react2.default.createElement( + 'div', + { className: 'edit-area' }, + _react2.default.createElement( + 'h2', + null, + title.replace('%s', label) + ), + this.renderFormFields(), + _react2.default.createElement( + 'div', + { className: 'actions' }, + _react2.default.createElement( + 'button', + { type: 'submit', className: 'btn btn-primary', + onClick: this.saveChanges.bind(this) }, + _i18n2.default.trans('SAVE_CHANGES') + ), + deleteButton + ) + ); + } + }]); + + return EditPage; +}(_RecordEditComponent3.default); + +exports.default = EditPage; + +/***/ }), +/* 334 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +var _jquery = __webpack_require__(11); + +var _jquery2 = _interopRequireDefault(_jquery); + +var _mixins = __webpack_require__(48); + +var _utils = __webpack_require__(12); + +var _utils2 = _interopRequireDefault(_utils); + +var _userLabel = __webpack_require__(90); + +var _userLabel2 = _interopRequireDefault(_userLabel); + +var _i18n = __webpack_require__(7); + +var _i18n2 = _interopRequireDefault(_i18n); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } + +var isTrue = function isTrue(value) { + return value === 'true' || value === 'yes' || value === '1'; +}; + +var isValidDate = function isValidDate(year, month, day) { + year = parseInt(year, 10); + month = parseInt(month, 10); + day = parseInt(day, 10); + var date = new Date(year, month - 1, day); + if (date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day) { + return true; + } + return false; +}; + +var InputWidgetMixin = { + mixins: [_mixins.BasicWidgetMixin], + + onChange: function onChange(event) { + var value = event.target.value; + if (this.postprocessValue) { + value = this.postprocessValue(value); + } + this.props.onChange(value); + }, + render: function render() { + var _props = this.props, + type = _props.type, + onChange = _props.onChange, + className = _props.className, + otherProps = _objectWithoutProperties(_props, ['type', 'onChange', 'className']); + + var help = null; + var failure = this.getValidationFailure(); + className = className || ''; + className += ' input-group'; + + if (failure !== null) { + className += ' has-feedback has-' + failure.type; + var valClassName = 'validation-block validation-block-' + failure.type; + help = _react2.default.createElement( + 'div', + { className: valClassName }, + failure.message + ); + } + + var addon = null; + var configuredAddon = type.addon_label_i18n; + if (configuredAddon) { + addon = _userLabel2.default.format(configuredAddon); + } else if (this.getInputAddon) { + addon = this.getInputAddon(); + } + + return _react2.default.createElement( + 'div', + { className: 'form-group' }, + _react2.default.createElement( + 'div', + { className: className }, + _react2.default.createElement('input', _extends({ + type: this.getInputType(), + className: this.getInputClass(), + onChange: onChange ? this.onChange : undefined + }, otherProps)), + addon ? _react2.default.createElement( + 'span', + { className: 'input-group-addon' }, + addon + ) : null + ), + help + ); + } +}; + +var SingleLineTextInputWidget = _react2.default.createClass({ + displayName: 'SingleLineTextInputWidget', + + mixins: [InputWidgetMixin], + + getInputType: function getInputType() { + return 'text'; + }, + getInputAddon: function getInputAddon() { + return _react2.default.createElement('i', { className: 'fa fa-paragraph' }); + } +}); + +var SlugInputWidget = _react2.default.createClass({ + displayName: 'SlugInputWidget', + + mixins: [InputWidgetMixin], + + postprocessValue: function postprocessValue(value) { + return value.replace(/\s+/g, '-'); + }, + getInputType: function getInputType() { + return 'text'; + }, + getInputAddon: function getInputAddon() { + return _react2.default.createElement('i', { className: 'fa fa-link' }); + } +}); + +var IntegerInputWidget = _react2.default.createClass({ + displayName: 'IntegerInputWidget', + + mixins: [InputWidgetMixin], + + postprocessValue: function postprocessValue(value) { + return value.match(/^\s*(.*?)\s*$/)[1]; + }, + getValidationFailureImpl: function getValidationFailureImpl() { + if (this.props.value && !this.props.value.match(/^\d+$/)) { + return new _mixins.ValidationFailure({ + message: _i18n2.default.trans('ERROR_INVALID_NUMBER') + }); + } + return null; + }, + getInputType: function getInputType() { + return 'text'; + }, + getInputAddon: function getInputAddon() { + return '0'; + } +}); + +var FloatInputWidget = _react2.default.createClass({ + displayName: 'FloatInputWidget', + + mixins: [InputWidgetMixin], + + postprocessValue: function postprocessValue(value) { + return value.match(/^\s*(.*?)\s*$/)[1]; + }, + getValidationFailureImpl: function getValidationFailureImpl() { + if (this.props.value && isNaN(parseFloat(this.props.value))) { + return new _mixins.ValidationFailure({ + message: _i18n2.default.trans('ERROR_INVALID_NUMBER') + }); + } + return null; + }, + getInputType: function getInputType() { + return 'text'; + }, + getInputAddon: function getInputAddon() { + return '0.0'; + } +}); + +var DateInputWidget = _react2.default.createClass({ + displayName: 'DateInputWidget', + + mixins: [InputWidgetMixin], + + postprocessValue: function postprocessValue(value) { + value = value.match(/^\s*(.*?)\s*$/)[1]; + var match = value.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})\s*$/); + var day = void 0, + month = void 0, + year = void 0; + if (match) { + day = parseInt(match[1], 10); + month = parseInt(match[2], 10); + year = parseInt(match[3], 10); + return year + '-' + (month < 10 ? '0' : '') + month + '-' + (day < 10 ? '0' : '') + day; + } + return value; + }, + getValidationFailureImpl: function getValidationFailureImpl() { + if (!this.props.value) { + return null; + } + + var match = this.props.value.match(/^\s*(\d{4})-(\d{1,2})-(\d{1,2})\s*$/); + if (match && isValidDate(match[1], match[2], match[3])) { + return null; + } + + return new _mixins.ValidationFailure({ + message: _i18n2.default.trans('ERROR_INVALID_DATE') + }); + }, + getInputType: function getInputType() { + return 'date'; + }, + getInputAddon: function getInputAddon() { + return _react2.default.createElement('i', { className: 'fa fa-calendar' }); + } +}); + +var UrlInputWidget = _react2.default.createClass({ + displayName: 'UrlInputWidget', + + mixins: [InputWidgetMixin], + + getValidationFailureImpl: function getValidationFailureImpl() { + if (this.props.value && !_utils2.default.isValidUrl(this.props.value)) { + return new _mixins.ValidationFailure({ + message: _i18n2.default.trans('ERROR_INVALID_URL') + }); + } + return null; + }, + getInputType: function getInputType() { + return 'text'; + }, + getInputAddon: function getInputAddon() { + return _react2.default.createElement('i', { className: 'fa fa-external-link' }); + } +}); + +var MultiLineTextInputWidget = _react2.default.createClass({ + displayName: 'MultiLineTextInputWidget', + + mixins: [_mixins.BasicWidgetMixin], + + onChange: function onChange(event) { + this.recalculateSize(); + if (this.props.onChange) { + this.props.onChange(event.target.value); + } + }, + componentDidMount: function componentDidMount() { + this.recalculateSize(); + window.addEventListener('resize', this.recalculateSize); + }, + componentWillUnmount: function componentWillUnmount() { + window.removeEventListener('resize', this.recalculateSize); + }, + componentDidUpdate: function componentDidUpdate(prevProps) { + this.recalculateSize(); + }, + isInAutoResizeMode: function isInAutoResizeMode() { + return this.props.rows === undefined; + }, + recalculateSize: function recalculateSize() { + if (!this.isInAutoResizeMode()) { + return; + } + var diff = void 0; + var node = this.refs.ta; + + if (window.getComputedStyle) { + var s = window.getComputedStyle(node); + if (s.getPropertyValue('box-sizing') === 'border-box' || s.getPropertyValue('-moz-box-sizing') === 'border-box' || s.getPropertyValue('-webkit-box-sizing') === 'border-box') { + diff = 0; + } else { + diff = parseInt(s.getPropertyValue('padding-bottom') || 0, 10) + parseInt(s.getPropertyValue('padding-top') || 0, 10); + } + } else { + diff = 0; + } + + var updateScrollPosition = (0, _jquery2.default)(node).is(':focus'); + // Cross-browser compatibility for scroll position + var oldScrollTop = document.documentElement.scrollTop || document.body.scrollTop; + var oldHeight = (0, _jquery2.default)(node).outerHeight(); + + node.style.height = 'auto'; + var newHeight = node.scrollHeight - diff; + node.style.height = newHeight + 'px'; + + if (updateScrollPosition) { + window.scrollTo(document.body.scrollLeft, oldScrollTop + (newHeight - oldHeight)); + } + }, + render: function render() { + var _props2 = this.props, + className = _props2.className, + type = _props2.type, + onChange = _props2.onChange, + style = _props2.style, + otherProps = _objectWithoutProperties(_props2, ['className', 'type', 'onChange', 'style']); // eslint-disable-line no-unused-vars + + + className = className || ''; + + style = style || {}; + if (this.isInAutoResizeMode()) { + style.display = 'block'; + style.overflow = 'hidden'; + style.resize = 'none'; + } + + return _react2.default.createElement( + 'div', + { className: className }, + _react2.default.createElement('textarea', _extends({ + ref: 'ta', + className: this.getInputClass(), + onChange: onChange ? this.onChange : undefined, + style: style + }, otherProps)) + ); + } +}); + +var BooleanInputWidget = _react2.default.createClass({ + displayName: 'BooleanInputWidget', + + mixins: [_mixins.BasicWidgetMixin], + + onChange: function onChange(event) { + this.props.onChange(event.target.checked ? 'yes' : 'no'); + }, + componentDidMount: function componentDidMount() { + var checkbox = this.refs.checkbox; + if (!this.props.value && this.props.placeholder) { + checkbox.indeterminate = true; + checkbox.checked = isTrue(this.props.placeholder); + } else { + checkbox.indeterminate = false; + } + }, + render: function render() { + var _props3 = this.props, + className = _props3.className, + type = _props3.type, + placeholder = _props3.placeholder, + onChange = _props3.onChange, + value = _props3.value, + otherProps = _objectWithoutProperties(_props3, ['className', 'type', 'placeholder', 'onChange', 'value']); // eslint-disable-line no-unused-vars + + + className = (className || '') + ' checkbox'; + + return _react2.default.createElement( + 'div', + { className: className }, + _react2.default.createElement( + 'label', + null, + _react2.default.createElement('input', _extends({ type: 'checkbox' + }, otherProps, { + ref: 'checkbox', + checked: isTrue(value), + onChange: onChange ? this.onChange : undefined })), + type.checkbox_label_i18n ? _i18n2.default.trans(type.checkbox_label_i18n) : null + ) + ); + } +}); + +exports.default = { + SingleLineTextInputWidget: SingleLineTextInputWidget, + SlugInputWidget: SlugInputWidget, + IntegerInputWidget: IntegerInputWidget, + FloatInputWidget: FloatInputWidget, + DateInputWidget: DateInputWidget, + UrlInputWidget: UrlInputWidget, + MultiLineTextInputWidget: MultiLineTextInputWidget, + BooleanInputWidget: BooleanInputWidget +}; + +/***/ }), +/* 335 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +var _utils = __webpack_require__(12); + +var _utils2 = _interopRequireDefault(_utils); + +var _i18n = __webpack_require__(7); + +var _i18n2 = _interopRequireDefault(_i18n); + +var _mixins = __webpack_require__(48); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } + +var CheckboxesInputWidget = _react2.default.createClass({ + displayName: 'CheckboxesInputWidget', + + mixins: [_mixins.BasicWidgetMixin], + + statics: { + deserializeValue: function deserializeValue(value) { + if (value === '') { + return null; + } + var rv = value.split(',').map(function (x) { + return x.match(/^\s*(.*?)\s*$/)[1]; + }); + if (rv.length === 1 && rv[0] === '') { + rv = []; + } + return rv; + }, + + serializeValue: function serializeValue(value) { + return (value || '').join(', '); + } + }, + + onChange: function onChange(field, event) { + var newValue = _utils2.default.flipSetValue(this.props.value, field, event.target.checked); + if (this.props.onChange) { + this.props.onChange(newValue); + } + }, + + isActive: function isActive(field) { + var value = this.props.value; + if (value == null) { + value = this.props.placeholder; + if (value == null) { + return false; + } + } + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = value[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var item = _step.value; + + if (item === field) { + return true; + } + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + return false; + }, + + render: function render() { + var _this = this; + + var _props = this.props, + className = _props.className, + value = _props.value, + placeholder = _props.placeholder, + type = _props.type, + otherProps = _objectWithoutProperties(_props, ['className', 'value', 'placeholder', 'type']); // eslint-disable-line no-unused-vars + + + className = (className || '') + ' checkbox'; + + var choices = this.props.type.choices.map(function (item) { + return _react2.default.createElement( + 'div', + { className: className, key: item[0] }, + _react2.default.createElement( + 'label', + null, + _react2.default.createElement('input', _extends({ type: 'checkbox' + }, otherProps, { + checked: _this.isActive(item[0]), + onChange: _this.onChange.bind(_this, item[0]) })), + _i18n2.default.trans(item[1]) + ) + ); + }); + return _react2.default.createElement( + 'div', + { className: 'checkboxes' }, + choices + ); + } +}); + +var SelectInputWidget = _react2.default.createClass({ + displayName: 'SelectInputWidget', + + mixins: [_mixins.BasicWidgetMixin], + + onChange: function onChange(event) { + this.props.onChange(event.target.value); + }, + render: function render() { + var _props2 = this.props, + className = _props2.className, + type = _props2.type, + value = _props2.value, + placeholder = _props2.placeholder, + onChange = _props2.onChange, + otherProps = _objectWithoutProperties(_props2, ['className', 'type', 'value', 'placeholder', 'onChange']); // eslint-disable-line no-unused-vars + + + value = value || placeholder; + + var choices = this.props.type.choices.map(function (item) { + return _react2.default.createElement( + 'option', + { key: item[0], value: item[0] }, + _i18n2.default.trans(item[1]) + ); + }); + choices.unshift(_react2.default.createElement( + 'option', + { key: '', value: '' }, + '----' + )); + + return _react2.default.createElement( + 'div', + { className: 'form-group' }, + _react2.default.createElement( + 'div', + { className: className }, + _react2.default.createElement( + 'select', + _extends({ + className: this.getInputClass(), + onChange: onChange ? this.onChange : null, + value: value + }, otherProps), + choices + ) + ) + ); + } +}); + +exports.default = { + CheckboxesInputWidget: CheckboxesInputWidget, + SelectInputWidget: SelectInputWidget +}; + +/***/ }), +/* 336 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* eslint-env browser */ + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +var _i18n = __webpack_require__(7); + +var _i18n2 = _interopRequireDefault(_i18n); + +var _metaformat = __webpack_require__(337); + +var _metaformat2 = _interopRequireDefault(_metaformat); + +var _mixins = __webpack_require__(48); + +var _userLabel = __webpack_require__(90); + +var _userLabel2 = _interopRequireDefault(_userLabel); + +var _widgets = __webpack_require__(89); + +var _widgets2 = _interopRequireDefault(_widgets); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/* circular references require us to do this */ +var getWidgetComponent = function getWidgetComponent(type) { + return _widgets2.default.getWidgetComponent(type); +}; + +var getWidgets = function getWidgets() { + return _widgets2.default; +}; + +var parseFlowFormat = function parseFlowFormat(value) { + var blocks = []; + var buf = []; + var lines = value.split(/\r?\n/); + var block = null; + + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = lines[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var line = _step.value; + + // leading whitespace is ignored. + if (block === null && line.match(/^\s*$/)) { + continue; + } + + var blockStart = line.match(/^####\s*([^#]*?)\s*####\s*$/); + if (!blockStart) { + if (block === null) { + // bad format :( + return null; + } + } else { + if (block !== null) { + blocks.push([block, buf]); + buf = []; + } + block = blockStart[1]; + continue; + } + + buf.push(line.replace(/^#####(.*?)#####$/, '####$1####')); + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + if (block !== null) { + blocks.push([block, buf]); + } + + return blocks; +}; + +var serializeFlowFormat = function serializeFlowFormat(blocks) { + var rv = []; + blocks.forEach(function (block) { + var _block = _slicedToArray(block, 2), + blockName = _block[0], + lines = _block[1]; + + rv.push('#### ' + blockName + ' ####\n'); + lines.forEach(function (line) { + rv.push(line.replace(/^(####(.*)####)(\r?\n)?$/, '#$1#$3')); + }); + }); + + rv = rv.join(''); + + /* we need to chop of the last newline if it exists because this would + otherwise add a newline to the last block. This is just a side effect + of how we serialize the meta format internally */ + if (rv[rv.length - 1] === '\n') { + rv = rv.substr(0, rv.length - 1); + } + + return rv; +}; + +var deserializeFlowBlock = function deserializeFlowBlock(flowBlockModel, lines, localId) { + var data = {}; + var rawData = {}; + + _metaformat2.default.tokenize(lines).forEach(function (item) { + var _item = _slicedToArray(item, 2), + key = _item[0], + lines = _item[1]; + + var value = lines.join(''); + rawData[key] = value; + }); + + flowBlockModel.fields.forEach(function (field) { + var value = rawData[field.name] || ''; + var Widget = getWidgetComponent(field.type); + if (!value && field['default']) { + value = field['default']; + } + if (Widget && Widget.deserializeValue) { + value = Widget.deserializeValue(value, field.type); + } + data[field.name] = value; + }); + + return { + localId: localId || null, + flowBlockModel: flowBlockModel, + data: data + }; +}; + +var serializeFlowBlock = function serializeFlowBlock(flockBlockModel, data) { + var rv = []; + flockBlockModel.fields.forEach(function (field) { + var Widget = getWidgetComponent(field.type); + if (Widget === null) { + return; + } + + var value = data[field.name]; + if (value === undefined || value === null) { + return; + } + + if (Widget.serializeValue) { + value = Widget.serializeValue(value, field.type); + } + + rv.push([field.name, value]); + }); + return _metaformat2.default.serialize(rv); +}; + +// ever growing counter of block ids. Good enough for what we do I think. +var lastBlockId = 0; + +var FlowWidget = _react2.default.createClass({ + displayName: 'FlowWidget', + + mixins: [_mixins.BasicWidgetMixin], + + statics: { + deserializeValue: function deserializeValue(value, type) { + return parseFlowFormat(value).map(function (item) { + var _item2 = _slicedToArray(item, 2), + id = _item2[0], + lines = _item2[1]; + + var flowBlock = type.flowblocks[id]; + if (flowBlock !== undefined) { + return deserializeFlowBlock(flowBlock, lines, ++lastBlockId); + } + return null; + }); + }, + + serializeValue: function serializeValue(value) { + return serializeFlowFormat(value.map(function (item) { + return [item.flowBlockModel.id, serializeFlowBlock(item.flowBlockModel, item.data)]; + })); + } + }, + + // XXX: the modification of props is questionable + + moveBlock: function moveBlock(idx, offset, event) { + event.preventDefault(); + + var newIndex = idx + offset; + if (newIndex < 0 || newIndex >= this.props.value.length) { + return; + } + + var tmp = this.props.value[newIndex]; + this.props.value[newIndex] = this.props.value[idx]; + this.props.value[idx] = tmp; + + if (this.props.onChange) { + this.props.onChange(this.props.value); + } + }, + + removeBlock: function removeBlock(idx, event) { + event.preventDefault(); + + if (confirm(_i18n2.default.trans('REMOVE_FLOWBLOCK_PROMPT'))) { + this.props.value.splice(idx, 1); + if (this.props.onChange) { + this.props.onChange(this.props.value); + } + } + }, + + addNewBlock: function addNewBlock(key, event) { + event.preventDefault(); + + var flowBlockModel = this.props.type.flowblocks[key]; + + // this is a rather ugly way to do this, but hey, it works. + this.props.value.push(deserializeFlowBlock(flowBlockModel, [], ++lastBlockId)); + if (this.props.onChange) { + this.props.onChange(this.props.value); + } + }, + + renderFormField: function renderFormField(blockInfo, field, idx) { + var _this = this; + + var widgets = getWidgets(); + var value = blockInfo.data[field.name]; + var placeholder = field['default']; + var Widget = widgets.getWidgetComponentWithFallback(field.type); + if (Widget.deserializeValue && placeholder != null) { + placeholder = Widget.deserializeValue(placeholder, field.type); + } + + var onChange = !this.props.onChange ? null : function (value) { + blockInfo.data[field.name] = value; + _this.props.onChange(_this.props.value); + }; + + return _react2.default.createElement(widgets.FieldBox, { + key: idx, + value: value, + placeholder: placeholder, + field: field, + onChange: onChange + }); + }, + + renderBlocks: function renderBlocks() { + var _this2 = this; + + var widgets = getWidgets(); + + return this.props.value.map(function (blockInfo, idx) { + // bad block is no block + if (blockInfo === null) { + return null; + } + + var fields = widgets.renderFieldRows(blockInfo.flowBlockModel.fields, null, _this2.renderFormField.bind(_this2, blockInfo)); + + return _react2.default.createElement( + 'div', + { key: blockInfo.localId, className: 'flow-block' }, + _react2.default.createElement( + 'div', + { className: 'btn-group action-bar' }, + _react2.default.createElement( + 'button', + { + className: 'btn btn-default btn-xs', + title: _i18n2.default.trans('UP'), + disabled: idx === 0, + onClick: _this2.moveBlock.bind(_this2, idx, -1) }, + _react2.default.createElement('i', { className: 'fa fa-fw fa-chevron-up' }) + ), + _react2.default.createElement( + 'button', + { + className: 'btn btn-default btn-xs', + title: _i18n2.default.trans('DOWN'), + disabled: idx >= _this2.props.value.length - 1, + onClick: _this2.moveBlock.bind(_this2, idx, 1) }, + _react2.default.createElement('i', { className: 'fa fa-fw fa-chevron-down' }) + ), + _react2.default.createElement( + 'button', + { + className: 'btn btn-default btn-xs', + title: _i18n2.default.trans('REMOVE'), + onClick: _this2.removeBlock.bind(_this2, idx) }, + _react2.default.createElement('i', { className: 'fa fa-fw fa-times' }) + ) + ), + _react2.default.createElement( + 'h4', + { className: 'block-name' }, + _userLabel2.default.format(blockInfo.flowBlockModel.name_i18n) + ), + fields + ); + }); + }, + renderAddBlockSection: function renderAddBlockSection() { + var _this3 = this; + + var choices = []; + + this.props.type.flowblock_order.forEach(function (key) { + var flowBlockModel = _this3.props.type.flowblocks[key]; + var label = flowBlockModel.button_label ? _userLabel2.default.format(flowBlockModel.button_label) : _userLabel2.default.format(flowBlockModel.name_i18n); + choices.push([flowBlockModel.id, label, _i18n2.default.trans(flowBlockModel.name_i18n)]); + }); + + var buttons = choices.map(function (item) { + var _item3 = _slicedToArray(item, 3), + key = _item3[0], + label = _item3[1], + title = _item3[2]; + + return _react2.default.createElement( + 'button', + { + className: 'btn btn-default', + onClick: _this3.addNewBlock.bind(_this3, key), + title: title, + key: key }, + label + ); + }); + + return _react2.default.createElement( + 'div', + { className: 'add-block' }, + _react2.default.createElement( + 'label', + null, + _i18n2.default.trans('ADD_FLOWBLOCK') + ': ' + ), + _react2.default.createElement( + 'div', + { className: 'btn-group' }, + buttons + ) + ); + }, + render: function render() { + var className = this.props.className; + + className = (className || '') + ' flow'; + + return _react2.default.createElement( + 'div', + { className: className }, + this.renderBlocks(), + this.renderAddBlockSection() + ); + } +}); + +exports.default = { + FlowWidget: FlowWidget +}; + +/***/ }), +/* 337 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); + +var lineIsDashes = function lineIsDashes(line) { + line = line.match(/^\s*(.*?)\s*$/)[1]; + return line.length >= 3 && line === new Array(line.length + 1).join('-'); +}; + +var processBuf = function processBuf(buf) { + var lines = buf.map(function (line) { + if (lineIsDashes(line)) { + line = line.substr(1); + } + return line; + }); + + if (lines.length > 0) { + var lastLine = lines[lines.length - 1]; + if (lastLine.substr(lastLine.length - 1) === '\n') { + lines[lines.length - 1] = lastLine.substr(0, lastLine.length - 1); + } + } + + return lines; +}; + +var tokenize = function tokenize(lines) { + var key = null; + var buf = []; + var wantNewline = false; + var rv = []; + + var flushItem = function flushItem() { + rv.push([key, processBuf(buf)]); + key = null; + buf = []; + }; + + for (var i = 0; i < lines.length; i++) { + var line = lines[i].match(/^(.*?)(\r?\n)*$/m)[1] + '\n'; + + if (line.match(/^(.*?)\s*$/m)[1] === '---') { + wantNewline = false; + if (key !== null) { + flushItem(); + } + } else if (key !== null) { + if (wantNewline) { + wantNewline = false; + if (line.match(/^\s*$/)) { + continue; + } + } + buf.push(line); + } else { + var bits = line.split(':'); + if (bits.length >= 2) { + key = bits.shift().match(/^\s*(.*?)\s*$/m)[1]; + var firstBit = bits.join(':').match(/^[\t ]*(.*?)[\t ]*$/m)[1]; + if (!firstBit.match(/^\s*$/)) { + buf = [firstBit]; + } else { + buf = []; + wantNewline = true; + } + } + } + } + + if (key !== null) { + flushItem(); + } + + return rv; +}; + +var serialize = function serialize(blocks) { + var rv = []; + + blocks.forEach(function (item, idx) { + var _item = _slicedToArray(item, 2), + key = _item[0], + value = _item[1]; + + if (idx > 0) { + rv.push('---\n'); + } + if (value.match(/([\r\n]|(^[\t ])|([\t ]$))/m)) { + rv.push(key + ':\n'); + rv.push('\n'); + var lines = value.split(/\n/); + if (lines[lines.length - 1] === '') { + lines.pop(); + } + lines.forEach(function (line, idx, arr) { + if (lineIsDashes(line)) { + line = '-' + line; + } + rv.push(line + '\n'); + }); + } else { + rv.push(key + ': ' + value + '\n'); + } + }); + + return rv; +}; + +exports.default = { + tokenize: tokenize, + serialize: serialize +}; + +/***/ }), +/* 338 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _propTypes = __webpack_require__(23); + +var _propTypes2 = _interopRequireDefault(_propTypes); + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +var _mixins = __webpack_require__(48); + +var _i18n = __webpack_require__(7); + +var _i18n2 = _interopRequireDefault(_i18n); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var FakeWidgetMixin = { + mixins: [_mixins.BasicWidgetMixin], + propTypes: { + field: _propTypes2.default.any + }, + + statics: { + isFakeWidget: true + } +}; + +var LineWidget = _react2.default.createClass({ + displayName: 'LineWidget', + + mixins: [FakeWidgetMixin], + + render: function render() { + return _react2.default.createElement('hr', null); + } +}); + +var SpacingWidget = _react2.default.createClass({ + displayName: 'SpacingWidget', + + mixins: [FakeWidgetMixin], + + render: function render() { + return _react2.default.createElement('div', { className: 'spacing' }); + } +}); + +var InfoWidget = _react2.default.createClass({ + displayName: 'InfoWidget', + + mixins: [FakeWidgetMixin], + + render: function render() { + var label = _i18n2.default.trans(this.props.field.label_i18n); + return _react2.default.createElement( + 'div', + { className: 'info' }, + _react2.default.createElement( + 'p', + null, + label ? _react2.default.createElement( + 'strong', + null, + label + ': ' + ) : null, + _i18n2.default.trans(this.props.field.description_i18n) + ) + ); + } +}); + +var HeadingWidget = _react2.default.createClass({ + displayName: 'HeadingWidget', + + mixins: [FakeWidgetMixin], + + render: function render() { + return _react2.default.createElement( + 'h3', + null, + _i18n2.default.trans(this.props.type.heading_i18n) + ); + } +}); + +exports.default = { + LineWidget: LineWidget, + SpacingWidget: SpacingWidget, + InfoWidget: InfoWidget, + HeadingWidget: HeadingWidget +}; + +/***/ }), +/* 339 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _propTypes = __webpack_require__(23); + +var _propTypes2 = _interopRequireDefault(_propTypes); + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +var _Component2 = __webpack_require__(16); + +var _Component3 = _interopRequireDefault(_Component2); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var ToggleGroup = function (_Component) { + _inherits(ToggleGroup, _Component); + + function ToggleGroup(props) { + _classCallCheck(this, ToggleGroup); + + var _this = _possibleConstructorReturn(this, (ToggleGroup.__proto__ || Object.getPrototypeOf(ToggleGroup)).call(this, props)); + + _this.state = { + isVisible: props.defaultVisibility + }; + return _this; + } + + _createClass(ToggleGroup, [{ + key: 'toggle', + value: function toggle(event) { + event.preventDefault(); + this.setState({ + isVisible: !this.state.isVisible + }); + } + }, { + key: 'render', + value: function render() { + var _props = this.props, + className = _props.className, + groupTitle = _props.groupTitle, + children = _props.children, + defaultVisibility = _props.defaultVisibility, + otherProps = _objectWithoutProperties(_props, ['className', 'groupTitle', 'children', 'defaultVisibility']); + + className = (className || '') + ' toggle-group'; + if (this.state.isVisible) { + className += ' toggle-group-open'; + } else { + className += ' toggle-group-closed'; + } + + return _react2.default.createElement( + 'div', + _extends({ className: className }, otherProps), + _react2.default.createElement( + 'div', + { className: 'header' }, + _react2.default.createElement( + 'h4', + { className: 'toggle', onClick: this.toggle.bind(this) }, + groupTitle + ) + ), + _react2.default.createElement( + 'div', + { className: 'children' }, + children + ) + ); + } + }]); + + return ToggleGroup; +}(_Component3.default); + +ToggleGroup.propTypes = { + groupTitle: _propTypes2.default.string, + defaultVisibility: _propTypes2.default.bool +}; + +exports.default = ToggleGroup; + +/***/ }), +/* 340 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +var _RecordEditComponent = __webpack_require__(151); + +var _RecordEditComponent2 = _interopRequireDefault(_RecordEditComponent); + +var _utils = __webpack_require__(12); + +var _utils2 = _interopRequireDefault(_utils); + +var _i18n = __webpack_require__(7); + +var _i18n2 = _interopRequireDefault(_i18n); + +var _hub = __webpack_require__(45); + +var _hub2 = _interopRequireDefault(_hub); + +var _events = __webpack_require__(46); + +var _richPromise = __webpack_require__(17); + +var _richPromise2 = _interopRequireDefault(_richPromise); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var DeletePage = function (_RecordComponent) { + _inherits(DeletePage, _RecordComponent); + + function DeletePage(props) { + _classCallCheck(this, DeletePage); + + var _this = _possibleConstructorReturn(this, (DeletePage.__proto__ || Object.getPrototypeOf(DeletePage)).call(this, props)); + + _this.state = { + recordInfo: null, + deleteMasterRecord: true + }; + return _this; + } + + _createClass(DeletePage, [{ + key: 'componentDidMount', + value: function componentDidMount() { + _get(DeletePage.prototype.__proto__ || Object.getPrototypeOf(DeletePage.prototype), 'componentDidMount', this).call(this); + this.syncDialog(); + } + }, { + key: 'componentWillReceiveProps', + value: function componentWillReceiveProps(nextProps) { + _get(DeletePage.prototype.__proto__ || Object.getPrototypeOf(DeletePage.prototype), 'componentWillReceiveProps', this).call(this, nextProps); + this.syncDialog(); + } + }, { + key: 'syncDialog', + value: function syncDialog() { + var _this2 = this; + + _utils2.default.loadData('/recordinfo', { path: this.getRecordPath() }, null, _richPromise2.default).then(function (resp) { + _this2.setState({ + recordInfo: resp, + deleteMasterRecord: _this2.isPrimary() + }); + }); + } + }, { + key: 'deleteRecord', + value: function deleteRecord(event) { + var _this3 = this; + + var path = this.getRecordPath(); + var parent = _utils2.default.getParentFsPath(path); + var targetPath = void 0; + if (parent === null) { + targetPath = 'root'; + } else { + targetPath = this.getUrlRecordPathWithAlt(parent); + } + + _utils2.default.apiRequest('/deleterecord', { data: { + path: path, + alt: this.getRecordAlt(), + delete_master: this.state.deleteMasterRecord ? '1' : '0' + }, + // eslint-disable-next-line indent + method: 'POST' }, _richPromise2.default).then(function (resp) { + if (_this3.state.recordInfo.is_attachment) { + _hub2.default.emit(new _events.AttachmentsChangedEvent({ + recordPath: _this3.getParentRecordPath(), + attachmentsRemoved: [_this3.state.recordInfo.id] + })); + } + _this3.transitionToAdminPage('.edit', { path: targetPath }); + }); + } + }, { + key: 'cancelDelete', + value: function cancelDelete(event) { + var urlPath = this.getUrlRecordPathWithAlt(); + this.transitionToAdminPage('.edit', { path: urlPath }); + } + }, { + key: 'onDeleteAllAltsChange', + value: function onDeleteAllAltsChange(event) { + this.setState({ + deleteMasterRecord: event.target.value === '1' + }); + } + }, { + key: 'isPrimary', + value: function isPrimary() { + return this.getRecordAlt() === '_primary'; + } + }, { + key: 'render', + value: function render() { + var ri = this.state.recordInfo; + + if (!ri || !ri.can_be_deleted) { + return null; + } + + var elements = []; + var children = []; + var alts = []; + var attachments = []; + var altInfo = null; + var altCount = 0; + + for (var i = 0; i < ri.alts.length; i++) { + if (ri.alts[i].alt === this.getRecordAlt()) { + altInfo = ri.alts[i]; + } + if (ri.alts[i].exists) { + altCount++; + } + } + + if (ri.is_attachment) { + elements.push(_react2.default.createElement( + 'p', + { key: 'attachment' }, + this.isPrimary() ? _i18n2.default.trans('DELETE_ATTACHMENT_PROMPT') : _i18n2.default.trans('DELETE_ATTACHMENT_ALT_PROMPT'), + ' ' + )); + } else { + elements.push(_react2.default.createElement( + 'p', + { key: 'child-info' }, + this.isPrimary() ? _i18n2.default.trans('DELETE_PAGE_PROMPT') : _i18n2.default.trans('DELETE_PAGE_ALT_PROMPT'), + ' ', + ri.children.length > 0 && this.isPrimary() ? _i18n2.default.trans('DELETE_PAGE_CHILDREN_WARNING') : null + )); + + if (ri.children.length > 0) { + children = ri.children.map(function (child) { + return _react2.default.createElement( + 'li', + { key: child.id }, + _i18n2.default.trans(child.label_i18n) + ); + }); + if (ri.child_count > children.length) { + children.push(_react2.default.createElement( + 'li', + { key: '...' }, + '...' + )); + } + } + + attachments = ri.attachments.map(function (atch) { + return _react2.default.createElement( + 'li', + { key: atch.id }, + atch.id, + ' (', + atch.type, + ')' + ); + }); + } + + if (altCount > 1 && this.getRecordAlt() === '_primary') { + ri.alts.forEach(function (item) { + if (!item.exists) { + return; + } + var title = _i18n2.default.trans(item.name_i18n); + if (item.is_primary) { + title += ' (' + _i18n2.default.trans('PRIMARY_ALT') + ')'; + } else if (item.primary_overlay) { + title += ' (' + _i18n2.default.trans('PRIMARY_OVERLAY') + ')'; + } + alts.push(_react2.default.createElement( + 'li', + { key: item.alt }, + title + )); + }); + elements.push(_react2.default.createElement( + 'p', + { key: 'alt-warning' }, + _i18n2.default.trans('DELETE_PRIMARY_ALT_INFO') + )); + elements.push(_react2.default.createElement( + 'ul', + { key: 'delete-all-alts' }, + _react2.default.createElement( + 'li', + null, + _react2.default.createElement('input', { type: 'radio', id: 'delete-all-alts', value: '1', name: 'delete-master-record', checked: this.state.deleteMasterRecord, onChange: this.onDeleteAllAltsChange.bind(this) }), + ' ', + _react2.default.createElement( + 'label', + { htmlFor: 'delete-all-alts' }, + _i18n2.default.trans(ri.is_attachment ? 'DELETE_ALL_ATTACHMENT_ALTS' : 'DELETE_ALL_PAGE_ALTS') + ) + ), + _react2.default.createElement( + 'li', + null, + _react2.default.createElement('input', { type: 'radio', id: 'delete-only-this-alt', value: '0', name: 'delete-master-record', checked: !this.state.deleteMasterRecord, onChange: this.onDeleteAllAltsChange.bind(this) }), + ' ', + _react2.default.createElement( + 'label', + { htmlFor: 'delete-only-this-alt' }, + _i18n2.default.trans(ri.is_attachment ? 'DELETE_ONLY_PRIMARY_ATTACHMENT_ALT' : 'DELETE_ONLY_PRIMARY_PAGE_ALT') + ) + ) + )); + } + + var label = ri.label_i18n ? _i18n2.default.trans(ri.label_i18n) : ri.id; + if (this.getRecordAlt() !== '_primary' && altInfo != null) { + label += ' (' + _i18n2.default.trans(altInfo.name_i18n) + ')'; + } + + return _react2.default.createElement( + 'div', + null, + _react2.default.createElement( + 'h2', + null, + _i18n2.default.trans('DELETE_RECORD').replace('%s', label) + ), + elements, + _react2.default.createElement( + 'div', + { style: { display: this.state.deleteMasterRecord && alts.length > 0 ? 'block' : 'none' } }, + _react2.default.createElement( + 'h4', + null, + _i18n2.default.trans('ALTS_TO_BE_DELETED') + ), + _react2.default.createElement( + 'ul', + null, + alts + ) + ), + _react2.default.createElement( + 'div', + { style: { display: this.state.deleteMasterRecord && children.length > 0 ? 'block' : 'none' } }, + _react2.default.createElement( + 'h4', + null, + _i18n2.default.trans('CHILD_PAGES_TO_BE_DELETED') + ), + _react2.default.createElement( + 'ul', + null, + children + ) + ), + _react2.default.createElement( + 'div', + { style: { display: this.state.deleteMasterRecord && attachments.length > 0 ? 'block' : 'none' } }, + _react2.default.createElement( + 'h4', + null, + _i18n2.default.trans('ATTACHMENTS_TO_BE_DELETED') + ), + _react2.default.createElement( + 'ul', + null, + attachments + ) + ), + _react2.default.createElement( + 'div', + { className: 'actions' }, + _react2.default.createElement( + 'button', + { className: 'btn btn-primary', + onClick: this.deleteRecord.bind(this) }, + _i18n2.default.trans('YES_DELETE') + ), + _react2.default.createElement( + 'button', + { className: 'btn btn-default', + onClick: this.cancelDelete.bind(this) }, + _i18n2.default.trans('NO_CANCEL') + ) + ) + ); + } + }]); + + return DeletePage; +}(_RecordEditComponent2.default); + +exports.default = DeletePage; + +/***/ }), +/* 341 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +var _utils = __webpack_require__(12); + +var _utils2 = _interopRequireDefault(_utils); + +var _RecordComponent2 = __webpack_require__(26); + +var _RecordComponent3 = _interopRequireDefault(_RecordComponent2); + +var _richPromise = __webpack_require__(17); + +var _richPromise2 = _interopRequireDefault(_richPromise); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var PreviewPage = function (_RecordComponent) { + _inherits(PreviewPage, _RecordComponent); + + function PreviewPage(props) { + _classCallCheck(this, PreviewPage); + + var _this = _possibleConstructorReturn(this, (PreviewPage.__proto__ || Object.getPrototypeOf(PreviewPage)).call(this, props)); + + _this.state = { + pageUrl: null, + pageUrlFor: null + }; + return _this; + } + + _createClass(PreviewPage, [{ + key: 'componentWillReceiveProps', + value: function componentWillReceiveProps(nextProps) { + _get(PreviewPage.prototype.__proto__ || Object.getPrototypeOf(PreviewPage.prototype), 'componentWillReceiveProps', this).call(this, nextProps); + this.setState({}, this.syncState.bind(this)); + } + }, { + key: 'componentDidMount', + value: function componentDidMount() { + _get(PreviewPage.prototype.__proto__ || Object.getPrototypeOf(PreviewPage.prototype), 'componentDidMount', this).call(this); + this.syncState(); + } + }, { + key: 'shouldComponentUpdate', + value: function shouldComponentUpdate() { + return this.getUrlRecordPathWithAlt() !== this.state.pageUrlFor; + } + }, { + key: 'syncState', + value: function syncState() { + var _this2 = this; + + var alt = this.getRecordAlt(); + var path = this.getRecordPath(); + if (path === null) { + this.setState(this.getInitialState()); + return; + } + + var recordUrl = this.getUrlRecordPathWithAlt(); + _utils2.default.loadData('/previewinfo', { path: path, alt: alt }, null, _richPromise2.default).then(function (resp) { + _this2.setState({ + pageUrl: resp.url, + pageUrlFor: recordUrl + }); + }); + } + }, { + key: 'getIntendedPath', + value: function getIntendedPath() { + if (this.state.pageUrlFor === this.getUrlRecordPathWithAlt()) { + return this.state.pageUrl; + } + return null; + } + }, { + key: 'componentDidUpdate', + value: function componentDidUpdate() { + var _this3 = this; + + var frame = this.refs.iframe; + var intendedPath = this.getIntendedPath(); + if (intendedPath !== null) { + var framePath = this.getFramePath(); + + if (!_utils2.default.urlPathsConsideredEqual(intendedPath, framePath)) { + frame.src = _utils2.default.getCanonicalUrl(intendedPath); + } + + frame.onload = function (event) { + _this3.onFrameNavigated(); + }; + } + } + }, { + key: 'getFramePath', + value: function getFramePath() { + var frameLocation = this.refs.iframe.contentWindow.location; + if (frameLocation.href === 'about:blank') { + return frameLocation.href; + } + return _utils2.default.fsPathFromAdminObservedPath(frameLocation.pathname); + } + }, { + key: 'onFrameNavigated', + value: function onFrameNavigated() { + var _this4 = this; + + var fsPath = this.getFramePath(); + if (fsPath === null) { + return; + } + _utils2.default.loadData('/matchurl', { url_path: fsPath }, null, _richPromise2.default).then(function (resp) { + if (resp.exists) { + var urlPath = _this4.getUrlRecordPathWithAlt(resp.path, resp.alt); + _this4.transitionToAdminPage('.preview', { path: urlPath }); + } + }); + } + }, { + key: 'render', + value: function render() { + return _react2.default.createElement( + 'div', + { className: 'preview' }, + _react2.default.createElement('iframe', { ref: 'iframe' }) + ); + } + }]); + + return PreviewPage; +}(_RecordComponent3.default); + +exports.default = PreviewPage; + +/***/ }), +/* 342 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* eslint-env browser */ + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +var _RecordComponent2 = __webpack_require__(26); + +var _RecordComponent3 = _interopRequireDefault(_RecordComponent2); + +var _i18n = __webpack_require__(7); + +var _i18n2 = _interopRequireDefault(_i18n); + +var _userLabel = __webpack_require__(90); + +var _userLabel2 = _interopRequireDefault(_userLabel); + +var _utils = __webpack_require__(12); + +var _utils2 = _interopRequireDefault(_utils); + +var _widgets = __webpack_require__(89); + +var _widgets2 = _interopRequireDefault(_widgets); + +var _richPromise = __webpack_require__(17); + +var _richPromise2 = _interopRequireDefault(_richPromise); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var getGoodDefaultModel = function getGoodDefaultModel(models) { + if (models.page !== undefined) { + return 'page'; + } + var choices = Object.keys(models); + choices.sort(); + return choices[0]; +}; + +var AddChildPage = function (_RecordComponent) { + _inherits(AddChildPage, _RecordComponent); + + function AddChildPage(props) { + _classCallCheck(this, AddChildPage); + + var _this = _possibleConstructorReturn(this, (AddChildPage.__proto__ || Object.getPrototypeOf(AddChildPage)).call(this, props)); + + _this.state = { + newChildInfo: null, + id: undefined, + selectedModel: null + }; + return _this; + } + + _createClass(AddChildPage, [{ + key: 'componentDidMount', + value: function componentDidMount() { + _get(AddChildPage.prototype.__proto__ || Object.getPrototypeOf(AddChildPage.prototype), 'componentDidMount', this).call(this); + this.syncDialog(); + } + }, { + key: 'componentWillReceiveProps', + value: function componentWillReceiveProps(nextProps) { + _get(AddChildPage.prototype.__proto__ || Object.getPrototypeOf(AddChildPage.prototype), 'componentWillReceiveProps', this).call(this, nextProps); + this.syncDialog(); + } + }, { + key: 'syncDialog', + value: function syncDialog() { + var _this2 = this; + + _utils2.default.loadData('/newrecord', { path: this.getRecordPath() }, null, _richPromise2.default).then(function (resp) { + var selectedModel = resp.implied_model; + if (!selectedModel) { + selectedModel = getGoodDefaultModel(resp.available_models); + } + + _this2.setState({ + newChildInfo: resp, + id: undefined, + primary: undefined, + selectedModel: selectedModel + }); + }); + } + }, { + key: 'onValueChange', + value: function onValueChange(id, value) { + var obj = {}; + obj[id] = value; + this.setState(obj); + } + }, { + key: 'getAvailableModels', + value: function getAvailableModels() { + var rv = []; + for (var key in this.state.newChildInfo.available_models) { + var model = this.state.newChildInfo.available_models[key]; + rv.push(model); + } + rv.sort(function (a, b) { + return a.name.toLowerCase().localeCompare(b.name.toLowerCase()); + }); + return rv; + } + }, { + key: 'onModelSelected', + value: function onModelSelected(event) { + this.setState({ + selectedModel: event.target.value + }); + } + }, { + key: 'getImpliedId', + value: function getImpliedId() { + return _utils2.default.slugify(this.state.primary || '').toLowerCase(); + } + }, { + key: 'getPrimaryField', + value: function getPrimaryField() { + var model = this.state.selectedModel; + return this.state.newChildInfo.available_models[model].primary_field; + } + }, { + key: 'createRecord', + value: function createRecord() { + var _this3 = this; + + var errMsg = function errMsg(text) { + alert(_i18n2.default.trans('ERROR_PREFIX') + text); + }; + + var id = this.state.id || this.getImpliedId(); + if (!id) { + errMsg(_i18n2.default.trans('ERROR_NO_ID_PROVIDED')); + return; + } + + var data = {}; + var params = { id: id, path: this.getRecordPath(), data: data }; + if (!this.state.newChildInfo.implied_model) { + data['_model'] = this.state.selectedModel; + } + var primaryField = this.getPrimaryField(); + if (primaryField) { + data[primaryField.name] = this.state.primary; + } + + _utils2.default.apiRequest('/newrecord', { json: params, method: 'POST' }, _richPromise2.default).then(function (resp) { + if (resp.exists) { + errMsg(_i18n2.default.trans('ERROR_PAGE_ID_DUPLICATE').replace('%s', id)); + } else if (!resp.valid_id) { + errMsg(_i18n2.default.trans('ERROR_INVALID_ID').replace('%s', id)); + } else { + var urlPath = _this3.getUrlRecordPathWithAlt(resp.path); + _this3.transitionToAdminPage('.edit', { path: urlPath }); + } + }); + } + }, { + key: 'renderFields', + value: function renderFields() { + var _this4 = this; + + var fields = []; + + if (!this.state.newChildInfo.implied_model) { + var choices = this.getAvailableModels().map(function (model) { + return _react2.default.createElement( + 'option', + { value: model.id, key: model.id }, + _i18n2.default.trans(model.name_i18n) + ); + }); + fields.push(_react2.default.createElement( + 'div', + { className: 'row', key: '_model' }, + _react2.default.createElement( + 'div', + { className: 'field-box col-md-12' }, + _react2.default.createElement( + 'dl', + { className: 'field' }, + _react2.default.createElement( + 'dt', + null, + _i18n2.default.trans('MODEL') + ), + _react2.default.createElement( + 'dd', + null, + _react2.default.createElement( + 'select', + { value: this.state.selectedModel, + className: 'form-control', + onChange: this.onModelSelected.bind(this) }, + choices + ) + ) + ) + ) + )); + } + + var addField = function addField(id, field, placeholder) { + var value = _this4.state[id]; + var Widget = _widgets2.default.getWidgetComponentWithFallback(field.type); + if (Widget.deserializeValue) { + value = Widget.deserializeValue(value, field.type); + } + fields.push(_react2.default.createElement( + 'div', + { className: 'row field-row', key: field.name }, + _react2.default.createElement( + 'div', + { className: 'field-box col-md-12' }, + _react2.default.createElement( + 'dl', + { className: 'field' }, + _react2.default.createElement( + 'dt', + null, + _userLabel2.default.format(field.label_i18n || field.label) + ), + _react2.default.createElement( + 'dd', + null, + _react2.default.createElement(Widget, { + value: value, + placeholder: placeholder, + onChange: _this4.onValueChange.bind(_this4, id), + type: field.type + }) + ) + ) + ) + )); + }; + + var primaryField = this.getPrimaryField(); + if (primaryField) { + addField('primary', primaryField); + } + + addField('id', { + name: '_id', + label: _i18n2.default.trans('ID'), + type: { name: 'slug', widget: 'slug' } + }, this.getImpliedId()); + + return fields; + } + }, { + key: 'render', + value: function render() { + var nci = this.state.newChildInfo; + + if (!nci) { + return null; + } + + return _react2.default.createElement( + 'div', + { className: 'edit-area' }, + _react2.default.createElement( + 'h2', + null, + _i18n2.default.trans('ADD_CHILD_PAGE_TO').replace('%s', this.state.newChildInfo.label) + ), + _react2.default.createElement( + 'p', + null, + _i18n2.default.trans('ADD_CHILD_PAGE_NOTE') + ), + this.renderFields(), + _react2.default.createElement( + 'div', + { className: 'actions' }, + _react2.default.createElement( + 'button', + { className: 'btn btn-primary', onClick: this.createRecord.bind(this) }, + _i18n2.default.trans('CREATE_CHILD_PAGE') + ) + ) + ); + } + }]); + + return AddChildPage; +}(_RecordComponent3.default); + +exports.default = AddChildPage; + +/***/ }), +/* 343 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/* eslint-env browser */ + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _react = __webpack_require__(2); + +var _react2 = _interopRequireDefault(_react); + +var _RecordComponent2 = __webpack_require__(26); + +var _RecordComponent3 = _interopRequireDefault(_RecordComponent2); + +var _hub = __webpack_require__(45); + +var _hub2 = _interopRequireDefault(_hub); + +var _events = __webpack_require__(46); + +var _utils = __webpack_require__(12); + +var _utils2 = _interopRequireDefault(_utils); + +var _i18n = __webpack_require__(7); + +var _i18n2 = _interopRequireDefault(_i18n); + +var _richPromise = __webpack_require__(17); + +var _richPromise2 = _interopRequireDefault(_richPromise); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var AddAttachmentPage = function (_RecordComponent) { + _inherits(AddAttachmentPage, _RecordComponent); + + function AddAttachmentPage(props) { + _classCallCheck(this, AddAttachmentPage); + + var _this = _possibleConstructorReturn(this, (AddAttachmentPage.__proto__ || Object.getPrototypeOf(AddAttachmentPage)).call(this, props)); + + _this.state = { + newAttachmentInfo: null, + currentFiles: [], + isUploading: false, + currentProgress: 0 + }; + return _this; + } + + _createClass(AddAttachmentPage, [{ + key: 'componentDidMount', + value: function componentDidMount() { + this.syncDialog(); + } + }, { + key: 'componentWillReceiveProps', + value: function componentWillReceiveProps(nextProps) { + this.syncDialog(); + } + }, { + key: 'syncDialog', + value: function syncDialog() { + var _this2 = this; + + _utils2.default.loadData('/newattachment', { path: this.getRecordPath() }, null, _richPromise2.default).then(function (resp) { + _this2.setState({ + newAttachmentInfo: resp + }); + }); + } + }, { + key: 'uploadFile', + value: function uploadFile(event) { + this.refs.file.click(); + } + }, { + key: 'onUploadProgress', + value: function onUploadProgress(event) { + var newProgress = Math.round(event.loaded * 100 / event.total); + if (newProgress !== this.state.currentProgress) { + this.setState({ + currentProgress: newProgress + }); + } + } + }, { + key: 'onUploadComplete', + value: function onUploadComplete(resp, event) { + var _this3 = this; + + this.setState({ + isUploading: false, + newProgress: 100 + }, function () { + _hub2.default.emit(new _events.AttachmentsChangedEvent({ + recordPath: _this3.getRecordPath(), + attachmentsAdded: resp.buckets.map(function (bucket) { + return bucket.stored_filename; + }) + })); + }); + } + }, { + key: 'onFileSelected', + value: function onFileSelected(event) { + var _this4 = this; + + if (this.state.isUploading) { + return; + } + + var files = this.refs.file.files; + this.setState({ + currentFiles: Array.prototype.slice.call(files, 0), + isUploading: true + }); + + var formData = new FormData(); + formData.append('path', this.getRecordPath()); + + for (var i = 0; i < files.length; i++) { + formData.append('file', files[i], files[i].name); + } + + var xhr = new XMLHttpRequest(); + xhr.open('POST', _utils2.default.getApiUrl('/newattachment')); + xhr.onload = function (event) { + _this4.onUploadComplete(JSON.parse(xhr.responseText), event); + }; + xhr.upload.onprogress = function (event) { + _this4.onUploadProgress(event); + }; + xhr.send(formData); + } + }, { + key: 'renderCurrentFiles', + value: function renderCurrentFiles() { + var files = this.state.currentFiles.map(function (file) { + return _react2.default.createElement( + 'li', + { key: file.name }, + file.name, + ' (', + file.type, + ')' + ); + }); + return _react2.default.createElement( + 'ul', + null, + files + ); + } + }, { + key: 'render', + value: function render() { + var nai = this.state.newAttachmentInfo; + + if (!nai) { + return null; + } + + return _react2.default.createElement( + 'div', + null, + _react2.default.createElement( + 'h2', + null, + _i18n2.default.trans('ADD_ATTACHMENT_TO').replace('%s', nai.label) + ), + _react2.default.createElement( + 'p', + null, + _i18n2.default.trans('ADD_ATTACHMENT_NOTE') + ), + this.renderCurrentFiles(), + _react2.default.createElement( + 'p', + null, + _i18n2.default.trans('PROGRESS'), + ': ', + this.state.currentProgress, + '%' + ), + _react2.default.createElement('input', { type: 'file', ref: 'file', multiple: true, + style: { display: 'none' }, onChange: this.onFileSelected.bind(this) }), + _react2.default.createElement( + 'div', + { className: 'actions' }, + _react2.default.createElement( + 'button', + { className: 'btn btn-primary', onClick: this.uploadFile.bind(this) }, + _i18n2.default.trans('UPLOAD') + ) + ) + ); + } + }]); + + return AddAttachmentPage; +}(_RecordComponent3.default); + +exports.default = AddAttachmentPage; + +/***/ }) +],[152]); +//# sourceMappingURL=app.js.map \ No newline at end of file diff --git a/venv/lib/python2.7/site-packages/lektor/admin/static/gen/app.js.map b/venv/lib/python2.7/site-packages/lektor/admin/static/gen/app.js.map new file mode 100644 index 0000000..389cd73 --- /dev/null +++ b/venv/lib/python2.7/site-packages/lektor/admin/static/gen/app.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack:///./js/i18n.jsx","webpack:///./js/utils.jsx","webpack:///./js/components/Component.jsx","webpack:///./js/richPromise.jsx","webpack:///./js/dialogSystem.jsx","webpack:///../node_modules/prop-types/index.js","webpack:///./js/components/RecordComponent.jsx","webpack:///../node_modules/history/lib/deprecate.js","webpack:///../node_modules/history/lib/parsePath.js","webpack:///../node_modules/warning/browser.js","webpack:///../node_modules/history/lib/Actions.js","webpack:///./js/hub.jsx","webpack:///./js/events.jsx","webpack:///../node_modules/history/lib/ExecutionEnvironment.js","webpack:///./js/widgets/mixins.jsx","webpack:///../node_modules/history/lib/DOMUtils.js","webpack:///./js/components/SlideDialog.jsx","webpack:///../node_modules/history/lib/runTransitionHook.js","webpack:///./js/widgets.jsx","webpack:///./js/userLabel.jsx","webpack:///../node_modules/history/lib/createLocation.js","webpack:///../node_modules/history/lib/extractPath.js","webpack:///../node_modules/history/lib/createBrowserHistory.js","webpack:///../node_modules/history/lib/DOMStateStorage.js","webpack:///../node_modules/history/lib/createDOMHistory.js","webpack:///../node_modules/history/lib/createHistory.js","webpack:///../node_modules/history/lib/useBeforeUnload.js","webpack:///../node_modules/history/lib/useQueries.js","webpack:///./js/components/Link.jsx","webpack:///./js/components/RecordEditComponent.jsx","webpack:///./js/main.jsx","webpack:///../node_modules/prop-types/factoryWithThrowingShims.js","webpack:///./js/components/BaseComponent.jsx","webpack:////home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations \\.json$","webpack:////home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/ca.json","webpack:////home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/de.json","webpack:////home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/en.json","webpack:////home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/es.json","webpack:////home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/fr.json","webpack:////home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/it.json","webpack:////home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/ja.json","webpack:////home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/ko.json","webpack:////home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/nl.json","webpack:////home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/pl.json","webpack:////home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/pt.json","webpack:////home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/ru.json","webpack:////home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/zh.json","webpack:///../node_modules/history/lib/index.js","webpack:///../node_modules/history/lib/AsyncUtils.js","webpack:///../node_modules/history/lib/createHashHistory.js","webpack:///../node_modules/history/lib/createMemoryHistory.js","webpack:///../node_modules/history/lib/useBasename.js","webpack:///../node_modules/history/lib/enableBeforeUnload.js","webpack:///../node_modules/history/lib/enableQueries.js","webpack:///./js/bootstrap-extras.jsx","webpack:///../node_modules/font-awesome/css/font-awesome.css","webpack:///../node_modules/event-source-polyfill/eventsource.js","webpack:///./js/views/App.jsx","webpack:///./js/components/BreadCrumbs.jsx","webpack:///./js/dialogs/findFiles.jsx","webpack:///./js/dialogs/errorDialog.jsx","webpack:///./js/dialogs/publish.jsx","webpack:///./js/dialogs/Refresh.jsx","webpack:///./js/components/Sidebar.jsx","webpack:///./js/components/DialogSlot.jsx","webpack:///./js/components/ServerStatus.jsx","webpack:///./js/views/Dash.jsx","webpack:///./js/views/EditPage.jsx","webpack:///./js/widgets/primitiveWidgets.jsx","webpack:///./js/widgets/multiWidgets.jsx","webpack:///./js/widgets/flowWidget.jsx","webpack:///./js/metaformat.jsx","webpack:///./js/widgets/fakeWidgets.jsx","webpack:///./js/components/ToggleGroup.jsx","webpack:///./js/views/DeletePage.jsx","webpack:///./js/views/PreviewPage.jsx","webpack:///./js/views/AddChildPage.jsx","webpack:///./js/views/AddAttachmentPage.jsx"],"names":["loadTranslations","ctx","rv","keys","forEach","key","langIdMatch","match","i18n","translations","currentLanguage","setLanguageFromLocale","locale","lang","split","toLowerCase","undefined","trans","en","slug","string","opts","toString","replacement","mode","defaults","modes","symbols","lengths","Object","multicharmap","len","length","indexOf","push","result","l","char","i","some","str","substr","charmap","replace","remove","pretty","utils","slugify","getCanonicalUrl","localPath","$LEKTOR_CONFIG","site_root","stripLeadingSlash","isValidUrl","url","stripTrailingSlash","joinFsPath","a","b","flipSetValue","originalSet","value","isActive","addToSet","removeFromSet","slice","off","splice","urlPathsConsideredEqual","fsPathFromAdminObservedPath","adminPath","base","getParentFsPath","fsPath","getApiUrl","admin_root","loadData","params","options","createPromise","resolve","reject","ajax","data","method","done","fail","code","apiRequest","json","JSON","stringify","contentType","fsToUrlPath","segments","unshift","join","urlToFsPath","urlPath","urlPathToSegments","scrolledToBottom","document","body","offsetHeight","scrollTop","scrollHeight","getPlatform","navigator","appVersion","isMetaKey","event","metaKey","ctrlKey","Component","props","_unlistenBeforeLeavingRoute","history","location","route","routeParams","routes","name","parts","map","x","node","shift","path","part","childRoutes","m","pushState","getPathToAdminPage","listenBeforeLeavingRoute","routerWillLeave","bind","nextLocation","preventNavigation","dismissDialog","bringUpDialog","error","dialogIsOpen","showDialog","makeRichPromise","callback","fallback","Promise","then","hasRejectionHandler","onFulfilled","onRejected","call","DialogSystem","_dialogInstance","dialog","emit","dialogOptions","currentDialog","dialogSystem","RecordComponent","component","items","_getRecordPathAndAlt","alt","newPath","newAlt","getRecordPath","getRecordAlt","getRecordPathSegments","curpath","id","title","Hub","_subscriptions","getEventType","subs","type","e","console","log","hub","Event","getPrototypeOf","constructor","RecordEvent","recordPath","AttachmentsChangedEvent","attachmentsAdded","attachmentsRemoved","DialogChangedEvent","ValidationFailure","message","BasicWidgetMixin","propTypes","any","object","placeholder","onChange","func","getInputClass","size","getValidationFailure","getValidationFailureImpl","SlideDialog","_onKeyPress","closeOnEscape","window","addEventListener","removeEventListener","which","preventDefault","children","hasCloseButton","className","_onCloseClick","bool","widgetComponents","SingleLineTextInputWidget","MultiLineTextInputWidget","DateInputWidget","IntegerInputWidget","FloatInputWidget","BooleanInputWidget","UrlInputWidget","SlugInputWidget","FlowWidget","CheckboxesInputWidget","SelectInputWidget","LineWidget","SpacingWidget","InfoWidget","HeadingWidget","FallbackWidget","createClass","mixins","render","widget","FieldBox","field","disabled","getFieldColumns","innerClassName","inner","Widget","getWidgetComponentWithFallback","isFakeWidget","description","description_i18n","hide_label","label_i18n","getWidgetComponent","widthSpec","width","Math","min","max","parseInt","getFieldRows","fields","isIllegalField","normalFields","systemFields","processFields","rowType","currentColumns","row","columns","renderFieldRows","renderFunc","normal","system","rows","item","idx","userLabel","format","inputConfig","label","iconData","LektorLink","to","module","exports","RecordEditComponent","hasPendingChanges","BadRoute","contextTypes","router","dash","getElementById","BaseComponent","nextProps","ready","click","target","attr","is","toggleClass","App","getRoutingProps","BreadCrumbs","state","recordPathInfo","updateCrumbs","prevProps","prevState","setState","resp","href","_onFindFiles","_onPublish","_onRefresh","crumbs","isRecordPreviewActive","lastItem","getUrlRecordPathWithAlt","exists","can_have_children","renderGlobalActions","FindFiles","query","currentSelection","results","refs","q","focus","sel","onActiveItem","index","transitionToAdminPage","parents","selectItem","onInputChange","onInputKey","renderResults","ErrorDialog","onClose","Publish","servers","activeTarget","currentState","syncDialog","isSafeToPublish","_beginBuild","_beginPublish","es","EventSource","encodeURIComponent","parse","close","concat","msg","server","name_i18n","short_target","progress","onSelectServer","onPublish","onCancel","Refresh","isSafeToNavigate","onRefresh","getBrowseButtonTitle","platform","CHILDREN_PER_PAGE","ChildPosCache","memo","record","page","childCount","ceil","Sidebar","_getInitialState","childPosCache","onAttachmentsChanged","recordAttachments","recordChildren","recordAlts","canHaveAttachments","canHaveChildren","isAttachment","canBeDeleted","recordExists","lastRecordRequest","childrenPage","_updateRecordInfo","subscribe","unsubscribe","alts","sort","nameA","is_primary","nameB","attachments","can_have_attachments","is_attachment","can_be_deleted","getPosition","okay","alert","links","deleteLink","fsOpen","primary_overlay","pages","goToPage","diff","newPage","rememberPosition","child","renderChildPagination","atch","sections","renderPageActions","renderAlts","renderChildActions","renderAttachmentActions","DialogSlot","currentDialogOptions","onDialogChanged","notifyDialogInstance","scrollTo","ref","initDialogInstance","ServerStatus","serverIsUp","projectId","intervalId","onInterval","setInterval","clearInterval","project_id","Dash","rootPreview","EditPage","recordInitialData","recordData","recordDataModel","recordInfo","syncEditor","saveChanges","datamodel","record_info","updates","$set","rd","serializeValue","newData","getValues","deserializeValue","slug_format","default_template","implied_attachment_type","getValueForField","getPlaceholderForField","onValueChange","alts_enabled","renderFormField","deleteButton","deleteRecord","renderFormFields","isTrue","isValidDate","year","month","day","date","Date","getFullYear","getMonth","getDate","InputWidgetMixin","postprocessValue","otherProps","help","failure","valClassName","addon","configuredAddon","addon_label_i18n","getInputAddon","getInputType","isNaN","parseFloat","recalculateSize","componentDidMount","componentWillUnmount","componentDidUpdate","isInAutoResizeMode","ta","getComputedStyle","s","getPropertyValue","updateScrollPosition","oldScrollTop","documentElement","oldHeight","outerHeight","style","height","newHeight","scrollLeft","display","overflow","resize","checked","checkbox","indeterminate","checkbox_label_i18n","statics","newValue","choices","getWidgets","parseFlowFormat","blocks","buf","lines","block","line","blockStart","serializeFlowFormat","blockName","deserializeFlowBlock","flowBlockModel","localId","rawData","tokenize","serializeFlowBlock","flockBlockModel","serialize","lastBlockId","flowBlock","flowblocks","moveBlock","offset","newIndex","tmp","removeBlock","confirm","addNewBlock","blockInfo","widgets","renderBlocks","renderAddBlockSection","flowblock_order","button_label","buttons","lineIsDashes","Array","processBuf","lastLine","wantNewline","flushItem","bits","firstBit","pop","arr","FakeWidgetMixin","heading_i18n","ToggleGroup","isVisible","defaultVisibility","groupTitle","toggle","DeletePage","deleteMasterRecord","isPrimary","parent","targetPath","delete_master","getParentRecordPath","ri","elements","altInfo","altCount","child_count","onDeleteAllAltsChange","cancelDelete","PreviewPage","pageUrl","pageUrlFor","syncState","getInitialState","recordUrl","frame","iframe","intendedPath","getIntendedPath","framePath","getFramePath","src","onload","onFrameNavigated","frameLocation","contentWindow","pathname","url_path","getGoodDefaultModel","models","AddChildPage","newChildInfo","selectedModel","implied_model","available_models","primary","obj","model","localeCompare","primary_field","errMsg","text","getImpliedId","primaryField","getPrimaryField","valid_id","getAvailableModels","onModelSelected","addField","nci","renderFields","createRecord","AddAttachmentPage","newAttachmentInfo","currentFiles","isUploading","currentProgress","file","newProgress","round","loaded","total","buckets","bucket","stored_filename","files","prototype","formData","FormData","append","xhr","XMLHttpRequest","open","onUploadComplete","responseText","upload","onprogress","onUploadProgress","send","nai","renderCurrentFiles","onFileSelected","uploadFile"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,IAAMA,mBAAmB,SAAnBA,gBAAmB,GAAM;AAC7B,MAAMC,MAAM,wBAAZ;AACA,MAAMC,KAAK,EAAX;AACAD,MAAIE,IAAJ,GAAWC,OAAX,CAAmB,UAACC,GAAD,EAAS;AAC1B,QAAMC,cAAcD,IAAIE,KAAJ,CAAU,UAAV,CAApB;AACAL,OAAGI,YAAY,CAAZ,CAAH,IAAqBL,IAAII,GAAJ,CAArB;AACD,GAHD;AAIA,SAAOH,EAAP;AACD,CARD;;AAUA,IAAMM,OAAO;AACXC,gBAAcT,kBADH;;AAGXU,mBAAiB,IAHN;;AAKXC,uBALW,iCAKYC,MALZ,EAKoB;AAC7B,QAAIA,MAAJ,EAAY;AACV,UAAIC,OAAOD,OAAOE,KAAP,CAAa,MAAb,EAAqB,CAArB,EAAwBC,WAAxB,EAAX;AACA,UAAI,KAAKN,YAAL,CAAkBI,IAAlB,MAA4BG,SAAhC,EAA2C;AACzC,aAAKN,eAAL,GAAuBG,IAAvB;AACD;AACF;AACF,GAZU;AAcXI,OAdW,iBAcJZ,GAdI,EAcC;AACV,QAAIH,WAAJ;AACA,QAAI,QAAOG,GAAP,yCAAOA,GAAP,OAAe,QAAnB,EAA6B;AAC3BH,WAAKG,IAAIG,KAAKE,eAAT,CAAL;AACA,UAAIR,OAAOc,SAAX,EAAsB;AACpBd,aAAKG,IAAIa,EAAT;AACD;AACD,aAAOhB,EAAP;AACD;AACD,WAAOM,KAAKC,YAAL,CAAkBD,KAAKE,eAAvB,EAAwCL,GAAxC,KAAgDA,GAAvD;AACD;AAxBU,CAAb;;kBA2BeG,I;;;;;;;;;;;;;;;;;ACrCf;;;;;;AAEA,IAAMW,OAAO,SAAPA,IAAO,CAACC,MAAD,EAASC,IAAT,EAAkB;AAC7BA,SAAOA,QAAQ,EAAf;AACAD,WAASA,OAAOE,QAAP,EAAT;AACA,MAAI,OAAOD,IAAP,KAAgB,QAApB,EAA8B;AAAEA,WAAO,EAACE,aAAaF,IAAd,EAAP;AAA4B;AAC5DA,OAAKG,IAAL,GAAYH,KAAKG,IAAL,IAAaL,KAAKM,QAAL,CAAcD,IAAvC;AACA,MAAMC,WAAWN,KAAKM,QAAL,CAAcC,KAAd,CAAoBL,KAAKG,IAAzB,CAAjB;AACA,GAAC,aAAD,EAAgB,cAAhB,EAAgC,SAAhC,EAA2C,QAA3C,EAAqDpB,OAArD,CAA6D,UAACC,GAAD,EAAS;AACpEgB,SAAKhB,GAAL,IAAYgB,KAAKhB,GAAL,KAAaoB,SAASpB,GAAT,CAAzB;AACD,GAFD;AAGA,MAAI,OAAOgB,KAAKM,OAAZ,KAAwB,WAA5B,EAAyC;AAAEN,SAAKM,OAAL,GAAeF,SAASE,OAAxB;AAAiC;AAC5E,MAAMC,UAAU,EAAhB;AACAC,SAAO1B,IAAP,CAAYkB,KAAKS,YAAjB,EAA+B1B,OAA/B,CAAuC,UAACC,GAAD,EAAS;AAC9C,QAAM0B,MAAM1B,IAAI2B,MAAhB;AACA,QAAIJ,QAAQK,OAAR,CAAgBF,GAAhB,MAAyB,CAAC,CAA9B,EAAiC;AAAEH,cAAQM,IAAR,CAAaH,GAAb;AAAmB;AACvD,GAHD;AAIA,MAAII,SAAS,EAAb;;AAf6B,wCAgBPC,CAhBO;AAiB3BC,YAAOjB,OAAOkB,EAAP,CAAP;AACA,QAAI,CAACV,QAAQW,IAAR,CAAa,UAACR,GAAD,EAAS;AACzB,UAAMS,MAAMpB,OAAOqB,MAAP,CAAcH,EAAd,EAAiBP,GAAjB,CAAZ;AACA,UAAIV,KAAKS,YAAL,CAAkBU,GAAlB,CAAJ,EAA4B;AAC1BF,cAAKP,MAAM,CAAX;AACAM,gBAAOhB,KAAKS,YAAL,CAAkBU,GAAlB,CAAP;AACA,eAAO,IAAP;AACD,OAJD,MAIO,OAAO,KAAP;AACR,KAPI,CAAL,EAOI;AACF,UAAInB,KAAKqB,OAAL,CAAaL,KAAb,CAAJ,EAAwB;AACtBA,gBAAOhB,KAAKqB,OAAL,CAAaL,KAAb,CAAP;AACD;AACF;AACDA,YAAOA,MAAKM,OAAL,CAAa,eAAb,EAA8B,EAA9B,CAAP,CA9B2B,CA8Bc;AACzC,QAAItB,KAAKuB,MAAT,EAAiBP,QAAOA,MAAKM,OAAL,CAAatB,KAAKuB,MAAlB,EAA0B,EAA1B,CAAP,CA/BU,CA+B2B;AACtDT,cAAUE,KAAV;AAhBOA,QAhBoB;AAgBdC,KAhBc;AAAA;;AAgB7B,OAAK,IAAID,IAAJ,EAAUC,IAAI,CAAd,EAAiBF,IAAIhB,OAAOY,MAAjC,EAAyCM,IAAIF,CAA7C,EAAgDE,GAAhD,EAAqD;AAAA,UAA5CD,IAA4C,EAAtCC,CAAsC,EAA/BF,CAA+B;AAiBpD;AACDD,WAASA,OAAOQ,OAAP,CAAe,YAAf,EAA6B,EAA7B,CAAT,CAlC6B,CAkCa;AAC1CR,WAASA,OAAOQ,OAAP,CAAe,SAAf,EAA0BtB,KAAKE,WAA/B,CAAT,CAnC6B,CAmCwB;AACrD,SAAOY,OAAOQ,OAAP,CAAetB,KAAKE,WAAL,GAAmB,GAAlC,EAAuC,EAAvC,CAAP,CApC6B,CAoCqB;AACnD,CArCD;;AAuCAJ,KAAKM,QAAL,GAAgB;AACdD,QAAM;AADQ,CAAhB;;AAIAL,KAAKW,YAAL,GAAoBX,KAAKM,QAAL,CAAcK,YAAd,GAA6B;AAC/C,QAAM,MADyC,EACjC,MAAM,KAD2B,EACpB,MAAM,IADc,EACR,MAAM;;AAG/C;AAJiD,CAAjD,CAKAX,KAAKuB,OAAL,GAAevB,KAAKM,QAAL,CAAciB,OAAd,GAAwB;AACrC;AACA,OAAK,GAFgC;AAGrC,OAAK,GAHgC;AAIrC,OAAK,GAJgC;AAKrC,OAAK,GALgC;AAMrC,OAAK,IANgC;AAOrC,OAAK,GAPgC;AAQrC,OAAK,IARgC;AASrC,OAAK,GATgC;AAUrC,OAAK,GAVgC;AAWrC,OAAK,GAXgC;AAYrC,OAAK,GAZgC;AAarC,OAAK,GAbgC;AAcrC,OAAK,GAdgC;AAerC,OAAK,GAfgC;AAgBrC,OAAK,GAhBgC;AAiBrC,OAAK,GAjBgC;AAkBrC,OAAK,GAlBgC;AAmBrC,OAAK,GAnBgC;AAoBrC,OAAK,GApBgC;AAqBrC,OAAK,GArBgC;AAsBrC,OAAK,GAtBgC;AAuBrC,OAAK,GAvBgC;AAwBrC,OAAK,IAxBgC;AAyBrC,OAAK,GAzBgC;AA0BrC,OAAK,GA1BgC;AA2BrC,OAAK,GA3BgC;AA4BrC,OAAK,GA5BgC;AA6BrC,OAAK,GA7BgC;AA8BrC,OAAK,IA9BgC;AA+BrC,OAAK,GA/BgC;AAgCrC,OAAK,GAhCgC;AAiCrC,OAAK,IAjCgC;AAkCrC,OAAK,IAlCgC;AAmCrC,OAAK,GAnCgC;AAoCrC,OAAK,GApCgC;AAqCrC,OAAK,GArCgC;AAsCrC,OAAK,GAtCgC;AAuCrC,OAAK,IAvCgC;AAwCrC,OAAK,GAxCgC;AAyCrC,OAAK,IAzCgC;AA0CrC,OAAK,GA1CgC;AA2CrC,OAAK,GA3CgC;AA4CrC,OAAK,GA5CgC;AA6CrC,OAAK,GA7CgC;AA8CrC,OAAK,GA9CgC;AA+CrC,OAAK,GA/CgC;AAgDrC,OAAK,GAhDgC;AAiDrC,OAAK,GAjDgC;AAkDrC,OAAK,GAlDgC;AAmDrC,OAAK,GAnDgC;AAoDrC,OAAK,GApDgC;AAqDrC,OAAK,GArDgC;AAsDrC,OAAK,GAtDgC;AAuDrC,OAAK,GAvDgC;AAwDrC,OAAK,GAxDgC;AAyDrC,OAAK,IAzDgC;AA0DrC,OAAK,GA1DgC;AA2DrC,OAAK,GA3DgC;AA4DrC,OAAK,GA5DgC;AA6DrC,OAAK,GA7DgC;AA8DrC,OAAK,GA9DgC;AA+DrC,OAAK,IA/DgC;AAgErC,OAAK,GAhEgC;AAiErC,OAAK,GAjEgC;AAkErC,OAAK,IAlEgC;AAmErC,OAAK,GAnEgC;AAoErC,OAAK,IApEgC;AAqErC;AACA,OAAK,GAtEgC;AAuErC,OAAK,GAvEgC;AAwErC,OAAK,GAxEgC;AAyErC,OAAK,GAzEgC;AA0ErC,OAAK,GA1EgC;AA2ErC,OAAK,GA3EgC;AA4ErC,OAAK,GA5EgC;AA6ErC,OAAK,GA7EgC;AA8ErC,OAAK,GA9EgC;AA+ErC,OAAK,GA/EgC;AAgFrC,OAAK,GAhFgC;AAiFrC,OAAK,GAjFgC;AAkFrC,OAAK,GAlFgC;AAmFrC,OAAK,GAnFgC;AAoFrC,OAAK,GApFgC;AAqFrC,OAAK,GArFgC;AAsFrC,OAAK,GAtFgC;AAuFrC,OAAK,GAvFgC;AAwFrC,OAAK,GAxFgC;AAyFrC,OAAK,GAzFgC;AA0FrC,OAAK,GA1FgC;AA2FrC,OAAK,GA3FgC;AA4FrC,OAAK,IA5FgC;AA6FrC,OAAK,GA7FgC;AA8FrC,OAAK,GA9FgC;AA+FrC,OAAK,GA/FgC;AAgGrC,OAAK,GAhGgC;AAiGrC,OAAK,GAjGgC;AAkGrC,OAAK,GAlGgC;AAmGrC,OAAK,GAnGgC;AAoGrC,OAAK,GApGgC;AAqGrC,OAAK,GArGgC;AAsGrC,OAAK,GAtGgC;AAuGrC,OAAK,GAvGgC;AAwGrC,OAAK,GAxGgC;AAyGrC,OAAK,GAzGgC;AA0GrC,OAAK,GA1GgC;AA2GrC,OAAK,GA3GgC;AA4GrC,OAAK,GA5GgC;AA6GrC,OAAK,GA7GgC;AA8GrC,OAAK,GA9GgC;AA+GrC,OAAK,GA/GgC;AAgHrC,OAAK,GAhHgC;AAiHrC,OAAK,GAjHgC;AAkHrC,OAAK,GAlHgC;AAmHrC,OAAK,GAnHgC;AAoHrC,OAAK,GApHgC;AAqHrC,OAAK,GArHgC;AAsHrC,OAAK,GAtHgC;AAuHrC,OAAK,GAvHgC;AAwHrC,OAAK,GAxHgC;AAyHrC,OAAK,GAzHgC;AA0HrC,OAAK,GA1HgC;AA2HrC,OAAK,GA3HgC;AA4HrC,OAAK,GA5HgC;AA6HrC,OAAK,GA7HgC;AA8HrC,OAAK,GA9HgC;AA+HrC,OAAK,GA/HgC;AAgIrC,OAAK,IAhIgC;AAiIrC,OAAK,GAjIgC;AAkIrC,OAAK,GAlIgC;AAmIrC,OAAK,GAnIgC;AAoIrC,OAAK,GApIgC;AAqIrC,OAAK,GArIgC;AAsIrC,OAAK,GAtIgC;AAuIrC,OAAK,GAvIgC;AAwIrC,OAAK,GAxIgC;AAyIrC,OAAK,GAzIgC;AA0IrC,OAAK,GA1IgC;AA2IrC;AACA,OAAK,GA5IgC;AA6IrC,OAAK,GA7IgC;AA8IrC,OAAK,GA9IgC;AA+IrC,OAAK,GA/IgC;AAgJrC,OAAK,GAhJgC;AAiJrC,OAAK,GAjJgC;AAkJrC;AACA,OAAK,GAnJgC;AAoJrC,OAAK,GApJgC;AAqJrC,OAAK,GArJgC;AAsJrC,OAAK,GAtJgC;AAuJrC,OAAK,GAvJgC;AAwJrC,OAAK,GAxJgC;AAyJrC,OAAK,IAzJgC;AA0JrC,OAAK,IA1JgC;AA2JrC,OAAK,GA3JgC;AA4JrC,OAAK,GA5JgC;AA6JrC,OAAK,GA7JgC;AA8JrC,OAAK,GA9JgC;AA+JrC,OAAK,GA/JgC;AAgKrC,OAAK,GAhKgC;AAiKrC,OAAK,GAjKgC;AAkKrC,OAAK,GAlKgC;AAmKrC,OAAK,GAnKgC;AAoKrC,OAAK,GApKgC;AAqKrC,OAAK,GArKgC;AAsKrC,OAAK,GAtKgC;AAuKrC,OAAK,GAvKgC;AAwKrC,OAAK,GAxKgC;AAyKrC,OAAK,GAzKgC;AA0KrC,OAAK,GA1KgC;AA2KrC,OAAK,IA3KgC;AA4KrC,OAAK,IA5KgC;AA6KrC,OAAK,IA7KgC;AA8KrC,OAAK,GA9KgC;AA+KrC,OAAK,GA/KgC;AAgLrC,OAAK,EAhLgC;AAiLrC,OAAK,GAjLgC;AAkLrC,OAAK,IAlLgC;AAmLrC,OAAK,IAnLgC;AAoLrC,OAAK,GApLgC;AAqLrC,OAAK,GArLgC;AAsLrC,OAAK,GAtLgC;AAuLrC,OAAK,GAvLgC;AAwLrC,OAAK,GAxLgC;AAyLrC,OAAK,GAzLgC;AA0LrC,OAAK,IA1LgC;AA2LrC,OAAK,IA3LgC;AA4LrC,OAAK,GA5LgC;AA6LrC,OAAK,GA7LgC;AA8LrC,OAAK,GA9LgC;AA+LrC,OAAK,GA/LgC;AAgMrC,OAAK,GAhMgC;AAiMrC,OAAK,GAjMgC;AAkMrC,OAAK,GAlMgC;AAmMrC,OAAK,GAnMgC;AAoMrC,OAAK,GApMgC;AAqMrC,OAAK,GArMgC;AAsMrC,OAAK,GAtMgC;AAuMrC,OAAK,GAvMgC;AAwMrC,OAAK,GAxMgC;AAyMrC,OAAK,GAzMgC;AA0MrC,OAAK,GA1MgC;AA2MrC,OAAK,GA3MgC;AA4MrC,OAAK,IA5MgC;AA6MrC,OAAK,IA7MgC;AA8MrC,OAAK,IA9MgC;AA+MrC,OAAK,GA/MgC;AAgNrC,OAAK,GAhNgC;AAiNrC,OAAK,EAjNgC;AAkNrC,OAAK,GAlNgC;AAmNrC,OAAK,IAnNgC;AAoNrC,OAAK,IApNgC;AAqNrC;AACA,OAAK,IAtNgC;AAuNrC,OAAK,GAvNgC;AAwNrC,OAAK,IAxNgC;AAyNrC,OAAK,GAzNgC;AA0NrC,OAAK,IA1NgC;AA2NrC,OAAK,GA3NgC;AA4NrC,OAAK,IA5NgC;AA6NrC,OAAK,GA7NgC;AA8NrC;AACA,OAAK,GA/NgC;AAgOrC,OAAK,GAhOgC;AAiOrC,OAAK,GAjOgC;AAkOrC,OAAK,GAlOgC;AAmOrC,OAAK,GAnOgC;AAoOrC,OAAK,GApOgC;AAqOrC,OAAK,GArOgC;AAsOrC,OAAK,GAtOgC;AAuOrC,OAAK,GAvOgC;AAwOrC,OAAK,GAxOgC;AAyOrC,OAAK,GAzOgC;AA0OrC,OAAK,GA1OgC;AA2OrC,OAAK,GA3OgC;AA4OrC,OAAK,GA5OgC;AA6OrC,OAAK,GA7OgC;AA8OrC,OAAK,GA9OgC;AA+OrC,OAAK,GA/OgC;AAgPrC,OAAK,GAhPgC;AAiPrC;AACA,OAAK,GAlPgC;AAmPrC,OAAK,GAnPgC;AAoPrC,OAAK,GApPgC;AAqPrC,OAAK,GArPgC;AAsPrC,OAAK,GAtPgC;AAuPrC,OAAK,GAvPgC;AAwPrC,OAAK,GAxPgC;AAyPrC,OAAK,GAzPgC;AA0PrC,OAAK,GA1PgC;AA2PrC,OAAK,GA3PgC;AA4PrC,OAAK,GA5PgC;AA6PrC,OAAK,GA7PgC;AA8PrC,OAAK,GA9PgC;AA+PrC,OAAK,GA/PgC;AAgQrC,OAAK,GAhQgC;AAiQrC,OAAK,GAjQgC;AAkQrC;AACA,OAAK,GAnQgC;AAoQrC,OAAK,GApQgC;AAqQrC,OAAK,GArQgC;AAsQrC,OAAK,GAtQgC;AAuQrC,OAAK,GAvQgC;AAwQrC,OAAK,GAxQgC;AAyQrC,OAAK,GAzQgC;AA0QrC,OAAK,GA1QgC;AA2QrC,OAAK,GA3QgC;AA4QrC,OAAK,GA5QgC;AA6QrC,OAAK,GA7QgC;AA8QrC,OAAK,GA9QgC;AA+QrC,OAAK,GA/QgC;AAgRrC,OAAK,GAhRgC;AAiRrC,OAAK,GAjRgC;AAkRrC,OAAK,GAlRgC;AAmRrC;AACA,OAAK,GApRgC;AAqRrC,OAAK,GArRgC;AAsRrC,OAAK,GAtRgC;AAuRrC,OAAK,GAvRgC;AAwRrC,OAAK,GAxRgC;AAyRrC,OAAK,GAzRgC;AA0RrC;AACA,OAAK,GA3RgC;AA4RrC,OAAK,GA5RgC;AA6RrC,OAAK,GA7RgC;AA8RrC,OAAK,GA9RgC;AA+RrC,OAAK,GA/RgC;AAgSrC,OAAK,GAhSgC;AAiSrC,OAAK,GAjSgC;AAkSrC,OAAK,GAlSgC;AAmSrC;AACA,OAAK,MApSgC;AAqSrC,OAAK,UArSgC;AAsSrC,OAAK,cAtSgC;AAuSrC,OAAK,OAvSgC;AAwSrC,OAAK,MAxSgC;AAySrC,OAAK,MAzSgC;AA0SrC,OAAK,OA1SgC;AA2SrC,OAAK,QA3SgC;AA4SrC,OAAK,OA5SgC;AA6SrC,OAAK,KA7SgC;AA8SrC,OAAK,aA9SgC;AA+SrC,OAAK,MA/SgC;AAgTrC,OAAK,KAhTgC;AAiTrC,OAAK,QAjTgC;AAkTrC,OAAK,SAlTgC;AAmTrC,OAAK,OAnTgC;AAoTrC,OAAK,MApTgC;AAqTrC,OAAK,SArTgC;AAsTrC,OAAK,SAtTgC;AAuTrC,OAAK,SAvTgC;AAwTrC,OAAK,MAxTgC;AAyTrC,OAAK,MAzTgC;AA0TrC,OAAK,KA1TgC;AA2TrC,OAAK,MA3TgC;AA4TrC,OAAK,KA5TgC;AA6TrC,OAAK,MA7TgC;AA8TrC,OAAK,KA9TgC;AA+TrC,OAAK,UA/TgC;AAgUrC,OAAK,MAhUgC;AAiUrC,OAAK,QAjUgC;AAkUrC,OAAK,cAlUgC;AAmUrC;AACA,OAAK,KApUgC;AAqUrC,OAAK,IArUgC;AAsUrC,OAAK,IAtUgC;AAuUrC,OAAK,KAvUgC;AAwUrC,OAAK,KAxUgC;AAyUrC,OAAK,GAzUgC;AA0UrC,OAAK,GA1UgC;AA2UrC,OAAK,GA3UgC;AA4UrC,OAAK,GA5UgC;AA6UrC,OAAK,GA7UgC;AA8UrC,OAAK,GA9UgC;AA+UrC,OAAK,GA/UgC;AAgVrC,OAAK,IAhVgC;AAiVrC,OAAK,IAjVgC;AAkVrC,OAAK,KAlVgC;AAmVrC,OAAK,GAnVgC;AAoVrC,OAAK,GApVgC;AAqVrC,OAAK,GArVgC;AAsVrC,OAAK,GAtVgC;AAuVrC,OAAK,OAvVgC;AAwVrC,OAAK,UAxVgC;AAyVrC,OAAK,MAzVgC;AA0VrC,OAAK,KA1VgC;AA2VrC,OAAK,IA3VgC;AA4VrC,OAAK,MA5VgC;AA6VrC,OAAK,SA7VgC;AA8VrC,OAAK;AA9VgC,CAAvC;;AAiWAvB,KAAKM,QAAL,CAAcC,KAAd,GAAsB;AACpBmB,UAAQ;AACNtB,iBAAa,GADP;AAENI,aAAS,IAFH;AAGNiB,YAAQ,MAHF;AAINF,aAASvB,KAAKM,QAAL,CAAciB,OAJjB;AAKNZ,kBAAcX,KAAKM,QAAL,CAAcK;AALtB;AADY,CAAtB;;AAUA,IAAMgB,QAAQ;AACZC,WAAS5B,IADG;;AAGZ6B,iBAHY,2BAGKC,SAHL,EAGgB;AAC1B,WAAOC,eAAeC,SAAf,CAAyB5C,KAAzB,CAA+B,YAA/B,EAA6C,CAA7C,IACL,GADK,GACCuC,MAAMM,iBAAN,CAAwBH,SAAxB,CADR;AAED,GANW;AAQZI,YARY,sBAQAC,GARA,EAQK;AACf,WAAO,CAAC,CAACA,IAAI/C,KAAJ,CAAU,wBAAV,CAAT;AACD,GAVW;AAYZ6C,mBAZY,6BAYOhC,MAZP,EAYe;AACzB,WAAOA,OAAOb,KAAP,CAAa,YAAb,EAA2B,CAA3B,CAAP;AACD,GAdW;AAgBZgD,oBAhBY,8BAgBQnC,MAhBR,EAgBgB;AAC1B,WAAOA,OAAOb,KAAP,CAAa,YAAb,EAA2B,CAA3B,CAAP;AACD,GAlBW;AAoBZiD,YApBY,sBAoBAC,CApBA,EAoBGC,CApBH,EAoBM;AAChB,WAAOZ,MAAMS,kBAAN,CAAyBE,CAAzB,IAA8B,GAA9B,GAAoCX,MAAMM,iBAAN,CAAwBM,CAAxB,CAA3C;AACD,GAtBW;AAwBZC,cAxBY,wBAwBEC,WAxBF,EAwBeC,KAxBf,EAwBsBC,QAxBtB,EAwBgC;AAC1C,QAAIA,QAAJ,EAAc;AACZ,aAAOhB,MAAMiB,QAAN,CAAeH,eAAe,EAA9B,EAAkCC,KAAlC,CAAP;AACD,KAFD,MAEO;AACL,aAAOf,MAAMkB,aAAN,CAAoBJ,eAAe,EAAnC,EAAuCC,KAAvC,CAAP;AACD;AACF,GA9BW;AAgCZE,UAhCY,oBAgCFH,WAhCE,EAgCWC,KAhCX,EAgCkB;AAC5B,SAAK,IAAIvB,MAAI,CAAb,EAAgBA,MAAIsB,YAAY5B,MAAhC,EAAwCM,KAAxC,EAA6C;AAC3C,UAAIsB,YAAYtB,GAAZ,MAAmBuB,KAAvB,EAA8B;AAC5B,eAAOD,WAAP;AACD;AACF;AACD,QAAM1D,KAAK0D,YAAYK,KAAZ,EAAX;AACA/D,OAAGgC,IAAH,CAAQ2B,KAAR;AACA,WAAO3D,EAAP;AACD,GAzCW;AA2CZ8D,eA3CY,yBA2CGJ,WA3CH,EA2CgBC,KA3ChB,EA2CuB;AACjC,QAAI3D,KAAK,IAAT;AACA,QAAIgE,MAAM,CAAV;AACA,SAAK,IAAI5B,MAAI,CAAb,EAAgBA,MAAIsB,YAAY5B,MAAhC,EAAwCM,KAAxC,EAA6C;AAC3C,UAAIsB,YAAYtB,GAAZ,MAAmBuB,KAAvB,EAA8B;AAC5B,YAAI3D,OAAO,IAAX,EAAiB;AACfA,eAAK0D,YAAYK,KAAZ,EAAL;AACD;AACD/D,WAAGiE,MAAH,CAAU7B,MAAK4B,KAAf,EAAuB,CAAvB;AACD;AACF;AACD,WAAQhE,OAAO,IAAR,GAAgB0D,WAAhB,GAA8B1D,EAArC;AACD,GAvDW;AAyDZkE,yBAzDY,mCAyDaX,CAzDb,EAyDgBC,CAzDhB,EAyDmB;AAC7B,QAAKD,KAAK,IAAN,IAAgBC,KAAK,IAAzB,EAAgC;AAC9B,aAAO,KAAP;AACD;AACD,WAAOZ,MAAMS,kBAAN,CAAyBE,CAAzB,MAAgCX,MAAMS,kBAAN,CAAyBG,CAAzB,CAAvC;AACD,GA9DW;AAgEZW,6BAhEY,uCAgEiBC,SAhEjB,EAgE4B;AACtC,QAAMC,OAAOrB,eAAeC,SAAf,CAAyB5C,KAAzB,CAA+B,YAA/B,EAA6C,CAA7C,CAAb;AACA,QAAI+D,UAAU7B,MAAV,CAAiB,CAAjB,EAAoB8B,KAAKvC,MAAzB,MAAqCuC,IAAzC,EAA+C;AAC7C,aAAO,IAAP;AACD;AACD,WAAO,MAAMD,UAAU7B,MAAV,CAAiB8B,KAAKvC,MAAtB,EAA8BzB,KAA9B,CAAoC,eAApC,EAAqD,CAArD,CAAb;AACD,GAtEW;AAwEZiE,iBAxEY,2BAwEKC,MAxEL,EAwEa;AACvB,WAAOA,OAAOlE,KAAP,CAAa,kBAAb,EAAiC,CAAjC,CAAP;AACD,GA1EW;AA4EZmE,WA5EY,qBA4EDpB,GA5EC,EA4EI;AACd,WAAOJ,eAAeyB,UAAf,GAA4B,MAA5B,GAAqCrB,GAA5C;AACD,GA9EW;AAgFZsB,UAhFY,oBAgFFtB,GAhFE,EAgFGuB,MAhFH,EAgFWC,OAhFX,EAgFoBC,aAhFpB,EAgFmC;AAC7CD,cAAUA,WAAW,EAArB;AACA,WAAOC,cAAc,UAACC,OAAD,EAAUC,MAAV,EAAqB;AACxC,uBAAOC,IAAP,CAAY;AACV5B,aAAKR,MAAM4B,SAAN,CAAgBpB,GAAhB,CADK;AAEV6B,cAAMN,MAFI;AAGVO,gBAAQN,QAAQM,MAAR,IAAkB;AAHhB,OAAZ,EAIGC,IAJH,CAIQ,UAACF,IAAD,EAAU;AAChBH,gBAAQG,IAAR;AACD,OAND,EAMGG,IANH,CAMQ,YAAM;AACZL,eAAO;AACLM,gBAAM;AADD,SAAP;AAGD,OAVD;AAWD,KAZM,CAAP;AAaD,GA/FW;AAiGZC,YAjGY,sBAiGAlC,GAjGA,EAiGKwB,OAjGL,EAiGcC,aAjGd,EAiG6B;AACvCD,cAAUA,WAAW,EAArB;AACAA,YAAQxB,GAAR,GAAcR,MAAM4B,SAAN,CAAgBpB,GAAhB,CAAd;AACA,QAAIwB,QAAQW,IAAR,KAAiBzE,SAArB,EAAgC;AAC9B8D,cAAQK,IAAR,GAAeO,KAAKC,SAAL,CAAeb,QAAQW,IAAvB,CAAf;AACAX,cAAQc,WAAR,GAAsB,kBAAtB;AACA,aAAOd,QAAQW,IAAf;AACD;AACD,QAAI,CAACX,QAAQM,MAAb,EAAqB;AACnBN,cAAQM,MAAR,GAAiB,KAAjB;AACD;;AAED,WAAOL,cAAc,UAACC,OAAD,EAAUC,MAAV,EAAqB;AACxC,uBAAOC,IAAP,CAAYJ,OAAZ,EACGO,IADH,CACQ,UAACF,IAAD,EAAU;AACdH,gBAAQG,IAAR;AACD,OAHH,EAIGG,IAJH,CAIQ,YAAM;AACVL,eAAO;AACLM,gBAAM;AADD,SAAP;AAGD,OARH;AASD,KAVM,CAAP;AAWD,GAxHW;AA0HZM,aA1HY,uBA0HCpB,MA1HD,EA0HS;AACnB,QAAIqB,WAAWrB,OAAOlE,KAAP,CAAa,eAAb,EAA8B,CAA9B,EAAiCO,KAAjC,CAAuC,GAAvC,CAAf;AACA,QAAIgF,SAAS9D,MAAT,KAAoB,CAApB,IAAyB8D,SAAS,CAAT,MAAgB,EAA7C,EAAiD;AAC/CA,iBAAW,EAAX;AACD;AACDA,aAASC,OAAT,CAAiB,MAAjB;AACA,WAAOD,SAASE,IAAT,CAAc,GAAd,CAAP;AACD,GAjIW;AAmIZC,aAnIY,uBAmICC,OAnID,EAmIU;AACpB,QAAMJ,WAAWI,QAAQ3F,KAAR,CAAc,aAAd,EAA6B,CAA7B,EAAgCO,KAAhC,CAAsC,GAAtC,CAAjB;AACA,QAAIgF,SAAS9D,MAAT,GAAkB,CAAlB,IAAuB8D,SAAS,CAAT,MAAgB,MAA3C,EAAmD;AACjD,aAAO,IAAP;AACD;AACDA,aAAS,CAAT,IAAc,EAAd;AACA,WAAOA,SAASE,IAAT,CAAc,GAAd,CAAP;AACD,GA1IW;AA4IZG,mBA5IY,6BA4IOD,OA5IP,EA4IgB;AAC1B,QAAI,CAACA,OAAL,EAAc;AACZ,aAAO,IAAP;AACD;AACD,QAAMhG,KAAKgG,QAAQ3F,KAAR,CAAc,aAAd,EAA6B,CAA7B,EAAgCO,KAAhC,CAAsC,GAAtC,CAAX;AACA,QAAIZ,GAAG8B,MAAH,IAAa,CAAb,IAAkB9B,GAAG,CAAH,MAAU,MAAhC,EAAwC;AACtC,aAAOA,GAAG+D,KAAH,CAAS,CAAT,CAAP;AACD;AACD,WAAO,IAAP;AACD,GArJW;AAuJZmC,kBAvJY,8BAuJQ;AAClB,WAAOC,SAASC,IAAT,CAAcC,YAAd,GAA6BF,SAASC,IAAT,CAAcE,SAA3C,IACLH,SAASC,IAAT,CAAcG,YADhB;AAED,GA1JW;AA4JZC,aA5JY,yBA4JG;AACb,QAAIC,UAAUC,UAAV,CAAqB3E,OAArB,CAA6B,KAA7B,MAAwC,CAAC,CAA7C,EAAgD;AAC9C,aAAO,SAAP;AACD,KAFD,MAEO,IAAI0E,UAAUC,UAAV,CAAqB3E,OAArB,CAA6B,KAA7B,MAAwC,CAAC,CAA7C,EAAgD;AACrD,aAAO,KAAP;AACD,KAFM,MAEA,IAAI0E,UAAUC,UAAV,CAAqB3E,OAArB,CAA6B,KAA7B,MAAwC,CAAC,CAAzC,IACP0E,UAAUC,UAAV,CAAqB3E,OAArB,CAA6B,OAA7B,MAA0C,CAAC,CADxC,EAC2C;AAChD,aAAO,OAAP;AACD;AACD,WAAO,OAAP;AACD,GAtKW;AAwKZ4E,WAxKY,qBAwKDC,KAxKC,EAwKM;AAChB,QAAIhE,MAAM4D,WAAN,OAAwB,KAA5B,EAAmC;AACjC,aAAOI,MAAMC,OAAb;AACD,KAFD,MAEO;AACL,aAAOD,MAAME,OAAb;AACD;AACF;AA9KW,CAAd;;kBAiLelE,K;;;;;;;;;;AC9kBf;;;;;;;;;;AACA;;;;AACA;;;;;;;;;;;;IAEMmE,S;;;AACJ,qBAAaC,KAAb,EAAoB;AAAA;;AAAA,sHACZA,KADY;;AAElB,UAAKC,2BAAL,GAAmC,IAAnC;AAFkB;AAGnB;;AAED;;;;;sCACmB;AACjB,aAAO;AACLC,iBAAS,KAAKF,KAAL,CAAWE,OADf;AAELC,kBAAU,KAAKH,KAAL,CAAWG,QAFhB;AAGLxC,gBAAQ,KAAKqC,KAAL,CAAWrC,MAHd;AAILyC,eAAO,KAAKJ,KAAL,CAAWI,KAJb;AAKLC,qBAAa,KAAKL,KAAL,CAAWK,WALnB;AAMLC,gBAAQ,KAAKN,KAAL,CAAWM;AANd,OAAP;AAQD;;AAED;;;;uCACoBC,I,EAAM5C,M,EAAQ;AAAA;;AAChC,UAAI6C,QAAQ,KAAKR,KAAL,CAAWM,MAAX,CAAkBG,GAAlB,CAAsB,UAACC,CAAD;AAAA,eAAOA,EAAEH,IAAT;AAAA,OAAtB,CAAZ;AACA,UAAIA,SAAS,IAAb,EAAmB;AACjB,YAAIA,KAAKhF,MAAL,CAAY,CAAZ,EAAe,CAAf,MAAsB,GAA1B,EAA+B;AAC7BiF,gBAAMA,MAAM1F,MAAN,GAAe,CAArB,IAA0ByF,KAAKhF,MAAL,CAAY,CAAZ,CAA1B;AACD,SAFD,MAEO;AACLiF,kBAAQD,KAAK3G,KAAL,CAAW,GAAX,CAAR;AACD;AACF;;AAED,UAAMZ,KAAK,EAAX;AACA,UAAI2H,OAAO,KAAKX,KAAL,CAAWM,MAAX,CAAkB,CAAlB,CAAX;AACA,UAAIK,KAAKJ,IAAL,KAAcC,MAAMI,KAAN,EAAlB,EAAiC;AAC/B,eAAO,IAAP;AACD;AACD5H,SAAGgC,IAAH,CAAQ2F,KAAKE,IAAb;;AAEAL,YAAMtH,OAAN,CAAc,UAAC4H,IAAD,EAAU;AACtB,aAAK,IAAI1F,IAAI,CAAb,EAAgBA,IAAIuF,KAAKI,WAAL,CAAiBjG,MAArC,EAA6CM,GAA7C,EAAkD;AAChD,cAAIuF,KAAKI,WAAL,CAAiB3F,CAAjB,EAAoBmF,IAApB,KAA6BO,IAAjC,EAAuC;AACrCH,mBAAOA,KAAKI,WAAL,CAAiB3F,CAAjB,CAAP;AACApC,eAAGgC,IAAH,CAAQ2F,KAAKE,IAAb;AACA;AACD;AACF;AACDF,eAAO,IAAP;AACD,OATD;;AAWA,aAAO3H,GAAG8F,IAAH,CAAQ,GAAR,EAAarD,OAAb,CAAqB,aAArB,EAAoC,UAACuF,CAAD,EAAO;AAChD,YAAM7H,MAAM6H,EAAEzF,MAAF,CAAS,CAAT,CAAZ;AACA,eAAOoC,OAAOxE,GAAP,KAAe,OAAK6G,KAAL,CAAWrC,MAAX,CAAkBxE,GAAlB,CAAtB;AACD,OAHM,CAAP;AAID;;AAED;;;;0CACuBoH,I,EAAM5C,M,EAAQ;AACnC,WAAKqC,KAAL,CAAWE,OAAX,CAAmBe,SAAnB,CAA6B,IAA7B,EAAmC,KAAKC,kBAAL,CAAwBX,IAAxB,EAA8B5C,MAA9B,CAAnC;AACD;;;wCAEoB;AACnB;AACA,UAAI,KAAKqC,KAAL,CAAWE,OAAX,KAAuBpG,SAA3B,EAAsC;AACpC,aAAKmG,2BAAL,GAAmC,KAAKD,KAAL,CAAWE,OAAX,CAAmBiB,wBAAnB,CACjC,KAAKnB,KAAL,CAAWI,KADsB,EACf,KAAKgB,eAAL,CAAqBC,IAArB,CAA0B,IAA1B,CADe,CAAnC;AAED;AACF;;;2CAEuB;AACtB;AACA,UAAI,KAAKpB,2BAAT,EAAsC;AACpC,aAAKA,2BAAL;AACD;AACF;;;oCAEgBqB,Y,EAAc;AAC7B,UAAI,uBAAaC,iBAAb,EAAJ,EAAsC;AACpC,eAAO,KAAP;AACD,OAFD,MAEO;AACL,+BAAaC,aAAb;AACD;AACF;;;;;;kBAEYzB,S;;;;;;;;;;;;;ACrFf;;;;AACA;;;;;;AAEA,IAAM0B,gBAAgB,SAAhBA,aAAgB,CAACC,KAAD,EAAW;AAC/B,MAAI,CAAC,uBAAaC,YAAb,EAAL,EAAkC;AAChC,2BAAaC,UAAb,wBAAqC;AACnCF,aAAOA;AAD4B,KAArC;AAGD;AACF,CAND;;AAQA,IAAMG,kBAAkB,SAAlBA,eAAkB,CAACC,QAAD,EAAwC;AAAA,MAA7BC,QAA6B,uEAAlBN,aAAkB;;AAC9D,MAAMzI,KAAK,IAAIgJ,OAAJ,CAAYF,QAAZ,CAAX;AACA,MAAMG,OAAOjJ,GAAGiJ,IAAhB;AACA,MAAIC,sBAAsB,KAA1B;;AAEAlJ,KAAGiJ,IAAH,CAAQ,IAAR,EAAc,UAACtF,KAAD,EAAW;AACvB,QAAI,CAACuF,mBAAL,EAA0B;AACxB,aAAOH,SAASpF,KAAT,CAAP;AACD;AACF,GAJD;;AAMA3D,KAAGiJ,IAAH,GAAU,UAACE,WAAD,EAAcC,UAAd,EAA6B;AACrC,QAAIA,UAAJ,EAAgB;AACdF,4BAAsB,IAAtB;AACD;AACD,WAAOD,KAAKI,IAAL,CAAUrJ,EAAV,EAAcmJ,WAAd,EAA2BC,UAA3B,CAAP;AACD,GALD;;AAOA,SAAOpJ,EAAP;AACD,CAnBD;;kBAqBe6I,e;;;;;;;;;;;AChCf;;;;;;;;AAEA;;;;AACA;;;;;;IAEMS,Y;AACJ,0BAAe;AAAA;;AACb,SAAKC,eAAL,GAAuB,IAAvB;AACD;;AAED;;;;;yCACsBC,M,EAAQ;AAC5B,WAAKD,eAAL,GAAuBC,MAAvB;AACD;;AAED;AACA;;;;+BACYA,M,EAAQ5E,O,EAAS;AAC3B;AACA;AACA,UAAI,CAAC,KAAK2D,iBAAL,EAAL,EAA+B;AAC7B,sBAAIkB,IAAJ,CAAS,+BAAuB;AAC9BD,kBAAQA,MADsB;AAE9BE,yBAAe9E,WAAW;AAFI,SAAvB,CAAT;AAID;AACF;;AAED;;;;oCACiB;AACf,UAAI,CAAC,KAAK2D,iBAAL,EAAL,EAA+B;AAC7B,sBAAIkB,IAAJ,CAAS,+BAAuB;AAC9BE,yBAAe;AADe,SAAvB,CAAT;AAGD;AACF;;AAED;;;;mCACgB;AACd,aAAO,CAAC,CAAC,KAAKJ,eAAd;AACD;;AAED;;;;wCACqB;AACnB,aACE,KAAKA,eAAL,IACA,KAAKA,eAAL,CAAqBhB,iBAArB,KAA2CzH,SAD3C,IAEA,KAAKyI,eAAL,CAAqBhB,iBAArB,EAHF;AAKD;;;;;;AAGH,IAAMqB,eAAe,IAAIN,YAAJ,EAArB;;kBAEeM,Y;;;;;;ACtDf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,CAAC;AACD;AACA;AACA;AACA;;;;;;;;;;;AC7BA;;;;;;;;;;AAEA;;;;AACA;;;;;;;;;;;;AAEA;;IAEMC,e;;;;;;;;;;;;AACJ;4CACyB;AACvB,UAAMvC,SAAS,KAAKN,KAAL,CAAWM,MAA1B;AACA,aACEA,OAAOxF,MAAP,GAAgB,CAAhB,IACAwF,OAAOA,OAAOxF,MAAP,GAAgB,CAAvB,EAA0BgI,SAA1B,CAAoCvC,IAApC,KAA6C,aAF/C;AAID;;AAED;;;;4CACyB;AACvB,UAAMM,OAAO,KAAKb,KAAL,CAAWrC,MAAX,CAAkBkD,IAA/B;AACA,aAAOA,OAAO,gBAAM5B,iBAAN,CAAwB4B,IAAxB,CAAP,GAAuC,EAA9C;AACD;;;2CAEuB;AACtB,UAAMA,OAAO,KAAKb,KAAL,CAAWrC,MAAX,CAAkBkD,IAA/B;AACA,UAAI,CAACA,IAAL,EAAW;AACT,eAAO,CAAC,IAAD,EAAO,IAAP,CAAP;AACD;AACD,UAAMkC,QAAQlC,KAAKjH,KAAL,CAAW,IAAX,EAAiB,CAAjB,CAAd;AACA,aAAO,CAAC,gBAAMmF,WAAN,CAAkBgE,MAAM,CAAN,CAAlB,CAAD,EAA8BA,MAAM,CAAN,CAA9B,CAAP;AACD;;AAED;;;;;oCAEiB;AAAA,kCACA,KAAKC,oBAAL,EADA;AAAA;AAAA,UACRnC,IADQ;;AAEf,aAAOA,IAAP;AACD;;AAED;;;;mCACgB;AAAA,kCACE,KAAKmC,oBAAL,EADF;AAAA;AAAA,UACLC,GADK;;AAEd,aAAO,CAACA,GAAD,GAAO,UAAP,GAAoBA,GAA3B;AACD;;AAED;;;;;4CAEyBC,O,EAASC,M,EAAQ;AACxC,UAAID,YAAYpJ,SAAZ,IAAyBoJ,YAAY,IAAzC,EAA+C;AAC7CA,kBAAU,KAAKE,aAAL,EAAV;AACD;AACD,UAAID,WAAWrJ,SAAX,IAAwBqJ,WAAW,IAAvC,EAA6C;AAC3CA,iBAAS,KAAKE,YAAL,EAAT;AACD;AACD,UAAIrK,KAAK,gBAAM2F,WAAN,CAAkBuE,OAAlB,CAAT;AACA,UAAIC,WAAW,UAAf,EAA2B;AACzBnK,cAAM,MAAMmK,MAAZ;AACD;AACD,aAAOnK,EAAP;AACD;;AAED;;;;0CACuB;AACrB,aAAO,gBAAMsE,eAAN,CAAsB,KAAK8F,aAAL,EAAtB,CAAP;AACD;;AAED;;;;mCACgB;AACd,aAAO,KAAKA,aAAL,OAAyB,EAAhC;AACD;;AAED;;;;sCACmB;AACjB,UAAMxE,WAAW,KAAK0E,qBAAL,EAAjB;AACA,UAAI1E,aAAa,IAAjB,EAAuB;AACrB,eAAO,EAAP;AACD;;AAEDA,eAASC,OAAT,CAAiB,MAAjB;;AAEA,UAAM7F,KAAK,EAAX;AACA,WAAK,IAAIoC,IAAI,CAAb,EAAgBA,IAAIwD,SAAS9D,MAA7B,EAAqCM,GAArC,EAA0C;AACxC,YAAMmI,UAAU3E,SAAS7B,KAAT,CAAe,CAAf,EAAkB3B,IAAI,CAAtB,EAAyB0D,IAAzB,CAA8B,GAA9B,CAAhB;AACA9F,WAAGgC,IAAH,CAAQ;AACNwI,cAAI,UAAUD,OADR;AAENvE,mBAASuE,OAFH;AAGN3E,oBAAUA,SAAS7B,KAAT,CAAe,CAAf,EAAkB3B,IAAI,CAAtB,CAHJ;AAINqI,iBAAO7E,SAASxD,CAAT;AAJD,SAAR;AAMD;;AAED,aAAOpC,EAAP;AACD;;;;;;kBAGY6J,e;;;;;;;;;;;AC/Ff;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,oC;;;;;;;+CCdA;;AAEA;;AAEA,sCAAsC,uCAAuC,kBAAkB;;AAE/F;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,oC;;;;;;;;AC3CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,qBAAqB,WAAW;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;;AAEA;;;;;;;;;;;;;;;AC3DA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,E;;;;;;;;;;;AC9BA;;;;;;;;;;IAEMa,G;AACJ,iBAAe;AAAA;;AACb,SAAKC,cAAL,GAAsB,EAAtB;AACD;;AAED;;;;;8BACW/D,K,EAAOkC,Q,EAAU;AAC1B,UAAI,OAAOlC,KAAP,KAAiB,QAArB,EAA+B;AAC7BA,gBAAQA,MAAMgE,YAAN,EAAR;AACD;;AAED,UAAIC,OAAO,KAAKF,cAAL,CAAoB/D,KAApB,CAAX;AACA,UAAIiE,SAAS/J,SAAb,EAAwB;AACtB,aAAK6J,cAAL,CAAoB/D,KAApB,IAA6BiE,OAAO,EAApC;AACD;;AAED,WAAK,IAAIzI,IAAI,CAAb,EAAgBA,IAAIyI,KAAK/I,MAAzB,EAAiCM,GAAjC,EAAsC;AACpC,YAAIyI,KAAKzI,CAAL,MAAY0G,QAAhB,EAA0B;AACxB,iBAAO,KAAP;AACD;AACF;;AAED+B,WAAK7I,IAAL,CAAU8G,QAAV;AACA,aAAO,IAAP;AACD;;AAED;;;;gCACalC,K,EAAOkC,Q,EAAU;AAC5B,UAAI,OAAOlC,KAAP,KAAiB,QAArB,EAA+B;AAC7BA,gBAAQA,MAAMgE,YAAN,EAAR;AACD;;AAED,UAAMC,OAAO,KAAKF,cAAL,CAAoB/D,KAApB,CAAb;AACA,UAAIiE,SAAS/J,SAAb,EAAwB;AACtB,eAAO,KAAP;AACD;;AAED,WAAK,IAAIsB,IAAI,CAAb,EAAgBA,IAAIyI,KAAK/I,MAAzB,EAAiCM,GAAjC,EAAsC;AACpC,YAAIyI,KAAKzI,CAAL,MAAY0G,QAAhB,EAA0B;AACxB+B,eAAK5G,MAAL,CAAY7B,CAAZ,EAAe,CAAf;AACA,iBAAO,IAAP;AACD;AACF;AACD,aAAO,KAAP;AACD;;AAED;;;;yBACMwE,K,EAAO;AACX,UAAMiE,OAAO,KAAKF,cAAL,CAAoB/D,MAAMkE,IAA1B,CAAb;AACA,UAAID,SAAS/J,SAAb,EAAwB;AACtB+J,aAAK3K,OAAL,CAAa,UAAC4I,QAAD,EAAc;AACzB,cAAI;AACFA,qBAASlC,KAAT;AACD,WAFD,CAEE,OAAOmE,CAAP,EAAU;AACVC,oBAAQC,GAAR,CAAY,yBAAZ,EAAuCF,CAAvC,EAA0C,WAA1C,EACEjC,QADF,EACY,QADZ,EACsBlC,KADtB;AAED;AACF,SAPD;AAQD;AACF;;;;;;AAGH,IAAMsE,MAAM,IAAIR,GAAJ,EAAZ;;kBAEeQ,G;;;;;;;AClEf;;;;;;;;;;;;;;IAEMC,K;;;;;;;+BAKQ;AACV,aAAO,YAAY,KAAKL,IAAjB,GAAwB,GAA/B;AACD;;;wBANW;AACV,aAAOnJ,OAAOyJ,cAAP,CAAsB,IAAtB,EAA4BC,WAA5B,CAAwCT,YAAxC,EAAP;AACD;;;;;;AAOHO,MAAMP,YAAN,GAAqB,YAAY;AAC/B,SAAO,KAAKrD,IAAZ;AACD,CAFD;;IAIM+D,W;;;AACJ,uBAAa1G,OAAb,EAAsB;AAAA;;AAAA,0HACdA,UAAUA,WAAW,EADP;;AAEpB,UAAK2G,UAAL,GAAkB3G,QAAQ2G,UAA1B;AAFoB;AAGrB;;;EAJuBJ,K;;IAOpBK,uB;;;AACJ,mCAAa5G,OAAb,EAAsB;AAAA;;AAAA,mJACdA,UAAUA,WAAW,EADP;;AAEpB,WAAK6G,gBAAL,GAAwB7G,QAAQ6G,gBAAR,IAA4B,EAApD;AACA,WAAKC,kBAAL,GAA0B9G,QAAQ8G,kBAAR,IAA8B,EAAxD;AAHoB;AAIrB;;;EALmCJ,W;;IAQhCK,kB;;;AACJ,8BAAa/G,OAAb,EAAsB;AAAA;;AAAA,yIACdA,UAAUA,WAAW,EADP;;AAEpB,WAAK4E,MAAL,GAAc5E,QAAQ4E,MAAtB;AACA,WAAKE,aAAL,GAAqB9E,QAAQ8E,aAA7B;AAHoB;AAIrB;;;EAL8ByB,K;;QAS/BA,K,GAAAA,K;QACAG,W,GAAAA,W;QACAE,uB,GAAAA,uB;QACAG,kB,GAAAA,kB;;;;;;;AC3CF;;AAEA;AACA;AACA,8B;;;;;;;;;;;;;;ACJA;;;;AACA;;;;;;AAEA,SAASC,iBAAT,CAA4BhH,OAA5B,EAAqC;AACnC,OAAKiH,OAAL,GAAejH,QAAQiH,OAAR,IAAmB,eAAK9K,KAAL,CAAW,eAAX,CAAlC;AACA,OAAK+J,IAAL,GAAYlG,QAAQkG,IAAR,IAAgB,OAA5B;AACD;;AAED,IAAMgB,mBAAmB;AACvBC,aAAW;AACTpI,WAAO,oBAAUqI,GADR;AAETlB,UAAM,oBAAUmB,MAFP;AAGTC,iBAAa,oBAAUF,GAHd;AAITG,cAAU,oBAAUC;AAJX,GADY;;AAQvBC,eARuB,2BAQN;AACf,QAAIrM,KAAK,cAAT;AACA,QAAI,KAAKgH,KAAL,CAAW8D,IAAX,CAAgBwB,IAAhB,KAAyB,OAA7B,EAAsC;AACpCtM,WAAK,cAAcA,EAAnB;AACD,KAFD,MAEO,IAAI,KAAKgH,KAAL,CAAW8D,IAAX,CAAgBwB,IAAhB,KAAyB,OAA7B,EAAsC;AAC3CtM,WAAK,cAAcA,EAAnB;AACD;AACD,WAAOA,EAAP;AACD,GAhBsB;AAkBvBuM,sBAlBuB,kCAkBC;AACtB,QAAI,KAAKC,wBAAT,EAAmC;AACjC,aAAO,KAAKA,wBAAL,EAAP;AACD;AACD,WAAO,IAAP;AACD;AAvBsB,CAAzB;;QA2BEZ,iB,GAAAA,iB;QACAE,gB,GAAAA,gB;;;;;;;;;;;;;;;;;;;ACpCF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,C;;;;;;;AC/EA;;;;;;;;;;;;AAEA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;;;;;;;;;;;IAEMW,W;;;AACJ,uBAAazF,KAAb,EAAoB;AAAA;;AAAA,0HACZA,KADY;;AAElB,UAAK0F,WAAL,GAAmB,MAAKA,WAAL,CAAiBrE,IAAjB,OAAnB;AAFkB;AAGnB;;;;wCAEoB;AACnB;AACA,UAAI,KAAKrB,KAAL,CAAW2F,aAAf,EAA8B;AAC5BC,eAAOC,gBAAP,CAAwB,SAAxB,EAAmC,KAAKH,WAAxC;AACD;AACF;;;2CAEuB;AACtBE,aAAOE,mBAAP,CAA2B,SAA3B,EAAsC,KAAKJ,WAA3C;AACA;AACD;;;gCAEY9F,K,EAAO;AAClB,UAAIA,MAAMmG,KAAN,KAAgB,EAAhB,IAAsB,KAAK/F,KAAL,CAAW2F,aAArC,EAAoD;AAClD/F,cAAMoG,cAAN;AACA,+BAAaxE,aAAb;AACD;AACF;;;kCAEc5B,K,EAAO;AACpBA,YAAMoG,cAAN;AACA,6BAAaxE,aAAb;AACD;;;6BAES;AAAA,mBACqD,KAAKxB,KAD1D;AAAA,UACHiG,QADG,UACHA,QADG;AAAA,UACOxC,KADP,UACOA,KADP;AAAA,UACcyC,cADd,UACcA,cADd;AAAA,UAC8BC,SAD9B,UAC8BA,SAD9B;AAAA,UAC4CnG,KAD5C;;AAERmG,kBAAY,CAACA,aAAa,EAAd,IAAoB,0BAAhC;AACA,aACE;AAAA;AAAA,mBAAK,WAAWA,SAAhB,IAA+BnG,KAA/B;AACE;AAAA;AAAA,YAAK,WAAU,0BAAf;AAEIkG,4BACA;AAAA;AAAA;AACE,oBAAK,GADP;AAEE,yBAAU,WAFZ;AAGE,uBAAS,KAAKE,aAAL,CAAmB/E,IAAnB,CAAwB,IAAxB;AAHX;AAKI,2BAAKtH,KAAL,CAAW,OAAX;AALJ,WAHJ;AAWE;AAAA;AAAA;AAAK0J;AAAL,WAXF;AAYGwC;AAZH;AADF,OADF;AAkBD;;;;;;AAGHR,YAAYV,SAAZ,GAAwB;AACtBtB,SAAO,oBAAUvJ,MADK;AAEtBgM,kBAAgB,oBAAUG,IAFJ;AAGtBV,iBAAe,oBAAUU;AAHH,CAAxB;;kBAMeZ,W;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+CCpEf;;AAEA;;AAEA,sCAAsC,uCAAuC,kBAAkB;;AAE/F;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;AACH,8JAA8J;AAC9J;AACA;;AAEA;AACA,oC;;;;;;;;ACvBA;;;;;;;;;;AAEA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;AACA;;;;AACA;;;;AACA;;;;;;;;;;;;AAEA,IAAMa,mBAAmB;AACvB,qBAAmB,2BAAiBC,yBADb;AAEvB,oBAAkB,2BAAiBC,wBAFZ;AAGvB,gBAAc,2BAAiBC,eAHR;AAIvB,aAAW,2BAAiBC,kBAJL;AAKvB,WAAS,2BAAiBC,gBALH;AAMvB,cAAY,2BAAiBC,kBANN;AAOvB,SAAO,2BAAiBC,cAPD;AAQvB,UAAQ,2BAAiBC,eARF;AASvB,UAAQ,qBAAWC,UATI;AAUvB,gBAAc,uBAAaC,qBAVJ;AAWvB,YAAU,uBAAaC,iBAXA;AAYvB,YAAU,sBAAYC,UAZC;AAavB,eAAa,sBAAYC,aAbF;AAcvB,YAAU,sBAAYC,UAdC;AAevB,eAAa,sBAAYC;AAfF,CAAzB;;AAkBA,IAAMC,iBAAiB,gBAAMC,WAAN,CAAkB;AAAA;;AACvCC,UAAQ,0BAD+B;AAEvCC,QAFuC,oBAE7B;AACR,WACE;AAAA;AAAA;AACE;AAAA;AAAA;AAAA;AACW,aAAKzH,KAAL,CAAW8D,IAAX,CAAgB4D,MAD3B;AAAA;AAEkB,aAAK1H,KAAL,CAAW8D,IAAX,CAAgBvD,IAFlC;AAAA;AAAA;AADF,KADF;AAQD;AAXsC,CAAlB,CAAvB;;IAcMoH,Q;;;;;;;;;;;6BACM;AAAA,mBACgD,KAAK3H,KADrD;AAAA,UACD4H,KADC,UACDA,KADC;AAAA,UACMjL,KADN,UACMA,KADN;AAAA,UACawI,QADb,UACaA,QADb;AAAA,UACuBD,WADvB,UACuBA,WADvB;AAAA,UACoC2C,QADpC,UACoCA,QADpC;;AAER,UAAM1B,YAAY,YAAY2B,gBAAgBF,KAAhB,CAAZ,GAAqC,YAAvD;AACA,UAAIG,iBAAiB,OAArB;AACA,UAAIC,cAAJ;;AAEA,UAAIJ,MAAMrH,IAAN,CAAWhF,MAAX,CAAkB,CAAlB,EAAqB,CAArB,MAA4B,GAAhC,EAAqC;AACnCwM,0BAAkB,eAAlB;AACD;;AAED,UAAME,SAASC,+BAA+BN,MAAM9D,IAArC,CAAf;AACA,UAAImE,OAAOE,YAAX,EAAyB;AACvBH,gBAAQ,8BAAC,MAAD,IAAQ,KAAKJ,MAAMrH,IAAnB,EAAyB,MAAMqH,MAAM9D,IAArC,EAA2C,OAAO8D,KAAlD,GAAR;AACD,OAFD,MAEO;AACL,YAAIQ,cAAc,IAAlB;AACA,YAAIR,MAAMS,gBAAV,EAA4B;AAC1BD,wBACE;AAAA;AAAA,cAAK,WAAU,WAAf;AACG,2BAAKrO,KAAL,CAAW6N,MAAMS,gBAAjB;AADH,WADF;AAKD;AACDL,gBACE;AAAA;AAAA,YAAI,WAAWD,cAAf;AACG,WAACH,MAAMU,UAAP,GAAoB;AAAA;AAAA;AAAK,2BAAKvO,KAAL,CAAW6N,MAAMW,UAAjB;AAAL,WAApB,GAA8D,IADjE;AAEE;AAAA;AAAA;AAAKH,uBAAL;AAAiB,0CAAC,MAAD;AACf,qBAAOzL,KADQ;AAEf,wBAAUwI,QAFK;AAGf,oBAAMyC,MAAM9D,IAHG;AAIf,2BAAaoB,WAJE;AAKf,wBAAU2C;AALK;AAAjB;AAFF,SADF;AAYD;;AAED,aACE;AAAA;AAAA,UAAK,WAAW1B,SAAhB,EAA2B,KAAKyB,MAAMrH,IAAtC;AACGyH;AADH,OADF;AAKD;;;;;;AAGHL,SAAS5C,SAAT,GAAqB;AACnBpI,SAAO,oBAAUqI,GADE;AAEnBG,YAAU,oBAAUC,IAFD;AAGnBwC,SAAO,oBAAU5C,GAHE;AAInBE,eAAa,oBAAUF;AAJJ,CAArB;;AAOA,IAAMwD,qBAAqB,SAArBA,kBAAqB,CAAC1E,IAAD,EAAU;AACnC,SAAOwC,iBAAiBxC,KAAK4D,MAAtB,KAAiC,IAAxC;AACD,CAFD;;AAIA,IAAMQ,iCAAiC,SAAjCA,8BAAiC,CAACpE,IAAD,EAAU;AAC/C,SAAOwC,iBAAiBxC,KAAK4D,MAAtB,KAAiCJ,cAAxC;AACD,CAFD;;AAIA,IAAMQ,kBAAkB,SAAlBA,eAAkB,CAACF,KAAD,EAAW;AACjC,MAAMa,YAAY,CAACb,MAAM9D,IAAN,CAAW4E,KAAX,IAAoB,KAArB,EAA4B9O,KAA5B,CAAkC,GAAlC,CAAlB;AACA,SAAO+O,KAAKC,GAAL,CAAS,EAAT,EAAaD,KAAKE,GAAL,CAAS,CAAT,EAAYC,SAC9B,KAAK,CAACL,UAAU,CAAV,CAAN,GAAqB,CAACA,UAAU,CAAV,CADQ,CAAZ,CAAb,CAAP;AAED,CAJD;;AAMA,IAAMM,eAAe,SAAfA,YAAe,CAACC,MAAD,EAASC,cAAT,EAA4B;AAC/C,MAAMC,eAAe,EAArB;AACA,MAAMC,eAAe,EAArB;;AAEA,MAAI,CAACF,cAAL,EAAqB;AACnBA,qBAAiB,wBAACvI,CAAD,EAAO;AAAE,aAAO,KAAP;AAAc,KAAxC;AACD;;AAEDsI,SAAO9P,OAAP,CAAe,UAAC0O,KAAD,EAAW;AACxB,QAAI,CAACqB,eAAerB,KAAf,CAAL,EAA4B;AAC1B,UAAIA,MAAMrH,IAAN,CAAWhF,MAAX,CAAkB,CAAlB,EAAqB,CAArB,MAA4B,GAAhC,EAAqC;AACnC4N,qBAAanO,IAAb,CAAkB4M,KAAlB;AACD,OAFD,MAEO;AACLsB,qBAAalO,IAAb,CAAkB4M,KAAlB;AACD;AACF;AACF,GARD;;AAUA,MAAMwB,gBAAgB,SAAhBA,aAAgB,CAACpQ,EAAD,EAAKqQ,OAAL,EAAcL,MAAd,EAAyB;AAC7C,QAAIM,iBAAiB,CAArB;AACA,QAAIC,MAAM,EAAV;;AAEAP,WAAO9P,OAAP,CAAe,UAAC0O,KAAD,EAAW;AACxB,UAAM4B,UAAU1B,gBAAgBF,KAAhB,CAAhB;AACA,UAAI4B,UAAUF,cAAV,GAA2B,EAA/B,EAAmC;AACjCtQ,WAAGgC,IAAH,CAAQ,CAACqO,OAAD,EAAUE,GAAV,CAAR;AACAD,yBAAiB,CAAjB;AACAC,cAAM,EAAN;AACD;AACDA,UAAIvO,IAAJ,CAAS4M,KAAT;AACA0B,wBAAkBE,OAAlB;AACD,KATD;;AAWA,QAAID,IAAIzO,MAAJ,GAAa,CAAjB,EAAoB;AAClB9B,SAAGgC,IAAH,CAAQ,CAACqO,OAAD,EAAUE,GAAV,CAAR;AACD;AACF,GAlBD;;AAoBA,MAAMvQ,KAAK,EAAX;AACAoQ,gBAAcpQ,EAAd,EAAkB,QAAlB,EAA4BkQ,YAA5B;AACAE,gBAAcpQ,EAAd,EAAkB,QAAlB,EAA4BmQ,YAA5B;AACA,SAAOnQ,EAAP;AACD,CA1CD;;AA4CA,IAAMyQ,kBAAkB,SAAlBA,eAAkB,CAACT,MAAD,EAASC,cAAT,EAAyBS,UAAzB,EAAwC;AAC9D,MAAM1Q,KAAK;AACT2Q,YAAQ,EADC;AAETC,YAAQ;AAFC,GAAX;;AAKA,MAAMC,OAAOd,aAAaC,MAAb,EAAqBC,cAArB,CAAb;;AAEAY,OAAK3Q,OAAL,CAAa,UAAC4Q,IAAD,EAAOC,GAAP,EAAe;AAAA,+BACHD,IADG;AAAA,QACnBT,OADmB;AAAA,QACVE,GADU;;AAE1BvQ,OAAGqQ,OAAH,EAAYrO,IAAZ,CACE;AAAA;AAAA,QAAK,WAAU,eAAf,EAA+B,KAAKqO,UAAU,GAAV,GAAgBU,GAApD;AACGR,UAAI9I,GAAJ,CAAQiJ,UAAR;AADH,KADF;AAKD,GAPD;;AASA,SAAO,CACL1Q,GAAG2Q,MADE,EAEL3Q,GAAG4Q,MAAH,CAAU9O,MAAV,GAAmB,CAAnB,GACI;AAAA;AAAA;AACA,WAAI,KADJ;AAEA,kBAAY,eAAKf,KAAL,CAAW,eAAX,CAFZ;AAGA,yBAAmB,KAHnB;AAG2Bf,OAAG4Q;AAH9B,GADJ,GAI0D,IANrD,CAAP;AAQD,CAzBD;;kBA2Be;AACbpB,sBAAoBA,kBADP;AAEbN,kCAAgCA,8BAFnB;AAGba,gBAAcA,YAHD;AAIbU,mBAAiBA,eAJJ;AAKb3B,mBAAiBA,eALJ;AAMbR,kBAAgBA,cANH;AAObK,YAAUA;AAPG,C;;;;;;;ACtLf;;;;;;AAEA;;;;AACA;;;;;;AAEA,IAAMqC,YAAY;;AAEhB;AACAC,QAHgB,kBAGRC,WAHQ,EAGK;AACnB,QAAIC,QAAQ,IAAZ;AACA,QAAI,OAAOD,WAAP,KAAuB,QAA3B,EAAqC;AACnCC,cAAQD,WAAR;AACD,KAFD,MAEO;AACLC,cAAQ,eAAKpQ,KAAL,CAAWmQ,WAAX,CAAR;AACD;AACD,QAAI,CAACC,KAAL,EAAY;AACV,aAAO,wCAAM,WAAU,EAAhB,GAAP;AACD;;AAED,QAAIC,WAAWD,MAAM9Q,KAAN,CAAY,sCAAZ,CAAf,CAXmB,CAWgD;AACnE,QAAI+Q,QAAJ,EAAc;AACZ,UAAIjE,YAAY,WAAWiE,SAAS,CAAT,CAA3B;AACA,UAAI,CAACA,SAAS,CAAT,KAAe,EAAhB,EAAoB/Q,KAApB,CAA0B,YAA1B,CAAJ,EAA6C;AAC3C8M,qBAAa,gBAAgBiE,SAAS,CAAT,CAA7B;AACD;AACD,aAAO,qCAAG,WAAWjE,SAAd,GAAP;AACD;;AAED,WAAO;AAAA;AAAA;AAAOgE;AAAP,KAAP;AACD;AAxBe,CAAlB;;kBA2BeH,S;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChCf;AACA;;AAEA;;AAEA,mDAAmD,gBAAgB,sBAAsB,OAAO,2BAA2B,0BAA0B,yDAAyD,2BAA2B,EAAE,EAAE,EAAE,eAAe;;AAE9P,sCAAsC,uCAAuC,kBAAkB;;AAE/F;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA,kEAAkE;AAClE;AACA;;AAEA,0BAA0B,aAAa,gBAAgB;;AAEvD;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,oC;;;;;;;ACrDA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA,oC;;;;;;;+CCZA;;AAEA;;AAEA,mDAAmD,gBAAgB,sBAAsB,OAAO,2BAA2B,0BAA0B,yDAAyD,2BAA2B,EAAE,EAAE,EAAE,eAAe;;AAE9P,sCAAsC,uCAAuC,kBAAkB;;AAE/F;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wEAAwE;;AAExE;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA,8DAA8D,iBAAiB,WAAW;AAC1F;;AAEA;;AAEA,6CAA6C,aAAa,eAAe;AACzE;;AAEA;AACA;;AAEA;AACA,4CAA4C;;AAE5C;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,wCAAwC;;AAExC;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,qBAAqB;AACrB,OAAO;AACP;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,qBAAqB;AACrB,OAAO;AACP;AACA;AACA;AACA;;AAEA,yDAAyD;AACzD;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA,oBAAoB;AACpB;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA,oC;;;;;;;;ACjLA;AACA;;AAEA;AACA;AACA;;AAEA,sCAAsC,uCAAuC,kBAAkB;;AAE/F;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA,0GAA0G;;AAE1G;AACA;;AAEA;AACA;AACA,0GAA0G;;AAE1G;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA,0GAA0G;;AAE1G;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA,C;;;;;;;;+CCnEA;;AAEA;;AAEA,mDAAmD,gBAAgB,sBAAsB,OAAO,2BAA2B,0BAA0B,yDAAyD,2BAA2B,EAAE,EAAE,EAAE,eAAe;;AAE9P,sCAAsC,uCAAuC,kBAAkB;;AAE/F;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA,GAAG;AACH;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;;AAEA,oBAAoB;AACpB;AACA,GAAG;AACH;;AAEA;AACA,oC;;;;;;;;ACvCA;AACA;;AAEA;;AAEA,mDAAmD,gBAAgB,sBAAsB,OAAO,2BAA2B,0BAA0B,yDAAyD,2BAA2B,EAAE,EAAE,EAAE,eAAe;;AAE9P,sCAAsC,uCAAuC,kBAAkB;;AAE/F;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA,wEAAwE;AACxE;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,OAAO;AACP;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA,KAAK;AACL;;AAEA;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,OAAO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,OAAO;AACP,KAAK;AACL;AACA;AACA;AACA,SAAS;AACT,OAAO;AACP;AACA;AACA,KAAK;AACL;;AAEA;;AAEA;AACA,sEAAsE;;AAEtE;;AAEA;AACA,mDAAmD;;AAEnD;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA,OAAO;AACP;AACA;;AAEA,4EAA4E;AAC5E;AACA,KAAK;AACL;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,4EAA4E;AAC5E;AACA;;AAEA;;AAEA,4BAA4B,aAAa,gBAAgB;;AAEzD;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA,gCAAgC;AAChC;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;;AAEA,mBAAmB,eAAe;AAClC;;AAEA;AACA;AACA;;AAEA,sBAAsB,eAAe;AACrC;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,uEAAuE;AACvE,iHAAiH;AACjH,uHAAuH;AACvH,0EAA0E;AAC1E,mFAAmF;AACnF;AACA;;AAEA;AACA,oC;;;;;;;+CClSA;;AAEA;;AAEA,mDAAmD,gBAAgB,sBAAsB,OAAO,2BAA2B,0BAA0B,yDAAyD,2BAA2B,EAAE,EAAE,EAAE,eAAe;;AAE9P,sCAAsC,uCAAuC,kBAAkB;;AAE/F;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA,qDAAqD,4BAA4B;AACjF;AACA,OAAO;AACP;;AAEA;AACA;;AAEA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;;AAEA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;;AAEA,sBAAsB;AACtB;;AAEA,yHAAyH;AACzH,+HAA+H;AAC/H,KAAK;AACL;AACA;;AAEA;AACA,oC;;;;;;;;+CC9GA;;AAEA;;AAEA,mDAAmD,gBAAgB,sBAAsB,OAAO,2BAA2B,0BAA0B,yDAAyD,2BAA2B,EAAE,EAAE,EAAE,eAAe;;AAE9P,sCAAsC,uCAAuC,kBAAkB;;AAE/F,8CAA8C,iBAAiB,qBAAqB,oCAAoC,6DAA6D,oBAAoB,EAAE,eAAe;;AAE1N;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,0EAA0E;AAC1E;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA,qCAAqC;AACrC;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA,sMAAsM;;AAEtM;;AAEA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;;AAEA;;AAEA,wBAAwB;AACxB;AACA,OAAO,gCAAgC,yCAAyC;AAChF;;AAEA;AACA;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,0DAA0D;AAC1D;AACA;AACA;;AAEA;AACA;AACA;AACA,0DAA0D;AAC1D;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,qBAAqB,eAAe,SAAS,eAAe;AAC5D;;AAEA;AACA;AACA;;AAEA,wBAAwB,eAAe,SAAS,eAAe;AAC/D;;AAEA,sBAAsB;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,4EAA4E;AAC5E,qFAAqF;AACrF,KAAK;AACL;AACA;;AAEA;AACA,oC;;;;;;;;;;;AC3KA;;;;AAEA;;;;AACA;;;;AACA;;AACA;;;;;;;;;;;;IAEMK,U;;;;;;;;;;;6BACM;AACR,UAAIxJ,OAAO,KAAKb,KAAL,CAAWsK,EAAtB;AACA,UAAIzJ,KAAKtF,MAAL,CAAY,CAAZ,EAAe,CAAf,MAAsB,GAA1B,EAA+B;AAC7BsF,eAAO7E,eAAeyB,UAAf,GAA4B,GAA5B,GAAkCoD,IAAzC;AACD;AACD,aACE;AAAA;AAAA,UAAM,IAAIA,IAAV,EAAgB,iBAAgB,QAAhC;AACG,aAAKb,KAAL,CAAWiG;AADd,OADF;AAKD;;;;;;AAGHoE,WAAWtF,SAAX,GAAuB;AACrBuF,MAAI,oBAAUpQ;AADO,CAAvB;;AAIAqQ,OAAOC,OAAP,GAAiBH,UAAjB,C;;;;;;;;ACzBA;;;;;;;;;;AAEA;;;;AACA;;;;;;;;;;;;IAEMI,mB;;;;;;;;;;;wCACiB;AACnB,aAAO,KAAP;AACD;;;oCAEgBnJ,Y,EAAc;AAC7B,UAAMtI,+IAA2BsI,YAA3B,CAAN;AACA,UAAItI,OAAOc,SAAX,EAAsB;AACpB,eAAOd,EAAP;AACD;AACD,UAAI,KAAK0R,iBAAL,EAAJ,EAA8B;AAC5B,eAAO,eAAK3Q,KAAL,CAAW,mBAAX,CAAP;AACD;AACF;;;;;;kBAGY0Q,mB;;;;;;;ACrBf;;;;AAEA;;;;AACA;;;;AACA;;;;AACA;;AACA;;;;AACA;;;;AACA;;AACA;;;;AAGA;;;;AACA;;;;AACA;;;;AAGA;;;;AACA;;;;AAIA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;;;;;;;;;AAjBA;;;AAKA;;AAGA;;AAEA;;;AASA,eAAKjR,eAAL,GAAuBwC,eAAerC,IAAtC;;IAEMgR,Q;;;;;;;;;;;6BACM;AACR,aACE;AAAA;AAAA;AACE;AAAA;AAAA;AAAA;AAAA,SADF;AAEE;AAAA;AAAA;AAAA;AAAA;AAFF,OADF;AAMD;;;;;;AAGHA,SAASC,YAAT,GAAwB;AACtBC,UAAQ,oBAAUzF;AADI,CAAxB;;AAIA,IAAM9E,SAAU,YAAM;AACpB;AACA,SACE;AAAA;AAAA,MAAO,MAAK,KAAZ,EAAkB,MAAMtE,eAAeyB,UAAvC,EAAmD,wBAAnD;AACE,wDAAO,MAAK,MAAZ,EAAmB,MAAK,YAAxB,EAAqC,6BAArC,GADF;AAEE,wDAAO,MAAK,QAAZ,EAAqB,MAAK,cAA1B,EAAyC,+BAAzC,GAFF;AAGE,wDAAO,MAAK,SAAZ,EAAsB,MAAK,eAA3B,EAA2C,gCAA3C,GAHF;AAIE,wDAAO,MAAK,WAAZ,EAAwB,MAAK,iBAA7B,EAA+C,iCAA/C,GAJF;AAKE,wDAAO,MAAK,QAAZ,EAAqB,MAAK,cAA1B,EAAyC,sCAAzC,GALF;AAME,6DAAY,yBAAZ,GANF;AAOE,6CAAO,MAAK,GAAZ,EAAgB,WAAWkN,QAA3B;AAPF,GADF;AAWD,CAbc,EAAf;;AAeA,IAAMG,OAAO3L,SAAS4L,cAAT,CAAwB,MAAxB,CAAb;;AAEA,IAAID,IAAJ,EAAU;AACR,qBAASrD,MAAT,CACE;AAAA;AAAA,MAAQ,SAAS,+DAAjB;AACGnH;AADH,GADF,EAIGwK,IAJH;AAKD,C;;;;;;;;ACtED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1DA;AACA;AACA;AACA;;AAEA;;;;;;;;AAEA;;;;;;;;;;;;IAEME,a;;;;;;;;;;;wCACiB,CACpB;;;2CAEuB,CACvB;;;yCAEqB,CACrB;;;8CAE0BC,S,EAAW,CACrC;;;;EAXyB,gBAAMlL,S;;kBAcnBiL,a;;;;;;ACvBf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wB;;;;;;AC7BA,kBAAkB,yzL;;;;;;ACAlB,kBAAkB,0+L;;;;;;ACAlB,kBAAkB,2+K;;;;;;ACAlB,kBAAkB,swL;;;;;;ACAlB,kBAAkB,kyM;;;;;;ACAlB,kBAAkB,i4L;;;;;;ACAlB,kBAAkB,knI;;;;;;ACAlB,kBAAkB,inI;;;;;;ACAlB,kBAAkB,82L;;;;;;ACAlB,kBAAkB,+yL;;;;;;ACAlB,kBAAkB,gqL;;;;;;ACAlB,kBAAkB,g5K;;;;;;ACAlB,kBAAkB,ogH;;;;;;;ACAlB;;AAEA;;AAEA,sCAAsC,uCAAuC,kBAAkB;;AAE/F;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA,wIAAwI;AACxI,wC;;;;;;;ACtEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA,C;;;;;;;+CCzBA;;AAEA;;AAEA,mDAAmD,gBAAgB,sBAAsB,OAAO,2BAA2B,0BAA0B,yDAAyD,2BAA2B,EAAE,EAAE,EAAE,eAAe;;AAE9P,sCAAsC,uCAAuC,kBAAkB;;AAE/F;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA,wEAAwE;;AAExE;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;;AAEA,6CAA6C,aAAa,eAAe;AACzE;;AAEA;AACA;;AAEA;AACA,iCAAiC;;AAEjC;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,wCAAwC;;AAExC;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;;AAEA,yDAAyD;AACzD;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA,oBAAoB;AACpB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA,oC;;;;;;;;+CCvPA;;AAEA;;AAEA,mDAAmD,gBAAgB,sBAAsB,OAAO,2BAA2B,0BAA0B,yDAAyD,2BAA2B,EAAE,EAAE,EAAE,eAAe;;AAE9P,sCAAsC,uCAAuC,kBAAkB;;AAE/F;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA,GAAG,IAAI;AACP;;AAEA;AACA,wEAAwE;;AAExE;AACA,eAAe;AACf,GAAG;AACH,eAAe;AACf;;AAEA,sDAAsD;AACtD;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA,GAAG;AACH;AACA;;AAEA;AACA;;AAEA,2CAA2C;;AAE3C,8DAA8D,UAAU,WAAW;;AAEnF;AACA,GAAG;;AAEH;AACA;AACA,GAAG;AACH;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;;AAEA;;AAEA,6CAA6C,aAAa,eAAe;AACzE;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA,sCAAsC,oBAAoB,uBAAuB;AACjF;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA,oC;;;;;;;;AC1JA;;AAEA;;AAEA,mDAAmD,gBAAgB,sBAAsB,OAAO,2BAA2B,0BAA0B,yDAAyD,2BAA2B,EAAE,EAAE,EAAE,eAAe;;AAE9P,sCAAsC,uCAAuC,kBAAkB;;AAE/F,8CAA8C,iBAAiB,qBAAqB,oCAAoC,6DAA6D,oBAAoB,EAAE,eAAe;;AAE1N;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA,0EAA0E;AAC1E;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,SAAS;AACT;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA,wBAAwB;AACxB;AACA,OAAO;AACP;;AAEA;AACA;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,qBAAqB,eAAe;AACpC;;AAEA;AACA;AACA;;AAEA,wBAAwB,eAAe;AACvC;;AAEA,sBAAsB;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,4EAA4E;AAC5E,qFAAqF;AACrF,KAAK;AACL;AACA;;AAEA;AACA,oC;;;;;;;AC3IA;;AAEA;;AAEA,sCAAsC,uCAAuC,kBAAkB;;AAE/F;;AAEA;;AAEA;;AAEA;;AAEA;AACA,oC;;;;;;;ACfA;;AAEA;;AAEA,sCAAsC,uCAAuC,kBAAkB;;AAE/F;;AAEA;;AAEA;;AAEA;;AAEA;AACA,oC;;;;;;;;;;;;;;;;;;;;;ACfA;;;;;;AAEA,sBAAE7L,QAAF,EAAY+L,KAAZ,CAAkB,YAAY;AAC5B,wBAAE,yBAAF,EAA6BC,KAA7B,CAAmC,YAAY;AAC7C,QAAMC,SAAS,sBAAE,sBAAE,IAAF,EAAQC,IAAR,CAAa,aAAb,KAA+B,kBAAjC,CAAf;AACA,QAAMzO,WAAWwO,OAAOE,EAAP,CAAU,SAAV,CAAjB;AACAF,WAAOG,WAAP,CAAmB,QAAnB,EAA6B,CAAC3O,QAA9B;AACA,0BAAE,IAAF,EAAQ2O,WAAR,CAAoB,QAApB,EAA8B,CAAC3O,QAA/B;AACD,GALD;AAMD,CAPD,E;;;;;;ACFA,yC;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gDAAgD;;AAEhD;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC;AACnC,2CAA2C;AAC3C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA;AACA;AACA,eAAe;AACf;AACA,eAAe;AACf;AACA,eAAe;AACf;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAmB;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,gEAAgE;AAChE;AACA;AACA,6BAA6B;AAC7B,OAAO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,CAAC;;;;;;;;ACpgBD;;;;;;;;AAEA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;;;;;;;;;IAEM4O,G;;;;;;;;;;;6BACM;AACR,aACE;AAAA;AAAA,UAAK,WAAU,aAAf;AACE,mEADF;AAEE;AAAA;AAAA;AACE;AAAA;AAAiB,iBAAKC,eAAL,EAAjB;AACE;AAAA;AAAA,gBAAQ,MAAK,QAAb,EAAsB,WAAU,eAAhC;AACE,+BAAY,WADd;AAEE,+BAAY,gBAFd;AAGE;AAAA;AAAA,kBAAM,WAAU,SAAhB;AAAA;AAAA,eAHF;AAIE,sDAAM,WAAU,WAAhB,GAJF;AAKE,sDAAM,WAAU,WAAhB,GALF;AAME,sDAAM,WAAU,WAAhB;AANF;AADF;AADF,SAFF;AAcE;AAAA;AAAA,YAAK,WAAU,kBAAf;AACE,8DAAgB,KAAKA,eAAL,EAAhB,CADF;AAEE;AAAA;AAAA,cAAK,WAAU,oDAAf;AACE;AAAA;AAAA,gBAAK,WAAU,6CAAf;AACE,+DAAa,KAAKA,eAAL,EAAb;AADF,aADF;AAIE;AAAA;AAAA,gBAAK,WAAU,yBAAf;AACG,mBAAKzL,KAAL,CAAWiG;AADd;AAJF;AAFF;AAdF,OADF;AA4BD;;;;;;kBAGYuF,G;;;;;;;AC1Cf;;;;;;;;;;AAEA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;;;;;;;;;IAEME,W;;;AACJ,uBAAa1L,KAAb,EAAoB;AAAA;;AAAA,0HACZA,KADY;;AAElB,UAAK2L,KAAL,GAAa;AACXC,sBAAgB;AADL,KAAb;AAGA,UAAKlG,WAAL,GAAmB,MAAKA,WAAL,CAAiBrE,IAAjB,OAAnB;AALkB;AAMnB;;;;wCAEoB;AACnB;AACA,WAAKwK,YAAL;AACAjG,aAAOC,gBAAP,CAAwB,SAAxB,EAAmC,KAAKH,WAAxC;AACD;;;uCAEmBoG,S,EAAWC,S,EAAW;AACxC,mIAAyBD,SAAzB,EAAoCC,SAApC;AACA,UAAID,UAAUnO,MAAV,CAAiBkD,IAAjB,KAA0B,KAAKb,KAAL,CAAWrC,MAAX,CAAkBkD,IAAhD,EAAsD;AACpD,aAAKgL,YAAL;AACD;AACF;;;2CAEuB;AACtBjG,aAAOE,mBAAP,CAA2B,SAA3B,EAAsC,KAAKJ,WAA3C;AACD;;;mCAEe;AAAA;;AACd,UAAM7E,OAAO,KAAKuC,aAAL,EAAb;AACA,UAAIvC,SAAS,IAAb,EAAmB;AACjB,aAAKmL,QAAL,CAAc;AACZJ,0BAAgB;AADJ,SAAd;AAGA;AACD;;AAED,sBAAMlO,QAAN,CAAe,WAAf,EAA4B,EAACmD,MAAMA,IAAP,EAA5B,EAA0C,IAA1C,yBACGoB,IADH,CACQ,UAACgK,IAAD,EAAU;AACd,eAAKD,QAAL,CAAc;AACZJ,0BAAgB;AACd/K,kBAAMA,IADQ;AAEdjC,sBAAUqN,KAAKrN;AAFD;AADJ,SAAd;AAMD,OARH;AASD;;;gCAEYgB,K,EAAO;AAClB;AACA,UAAIA,MAAMmG,KAAN,KAAgB,EAAhB,IAAsB,gBAAMpG,SAAN,CAAgBC,KAAhB,CAA1B,EAAkD;AAChDA,cAAMoG,cAAN;AACA,+BAAapE,UAAb;AACD;AACF;;;kCAEcmC,C,EAAG;AAChB,sBAAMrG,QAAN,CAAe,cAAf,EAA+B;AAC7BmD,cAAM,KAAKuC,aAAL,EADuB;AAE7BH,aAAK,KAAKI,YAAL;AAFwB,OAA/B,EAGG,IAHH,yBAIGpB,IAJH,CAIQ,UAACgK,IAAD,EAAU;AACd,YAAIA,KAAK7P,GAAL,KAAa,IAAjB,EAAuB;AACrBwJ,iBAAOzF,QAAP,CAAgB+L,IAAhB,GAAuB,gBAAMpQ,eAAN,CAAsB,GAAtB,CAAvB;AACD,SAFD,MAEO;AACL8J,iBAAOzF,QAAP,CAAgB+L,IAAhB,GAAuB,gBAAMpQ,eAAN,CAAsBmQ,KAAK7P,GAA3B,CAAvB;AACD;AACF,OAVH;AAWD;;;iCAEa2H,C,EAAG;AACf,6BAAanC,UAAb;AACD;;;+BAEWmC,C,EAAG;AACb,6BAAanC,UAAb;AACD;;;+BAEWmC,C,EAAG;AACb,6BAAanC,UAAb;AACD;;;0CAEsB;AACrB,aACE;AAAA;AAAA,UAAK,WAAU,WAAf;AACE;AAAA;AAAA,YAAQ,WAAU,iBAAlB,EAAoC,SAClC,KAAKuK,YAAL,CAAkB9K,IAAlB,CAAuB,IAAvB,CADF,EACgC,OAAO,eAAKtH,KAAL,CAAW,YAAX,CADvC;AAEE,+CAAG,WAAU,oBAAb;AAFF,SADF;AAIE;AAAA;AAAA,YAAQ,WAAU,iBAAlB,EAAoC,SAClC,KAAKqS,UAAL,CAAgB/K,IAAhB,CAAqB,IAArB,CADF,EAC8B,OAAO,eAAKtH,KAAL,CAAW,SAAX,CADrC;AAEE,+CAAG,WAAU,0BAAb;AAFF,SAJF;AAOE;AAAA;AAAA,YAAQ,WAAU,iBAAlB,EAAoC,SAClC,KAAKsS,UAAL,CAAgBhL,IAAhB,CAAqB,IAArB,CADF,EAC8B,OAAO,eAAKtH,KAAL,CAAW,eAAX,CADrC;AAEE,+CAAG,WAAU,qBAAb;AAFF,SAPF;AAUE;AAAA;AAAA,YAAQ,WAAU,iBAAlB,EAAoC,SAClC,KAAKqM,aAAL,CAAmB/E,IAAnB,CAAwB,IAAxB,CADF,EACiC,OAAO,eAAKtH,KAAL,CAAW,mBAAX,CADxC;AAEE,+CAAG,WAAU,iBAAb;AAFF;AAVF,OADF;AAgBD;;;6BAES;AAAA;;AACR,UAAIuS,SAAS,EAAb;AACA,UAAMlB,SAAS,KAAKmB,qBAAL,KAA+B,UAA/B,GAA4C,OAA3D;AACA,UAAIC,WAAW,IAAf;;AAEA,UAAI,KAAKb,KAAL,CAAWC,cAAX,IAA6B,IAAjC,EAAuC;AACrCU,iBAAS,KAAKX,KAAL,CAAWC,cAAX,CAA0BhN,QAA1B,CAAmC6B,GAAnC,CAAuC,UAACqJ,IAAD,EAAU;AACxD,cAAM9K,UAAU,OAAKyN,uBAAL,CAA6B3C,KAAKjJ,IAAlC,CAAhB;AACA,cAAIsJ,QAAQL,KAAKvB,UAAL,GAAkB,eAAKxO,KAAL,CAAW+P,KAAKvB,UAAhB,CAAlB,GAAgDuB,KAAKK,KAAjE;AACA,cAAIhE,YAAY,cAAhB;;AAEA,cAAI,CAAC2D,KAAK4C,MAAV,EAAkB;AAChBvC,oBAAQL,KAAKtG,EAAb;AACA2C,yBAAa,uBAAb;AACD;AACDqG,qBAAW1C,IAAX;;AAEA,cAAM1M,YAAY,OAAK8D,kBAAL,CAAwBkK,MAAxB,EAAgC,EAACvK,MAAM7B,OAAP,EAAhC,CAAlB;;AAEA,iBACE;AAAA;AAAA,cAAI,KAAK8K,KAAKjJ,IAAd,EAAoB,WAAWsF,SAA/B;AACE;AAAA;AAAA,gBAAM,IAAI/I,SAAV;AAAsB+M;AAAtB;AADF,WADF;AAKD,SAlBQ,CAAT;AAmBD,OApBD,MAoBO;AACLmC,iBACE;AAAA;AAAA;AAAI;AAAA;AAAA,cAAM,IAAI,KAAKpL,kBAAL,CAAwB,OAAxB,EAAiC,EAACL,MAAM,MAAP,EAAjC,CAAV;AACD,2BAAK9G,KAAL,CAAW,kBAAX;AADC;AAAJ,SADF;AAID;;AAED,aACE;AAAA;AAAA,UAAK,WAAU,aAAf;AACE;AAAA;AAAA,YAAI,WAAU,sBAAd;AACG,eAAKiG,KAAL,CAAWiG,QADd;AAEGqG,gBAFH;AAGGE,sBAAYA,SAASG,iBAArB,GACC;AAAA;AAAA,cAAI,WAAU,kBAAd;AACE;AAAA;AAAA,gBAAM,IAAI,KAAKzL,kBAAL,CAAwB,YAAxB,EAAsC;AAC9CL,wBAAM,KAAK4L,uBAAL,CACJD,SAAS3L,IADL,CADwC,EAAtC,CAAV;AAAA;AAAA;AADF,WADD,GAMG,IATN;AAUG,aAVH,CAUO,yCAVP;AAWE;AAAA;AAAA,cAAI,WAAU,MAAd;AACG,iBAAK+L,mBAAL;AADH;AAXF;AADF,OADF;AAmBD;;;;;;kBAGYlB,W;;;;;;;ACtKf;;;;;;;;;;AAEA;;;;AAEA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;;;;;;;;;IAEMmB,S;;;AACJ,qBAAa7M,KAAb,EAAoB;AAAA;;AAAA,sHACZA,KADY;;AAElB,UAAK2L,KAAL,GAAa;AACXmB,aAAO,EADI;AAEXC,wBAAkB,CAAC,CAFR;AAGXC,eAAS;AAHE,KAAb;AAFkB;AAOnB;;;;wCAEoB;AACnB;AACA,WAAKC,IAAL,CAAUC,CAAV,CAAYC,KAAZ;AACD;;;kCAEcpJ,C,EAAG;AAAA;;AAChB,UAAMmJ,IAAInJ,EAAEqH,MAAF,CAASzO,KAAnB;;AAEA,UAAIuQ,MAAM,EAAV,EAAc;AACZ,aAAKlB,QAAL,CAAc;AACZc,iBAAO,EADK;AAEZE,mBAAS,EAFG;AAGZD,4BAAkB,CAAC;AAHP,SAAd;AAKD,OAND,MAMO;AACL,aAAKf,QAAL,CAAc;AACZc,iBAAOI;AADK,SAAd;;AAIA,wBAAM5O,UAAN,CAAiB,OAAjB,EAA0B;AACxBL,gBAAM;AACJiP,eAAGA,CADC;AAEJjK,iBAAK,KAAKI,YAAL,EAFD;AAGJ1J,kBAAM,eAAKH;AAHP,WADkB;AAMxB0E,kBAAQ;AANgB,SAA1B,yBAOoB+D,IAPpB,CAOyB,UAACgK,IAAD,EAAU;AACjC,iBAAKD,QAAL,CAAc;AACZgB,qBAASf,KAAKe,OADF;AAEZD,8BAAkBpE,KAAKC,GAAL,CAAS,OAAK+C,KAAL,CAAWoB,gBAApB,EAChBd,KAAKe,OAAL,CAAalS,MAAb,GAAsB,CADN;AAFN,WAAd;AAKD,SAbD;AAcD;AACF;;;+BAEWiJ,C,EAAG;AACb,UAAIqJ,MAAM,KAAKzB,KAAL,CAAWoB,gBAArB;AACA,UAAMlE,MAAM,KAAK8C,KAAL,CAAWqB,OAAX,CAAmBlS,MAA/B;AACA,UAAIiJ,EAAEgC,KAAF,KAAY,EAAhB,EAAoB;AAClBhC,UAAEiC,cAAF;AACAoH,cAAM,CAACA,MAAM,CAAP,IAAYvE,GAAlB;AACD,OAHD,MAGO,IAAI9E,EAAEgC,KAAF,KAAY,EAAhB,EAAoB;AACzBhC,UAAEiC,cAAF;AACAoH,cAAM,CAACA,MAAM,CAAN,GAAUvE,GAAX,IAAkBA,GAAxB;AACD,OAHM,MAGA,IAAI9E,EAAEgC,KAAF,KAAY,EAAhB,EAAoB;AACzB,aAAKsH,YAAL,CAAkB,KAAK1B,KAAL,CAAWoB,gBAA7B;AACD;AACD,WAAKf,QAAL,CAAc;AACZe,0BAAkBK;AADN,OAAd;AAGD;;;iCAEaE,K,EAAO;AACnB,UAAMxD,OAAO,KAAK6B,KAAL,CAAWqB,OAAX,CAAmBM,KAAnB,CAAb;AACA,UAAIxD,SAAShQ,SAAb,EAAwB;AACtB,YAAMsR,SAAS,KAAKmB,qBAAL,KAA+B,UAA/B,GAA4C,OAA3D;AACA,YAAMvN,UAAU,KAAKyN,uBAAL,CAA6B3C,KAAKjJ,IAAlC,CAAhB;AACA,+BAAaW,aAAb;AACA,aAAK+L,qBAAL,CAA2BnC,MAA3B,EAAmC,EAACvK,MAAM7B,OAAP,EAAnC;AACD;AACF;;;+BAEWsO,K,EAAO;AACjB,WAAKtB,QAAL,CAAc;AACZe,0BAAkBpE,KAAKC,GAAL,CAAS0E,KAAT,EAAgB,KAAK3B,KAAL,CAAWqB,OAAX,CAAmBlS,MAAnB,GAA4B,CAA5C;AADN,OAAd;AAGD;;;oCAEgB;AAAA;;AACf,UAAM9B,KAAK,KAAK2S,KAAL,CAAWqB,OAAX,CAAmBvM,GAAnB,CAAuB,UAACxF,MAAD,EAAS8O,GAAT,EAAiB;AACjD,YAAMyD,UAAUvS,OAAOuS,OAAP,CAAe/M,GAAf,CAAmB,UAACqJ,IAAD,EAAOC,GAAP,EAAe;AAChD,iBACE;AAAA;AAAA,cAAM,WAAU,QAAhB,EAAyB,KAAKA,GAA9B;AACGD,iBAAKrG;AADR,WADF;AAKD,SANe,CAAhB;;AAQA,eACE;AAAA;AAAA;AACE,iBAAKsG,GADP;AAEE,uBAAWA,QAAQ,OAAK4B,KAAL,CAAWoB,gBAAnB,GAAsC,QAAtC,GAAiD,EAF9D;AAGE,qBAAS,OAAKM,YAAL,CAAkBhM,IAAlB,SAA6B0I,GAA7B,CAHX;AAIE,0BAAc,OAAK0D,UAAL,CAAgBpM,IAAhB,SAA2B0I,GAA3B,CAJhB;AAKGyD,iBALH;AAME;AAAA;AAAA;AAASvS,mBAAOwI;AAAhB;AANF,SADF;AAUD,OAnBU,CAAX;;AAqBA,aACE;AAAA;AAAA,UAAI,WAAU,gBAAd;AAAgCzK;AAAhC,OADF;AAGD;;;6BAES;AACR,aACE;AAAA;AAAA;AACE,8BADF;AAEE,6BAFF;AAGE,iBAAO,eAAKe,KAAL,CAAW,YAAX,CAHT;AAIE;AAAA;AAAA,YAAK,WAAU,YAAf;AACE,mDAAO,MAAK,MAAZ;AACE,iBAAI,GADN;AAEE,uBAAU,cAFZ;AAGE,mBAAO,KAAK4R,KAAL,CAAWmB,KAHpB;AAIE,sBAAU,KAAKY,aAAL,CAAmBrM,IAAnB,CAAwB,IAAxB,CAJZ;AAKE,uBAAW,KAAKsM,UAAL,CAAgBtM,IAAhB,CAAqB,IAArB,CALb;AAME,yBAAa,eAAKtH,KAAL,CAAW,wBAAX,CANf;AADF,SAJF;AAaG,aAAK6T,aAAL;AAbH,OADF;AAiBD;;;;;;kBAGYf,S;;;;;;;AC1If;;;;;;;;AAEA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;;;;;;;;;IAEMgB,W;;;;;;;;;;;8BACO;AACT,6BAAarM,aAAb;AACD;;;6BAES;AACR,aACE;AAAA;AAAA;AACE,8BADF;AAEE,6BAFF;AAGE,iBAAO,eAAKzH,KAAL,CAAW,OAAX,CAHT;AAIE;AAAA;AAAA;AACG,yBAAKA,KAAL,CAAW,eAAX,CADH;AACgC,cADhC;AAEG,yBAAKA,KAAL,CAAW,WAAW,KAAKiG,KAAL,CAAW0B,KAAX,CAAiBrD,IAAvC;AAFH,SAJF;AAQE;AAAA;AAAA,YAAK,WAAU,SAAf;AACE;AAAA;AAAA,cAAQ,MAAK,QAAb,EAAsB,WAAU,iBAAhC;AACE,uBAAS,KAAKyP,OAAL,CAAazM,IAAb,CAAkB,IAAlB,CADX;AACqC,2BAAKtH,KAAL,CAAW,OAAX;AADrC;AADF;AARF,OADF;AAeD;;;;;;AAGH8T,YAAY9I,SAAZ,GAAwB;AACtBrD,SAAO,oBAAUuD;AADK,CAAxB;;kBAIe4I,W;;;;;;;ACrCf;;AAEA;;;;;;;;;;AAEA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;;;;;;;;;IAEME,O;;;AACJ,mBAAa/N,KAAb,EAAoB;AAAA;;AAAA,kHACZA,KADY;;AAGlB,UAAK2L,KAAL,GAAa;AACXqC,eAAS,EADE;AAEXC,oBAAc,IAFH;AAGXhK,WAAK,EAHM;AAIXiK,oBAAc;AAJH,KAAb;AAHkB;AASnB;;;;wCAEoB;AACnB;AACA,WAAKC,UAAL;AACD;;;2CAEuB;AACtB;AACD;;;8CAE0BlD,S,EAAW;AACpC,WAAKkD,UAAL;AACD;;;wCAEoB;AACnB,aAAO,CAAC,KAAKC,eAAL,EAAR;AACD;;;iCAEa;AAAA;;AACZ,sBAAM1Q,QAAN,CAAe,UAAf,EAA2B,EAA3B,EAA+B,IAA/B,yBACGuE,IADH,CACQ,gBAAiB;AAAA,YAAd+L,OAAc,QAAdA,OAAc;;AACrB,eAAKhC,QAAL,CAAc;AACZgC,mBAASA,OADG;AAEZC,wBAAcD,WAAWA,QAAQlT,MAAnB,GACVkT,QAAQ,CAAR,EAAWxK,EADD,GAEV;AAJQ,SAAd;AAMD,OARH;AASD;;;sCAEkB;AACjB,aAAO,KAAKmI,KAAL,CAAWuC,YAAX,KAA4B,MAA5B,IACL,KAAKvC,KAAL,CAAWuC,YAAX,KAA4B,MAD9B;AAED;;;gCAEY;AACX,UAAI,KAAKE,eAAL,EAAJ,EAA4B;AAC1B,aAAKC,WAAL;AACD;AACF;;;+BAEW;AACV,6BAAa7M,aAAb;AACD;;;kCAEc;AAAA;;AACb,WAAKwK,QAAL,CAAc;AACZ/H,aAAK,EADO;AAEZiK,sBAAc;AAFF,OAAd;AAIA,sBAAM5P,UAAN,CAAiB,QAAjB,EAA2B;AACzBJ,gBAAQ;AADiB,OAA3B,yBAEoB+D,IAFpB,CAEyB,UAACgK,IAAD,EAAU;AACjC,eAAKqC,aAAL;AACD,OAJD;AAKD;;;oCAEgB;AAAA;;AACf,WAAKtC,QAAL,CAAc;AACZkC,sBAAc;AADF,OAAd;;AAIA,UAAMK,KAAK,IAAIC,WAAJ,CAAgB,gBAAMhR,SAAN,CAAgB,UAAhB,IACzB,UADyB,GACZiR,mBAAmB,KAAK9C,KAAL,CAAWsC,YAA9B,CADJ,CAAX;AAEAM,SAAG1I,gBAAH,CAAoB,SAApB,EAA+B,UAACjG,KAAD,EAAW;AACxC,YAAM3B,OAAOO,KAAKkQ,KAAL,CAAW9O,MAAM3B,IAAjB,CAAb;AACA,YAAIA,SAAS,IAAb,EAAmB;AACjB,iBAAK+N,QAAL,CAAc;AACZkC,0BAAc;AADF,WAAd;AAGAK,aAAGI,KAAH;AACD,SALD,MAKO;AACL,iBAAK3C,QAAL,CAAc;AACZ/H,iBAAK,OAAK0H,KAAL,CAAW1H,GAAX,CAAe2K,MAAf,CAAsB3Q,KAAK4Q,GAA3B;AADO,WAAd;AAGD;AACF,OAZD;AAaD;;;mCAEejP,K,EAAO;AACrB,WAAKoM,QAAL,CAAc;AACZiC,sBAAcrO,MAAMwL,MAAN,CAAazO;AADf,OAAd;AAGD;;;yCAEqB;AACpB;AACA,UAAMgE,OAAO,KAAKsM,IAAL,CAAUhJ,GAAvB;AACA,UAAItD,IAAJ,EAAU;AACRA,aAAKrB,SAAL,GAAiBqB,KAAKpB,YAAtB;AACD;AACF;;;6BAES;AACR,UAAMyO,UAAU,KAAKrC,KAAL,CAAWqC,OAAX,CAAmBvN,GAAnB,CAAuB,UAACqO,MAAD,EAAY;AACjD,eACE;AAAA;AAAA,YAAQ,OAAOA,OAAOtL,EAAtB,EAA0B,KAAKsL,OAAOtL,EAAtC;AACG,yBAAKzJ,KAAL,CAAW+U,OAAOC,SAAlB,IAA+B,IAA/B,GAAsCD,OAAOE,YAA7C,GAA4D;AAD/D,SADF;AAKD,OANe,CAAhB;;AAQA,UAAIC,WAAW,IAAf;AACA,UAAI,KAAKtD,KAAL,CAAWuC,YAAX,KAA4B,MAAhC,EAAwC;AACtCe,mBACE;AAAA;AAAA;AACE;AAAA;AAAA;AAAK,iBAAKtD,KAAL,CAAWuC,YAAX,KAA4B,MAA5B,GACD,eAAKnU,KAAL,CAAW,sBAAX,CADC,GAED,eAAKA,KAAL,CAAW,cAAX;AAFJ,WADF;AAIE;AAAA;AAAA;AAAM,2BAAKA,KAAL,CAAW,OAAX,IAAsB,IAAtB,GACJ,eAAKA,KAAL,CAAW,mBAAmB,KAAK4R,KAAL,CAAWuC,YAAzC;AADF,WAJF;AAME;AAAA;AAAA,cAAK,KAAI,KAAT,EAAe,WAAU,WAAzB;AAAsC,iBAAKvC,KAAL,CAAW1H,GAAX,CAAenF,IAAf,CAAoB,IAApB;AAAtC;AANF,SADF;AAUD;;AAED,aACE;AAAA;AAAA;AACE,0BAAgB,KADlB;AAEE,6BAFF;AAGE,iBAAO,eAAK/E,KAAL,CAAW,SAAX,CAHT;AAIE;AAAA;AAAA;AAAI,yBAAKA,KAAL,CAAW,cAAX;AAAJ,SAJF;AAKE;AAAA;AAAA;AACE;AAAA;AAAA;AAAK,2BAAKA,KAAL,CAAW,gBAAX;AAAL,WADF;AAEE;AAAA;AAAA;AACE;AAAA;AAAA,gBAAK,WAAU,aAAf;AACE;AAAA;AAAA;AACE,yBAAO,KAAK4R,KAAL,CAAWsC,YADpB;AAEE,4BAAU,KAAKiB,cAAL,CAAoB7N,IAApB,CAAyB,IAAzB,CAFZ;AAGE,6BAAU,cAHZ;AAIG2M;AAJH;AADF;AADF;AAFF,SALF;AAkBE;AAAA;AAAA,YAAK,WAAU,SAAf;AACE;AAAA;AAAA,cAAQ,MAAK,QAAb,EAAsB,WAAU,iBAAhC;AACE,wBAAU,CAAC,KAAKI,eAAL,EADb;AAEE,uBAAS,KAAKe,SAAL,CAAe9N,IAAf,CAAoB,IAApB,CAFX;AAEuC,2BAAKtH,KAAL,CAAW,SAAX;AAFvC,WADF;AAIE;AAAA;AAAA,cAAQ,MAAK,QAAb,EAAsB,WAAU,iBAAhC;AACE,wBAAU,CAAC,KAAKqU,eAAL,EADb;AAEE,uBAAS,KAAKgB,QAAL,CAAc/N,IAAd,CAAmB,IAAnB,CAFX;AAEsC,2BAAKtH,KAAL,CAClC,KAAK4R,KAAL,CAAWuC,YAAX,KAA4B,MAA5B,GAAqC,OAArC,GAA+C,QADb;AAFtC;AAJF,SAlBF;AA2BGe;AA3BH,OADF;AA+BD;;;;;;kBAGYlB,O;;;;;;;AC7Kf;;;;;;;;;;AAEA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;;;;;;;;;IAEMsB,O;;;AACJ,mBAAarP,KAAb,EAAoB;AAAA;;AAAA,kHACZA,KADY;;AAElB,UAAK2L,KAAL,GAAa;AACXuC,oBAAc;AADH,KAAb;AAFkB;AAKnB;;;;wCAEoB;AACnB;AACA,WAAKC,UAAL;AACD;;;wCAEoB;AACnB,aAAO,CAAC,KAAKmB,gBAAL,EAAR;AACD;;;uCAEmB;AAClB,aAAO,KAAK3D,KAAL,CAAWuC,YAAX,KAA4B,MAA5B,IACL,KAAKvC,KAAL,CAAWuC,YAAX,KAA4B,MAD9B;AAED;;;gCAEY;AAAA;;AACX,WAAKlC,QAAL,CAAc;AACZkC,sBAAc;AADF,OAAd;AAGA,sBAAM5P,UAAN,CAAiB,QAAjB,EAA2B;AACzBJ,gBAAQ;AADiB,OAA3B,yBAEoB+D,IAFpB,CAEyB,UAACgK,IAAD,EAAU;AACjC,eAAKD,QAAL,CAAc;AACZkC,wBAAc;AADF,SAAd;AAGD,OAND;AAOD;;;+BAEW;AACV,6BAAa1M,aAAb;AACD;;;6BAES;AACR,UAAIyN,WAAW,IAAf;AACA,UAAI,KAAKtD,KAAL,CAAWuC,YAAX,KAA4B,MAAhC,EAAwC;AACtCe,mBACE;AAAA;AAAA;AACE;AAAA;AAAA;AAAK,iBAAKtD,KAAL,CAAWuC,YAAX,KAA4B,MAA5B,GACD,eAAKnU,KAAL,CAAW,4BAAX,CADC,GAED,eAAKA,KAAL,CAAW,uBAAX;AAFJ;AADF,SADF;AAOD;;AAED,aACE;AAAA;AAAA;AACE,0BAAgB,KADlB;AAEE,6BAFF;AAGE,iBAAO,eAAKA,KAAL,CAAW,eAAX,CAHT;AAIE;AAAA;AAAA;AAAI,yBAAKA,KAAL,CAAW,oBAAX;AAAJ,SAJF;AAKGkV,gBALH;AAME;AAAA;AAAA,YAAK,WAAU,SAAf;AACE;AAAA;AAAA,cAAQ,MAAK,QAAb,EAAsB,WAAU,iBAAhC;AACE,wBAAU,CAAC,KAAKK,gBAAL,EADb;AAEE,uBAAS,KAAKC,SAAL,CAAelO,IAAf,CAAoB,IAApB,CAFX;AAEuC,2BAAKtH,KAAL,CAAW,eAAX;AAFvC,WADF;AAIE;AAAA;AAAA,cAAQ,MAAK,QAAb,EAAsB,WAAU,iBAAhC;AACE,wBAAU,CAAC,KAAKuV,gBAAL,EADb;AAEE,uBAAS,KAAKF,QAAL,CAAc/N,IAAd,CAAmB,IAAnB,CAFX;AAEsC,2BAAKtH,KAAL,CAClC,KAAK4R,KAAL,CAAWuC,YAAX,KAA4B,MAA5B,GAAqC,OAArC,GAA+C,QADb;AAFtC;AAJF;AANF,OADF;AAkBD;;;;;;kBAGYmB,O;;;;;;;AClFf;;AAEA;;;;;;;;;;AAEA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;AACA;;;;AACA;;;;AACA;;;;;;;;;;;;AAEA,IAAMG,uBAAuB,SAAvBA,oBAAuB,GAAM;AACjC,MAAMC,WAAW,gBAAMjQ,WAAN,EAAjB;AACA,MAAIiQ,aAAa,KAAjB,EAAwB;AACtB,WAAO,eAAK1V,KAAL,CAAW,eAAX,CAAP;AACD,GAFD,MAEO,IAAI0V,aAAa,SAAjB,EAA4B;AACjC,WAAO,eAAK1V,KAAL,CAAW,mBAAX,CAAP;AACD,GAFM,MAEA;AACL,WAAO,eAAKA,KAAL,CAAW,WAAX,CAAP;AACD;AACF,CATD;;AAWA,IAAM2V,oBAAoB,EAA1B;;IAEMC,a;AACJ,2BAAe;AAAA;;AACb,SAAKC,IAAL,GAAY,EAAZ;AACD;;;;qCAEiBC,M,EAAQC,I,EAAM;AAC9B,WAAK,IAAI1U,IAAI,CAAb,EAAgBA,IAAI,KAAKwU,IAAL,CAAU9U,MAA9B,EAAsCM,GAAtC,EAA2C;AACzC,YAAI,KAAKwU,IAAL,CAAUxU,CAAV,EAAa,CAAb,MAAoByU,MAAxB,EAAgC;AAC9B,eAAKD,IAAL,CAAUxU,CAAV,EAAa,CAAb,IAAkB0U,IAAlB;AACA;AACD;AACF;AACD,WAAKF,IAAL,CAAU/Q,OAAV,CAAkB,CAACgR,MAAD,EAASC,IAAT,CAAlB;AACA,UAAI,KAAKF,IAAL,CAAU9U,MAAV,GAAmB,CAAvB,EAA0B;AACxB,aAAK8U,IAAL,CAAU9U,MAAV,GAAmB,CAAnB;AACD;AACF;;;gCAEY+U,M,EAAQE,U,EAAY;AAC/B,WAAK,IAAI3U,IAAI,CAAb,EAAgBA,IAAI,KAAKwU,IAAL,CAAU9U,MAA9B,EAAsCM,GAAtC,EAA2C;AACzC,YAAI,KAAKwU,IAAL,CAAUxU,CAAV,EAAa,CAAb,MAAoByU,MAAxB,EAAgC;AAC9B,cAAI7W,KAAK,KAAK4W,IAAL,CAAUxU,CAAV,EAAa,CAAb,CAAT;AACA,cAAI2U,eAAejW,SAAnB,EAA8B;AAC5Bd,iBAAK2P,KAAKC,GAAL,CAAS5P,EAAT,EAAa2P,KAAKqH,IAAL,CAAUD,aAAaL,iBAAvB,CAAb,CAAL;AACD;AACD,iBAAO1W,EAAP;AACD;AACF;AACD,aAAO,CAAP;AACD;;;;;;IAGGiX,O;;;AACJ,mBAAajQ,KAAb,EAAoB;AAAA;;AAAA,kHACZA,KADY;;AAGlB,UAAK2L,KAAL,GAAa,MAAKuE,gBAAL,EAAb;AACA,UAAKC,aAAL,GAAqB,IAAIR,aAAJ,EAArB;AACA,UAAKS,oBAAL,GAA4B,MAAKA,oBAAL,CAA0B/O,IAA1B,OAA5B;AALkB;AAMnB;;;;uCAEmB;AAClB,aAAO;AACLgP,2BAAmB,EADd;AAELC,wBAAgB,EAFX;AAGLC,oBAAY,EAHP;AAILC,4BAAoB,KAJf;AAKLC,yBAAiB,KALZ;AAMLC,sBAAc,KANT;AAOLC,sBAAc,KAPT;AAQLC,sBAAc,KART;AASLC,2BAAmB,IATd;AAULC,sBAAc;AAVT,OAAP;AAYD;;;wCAEoB;AACnB;AACA,WAAKC,iBAAL;;AAEA,oBAAIC,SAAJ,kCAAuC,KAAKZ,oBAA5C;AACD;;;uCAEmBtE,S,EAAWC,S,EAAW;AACxC,2HAAyBD,SAAzB,EAAoCC,SAApC;AACA,UAAID,UAAUnO,MAAV,CAAiBkD,IAAjB,KAA0B,KAAKb,KAAL,CAAWrC,MAAX,CAAkBkD,IAAhD,EAAsD;AACpD,aAAKkQ,iBAAL;AACD;AACF;;;2CAEuB;AACtB;AACA,oBAAIE,WAAJ,kCAAyC,KAAKb,oBAA9C;AACD;;;yCAEqBxQ,K,EAAO;AAC3B,UAAIA,MAAM2E,UAAN,KAAqB,KAAKnB,aAAL,EAAzB,EAA+C;AAC7C,aAAK2N,iBAAL;AACD;AACF;;;wCAEoB;AAAA;;AACnB,UAAMlQ,OAAO,KAAKuC,aAAL,EAAb;AACA,UAAIvC,SAAS,IAAb,EAAmB;AACjB,aAAKmL,QAAL,CAAc,KAAKkE,gBAAL,EAAd;AACA;AACD;;AAED,WAAKlE,QAAL,CAAc;AACZ6E,2BAAmBhQ;AADP,OAAd,EAEG,YAAM;AACP,wBAAMnD,QAAN,CAAe,aAAf,EAA8B,EAACmD,MAAMA,IAAP,EAA9B,EAA4C,IAA5C,yBACGoB,IADH,CACQ,UAACgK,IAAD,EAAU;AACd;AACA,cAAIpL,SAAS,OAAK8K,KAAL,CAAWkF,iBAAxB,EAA2C;AACzC;AACD;AACD,cAAMK,OAAOjF,KAAKiF,IAAlB;AACAA,eAAKC,IAAL,CAAU,UAAC5U,CAAD,EAAIC,CAAJ,EAAU;AAClB,gBAAM4U,QAAQ,CAAC7U,EAAE8U,UAAF,GAAe,GAAf,GAAqB,GAAtB,IAA6B,eAAKtX,KAAL,CAAWwC,EAAEwS,SAAb,CAA3C;AACA,gBAAMuC,QAAQ,CAAC9U,EAAE6U,UAAF,GAAe,GAAf,GAAqB,GAAtB,IAA6B,eAAKtX,KAAL,CAAWyC,EAAEuS,SAAb,CAA3C;AACA,mBAAOqC,UAAUE,KAAV,GAAkB,CAAlB,GAAsBF,QAAQE,KAAR,GAAgB,CAAC,CAAjB,GAAqB,CAAlD;AACD,WAJD;AAKA,iBAAKtF,QAAL,CAAc;AACZqE,+BAAmBpE,KAAKsF,WADZ;AAEZjB,4BAAgBrE,KAAKhG,QAFT;AAGZsK,wBAAYW,IAHA;AAIZV,gCAAoBvE,KAAKuF,oBAJb;AAKZf,6BAAiBxE,KAAKU,iBALV;AAMZ+D,0BAAczE,KAAKwF,aANP;AAOZd,0BAAc1E,KAAKyF,cAPP;AAQZd,0BAAc3E,KAAKS,MARP;AASZoE,0BAAc,OAAKX,aAAL,CAAmBwB,WAAnB,CACZ9Q,IADY,EACNoL,KAAKhG,QAAL,CAAcnL,MADR;AATF,WAAd;AAYD,SAxBH;AAyBD,OA5BD;AA6BD;;;2BAEO8E,K,EAAO;AACbA,YAAMoG,cAAN;AACA,sBAAM1H,UAAN,CAAiB,WAAjB,EAA8B,EAACL,MAAM;AACnC4C,gBAAM,KAAKuC,aAAL,EAD6B;AAEnCH,eAAK,KAAKI,YAAL;AAF8B,SAAP;AAI5B;AACAnF,gBAAQ,MALoB,EAA9B,yBAMG+D,IANH,CAMQ,UAACgK,IAAD,EAAU;AACd,YAAI,CAACA,KAAK2F,IAAV,EAAgB;AACdC,gBAAM,eAAK9X,KAAL,CAAW,wBAAX,CAAN;AACD;AACF,OAVH;AAWD;;;wCAEoB;AACnB,UAAMiF,UAAU,KAAKyN,uBAAL,EAAhB;AACA,UAAMqF,QAAQ,EAAd;AACA,UAAMC,aAAa,IAAnB;;AAEAD,YAAM9W,IAAN,CACE;AAAA;AAAA,UAAI,KAAI,MAAR;AACE;AAAA;AAAA,YAAM,IAAOgE,OAAP,UAAN;AACG,eAAK2M,KAAL,CAAW+E,YAAX,GACG,eAAK3W,KAAL,CAAW,eAAX,CADH,GAEG,eAAKA,KAAL,CAAW,MAAX;AAHN;AADF,OADF;;AAUA,UAAI,KAAK4R,KAAL,CAAWgF,YAAf,EAA6B;AAC3BmB,cAAM9W,IAAN,CACE;AAAA;AAAA,YAAI,KAAI,QAAR;AAAiB;AAAA;AAAA,cAAM,IAAOgE,OAAP,YAAN;AACd,2BAAKjF,KAAL,CAAW,QAAX;AADc;AAAjB,SADF;AAID;;AAED+X,YAAM9W,IAAN,CACE;AAAA;AAAA,UAAI,KAAI,SAAR;AAAkB;AAAA;AAAA,YAAM,IAAOgE,OAAP,aAAN;AACf,yBAAKjF,KAAL,CAAW,SAAX;AADe;AAAlB,OADF;;AAKA,UAAI,KAAK4R,KAAL,CAAWiF,YAAf,EAA6B;AAC3BkB,cAAM9W,IAAN,CACE;AAAA;AAAA,YAAI,KAAI,SAAR;AACE;AAAA;AAAA,cAAG,MAAK,GAAR,EAAY,SAAS,KAAKgX,MAAL,CAAY3Q,IAAZ,CAAiB,IAAjB,CAArB;AACGmO;AADH;AADF,SADF;AAOD;;AAED,UAAI,KAAK7D,KAAL,CAAW8E,eAAf,EAAgC;AAC9BqB,cAAM9W,IAAN,CACE;AAAA;AAAA,YAAI,KAAI,WAAR;AAAoB;AAAA;AAAA,cAAM,IAAOgE,OAAP,eAAN;AACjB,2BAAKjF,KAAL,CAAW,gBAAX;AADiB;AAApB,SADF;AAID;;AAED,UAAI,KAAK4R,KAAL,CAAW6E,kBAAf,EAAmC;AACjCsB,cAAM9W,IAAN,CACE;AAAA;AAAA,YAAI,KAAI,gBAAR;AAAyB;AAAA;AAAA,cAAM,IAAOgE,OAAP,YAAN;AACtB,2BAAKjF,KAAL,CAAW,gBAAX;AADsB;AAAzB,SADF;AAID;;AAED,UAAM0J,QAAQ,KAAKkI,KAAL,CAAW+E,YAAX,GACV,eAAK3W,KAAL,CAAW,oBAAX,CADU,GAEV,eAAKA,KAAL,CAAW,cAAX,CAFJ;;AAIA,aACE;AAAA;AAAA,UAAK,KAAI,SAAT,EAAmB,WAAU,SAA7B;AACE;AAAA;AAAA;AAAK0J;AAAL,SADF;AAEE;AAAA;AAAA,YAAI,WAAU,KAAd;AACGqO,eADH;AAEGC;AAFH;AAFF,OADF;AASD;;;iCAEa;AAAA;;AACZ,UAAI,KAAKpG,KAAL,CAAW4E,UAAX,CAAsBzV,MAAtB,GAA+B,CAAnC,EAAsC;AACpC,eAAO,IAAP;AACD;;AAED,UAAMiI,QAAQ,KAAK4I,KAAL,CAAW4E,UAAX,CAAsB9P,GAAtB,CAA0B,UAACqJ,IAAD,EAAU;AAChD,YAAIrG,QAAQ,eAAK1J,KAAL,CAAW+P,KAAKiF,SAAhB,CAAZ;AACA,YAAI5I,YAAY,KAAhB;AACA,YAAI2D,KAAKuH,UAAT,EAAqB;AACnB5N,mBAAS,OAAO,eAAK1J,KAAL,CAAW,aAAX,CAAP,GAAmC,GAA5C;AACD,SAFD,MAEO,IAAI+P,KAAKmI,eAAT,EAA0B;AAC/BxO,mBAAS,OAAO,eAAK1J,KAAL,CAAW,iBAAX,CAAP,GAAuC,GAAhD;AACD;AACD,YAAI,CAAC+P,KAAK4C,MAAV,EAAkB;AAChBvG,uBAAa,cAAb;AACD;;AAED,YAAMtF,OAAO,OAAKK,kBAAL,CAAwB,IAAxB,EAA8B;AACzCL,gBAAM,OAAK4L,uBAAL,CAA6B,IAA7B,EAAmC3C,KAAK7G,GAAxC;AADmC,SAA9B,CAAb;AAGA,eACE;AAAA;AAAA,YAAI,KAAK6G,KAAK7G,GAAd,EAAmB,WAAWkD,SAA9B;AACE;AAAA;AAAA,cAAM,IAAItF,IAAV;AAAiB4C;AAAjB;AADF,SADF;AAKD,OApBa,CAAd;;AAsBA,aACE;AAAA;AAAA,UAAK,KAAI,MAAT,EAAgB,WAAU,SAA1B;AACE;AAAA;AAAA;AAAK,yBAAK1J,KAAL,CAAW,MAAX;AAAL,SADF;AAEE;AAAA;AAAA,YAAI,WAAU,KAAd;AACGgJ;AADH;AAFF,OADF;AAQD;;;4CAEwB;AAAA;;AACvB,UAAImP,QAAQvJ,KAAKqH,IAAL,CAAU,KAAKrE,KAAL,CAAW2E,cAAX,CAA0BxV,MAA1B,GAAmC4U,iBAA7C,CAAZ;AACA,UAAIwC,SAAS,CAAb,EAAgB;AACd,eAAO,IAAP;AACD;AACD,UAAIpC,OAAO,KAAKnE,KAAL,CAAWmF,YAAtB;AACA,UAAIqB,WAAW,SAAXA,QAAW,CAACC,IAAD,EAAOxS,KAAP,EAAiB;AAC9BA,cAAMoG,cAAN;AACA,YAAIqM,UAAUvC,OAAOsC,IAArB;AACA,eAAKjC,aAAL,CAAmBmC,gBAAnB,CAAoC,OAAKlP,aAAL,EAApC,EAA0DiP,OAA1D;AACA,eAAKrG,QAAL,CAAc;AACZ8E,wBAAcuB;AADF,SAAd;AAGD,OAPD;;AASA,aACE;AAAA;AAAA,UAAI,WAAU,YAAd;AACGvC,eAAO,CAAP,GACG;AAAA;AAAA,YAAG,MAAK,GAAR,EAAY,SAASqC,SAAS9Q,IAAT,CAAc,IAAd,EAAoB,CAAC,CAArB,CAArB;AAAA;AAAA,SADH,GAEG;AAAA;AAAA;AAAA;AAAA,SAHN;AAIE;AAAA;AAAA,YAAM,WAAU,MAAhB;AAAwByO,iBAAO,KAAP,GAAeoC;AAAvC,SAJF;AAKGpC,eAAOoC,KAAP,GACG;AAAA;AAAA,YAAG,MAAK,GAAR,EAAY,SAASC,SAAS9Q,IAAT,CAAc,IAAd,EAAoB,CAAC,CAArB,CAArB;AAAA;AAAA,SADH,GAEG;AAAA;AAAA;AAAA;AAAA;AAPN,OADF;AAWD;;;yCAEqB;AAAA;;AACpB,UAAM+J,SAAS,KAAKmB,qBAAL,KAA+B,SAA/B,GAA2C,MAA1D;;AAEA,UAAMtG,WAAW,KAAK0F,KAAL,CAAW2E,cAAX,CAA0BvT,KAA1B,CACf,CAAC,KAAK4O,KAAL,CAAWmF,YAAX,GAA0B,CAA3B,IAAgCpB,iBADjB,EAEf,KAAK/D,KAAL,CAAWmF,YAAX,GAA0BpB,iBAFX,CAAjB;;AAIA,UAAM3M,QAAQkD,SAASxF,GAAT,CAAa,UAAC8R,KAAD,EAAW;AACpC,YAAMvT,UAAU,OAAKyN,uBAAL,CAA6B8F,MAAM1R,IAAnC,CAAhB;AACA,eACE;AAAA;AAAA,YAAI,KAAK0R,MAAM/O,EAAf;AACE;AAAA;AAAA,cAAM,IAAOxE,OAAP,SAAkBoM,MAAxB;AACG,2BAAKrR,KAAL,CAAWwY,MAAMhK,UAAjB;AADH;AADF,SADF;AAMD,OARa,CAAd;;AAUA,UAAIxF,MAAMjI,MAAN,KAAiB,CAArB,EAAwB;AACtBiI,cAAM/H,IAAN,CACE;AAAA;AAAA,YAAI,KAAI,UAAR;AACE;AAAA;AAAA;AAAK,2BAAKjB,KAAL,CAAW,gBAAX;AAAL;AADF,SADF;AAKD;;AAED,aACE;AAAA;AAAA,UAAK,KAAI,UAAT,EAAoB,WAAU,SAA9B;AACE;AAAA;AAAA;AAAK,yBAAKA,KAAL,CAAW,aAAX;AAAL,SADF;AAEE;AAAA;AAAA,YAAI,WAAU,qBAAd;AACG,eAAKyY,qBAAL,EADH;AAEGzP;AAFH;AAFF,OADF;AASD;;;8CAE0B;AAAA;;AACzB,UAAMA,QAAQ,KAAK4I,KAAL,CAAW0E,iBAAX,CAA6B5P,GAA7B,CAAiC,UAACgS,IAAD,EAAU;AACvD,YAAMzT,UAAU,OAAKyN,uBAAL,CAA6BgG,KAAK5R,IAAlC,CAAhB;AACA,eACE;AAAA;AAAA,YAAI,KAAK4R,KAAKjP,EAAd;AACE;AAAA;AAAA,cAAM,IAAOxE,OAAP,UAAN;AACGyT,iBAAKjP,EADR;AAAA;AACciP,iBAAK3O,IADnB;AAAA;AAAA;AADF,SADF;AAMD,OARa,CAAd;;AAUA,UAAIf,MAAMjI,MAAN,KAAiB,CAArB,EAAwB;AACtBiI,cAAM/H,IAAN,CACE;AAAA;AAAA,YAAI,KAAI,UAAR;AACE;AAAA;AAAA;AAAK,2BAAKjB,KAAL,CAAW,gBAAX;AAAL;AADF,SADF;AAKD;;AAED,aACE;AAAA;AAAA,UAAK,KAAI,aAAT,EAAuB,WAAU,SAAjC;AACE;AAAA;AAAA;AAAK,yBAAKA,KAAL,CAAW,aAAX;AAAL,SADF;AAEE;AAAA;AAAA,YAAI,WAAU,wBAAd;AACGgJ;AADH;AAFF,OADF;AAQD;;;6BAES;AACR,UAAM2P,WAAW,EAAjB;;AAEA,UAAI,KAAKtP,aAAL,OAAyB,IAA7B,EAAmC;AACjCsP,iBAAS1X,IAAT,CAAc,KAAK2X,iBAAL,EAAd;AACD;;AAEDD,eAAS1X,IAAT,CAAc,KAAK4X,UAAL,EAAd;;AAEA,UAAI,KAAKjH,KAAL,CAAW8E,eAAf,EAAgC;AAC9BiC,iBAAS1X,IAAT,CAAc,KAAK6X,kBAAL,EAAd;AACD;;AAED,UAAI,KAAKlH,KAAL,CAAW6E,kBAAf,EAAmC;AACjCkC,iBAAS1X,IAAT,CAAc,KAAK8X,uBAAL,EAAd;AACD;;AAED,aAAO;AAAA;AAAA,UAAK,WAAU,iBAAf;AAAkCJ;AAAlC,OAAP;AACD;;;;;;kBAGYzC,O;;;;;;;ACzXf;;;;;;;;;;;;AAEA;;;;AACA;;;;AACA;;;;AACA;;AACA;;;;;;;;;;;;IAEM8C,U;;;AACJ,sBAAa/S,KAAb,EAAoB;AAAA;;AAAA,wHACZA,KADY;;AAElB,UAAK2L,KAAL,GAAa;AACXhJ,qBAAe,IADJ;AAEXqQ,4BAAsB;AAFX,KAAb;AAIA,UAAKC,eAAL,GAAuB,MAAKA,eAAL,CAAqB5R,IAArB,OAAvB;AANkB;AAOnB;;;;wCAEoB;AACnB;AACA,oBAAI2P,SAAJ,6BAAkC,KAAKiC,eAAvC;AACD;;;2CAEuB;AACtB;AACA,oBAAIhC,WAAJ,6BAAoC,KAAKgC,eAAzC;AACD;;;oCAEgBrT,K,EAAO;AACtB,WAAKoM,QAAL,CAAc;AACZrJ,uBAAe/C,MAAM4C,MADT;AAEZwQ,8BAAsBpT,MAAM8C,aAAN,IAAuB;AAFjC,OAAd;AAID;;;uCAEmBF,M,EAAQ;AAC1B,6BAAa0Q,oBAAb,CAAkC1Q,MAAlC;AACAoD,aAAOuN,QAAP,CAAgB,CAAhB,EAAmB,CAAnB;AACD;;;6BAES;AAAA;;AACR,UAAI3Q,SAAS,IAAb;AACA,UAAI,KAAKmJ,KAAL,CAAWhJ,aAAf,EAA8B;AAC5BH,iBAAS,mCAAM,KAAN,CAAY,aAAZ;AACP,eAAK,aAAC4Q,IAAD;AAAA,mBAAS,OAAKC,kBAAL,CAAwBD,IAAxB,CAAT;AAAA;AADE,WAEH,KAAK3H,eAAL,EAFG,EAGH,KAAKE,KAAL,CAAWqH,oBAHR,EAAT;AAKD,OAND,MAMO;AACL,+BAAaE,oBAAb,CAAkC,IAAlC;AACD;;AAED,UAAI,CAAC1Q,MAAL,EAAa;AACX,eAAO,IAAP;AACD;;AAED,aACE;AAAA;AAAA,UAAK,WAAU,aAAf;AACGA,cADH;AAEE,+CAAK,WAAU,qBAAf;AAFF,OADF;AAMD;;;;;;kBAGYuQ,U;;;;;;;ACjEf;;;;;;;;;;AAEA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;;;;;;;;;IAEMO,Y;;;AACJ,wBAAatT,KAAb,EAAoB;AAAA;;AAAA,4HACZA,KADY;;AAElB,UAAK2L,KAAL,GAAa;AACX4H,kBAAY,IADD;AAEXC,iBAAW;AAFA,KAAb;;AAKA,UAAKC,UAAL,GAAkB,IAAlB;AACA,UAAKC,UAAL,GAAkB,MAAKA,UAAL,CAAgBrS,IAAhB,OAAlB;AARkB;AASnB;;;;wCAEoB;AACnB;AACA,WAAKoS,UAAL,GAAkB7N,OAAO+N,WAAP,CAAmB,KAAKD,UAAxB,EAAoC,IAApC,CAAlB;AACD;;;2CAEuB;AACtB,UAAI,KAAKD,UAAL,KAAoB,IAAxB,EAA8B;AAC5B7N,eAAOgO,aAAP,CAAqB,KAAKH,UAA1B;AACA,aAAKA,UAAL,GAAkB,IAAlB;AACD;AACD;AACD;;;iCAEa;AAAA;;AACZ,sBAAM/V,QAAN,CAAe,OAAf,EAAwB,EAAxB,EAA4B,IAA5B,yBACGuE,IADH,CACQ,UAACgK,IAAD,EAAU;AACd,YAAI,OAAKN,KAAL,CAAW6H,SAAX,KAAyB,IAA7B,EAAmC;AACjC,iBAAKxH,QAAL,CAAc;AACZwH,uBAAWvH,KAAK4H;AADJ,WAAd;AAGD;AACD,eAAK7H,QAAL,CAAc;AACZuH,sBAAY,OAAK5H,KAAL,CAAW6H,SAAX,KAAyBvH,KAAK4H;AAD9B,SAAd;AAGD,OAVH,EAUK,YAAM;AACP,eAAK7H,QAAL,CAAc;AACZuH,sBAAY;AADA,SAAd;AAGD,OAdH;AAeD;;;6BAES;AACR,UAAI,KAAK5H,KAAL,CAAW4H,UAAf,EAA2B;AACzB,eAAO,IAAP;AACD;AACD,aACE;AAAA;AAAA,UAAK,WAAU,mBAAf;AACE;AAAA;AAAA,YAAK,WAAU,oBAAf;AACE;AAAA;AAAA;AAAK,2BAAKxZ,KAAL,CAAW,0BAAX;AAAL,WADF;AAEE;AAAA;AAAA;AAAI,2BAAKA,KAAL,CAAW,kCAAX;AAAJ;AAFF;AADF,OADF;AAQD;;;;;;kBAGYuZ,Y;;;;;;;AClEf;;;;;;;;;;AAEA;;;;;;;;;;;;IAEMQ,I;;;;;;;;;;;wCACiB;AACnB;AACA,UAAMC,cAAc/X,eAAeyB,UAAf,GAA4B,eAAhD;AACA,WAAKuC,KAAL,CAAWE,OAAX,CAAmBe,SAAnB,CAA6B,IAA7B,EAAmC8S,WAAnC;AACD;;;6BAES;AACR,aAAO,IAAP;AACD;;;;;;kBAGYD,I;;;;;;;AChBf;;;;;;;;;;AAEA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;;;;;;;;;IAEME,Q;;;AACJ,oBAAahU,KAAb,EAAoB;AAAA;;AAAA,oHACZA,KADY;;AAGlB,UAAK2L,KAAL,GAAa;AACXsI,yBAAmB,IADR;AAEXC,kBAAY,IAFD;AAGXC,uBAAiB,IAHN;AAIXC,kBAAY,IAJD;AAKX1J,yBAAmB;AALR,KAAb;AAOA,UAAKhF,WAAL,GAAmB,MAAKA,WAAL,CAAiBrE,IAAjB,OAAnB;AAVkB;AAWnB;;;;wCAEoB;AACnB;AACA,WAAKgT,UAAL;AACAzO,aAAOC,gBAAP,CAAwB,SAAxB,EAAmC,KAAKH,WAAxC;AACD;;;8CAE0BuF,S,EAAW;AACpC;;;;;AAKD;;;uCAEmBa,S,EAAWC,S,EAAW;AACxC,UAAID,UAAUnO,MAAV,CAAiBkD,IAAjB,KAA0B,KAAKb,KAAL,CAAWrC,MAAX,CAAkBkD,IAAhD,EAAsD;AACpD,aAAKwT,UAAL;AACD;AACF;;;2CAEuB;AACtBzO,aAAOE,mBAAP,CAA2B,SAA3B,EAAsC,KAAKJ,WAA3C;AACD;;;wCAEoB;AACnB,aAAO,KAAKiG,KAAL,CAAWjB,iBAAlB;AACD;;;gCAEY9K,K,EAAO;AAClB;AACA,UAAIA,MAAMmG,KAAN,KAAgB,EAAhB,IAAsB,gBAAMpG,SAAN,CAAgBC,KAAhB,CAA1B,EAAkD;AAChDA,cAAMoG,cAAN;AACA,aAAKsO,WAAL;AACD;AACF;;;mCAEe1M,K,EAAO;AACrB,cAAQA,MAAMrH,IAAd;AACE,aAAK,KAAL;AACA,aAAK,OAAL;AACA,aAAK,MAAL;AACA,aAAK,MAAL;AACA,aAAK,aAAL;AACA,aAAK,QAAL;AACA,aAAK,iBAAL;AACE,iBAAO,IAAP;AACF,aAAK,kBAAL;AACE,iBAAO,CAAC,KAAKoL,KAAL,CAAWyI,UAAX,CAAsB3C,aAA9B;AAVJ;AAYA,aAAO,KAAP;AACD;;;iCAEa;AAAA;;AACZ,sBAAM/T,QAAN,CAAe,YAAf,EAA6B;AAC3BmD,cAAM,KAAKuC,aAAL,EADqB;AAE3BH,aAAK,KAAKI,YAAL;AAFsB,OAA7B,EAGG,IAHH,yBAIGpB,IAJH,CAIQ,UAACgK,IAAD,EAAU;AACd,eAAKD,QAAL,CAAc;AACZiI,6BAAmBhI,KAAKhO,IADZ;AAEZiW,sBAAY,EAFA;AAGZC,2BAAiBlI,KAAKsI,SAHV;AAIZH,sBAAYnI,KAAKuI,WAJL;AAKZ9J,6BAAmB;AALP,SAAd;AAOD,OAZH;AAaD;;;kCAEc9C,K,EAAOjL,K,EAAO;AAC3B,UAAI8X,UAAU,EAAd;AACAA,cAAQ7M,MAAMrH,IAAd,IAAsB,EAACmU,MAAM/X,SAAS,EAAhB,EAAtB;AACA,UAAMgY,KAAK,iCAAO,KAAKhJ,KAAL,CAAWuI,UAAlB,EAA8BO,OAA9B,CAAX;AACA,WAAKzI,QAAL,CAAc;AACZkI,oBAAYS,EADA;AAEZjK,2BAAmB;AAFP,OAAd;AAID;;;gCAEY;AAAA;;AACX,UAAI1R,KAAK,EAAT;AACA,WAAK2S,KAAL,CAAWwI,eAAX,CAA2BnL,MAA3B,CAAkC9P,OAAlC,CAA0C,UAAC0O,KAAD,EAAW;AACnD,YAAI,OAAKqB,cAAL,CAAoBrB,KAApB,CAAJ,EAAgC;AAC9B;AACD;;AAED,YAAIjL,QAAQ,OAAKgP,KAAL,CAAWuI,UAAX,CAAsBtM,MAAMrH,IAA5B,CAAZ;;AAEA,YAAI5D,UAAU7C,SAAd,EAAyB;AACvB,cAAMmO,SAAS,kBAAQC,8BAAR,CAAuCN,MAAM9D,IAA7C,CAAf;AACA,cAAImE,OAAO2M,cAAX,EAA2B;AACzBjY,oBAAQsL,OAAO2M,cAAP,CAAsBjY,KAAtB,EAA6BiL,MAAM9D,IAAnC,CAAR;AACD;AACF,SALD,MAKO;AACLnH,kBAAQ,OAAKgP,KAAL,CAAWsI,iBAAX,CAA6BrM,MAAMrH,IAAnC,CAAR;AACA,cAAI5D,UAAU7C,SAAd,EAAyB;AACvB6C,oBAAQ,IAAR;AACD;AACF;;AAED3D,WAAG4O,MAAMrH,IAAT,IAAiB5D,KAAjB;AACD,OApBD;;AAsBA,aAAO3D,EAAP;AACD;;;kCAEc;AAAA;;AACb,UAAM6H,OAAO,KAAKuC,aAAL,EAAb;AACA,UAAMH,MAAM,KAAKI,YAAL,EAAZ;AACA,UAAMwR,UAAU,KAAKC,SAAL,EAAhB;AACA,sBAAMxW,UAAN,CAAiB,YAAjB,EAA+B,EAACC,MAAM;AACpCN,gBAAM4W,OAD8B,EACrBhU,MAAMA,IADe,EACToC,KAAKA,GADI,EAAP;AAE7B;AACA/E,gBAAQ,KAHqB,EAA/B,yBAIG+D,IAJH,CAIQ,UAACgK,IAAD,EAAU;AACd,eAAKD,QAAL,CAAc;AACZtB,6BAAmB;AADP,SAAd,EAEG,YAAM;AACP,iBAAK6C,qBAAL,CAA2B,UAA3B,EAAuC;AACrC1M,kBAAM,OAAK4L,uBAAL,CAA6B5L,IAA7B;AAD+B,WAAvC;AAGD,SAND;AAOD,OAZH;AAaD;;;iCAEajB,K,EAAO;AACnB,WAAK2N,qBAAL,CAA2B,SAA3B,EAAsC;AACpC1M,cAAM,KAAK4L,uBAAL;AAD8B,OAAtC;AAGD;;;qCAEiB/E,M,EAAQE,K,EAAO;AAC/B,UAAIjL,QAAQ,KAAKgP,KAAL,CAAWuI,UAAX,CAAsBtM,MAAMrH,IAA5B,CAAZ;AACA,UAAI5D,UAAU7C,SAAd,EAAyB;AACvB6C,gBAAQ,KAAKgP,KAAL,CAAWsI,iBAAX,CAA6BrM,MAAMrH,IAAnC,KAA4C,EAApD;AACA,YAAImH,OAAOqN,gBAAX,EAA6B;AAC3BpY,kBAAQ+K,OAAOqN,gBAAP,CAAwBpY,KAAxB,EAA+BiL,MAAM9D,IAArC,CAAR;AACD;AACF;AACD,aAAOnH,KAAP;AACD;;;2CAEuB+K,M,EAAQE,K,EAAO;AACrC,UAAIA,MAAM,SAAN,MAAqB,IAAzB,EAA+B;AAC7B,YAAIF,OAAOqN,gBAAX,EAA6B;AAC3B,iBAAOrN,OAAOqN,gBAAP,CAAwBnN,MAAM,SAAN,CAAxB,EAA0CA,MAAM9D,IAAhD,CAAP;AACD;AACD,eAAO8D,MAAM,SAAN,CAAP;AACD,OALD,MAKO,IAAIA,MAAMrH,IAAN,KAAe,OAAnB,EAA4B;AACjC,eAAO,KAAKoL,KAAL,CAAWyI,UAAX,CAAsBY,WAA7B;AACD,OAFM,MAEA,IAAIpN,MAAMrH,IAAN,KAAe,WAAnB,EAAgC;AACrC,eAAO,KAAKoL,KAAL,CAAWyI,UAAX,CAAsBa,gBAA7B;AACD,OAFM,MAEA,IAAIrN,MAAMrH,IAAN,KAAe,kBAAnB,EAAuC;AAC5C,eAAO,KAAKoL,KAAL,CAAWyI,UAAX,CAAsBc,uBAA7B;AACD;AACD,aAAO,IAAP;AACD;;;oCAEgBtN,K,EAAOmC,G,EAAK;AAC3B,UAAMrC,SAAS,kBAAQQ,8BAAR,CAAuCN,MAAM9D,IAA7C,CAAf;AACA,aACE,gDAAS,QAAT;AACE,aAAKiG,GADP;AAEE,eAAO,KAAKoL,gBAAL,CAAsBzN,MAAtB,EAA8BE,KAA9B,CAFT;AAGE,qBAAa,KAAKwN,sBAAL,CAA4B1N,MAA5B,EAAoCE,KAApC,CAHf;AAIE,eAAOA,KAJT;AAKE,kBAAU,KAAKyN,aAAL,CAAmBhU,IAAnB,CAAwB,IAAxB,EAA8BuG,KAA9B,CALZ;AAME,kBAAU,EAAEA,MAAM0N,YAAN,IAAsB,IAAtB,IAA+B1N,MAAM0N,YAAN,GAAqB,KAAK3J,KAAL,CAAWyI,UAAX,CAAsBnR,GAAtB,KAA8B,UAApF;AANZ,QADF;AAUD;;;uCAEmB;AAClB,aAAO,kBAAQwG,eAAR,CACL,KAAKkC,KAAL,CAAWwI,eAAX,CAA2BnL,MADtB,EAEL,KAAKC,cAAL,CAAoB5H,IAApB,CAAyB,IAAzB,CAFK,EAGL,KAAKkU,eAAL,CAAqBlU,IAArB,CAA0B,IAA1B,CAHK,CAAP;AAKD;;;6BAES;AACR;AACA,UAAI,KAAKsK,KAAL,CAAWyI,UAAX,KAA0B,IAA9B,EAAoC;AAClC,eAAO,IAAP;AACD;;AAED,UAAIoB,eAAe,IAAnB;AACA,UAAI,KAAK7J,KAAL,CAAWyI,UAAX,CAAsB1C,cAA1B,EAA0C;AACxC8D,uBACE;AAAA;AAAA,YAAQ,MAAK,QAAb,EAAsB,WAAU,iBAAhC;AACE,qBAAS,KAAKC,YAAL,CAAkBpU,IAAlB,CAAuB,IAAvB,CADX;AAC0C,yBAAKtH,KAAL,CAAW,QAAX;AAD1C,SADF;AAID;;AAED,UAAM0J,QAAQ,KAAKkI,KAAL,CAAWyI,UAAX,CAAsB3C,aAAtB,GACV,eAAK1X,KAAL,CAAW,6BAAX,CADU,GAEV,eAAKA,KAAL,CAAW,gBAAX,CAFJ;;AAIA,UAAMoQ,QAAQ,KAAKwB,KAAL,CAAWyI,UAAX,CAAsB7L,UAAtB,GACV,eAAKxO,KAAL,CAAW,KAAK4R,KAAL,CAAWyI,UAAX,CAAsB7L,UAAjC,CADU,GAEV,KAAKoD,KAAL,CAAWyI,UAAX,CAAsBjK,KAF1B;;AAIA,aACE;AAAA;AAAA,UAAK,WAAU,WAAf;AACE;AAAA;AAAA;AAAK1G,gBAAMhI,OAAN,CAAc,IAAd,EAAoB0O,KAApB;AAAL,SADF;AAEG,aAAKuL,gBAAL,EAFH;AAGE;AAAA;AAAA,YAAK,WAAU,SAAf;AACE;AAAA;AAAA,cAAQ,MAAK,QAAb,EAAsB,WAAU,iBAAhC;AACE,uBAAS,KAAKpB,WAAL,CAAiBjT,IAAjB,CAAsB,IAAtB,CADX;AACyC,2BAAKtH,KAAL,CAAW,cAAX;AADzC,WADF;AAGGyb;AAHH;AAHF,OADF;AAWD;;;;;;kBAGYxB,Q;;;;;;;AC/Of;;;;;;;;AAEA;;;;AACA;;;;AACA;;AACA;;;;AACA;;;;AACA;;;;;;;;AAEA,IAAM2B,SAAS,SAATA,MAAS,CAAChZ,KAAD,EAAW;AACxB,SAAOA,UAAU,MAAV,IAAoBA,UAAU,KAA9B,IAAuCA,UAAU,GAAxD;AACD,CAFD;;AAIA,IAAMiZ,cAAc,SAAdA,WAAc,CAACC,IAAD,EAAOC,KAAP,EAAcC,GAAd,EAAsB;AACxCF,SAAO/M,SAAS+M,IAAT,EAAe,EAAf,CAAP;AACAC,UAAQhN,SAASgN,KAAT,EAAgB,EAAhB,CAAR;AACAC,QAAMjN,SAASiN,GAAT,EAAc,EAAd,CAAN;AACA,MAAMC,OAAO,IAAIC,IAAJ,CAASJ,IAAT,EAAeC,QAAQ,CAAvB,EAA0BC,GAA1B,CAAb;AACA,MAAIC,KAAKE,WAAL,OAAuBL,IAAvB,IACAG,KAAKG,QAAL,OAAoBL,QAAQ,CAD5B,IAEAE,KAAKI,OAAL,OAAmBL,GAFvB,EAE4B;AAC1B,WAAO,IAAP;AACD;AACD,SAAO,KAAP;AACD,CAXD;;AAaA,IAAMM,mBAAmB;AACvB7O,UAAQ,0BADe;;AAGvBrC,UAHuB,oBAGbvF,KAHa,EAGN;AACf,QAAIjD,QAAQiD,MAAMwL,MAAN,CAAazO,KAAzB;AACA,QAAI,KAAK2Z,gBAAT,EAA2B;AACzB3Z,cAAQ,KAAK2Z,gBAAL,CAAsB3Z,KAAtB,CAAR;AACD;AACD,SAAKqD,KAAL,CAAWmF,QAAX,CAAoBxI,KAApB;AACD,GATsB;AAWvB8K,QAXuB,oBAWb;AAAA,iBACyC,KAAKzH,KAD9C;AAAA,QACH8D,IADG,UACHA,IADG;AAAA,QACGqB,QADH,UACGA,QADH;AAAA,QACagB,SADb,UACaA,SADb;AAAA,QAC2BoQ,UAD3B;;AAER,QAAIC,OAAO,IAAX;AACA,QAAMC,UAAU,KAAKlR,oBAAL,EAAhB;AACAY,gBAAaA,aAAa,EAA1B;AACAA,iBAAa,cAAb;;AAEA,QAAIsQ,YAAY,IAAhB,EAAsB;AACpBtQ,mBAAa,uBAAuBsQ,QAAQ3S,IAA5C;AACA,UAAM4S,eAAe,uCAAuCD,QAAQ3S,IAApE;AACA0S,aAAO;AAAA;AAAA,UAAK,WAAWE,YAAhB;AAA+BD,gBAAQ5R;AAAvC,OAAP;AACD;;AAED,QAAI8R,QAAQ,IAAZ;AACA,QAAMC,kBAAkB9S,KAAK+S,gBAA7B;AACA,QAAID,eAAJ,EAAqB;AACnBD,cAAQ,oBAAU1M,MAAV,CAAiB2M,eAAjB,CAAR;AACD,KAFD,MAEO,IAAI,KAAKE,aAAT,EAAwB;AAC7BH,cAAQ,KAAKG,aAAL,EAAR;AACD;;AAED,WACE;AAAA;AAAA,QAAK,WAAU,YAAf;AACE;AAAA;AAAA,UAAK,WAAW3Q,SAAhB;AACE;AACE,gBAAM,KAAK4Q,YAAL,EADR;AAEE,qBAAW,KAAK1R,aAAL,EAFb;AAGE,oBAAUF,WAAW,KAAKA,QAAhB,GAA2BrL;AAHvC,WAIMyc,UAJN,EADF;AAMGI,gBAAQ;AAAA;AAAA,YAAM,WAAU,mBAAhB;AAAqCA;AAArC,SAAR,GAA6D;AANhE,OADF;AASGH;AATH,KADF;AAaD;AA7CsB,CAAzB;;AAgDA,IAAMjQ,4BAA4B,gBAAMgB,WAAN,CAAkB;AAAA;;AAClDC,UAAQ,CAAC6O,gBAAD,CAD0C;;AAGlDU,cAHkD,0BAGlC;AACd,WAAO,MAAP;AACD,GALiD;AAOlDD,eAPkD,2BAOjC;AACf,WAAO,qCAAG,WAAU,iBAAb,GAAP;AACD;AATiD,CAAlB,CAAlC;;AAYA,IAAMhQ,kBAAkB,gBAAMS,WAAN,CAAkB;AAAA;;AACxCC,UAAQ,CAAC6O,gBAAD,CADgC;;AAGxCC,kBAHwC,4BAGtB3Z,KAHsB,EAGf;AACvB,WAAOA,MAAMlB,OAAN,CAAc,MAAd,EAAsB,GAAtB,CAAP;AACD,GALuC;AAOxCsb,cAPwC,0BAOxB;AACd,WAAO,MAAP;AACD,GATuC;AAWxCD,eAXwC,2BAWvB;AACf,WAAO,qCAAG,WAAU,YAAb,GAAP;AACD;AAbuC,CAAlB,CAAxB;;AAgBA,IAAMpQ,qBAAqB,gBAAMa,WAAN,CAAkB;AAAA;;AAC3CC,UAAQ,CAAC6O,gBAAD,CADmC;;AAG3CC,kBAH2C,4BAGzB3Z,KAHyB,EAGlB;AACvB,WAAOA,MAAMtD,KAAN,CAAY,eAAZ,EAA6B,CAA7B,CAAP;AACD,GAL0C;AAO3CmM,0BAP2C,sCAOf;AAC1B,QAAI,KAAKxF,KAAL,CAAWrD,KAAX,IAAoB,CAAC,KAAKqD,KAAL,CAAWrD,KAAX,CAAiBtD,KAAjB,CAAuB,OAAvB,CAAzB,EAA0D;AACxD,aAAO,8BAAsB;AAC3BwL,iBAAS,eAAK9K,KAAL,CAAW,sBAAX;AADkB,OAAtB,CAAP;AAGD;AACD,WAAO,IAAP;AACD,GAd0C;AAgB3Cgd,cAhB2C,0BAgB3B;AACd,WAAO,MAAP;AACD,GAlB0C;AAoB3CD,eApB2C,2BAoB1B;AACf,WAAO,GAAP;AACD;AAtB0C,CAAlB,CAA3B;;AAyBA,IAAMnQ,mBAAmB,gBAAMY,WAAN,CAAkB;AAAA;;AACzCC,UAAQ,CAAC6O,gBAAD,CADiC;;AAGzCC,kBAHyC,4BAGvB3Z,KAHuB,EAGhB;AACvB,WAAOA,MAAMtD,KAAN,CAAY,eAAZ,EAA6B,CAA7B,CAAP;AACD,GALwC;AAOzCmM,0BAPyC,sCAOb;AAC1B,QAAI,KAAKxF,KAAL,CAAWrD,KAAX,IAAoBqa,MAAMC,WAAW,KAAKjX,KAAL,CAAWrD,KAAtB,CAAN,CAAxB,EAA6D;AAC3D,aAAO,8BAAsB;AAC3BkI,iBAAS,eAAK9K,KAAL,CAAW,sBAAX;AADkB,OAAtB,CAAP;AAGD;AACD,WAAO,IAAP;AACD,GAdwC;AAgBzCgd,cAhByC,0BAgBzB;AACd,WAAO,MAAP;AACD,GAlBwC;AAoBzCD,eApByC,2BAoBxB;AACf,WAAO,KAAP;AACD;AAtBwC,CAAlB,CAAzB;;AAyBA,IAAMrQ,kBAAkB,gBAAMc,WAAN,CAAkB;AAAA;;AACxCC,UAAQ,CAAC6O,gBAAD,CADgC;;AAGxCC,kBAHwC,4BAGtB3Z,KAHsB,EAGf;AACvBA,YAAQA,MAAMtD,KAAN,CAAY,eAAZ,EAA6B,CAA7B,CAAR;AACA,QAAMA,QAAQsD,MAAMtD,KAAN,CAAY,oCAAZ,CAAd;AACA,QAAI0c,YAAJ;AAAA,QAASD,cAAT;AAAA,QAAgBD,aAAhB;AACA,QAAIxc,KAAJ,EAAW;AACT0c,YAAMjN,SAASzP,MAAM,CAAN,CAAT,EAAmB,EAAnB,CAAN;AACAyc,cAAQhN,SAASzP,MAAM,CAAN,CAAT,EAAmB,EAAnB,CAAR;AACAwc,aAAO/M,SAASzP,MAAM,CAAN,CAAT,EAAmB,EAAnB,CAAP;AACA,aACEwc,OAAO,GAAP,IACCC,QAAQ,EAAR,GAAa,GAAb,GAAmB,EADpB,IAC0BA,KAD1B,GACkC,GADlC,IAECC,MAAM,EAAN,GAAW,GAAX,GAAiB,EAFlB,IAEwBA,GAH1B;AAKD;AACD,WAAOpZ,KAAP;AACD,GAlBuC;AAoBxC6I,0BApBwC,sCAoBZ;AAC1B,QAAI,CAAC,KAAKxF,KAAL,CAAWrD,KAAhB,EAAuB;AACrB,aAAO,IAAP;AACD;;AAED,QAAMtD,QAAQ,KAAK2G,KAAL,CAAWrD,KAAX,CAAiBtD,KAAjB,CAAuB,qCAAvB,CAAd;AACA,QAAIA,SAASuc,YAAYvc,MAAM,CAAN,CAAZ,EAAsBA,MAAM,CAAN,CAAtB,EAAgCA,MAAM,CAAN,CAAhC,CAAb,EAAwD;AACtD,aAAO,IAAP;AACD;;AAED,WAAO,8BAAsB;AAC3BwL,eAAS,eAAK9K,KAAL,CAAW,oBAAX;AADkB,KAAtB,CAAP;AAGD,GAjCuC;AAmCxCgd,cAnCwC,0BAmCxB;AACd,WAAO,MAAP;AACD,GArCuC;AAuCxCD,eAvCwC,2BAuCvB;AACf,WAAO,qCAAG,WAAU,gBAAb,GAAP;AACD;AAzCuC,CAAlB,CAAxB;;AA4CA,IAAMjQ,iBAAiB,gBAAMU,WAAN,CAAkB;AAAA;;AACvCC,UAAQ,CAAC6O,gBAAD,CAD+B;;AAGvC7Q,0BAHuC,sCAGX;AAC1B,QAAI,KAAKxF,KAAL,CAAWrD,KAAX,IAAoB,CAAC,gBAAMR,UAAN,CAAiB,KAAK6D,KAAL,CAAWrD,KAA5B,CAAzB,EAA6D;AAC3D,aAAO,8BAAsB;AAC3BkI,iBAAS,eAAK9K,KAAL,CAAW,mBAAX;AADkB,OAAtB,CAAP;AAGD;AACD,WAAO,IAAP;AACD,GAVsC;AAYvCgd,cAZuC,0BAYvB;AACd,WAAO,MAAP;AACD,GAdsC;AAgBvCD,eAhBuC,2BAgBtB;AACf,WAAO,qCAAG,WAAU,qBAAb,GAAP;AACD;AAlBsC,CAAlB,CAAvB;;AAqBA,IAAMtQ,2BAA2B,gBAAMe,WAAN,CAAkB;AAAA;;AACjDC,UAAQ,0BADyC;;AAGjDrC,UAHiD,oBAGvCvF,KAHuC,EAGhC;AACf,SAAKsX,eAAL;AACA,QAAI,KAAKlX,KAAL,CAAWmF,QAAf,EAAyB;AACvB,WAAKnF,KAAL,CAAWmF,QAAX,CAAoBvF,MAAMwL,MAAN,CAAazO,KAAjC;AACD;AACF,GARgD;AAUjDwa,mBAViD,+BAU5B;AACnB,SAAKD,eAAL;AACAtR,WAAOC,gBAAP,CAAwB,QAAxB,EAAkC,KAAKqR,eAAvC;AACD,GAbgD;AAejDE,sBAfiD,kCAezB;AACtBxR,WAAOE,mBAAP,CAA2B,QAA3B,EAAqC,KAAKoR,eAA1C;AACD,GAjBgD;AAmBjDG,oBAnBiD,8BAmB7BvL,SAnB6B,EAmBlB;AAC7B,SAAKoL,eAAL;AACD,GArBgD;AAuBjDI,oBAvBiD,gCAuB3B;AACpB,WAAO,KAAKtX,KAAL,CAAW6J,IAAX,KAAoB/P,SAA3B;AACD,GAzBgD;AA2BjDod,iBA3BiD,6BA2B9B;AACjB,QAAI,CAAC,KAAKI,kBAAL,EAAL,EAAgC;AAC9B;AACD;AACD,QAAIlF,aAAJ;AACA,QAAIzR,OAAO,KAAKsM,IAAL,CAAUsK,EAArB;;AAEA,QAAI3R,OAAO4R,gBAAX,EAA6B;AAC3B,UAAMC,IAAI7R,OAAO4R,gBAAP,CAAwB7W,IAAxB,CAAV;AACA,UAAI8W,EAAEC,gBAAF,CAAmB,YAAnB,MAAqC,YAArC,IACAD,EAAEC,gBAAF,CAAmB,iBAAnB,MAA0C,YAD1C,IAEAD,EAAEC,gBAAF,CAAmB,oBAAnB,MAA6C,YAFjD,EAE+D;AAC7DtF,eAAO,CAAP;AACD,OAJD,MAIO;AACLA,eACEtJ,SAAS2O,EAAEC,gBAAF,CAAmB,gBAAnB,KAAwC,CAAjD,EAAoD,EAApD,IACA5O,SAAS2O,EAAEC,gBAAF,CAAmB,aAAnB,KAAqC,CAA9C,EAAiD,EAAjD,CAFF;AAID;AACF,KAZD,MAYO;AACLtF,aAAO,CAAP;AACD;;AAED,QAAMuF,uBAAuB,sBAAOhX,IAAP,EAAa2K,EAAb,CAAgB,QAAhB,CAA7B;AACA;AACA,QAAMsM,eAAezY,SAAS0Y,eAAT,CAAyBvY,SAAzB,IAAsCH,SAASC,IAAT,CAAcE,SAAzE;AACA,QAAMwY,YAAY,sBAAOnX,IAAP,EAAaoX,WAAb,EAAlB;;AAEApX,SAAKqX,KAAL,CAAWC,MAAX,GAAoB,MAApB;AACA,QAAMC,YAAavX,KAAKpB,YAAL,GAAoB6S,IAAvC;AACAzR,SAAKqX,KAAL,CAAWC,MAAX,GAAoBC,YAAY,IAAhC;;AAEA,QAAIP,oBAAJ,EAA0B;AACxB/R,aAAOuN,QAAP,CACEhU,SAASC,IAAT,CAAc+Y,UADhB,EAC4BP,gBAAgBM,YAAYJ,SAA5B,CAD5B;AAED;AACF,GA/DgD;AAiEjDrQ,QAjEiD,oBAiEvC;AAAA,kBACgD,KAAKzH,KADrD;AAAA,QACHmG,SADG,WACHA,SADG;AAAA,QACQrC,IADR,WACQA,IADR;AAAA,QACcqB,QADd,WACcA,QADd;AAAA,QACwB6S,KADxB,WACwBA,KADxB;AAAA,QACkCzB,UADlC,kFAC2D;;;AACnEpQ,gBAAaA,aAAa,EAA1B;;AAEA6R,YAAQA,SAAS,EAAjB;AACA,QAAI,KAAKV,kBAAL,EAAJ,EAA+B;AAC7BU,YAAMI,OAAN,GAAgB,OAAhB;AACAJ,YAAMK,QAAN,GAAiB,QAAjB;AACAL,YAAMM,MAAN,GAAe,MAAf;AACD;;AAED,WACE;AAAA;AAAA,QAAK,WAAWnS,SAAhB;AACE;AACE,aAAI,IADN;AAEE,mBAAW,KAAKd,aAAL,EAFb;AAGE,kBAAUF,WAAW,KAAKA,QAAhB,GAA2BrL,SAHvC;AAIE,eAAOke;AAJT,SAKMzB,UALN;AADF,KADF;AAUD;AAtFgD,CAAlB,CAAjC;;AAyFA,IAAM3P,qBAAqB,gBAAMW,WAAN,CAAkB;AAAA;;AAC3CC,UAAQ,0BADmC;;AAG3CrC,UAH2C,oBAGjCvF,KAHiC,EAG1B;AACf,SAAKI,KAAL,CAAWmF,QAAX,CAAoBvF,MAAMwL,MAAN,CAAamN,OAAb,GAAuB,KAAvB,GAA+B,IAAnD;AACD,GAL0C;AAO3CpB,mBAP2C,+BAOtB;AACnB,QAAMqB,WAAW,KAAKvL,IAAL,CAAUuL,QAA3B;AACA,QAAI,CAAC,KAAKxY,KAAL,CAAWrD,KAAZ,IAAqB,KAAKqD,KAAL,CAAWkF,WAApC,EAAiD;AAC/CsT,eAASC,aAAT,GAAyB,IAAzB;AACAD,eAASD,OAAT,GAAmB5C,OAAO,KAAK3V,KAAL,CAAWkF,WAAlB,CAAnB;AACD,KAHD,MAGO;AACLsT,eAASC,aAAT,GAAyB,KAAzB;AACD;AACF,GAf0C;AAiB3ChR,QAjB2C,oBAiBjC;AAAA,kBAC6D,KAAKzH,KADlE;AAAA,QACHmG,SADG,WACHA,SADG;AAAA,QACQrC,IADR,WACQA,IADR;AAAA,QACcoB,WADd,WACcA,WADd;AAAA,QAC2BC,QAD3B,WAC2BA,QAD3B;AAAA,QACqCxI,KADrC,WACqCA,KADrC;AAAA,QAC+C4Z,UAD/C,iGACwE;;;AAChFpQ,gBAAY,CAACA,aAAa,EAAd,IAAoB,WAAhC;;AAEA,WACE;AAAA;AAAA,QAAK,WAAWA,SAAhB;AACE;AAAA;AAAA;AACE,0DAAO,MAAK;AAAZ,WACMoQ,UADN;AAEE,eAAI,UAFN;AAGE,mBAASZ,OAAOhZ,KAAP,CAHX;AAIE,oBAAUwI,WAAW,KAAKA,QAAhB,GAA2BrL,SAJvC,IADF;AAMGgK,aAAK4U,mBAAL,GAA2B,eAAK3e,KAAL,CAAW+J,KAAK4U,mBAAhB,CAA3B,GAAkE;AANrE;AADF,KADF;AAYD;AAjC0C,CAAlB,CAA3B;;kBAoCe;AACbnS,6BAA2BA,yBADd;AAEbO,mBAAiBA,eAFJ;AAGbJ,sBAAoBA,kBAHP;AAIbC,oBAAkBA,gBAJL;AAKbF,mBAAiBA,eALJ;AAMbI,kBAAgBA,cANH;AAObL,4BAA0BA,wBAPb;AAQbI,sBAAoBA;AARP,C;;;;;;;ACtVf;;;;;;;;AAEA;;;;AACA;;;;AACA;;;;AACA;;;;;;AAEA,IAAMI,wBAAwB,gBAAMO,WAAN,CAAkB;AAAA;;AAC9CC,UAAQ,0BADsC;;AAG9CmR,WAAS;AACP5D,sBAAkB,0BAACpY,KAAD,EAAW;AAC3B,UAAIA,UAAU,EAAd,EAAkB;AAChB,eAAO,IAAP;AACD;AACD,UAAI3D,KAAK2D,MAAM/C,KAAN,CAAY,GAAZ,EAAiB6G,GAAjB,CAAqB,UAACC,CAAD,EAAO;AACnC,eAAOA,EAAErH,KAAF,CAAQ,eAAR,EAAyB,CAAzB,CAAP;AACD,OAFQ,CAAT;AAGA,UAAIL,GAAG8B,MAAH,KAAc,CAAd,IAAmB9B,GAAG,CAAH,MAAU,EAAjC,EAAqC;AACnCA,aAAK,EAAL;AACD;AACD,aAAOA,EAAP;AACD,KAZM;;AAcP4b,oBAAgB,wBAACjY,KAAD,EAAW;AACzB,aAAO,CAACA,SAAS,EAAV,EAAcmC,IAAd,CAAmB,IAAnB,CAAP;AACD;AAhBM,GAHqC;;AAsB9CqG,YAAU,kBAAUyC,KAAV,EAAiBhI,KAAjB,EAAwB;AAChC,QAAMgZ,WAAW,gBAAMnc,YAAN,CAAmB,KAAKuD,KAAL,CAAWrD,KAA9B,EACfiL,KADe,EACRhI,MAAMwL,MAAN,CAAamN,OADL,CAAjB;AAEA,QAAI,KAAKvY,KAAL,CAAWmF,QAAf,EAAyB;AACvB,WAAKnF,KAAL,CAAWmF,QAAX,CAAoByT,QAApB;AACD;AACF,GA5B6C;;AA8B9Chc,YAAU,kBAAUgL,KAAV,EAAiB;AACzB,QAAIjL,QAAQ,KAAKqD,KAAL,CAAWrD,KAAvB;AACA,QAAIA,SAAS,IAAb,EAAmB;AACjBA,cAAQ,KAAKqD,KAAL,CAAWkF,WAAnB;AACA,UAAIvI,SAAS,IAAb,EAAmB;AACjB,eAAO,KAAP;AACD;AACF;AAPwB;AAAA;AAAA;;AAAA;AAQzB,2BAAmBA,KAAnB,8HAA0B;AAAA,YAAfmN,IAAe;;AACxB,YAAIA,SAASlC,KAAb,EAAoB;AAClB,iBAAO,IAAP;AACD;AACF;AAZwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAazB,WAAO,KAAP;AACD,GA5C6C;;AA8C9CH,QA9C8C,oBA8CpC;AAAA;;AAAA,iBACmD,KAAKzH,KADxD;AAAA,QACHmG,SADG,UACHA,SADG;AAAA,QACQxJ,KADR,UACQA,KADR;AAAA,QACeuI,WADf,UACeA,WADf;AAAA,QAC4BpB,IAD5B,UAC4BA,IAD5B;AAAA,QACqCyS,UADrC,oFAC8D;;;AACtEpQ,gBAAY,CAACA,aAAa,EAAd,IAAoB,WAAhC;;AAEA,QAAM0S,UAAU,KAAK7Y,KAAL,CAAW8D,IAAX,CAAgB+U,OAAhB,CAAwBpY,GAAxB,CAA4B,UAACqJ,IAAD,EAAU;AACpD,aACE;AAAA;AAAA,UAAK,WAAW3D,SAAhB,EAA2B,KAAK2D,KAAK,CAAL,CAAhC;AACE;AAAA;AAAA;AACE,4DAAO,MAAK;AAAZ,aACMyM,UADN;AAEE,qBAAS,MAAK3Z,QAAL,CAAckN,KAAK,CAAL,CAAd,CAFX;AAGE,sBAAU,MAAK3E,QAAL,CAAc9D,IAAd,QAAyByI,KAAK,CAAL,CAAzB,CAHZ,IADF;AAKG,yBAAK/P,KAAL,CAAW+P,KAAK,CAAL,CAAX;AALH;AADF,OADF;AAWD,KAZe,CAAhB;AAaA,WACE;AAAA;AAAA,QAAK,WAAU,YAAf;AACG+O;AADH,KADF;AAKD;AApE6C,CAAlB,CAA9B;;AAuEA,IAAM5R,oBAAoB,gBAAMM,WAAN,CAAkB;AAAA;;AAC1CC,UAAQ,0BADkC;;AAG1CrC,UAH0C,oBAGhCvF,KAHgC,EAGzB;AACf,SAAKI,KAAL,CAAWmF,QAAX,CAAoBvF,MAAMwL,MAAN,CAAazO,KAAjC;AACD,GALyC;AAO1C8K,QAP0C,oBAOhC;AAAA,kBAC6D,KAAKzH,KADlE;AAAA,QACHmG,SADG,WACHA,SADG;AAAA,QACQrC,IADR,WACQA,IADR;AAAA,QACcnH,KADd,WACcA,KADd;AAAA,QACqBuI,WADrB,WACqBA,WADrB;AAAA,QACkCC,QADlC,WACkCA,QADlC;AAAA,QAC+CoR,UAD/C,iGACwE;;;AAChF5Z,YAAQA,SAASuI,WAAjB;;AAEA,QAAI2T,UAAU,KAAK7Y,KAAL,CAAW8D,IAAX,CAAgB+U,OAAhB,CAAwBpY,GAAxB,CAA4B,UAACqJ,IAAD,EAAU;AAClD,aACE;AAAA;AAAA,UAAQ,KAAKA,KAAK,CAAL,CAAb,EAAsB,OAAOA,KAAK,CAAL,CAA7B;AACG,uBAAK/P,KAAL,CAAW+P,KAAK,CAAL,CAAX;AADH,OADF;AAKD,KANa,CAAd;AAOA+O,YAAQha,OAAR,CACE;AAAA;AAAA,QAAQ,KAAI,EAAZ,EAAe,OAAM,EAArB;AAAyB;AAAzB,KADF;;AAIA,WACE;AAAA;AAAA,QAAK,WAAU,YAAf;AACE;AAAA;AAAA,UAAK,WAAWsH,SAAhB;AACE;AAAA;AAAA;AACE,uBAAW,KAAKd,aAAL,EADb;AAEE,sBAAUF,WAAW,KAAKA,QAAhB,GAA2B,IAFvC;AAGE,mBAAOxI;AAHT,aAIM4Z,UAJN;AAKGsC;AALH;AADF;AADF,KADF;AAaD;AAnCyC,CAAlB,CAA1B;;kBAsCe;AACb7R,yBAAuBA,qBADV;AAEbC,qBAAmBA;AAFN,C;;;;;;;ACpHf;;AAEA;;;;;;;;AAEA;;;;AACA;;;;AACA;;;;AACA;;AACA;;;;AACA;;;;;;AAEA;AACA,IAAMuB,qBAAqB,SAArBA,kBAAqB,CAAC1E,IAAD,EAAU;AACnC,SAAO,kBAAQ0E,kBAAR,CAA2B1E,IAA3B,CAAP;AACD,CAFD;;AAIA,IAAMgV,aAAa,SAAbA,UAAa,GAAM;AACvB;AACD,CAFD;;AAIA,IAAMC,kBAAkB,SAAlBA,eAAkB,CAACpc,KAAD,EAAW;AACjC,MAAIqc,SAAS,EAAb;AACA,MAAIC,MAAM,EAAV;AACA,MAAIC,QAAQvc,MAAM/C,KAAN,CAAY,OAAZ,CAAZ;AACA,MAAIuf,QAAQ,IAAZ;;AAJiC;AAAA;AAAA;;AAAA;AAMjC,yBAAmBD,KAAnB,8HAA0B;AAAA,UAAfE,IAAe;;AACxB;AACA,UAAID,UAAU,IAAV,IAAkBC,KAAK/f,KAAL,CAAW,OAAX,CAAtB,EAA2C;AACzC;AACD;;AAED,UAAMggB,aAAaD,KAAK/f,KAAL,CAAW,6BAAX,CAAnB;AACA,UAAI,CAACggB,UAAL,EAAiB;AACf,YAAIF,UAAU,IAAd,EAAoB;AAClB;AACA,iBAAO,IAAP;AACD;AACF,OALD,MAKO;AACL,YAAIA,UAAU,IAAd,EAAoB;AAClBH,iBAAOhe,IAAP,CAAY,CAACme,KAAD,EAAQF,GAAR,CAAZ;AACAA,gBAAM,EAAN;AACD;AACDE,gBAAQE,WAAW,CAAX,CAAR;AACA;AACD;;AAEDJ,UAAIje,IAAJ,CAASoe,KAAK3d,OAAL,CAAa,mBAAb,EAAkC,YAAlC,CAAT;AACD;AA5BgC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AA8BjC,MAAI0d,UAAU,IAAd,EAAoB;AAClBH,WAAOhe,IAAP,CAAY,CAACme,KAAD,EAAQF,GAAR,CAAZ;AACD;;AAED,SAAOD,MAAP;AACD,CAnCD;;AAqCA,IAAMM,sBAAsB,SAAtBA,mBAAsB,CAACN,MAAD,EAAY;AACtC,MAAIhgB,KAAK,EAAT;AACAggB,SAAO9f,OAAP,CAAe,UAACigB,KAAD,EAAW;AAAA,gCACGA,KADH;AAAA,QACjBI,SADiB;AAAA,QACNL,KADM;;AAExBlgB,OAAGgC,IAAH,CAAQ,UAAUue,SAAV,GAAsB,SAA9B;AACAL,UAAMhgB,OAAN,CAAc,UAACkgB,IAAD,EAAU;AACtBpgB,SAAGgC,IAAH,CAAQoe,KAAK3d,OAAL,CAAa,0BAAb,EAAyC,QAAzC,CAAR;AACD,KAFD;AAGD,GAND;;AAQAzC,OAAKA,GAAG8F,IAAH,CAAQ,EAAR,CAAL;;AAEA;;;AAGA,MAAI9F,GAAGA,GAAG8B,MAAH,GAAY,CAAf,MAAsB,IAA1B,EAAgC;AAC9B9B,SAAKA,GAAGuC,MAAH,CAAU,CAAV,EAAavC,GAAG8B,MAAH,GAAY,CAAzB,CAAL;AACD;;AAED,SAAO9B,EAAP;AACD,CApBD;;AAsBA,IAAMwgB,uBAAuB,SAAvBA,oBAAuB,CAACC,cAAD,EAAiBP,KAAjB,EAAwBQ,OAAxB,EAAoC;AAC/D,MAAIzb,OAAO,EAAX;AACA,MAAI0b,UAAU,EAAd;;AAEA,uBAAWC,QAAX,CAAoBV,KAApB,EAA2BhgB,OAA3B,CAAmC,UAAC4Q,IAAD,EAAU;AAAA,+BACtBA,IADsB;AAAA,QACpC3Q,GADoC;AAAA,QAC/B+f,KAD+B;;AAE3C,QAAMvc,QAAQuc,MAAMpa,IAAN,CAAW,EAAX,CAAd;AACA6a,YAAQxgB,GAAR,IAAewD,KAAf;AACD,GAJD;;AAMA8c,iBAAezQ,MAAf,CAAsB9P,OAAtB,CAA8B,UAAC0O,KAAD,EAAW;AACvC,QAAIjL,QAAQgd,QAAQ/R,MAAMrH,IAAd,KAAuB,EAAnC;AACA,QAAM0H,SAASO,mBAAmBZ,MAAM9D,IAAzB,CAAf;AACA,QAAI,CAACnH,KAAD,IAAUiL,MAAM,SAAN,CAAd,EAAgC;AAC9BjL,cAAQiL,MAAM,SAAN,CAAR;AACD;AACD,QAAIK,UAAUA,OAAO8M,gBAArB,EAAuC;AACrCpY,cAAQsL,OAAO8M,gBAAP,CAAwBpY,KAAxB,EAA+BiL,MAAM9D,IAArC,CAAR;AACD;AACD7F,SAAK2J,MAAMrH,IAAX,IAAmB5D,KAAnB;AACD,GAVD;;AAYA,SAAO;AACL+c,aAASA,WAAW,IADf;AAELD,oBAAgBA,cAFX;AAGLxb,UAAMA;AAHD,GAAP;AAKD,CA3BD;;AA6BA,IAAM4b,qBAAqB,SAArBA,kBAAqB,CAACC,eAAD,EAAkB7b,IAAlB,EAA2B;AACpD,MAAIjF,KAAK,EAAT;AACA8gB,kBAAgB9Q,MAAhB,CAAuB9P,OAAvB,CAA+B,UAAC0O,KAAD,EAAW;AACxC,QAAMK,SAASO,mBAAmBZ,MAAM9D,IAAzB,CAAf;AACA,QAAImE,WAAW,IAAf,EAAqB;AACnB;AACD;;AAED,QAAItL,QAAQsB,KAAK2J,MAAMrH,IAAX,CAAZ;AACA,QAAI5D,UAAU7C,SAAV,IAAuB6C,UAAU,IAArC,EAA2C;AACzC;AACD;;AAED,QAAIsL,OAAO2M,cAAX,EAA2B;AACzBjY,cAAQsL,OAAO2M,cAAP,CAAsBjY,KAAtB,EAA6BiL,MAAM9D,IAAnC,CAAR;AACD;;AAED9K,OAAGgC,IAAH,CAAQ,CAAC4M,MAAMrH,IAAP,EAAa5D,KAAb,CAAR;AACD,GAhBD;AAiBA,SAAO,qBAAWod,SAAX,CAAqB/gB,EAArB,CAAP;AACD,CApBD;;AAsBA;AACA,IAAIghB,cAAc,CAAlB;;AAEA,IAAMjT,aAAa,gBAAMQ,WAAN,CAAkB;AAAA;;AACnCC,UAAQ,0BAD2B;;AAGnCmR,WAAS;AACP5D,sBAAkB,0BAACpY,KAAD,EAAQmH,IAAR,EAAiB;AACjC,aAAOiV,gBAAgBpc,KAAhB,EAAuB8D,GAAvB,CAA2B,UAACqJ,IAAD,EAAU;AAAA,oCACtBA,IADsB;AAAA,YACnCtG,EADmC;AAAA,YAC/B0V,KAD+B;;AAE1C,YAAMe,YAAYnW,KAAKoW,UAAL,CAAgB1W,EAAhB,CAAlB;AACA,YAAIyW,cAAcngB,SAAlB,EAA6B;AAC3B,iBAAO0f,qBAAqBS,SAArB,EAAgCf,KAAhC,EAAuC,EAAEc,WAAzC,CAAP;AACD;AACD,eAAO,IAAP;AACD,OAPM,CAAP;AAQD,KAVM;;AAYPpF,oBAAgB,wBAACjY,KAAD,EAAW;AACzB,aAAO2c,oBAAoB3c,MAAM8D,GAAN,CAAU,UAACqJ,IAAD,EAAU;AAC7C,eAAO,CACLA,KAAK2P,cAAL,CAAoBjW,EADf,EAELqW,mBAAmB/P,KAAK2P,cAAxB,EAAwC3P,KAAK7L,IAA7C,CAFK,CAAP;AAID,OAL0B,CAApB,CAAP;AAMD;AAnBM,GAH0B;;AAyBnC;;AAEAkc,aAAW,mBAAUpQ,GAAV,EAAeqQ,MAAf,EAAuBxa,KAAvB,EAA8B;AACvCA,UAAMoG,cAAN;;AAEA,QAAMqU,WAAWtQ,MAAMqQ,MAAvB;AACA,QAAIC,WAAW,CAAX,IAAgBA,YAAY,KAAKra,KAAL,CAAWrD,KAAX,CAAiB7B,MAAjD,EAAyD;AACvD;AACD;;AAED,QAAMwf,MAAM,KAAKta,KAAL,CAAWrD,KAAX,CAAiB0d,QAAjB,CAAZ;AACA,SAAKra,KAAL,CAAWrD,KAAX,CAAiB0d,QAAjB,IAA6B,KAAKra,KAAL,CAAWrD,KAAX,CAAiBoN,GAAjB,CAA7B;AACA,SAAK/J,KAAL,CAAWrD,KAAX,CAAiBoN,GAAjB,IAAwBuQ,GAAxB;;AAEA,QAAI,KAAKta,KAAL,CAAWmF,QAAf,EAAyB;AACvB,WAAKnF,KAAL,CAAWmF,QAAX,CAAoB,KAAKnF,KAAL,CAAWrD,KAA/B;AACD;AACF,GA1CkC;;AA4CnC4d,eAAa,qBAAUxQ,GAAV,EAAenK,KAAf,EAAsB;AACjCA,UAAMoG,cAAN;;AAEA,QAAIwU,QAAQ,eAAKzgB,KAAL,CAAW,yBAAX,CAAR,CAAJ,EAAoD;AAClD,WAAKiG,KAAL,CAAWrD,KAAX,CAAiBM,MAAjB,CAAwB8M,GAAxB,EAA6B,CAA7B;AACA,UAAI,KAAK/J,KAAL,CAAWmF,QAAf,EAAyB;AACvB,aAAKnF,KAAL,CAAWmF,QAAX,CAAoB,KAAKnF,KAAL,CAAWrD,KAA/B;AACD;AACF;AACF,GArDkC;;AAuDnC8d,eAAa,qBAAUthB,GAAV,EAAeyG,KAAf,EAAsB;AACjCA,UAAMoG,cAAN;;AAEA,QAAMyT,iBAAiB,KAAKzZ,KAAL,CAAW8D,IAAX,CAAgBoW,UAAhB,CAA2B/gB,GAA3B,CAAvB;;AAEA;AACA,SAAK6G,KAAL,CAAWrD,KAAX,CAAiB3B,IAAjB,CAAsBwe,qBAAqBC,cAArB,EAAqC,EAArC,EACpB,EAAEO,WADkB,CAAtB;AAEA,QAAI,KAAKha,KAAL,CAAWmF,QAAf,EAAyB;AACvB,WAAKnF,KAAL,CAAWmF,QAAX,CAAoB,KAAKnF,KAAL,CAAWrD,KAA/B;AACD;AACF,GAlEkC;;AAoEnC4Y,mBAAiB,yBAAUmF,SAAV,EAAqB9S,KAArB,EAA4BmC,GAA5B,EAAiC;AAAA;;AAChD,QAAM4Q,UAAU7B,YAAhB;AACA,QAAMnc,QAAQ+d,UAAUzc,IAAV,CAAe2J,MAAMrH,IAArB,CAAd;AACA,QAAI2E,cAAc0C,MAAM,SAAN,CAAlB;AACA,QAAMK,SAAS0S,QAAQzS,8BAAR,CAAuCN,MAAM9D,IAA7C,CAAf;AACA,QAAImE,OAAO8M,gBAAP,IAA2B7P,eAAe,IAA9C,EAAoD;AAClDA,oBAAc+C,OAAO8M,gBAAP,CAAwB7P,WAAxB,EAAqC0C,MAAM9D,IAA3C,CAAd;AACD;;AAED,QAAMqB,WAAW,CAAC,KAAKnF,KAAL,CAAWmF,QAAZ,GAAuB,IAAvB,GAA8B,UAACxI,KAAD,EAAW;AACxD+d,gBAAUzc,IAAV,CAAe2J,MAAMrH,IAArB,IAA6B5D,KAA7B;AACA,YAAKqD,KAAL,CAAWmF,QAAX,CAAoB,MAAKnF,KAAL,CAAWrD,KAA/B;AACD,KAHD;;AAKA,WACE,8BAAC,OAAD,CAAS,QAAT;AACE,WAAKoN,GADP;AAEE,aAAOpN,KAFT;AAGE,mBAAauI,WAHf;AAIE,aAAO0C,KAJT;AAKE,gBAAUzC;AALZ,MADF;AASD,GA3FkC;;AA6FnCyV,cA7FmC,0BA6FnB;AAAA;;AACd,QAAMD,UAAU7B,YAAhB;;AAEA,WAAO,KAAK9Y,KAAL,CAAWrD,KAAX,CAAiB8D,GAAjB,CAAqB,UAACia,SAAD,EAAY3Q,GAAZ,EAAoB;AAC9C;AACA,UAAI2Q,cAAc,IAAlB,EAAwB;AACtB,eAAO,IAAP;AACD;;AAED,UAAM1R,SAAS2R,QAAQlR,eAAR,CACbiR,UAAUjB,cAAV,CAAyBzQ,MADZ,EAEb,IAFa,EAGb,OAAKuM,eAAL,CAAqBlU,IAArB,SAAgCqZ,SAAhC,CAHa,CAAf;;AAMA,aACE;AAAA;AAAA,UAAK,KAAKA,UAAUhB,OAApB,EAA6B,WAAU,YAAvC;AACE;AAAA;AAAA,YAAK,WAAU,sBAAf;AACE;AAAA;AAAA;AACE,yBAAU,wBADZ;AAEE,qBAAO,eAAK3f,KAAL,CAAW,IAAX,CAFT;AAGE,wBAAUgQ,QAAQ,CAHpB;AAIE,uBAAS,OAAKoQ,SAAL,CAAe9Y,IAAf,SAA0B0I,GAA1B,EAA+B,CAAC,CAAhC,CAJX;AAKE,iDAAG,WAAU,wBAAb;AALF,WADF;AAQE;AAAA;AAAA;AACE,yBAAU,wBADZ;AAEE,qBAAO,eAAKhQ,KAAL,CAAW,MAAX,CAFT;AAGE,wBAAUgQ,OAAO,OAAK/J,KAAL,CAAWrD,KAAX,CAAiB7B,MAAjB,GAA0B,CAH7C;AAIE,uBAAS,OAAKqf,SAAL,CAAe9Y,IAAf,SAA0B0I,GAA1B,EAA+B,CAA/B,CAJX;AAKE,iDAAG,WAAU,0BAAb;AALF,WARF;AAeE;AAAA;AAAA;AACE,yBAAU,wBADZ;AAEE,qBAAO,eAAKhQ,KAAL,CAAW,QAAX,CAFT;AAGE,uBAAS,OAAKwgB,WAAL,CAAiBlZ,IAAjB,SAA4B0I,GAA5B,CAHX;AAIE,iDAAG,WAAU,mBAAb;AAJF;AAfF,SADF;AAuBE;AAAA;AAAA,YAAI,WAAU,YAAd;AAA4B,8BAAUE,MAAV,CAAiByQ,UAAUjB,cAAV,CAAyB1K,SAA1C;AAA5B,SAvBF;AAwBG/F;AAxBH,OADF;AA4BD,KAxCM,CAAP;AAyCD,GAzIkC;AA2InC6R,uBA3ImC,mCA2IV;AAAA;;AACvB,QAAIhC,UAAU,EAAd;;AAEA,SAAK7Y,KAAL,CAAW8D,IAAX,CAAgBgX,eAAhB,CAAgC5hB,OAAhC,CAAwC,UAACC,GAAD,EAAS;AAC/C,UAAIsgB,iBAAiB,OAAKzZ,KAAL,CAAW8D,IAAX,CAAgBoW,UAAhB,CAA2B/gB,GAA3B,CAArB;AACA,UAAIgR,QAAQsP,eAAesB,YAAf,GACR,oBAAU9Q,MAAV,CAAiBwP,eAAesB,YAAhC,CADQ,GAER,oBAAU9Q,MAAV,CAAiBwP,eAAe1K,SAAhC,CAFJ;AAGA8J,cAAQ7d,IAAR,CAAa,CAACye,eAAejW,EAAhB,EAAoB2G,KAApB,EAA2B,eAAKpQ,KAAL,CAAW0f,eAAe1K,SAA1B,CAA3B,CAAb;AACD,KAND;;AAQA,QAAMiM,UAAUnC,QAAQpY,GAAR,CAAY,UAACqJ,IAAD,EAAU;AAAA,kCACRA,IADQ;AAAA,UAC7B3Q,GAD6B;AAAA,UACxBgR,KADwB;AAAA,UACjB1G,KADiB;;AAEpC,aACE;AAAA;AAAA;AACE,qBAAU,iBADZ;AAEE,mBAAS,OAAKgX,WAAL,CAAiBpZ,IAAjB,SAA4BlI,GAA5B,CAFX;AAGE,iBAAOsK,KAHT;AAIE,eAAKtK,GAJP;AAIagR;AAJb,OADF;AAOD,KATe,CAAhB;;AAWA,WACE;AAAA;AAAA,QAAK,WAAU,WAAf;AACE;AAAA;AAAA;AAAQ,uBAAKpQ,KAAL,CAAW,eAAX,IAA8B;AAAtC,OADF;AAEE;AAAA;AAAA,UAAK,WAAU,WAAf;AACGihB;AADH;AAFF,KADF;AAQD,GAzKkC;AA2KnCvT,QA3KmC,oBA2KzB;AAAA,QACHtB,SADG,GACU,KAAKnG,KADf,CACHmG,SADG;;AAERA,gBAAY,CAACA,aAAa,EAAd,IAAoB,OAAhC;;AAEA,WACE;AAAA;AAAA,QAAK,WAAWA,SAAhB;AACG,WAAKyU,YAAL,EADH;AAEG,WAAKC,qBAAL;AAFH,KADF;AAMD;AArLkC,CAAlB,CAAnB;;kBAwLe;AACb9T,cAAYA;AADC,C;;;;;;;AC7Tf;;;;;;;;AAEA,IAAMkU,eAAe,SAAfA,YAAe,CAAC7B,IAAD,EAAU;AAC7BA,SAAOA,KAAK/f,KAAL,CAAW,eAAX,EAA4B,CAA5B,CAAP;AACA,SAAO+f,KAAKte,MAAL,IAAe,CAAf,IAAoBse,SAAU,IAAI8B,KAAJ,CAAU9B,KAAKte,MAAL,GAAc,CAAxB,CAAD,CAA6BgE,IAA7B,CAAkC,GAAlC,CAApC;AACD,CAHD;;AAKA,IAAMqc,aAAa,SAAbA,UAAa,CAAClC,GAAD,EAAS;AAC1B,MAAMC,QAAQD,IAAIxY,GAAJ,CAAQ,UAAC2Y,IAAD,EAAU;AAC9B,QAAI6B,aAAa7B,IAAb,CAAJ,EAAwB;AACtBA,aAAOA,KAAK7d,MAAL,CAAY,CAAZ,CAAP;AACD;AACD,WAAO6d,IAAP;AACD,GALa,CAAd;;AAOA,MAAIF,MAAMpe,MAAN,GAAe,CAAnB,EAAsB;AACpB,QAAMsgB,WAAWlC,MAAMA,MAAMpe,MAAN,GAAe,CAArB,CAAjB;AACA,QAAIsgB,SAAS7f,MAAT,CAAgB6f,SAAStgB,MAAT,GAAkB,CAAlC,MAAyC,IAA7C,EAAmD;AACjDoe,YAAMA,MAAMpe,MAAN,GAAe,CAArB,IAA0BsgB,SAAS7f,MAAT,CAAgB,CAAhB,EAAmB6f,SAAStgB,MAAT,GAAkB,CAArC,CAA1B;AACD;AACF;;AAED,SAAOoe,KAAP;AACD,CAhBD;;AAkBA,IAAMU,WAAW,SAAXA,QAAW,CAACV,KAAD,EAAW;AAC1B,MAAI/f,MAAM,IAAV;AACA,MAAI8f,MAAM,EAAV;AACA,MAAIoC,cAAc,KAAlB;AACA,MAAMriB,KAAK,EAAX;;AAEA,MAAMsiB,YAAY,SAAZA,SAAY,GAAM;AACtBtiB,OAAGgC,IAAH,CAAQ,CAAC7B,GAAD,EAAMgiB,WAAWlC,GAAX,CAAN,CAAR;AACA9f,UAAM,IAAN;AACA8f,UAAM,EAAN;AACD,GAJD;;AAMA,OAAK,IAAI7d,IAAI,CAAb,EAAgBA,IAAI8d,MAAMpe,MAA1B,EAAkCM,GAAlC,EAAuC;AACrC,QAAMge,OAAOF,MAAM9d,CAAN,EAAS/B,KAAT,CAAe,kBAAf,EAAmC,CAAnC,IAAwC,IAArD;;AAEA,QAAI+f,KAAK/f,KAAL,CAAW,aAAX,EAA0B,CAA1B,MAAiC,KAArC,EAA4C;AAC1CgiB,oBAAc,KAAd;AACA,UAAIliB,QAAQ,IAAZ,EAAkB;AAChBmiB;AACD;AACF,KALD,MAKO,IAAIniB,QAAQ,IAAZ,EAAkB;AACvB,UAAIkiB,WAAJ,EAAiB;AACfA,sBAAc,KAAd;AACA,YAAIjC,KAAK/f,KAAL,CAAW,OAAX,CAAJ,EAAyB;AACvB;AACD;AACF;AACD4f,UAAIje,IAAJ,CAASoe,IAAT;AACD,KARM,MAQA;AACL,UAAMmC,OAAOnC,KAAKxf,KAAL,CAAW,GAAX,CAAb;AACA,UAAI2hB,KAAKzgB,MAAL,IAAe,CAAnB,EAAsB;AACpB3B,cAAMoiB,KAAK3a,KAAL,GAAavH,KAAb,CAAmB,gBAAnB,EAAqC,CAArC,CAAN;AACA,YAAMmiB,WAAWD,KAAKzc,IAAL,CAAU,GAAV,EAAezF,KAAf,CAAqB,sBAArB,EAA6C,CAA7C,CAAjB;AACA,YAAI,CAACmiB,SAASniB,KAAT,CAAe,OAAf,CAAL,EAA8B;AAC5B4f,gBAAM,CAACuC,QAAD,CAAN;AACD,SAFD,MAEO;AACLvC,gBAAM,EAAN;AACAoC,wBAAc,IAAd;AACD;AACF;AACF;AACF;;AAED,MAAIliB,QAAQ,IAAZ,EAAkB;AAChBmiB;AACD;;AAED,SAAOtiB,EAAP;AACD,CAhDD;;AAkDA,IAAM+gB,YAAY,SAAZA,SAAY,CAACf,MAAD,EAAY;AAC5B,MAAMhgB,KAAK,EAAX;;AAEAggB,SAAO9f,OAAP,CAAe,UAAC4Q,IAAD,EAAOC,GAAP,EAAe;AAAA,+BACPD,IADO;AAAA,QACrB3Q,GADqB;AAAA,QAChBwD,KADgB;;AAE5B,QAAIoN,MAAM,CAAV,EAAa;AACX/Q,SAAGgC,IAAH,CAAQ,OAAR;AACD;AACD,QAAI2B,MAAMtD,KAAN,CAAY,6BAAZ,CAAJ,EAAgD;AAC9CL,SAAGgC,IAAH,CAAQ7B,MAAM,KAAd;AACAH,SAAGgC,IAAH,CAAQ,IAAR;AACA,UAAMke,QAAQvc,MAAM/C,KAAN,CAAY,IAAZ,CAAd;AACA,UAAIsf,MAAMA,MAAMpe,MAAN,GAAe,CAArB,MAA4B,EAAhC,EAAoC;AAClCoe,cAAMuC,GAAN;AACD;AACDvC,YAAMhgB,OAAN,CAAc,UAACkgB,IAAD,EAAOrP,GAAP,EAAY2R,GAAZ,EAAoB;AAChC,YAAIT,aAAa7B,IAAb,CAAJ,EAAwB;AACtBA,iBAAO,MAAMA,IAAb;AACD;AACDpgB,WAAGgC,IAAH,CAAQoe,OAAO,IAAf;AACD,OALD;AAMD,KAbD,MAaO;AACLpgB,SAAGgC,IAAH,CAAQ7B,MAAM,IAAN,GAAawD,KAAb,GAAqB,IAA7B;AACD;AACF,GArBD;;AAuBA,SAAO3D,EAAP;AACD,CA3BD;;kBA6Be;AACb4gB,YAAUA,QADG;AAEbG,aAAWA;AAFE,C;;;;;;;ACxGf;;;;;;AAEA;;;;AACA;;;;AACA;;AACA;;;;;;AAEA,IAAM4B,kBAAkB;AACtBnU,UAAQ,0BADc;AAEtBzC,aAAW;AACT6C,WAAO,oBAAU5C;AADR,GAFW;;AAMtB2T,WAAS;AACPxQ,kBAAc;AADP;AANa,CAAxB;;AAWA,IAAMjB,aAAa,gBAAMK,WAAN,CAAkB;AAAA;;AACnCC,UAAQ,CAACmU,eAAD,CAD2B;;AAGnClU,QAHmC,oBAGzB;AACR,WAAO,yCAAP;AACD;AALkC,CAAlB,CAAnB;;AAQA,IAAMN,gBAAgB,gBAAMI,WAAN,CAAkB;AAAA;;AACtCC,UAAQ,CAACmU,eAAD,CAD8B;;AAGtClU,QAHsC,oBAG5B;AACR,WAAO,uCAAK,WAAU,SAAf,GAAP;AACD;AALqC,CAAlB,CAAtB;;AAQA,IAAML,aAAa,gBAAMG,WAAN,CAAkB;AAAA;;AACnCC,UAAQ,CAACmU,eAAD,CAD2B;;AAGnClU,QAHmC,oBAGzB;AACR,QAAM0C,QAAQ,eAAKpQ,KAAL,CAAW,KAAKiG,KAAL,CAAW4H,KAAX,CAAiBW,UAA5B,CAAd;AACA,WACE;AAAA;AAAA,QAAK,WAAU,MAAf;AACE;AAAA;AAAA;AACG4B,gBAAQ;AAAA;AAAA;AAASA,kBAAQ;AAAjB,SAAR,GAA0C,IAD7C;AAEG,uBAAKpQ,KAAL,CAAW,KAAKiG,KAAL,CAAW4H,KAAX,CAAiBS,gBAA5B;AAFH;AADF,KADF;AAQD;AAbkC,CAAlB,CAAnB;;AAgBA,IAAMhB,gBAAgB,gBAAME,WAAN,CAAkB;AAAA;;AACtCC,UAAQ,CAACmU,eAAD,CAD8B;;AAGtClU,QAHsC,oBAG5B;AACR,WACE;AAAA;AAAA;AAAK,qBAAK1N,KAAL,CAAW,KAAKiG,KAAL,CAAW8D,IAAX,CAAgB8X,YAA3B;AAAL,KADF;AAGD;AAPqC,CAAlB,CAAtB;;kBAUe;AACb1U,cAAYA,UADC;AAEbC,iBAAeA,aAFF;AAGbC,cAAYA,UAHC;AAIbC,iBAAeA;AAJF,C;;;;;;;AC5Df;;;;;;;;;;AAEA;;;;AACA;;;;AACA;;;;;;;;;;;;;;IAEMwU,W;;;AACJ,uBAAa7b,KAAb,EAAoB;AAAA;;AAAA,0HACZA,KADY;;AAElB,UAAK2L,KAAL,GAAa;AACXmQ,iBAAW9b,MAAM+b;AADN,KAAb;AAFkB;AAKnB;;;;2BAEOnc,K,EAAO;AACbA,YAAMoG,cAAN;AACA,WAAKgG,QAAL,CAAc;AACZ8P,mBAAW,CAAC,KAAKnQ,KAAL,CAAWmQ;AADX,OAAd;AAGD;;;6BAES;AAAA,mBACkE,KAAK9b,KADvE;AAAA,UACHmG,SADG,UACHA,SADG;AAAA,UACQ6V,UADR,UACQA,UADR;AAAA,UACoB/V,QADpB,UACoBA,QADpB;AAAA,UAC8B8V,iBAD9B,UAC8BA,iBAD9B;AAAA,UACoDxF,UADpD;;AAERpQ,kBAAY,CAACA,aAAa,EAAd,IAAoB,eAAhC;AACA,UAAI,KAAKwF,KAAL,CAAWmQ,SAAf,EAA0B;AACxB3V,qBAAa,oBAAb;AACD,OAFD,MAEO;AACLA,qBAAa,sBAAb;AACD;;AAED,aACE;AAAA;AAAA,mBAAK,WAAWA,SAAhB,IAA+BoQ,UAA/B;AACE;AAAA;AAAA,YAAK,WAAU,QAAf;AACE;AAAA;AAAA,cAAI,WAAU,QAAd,EAAuB,SACrB,KAAK0F,MAAL,CAAY5a,IAAZ,CAAiB,IAAjB,CADF;AAC2B2a;AAD3B;AADF,SADF;AAKE;AAAA;AAAA,YAAK,WAAU,UAAf;AACG/V;AADH;AALF,OADF;AAWD;;;;;;AAGH4V,YAAY9W,SAAZ,GAAwB;AACtBiX,cAAY,oBAAU9hB,MADA;AAEtB6hB,qBAAmB,oBAAU1V;AAFP,CAAxB;;kBAKewV,W;;;;;;;ACjDf;;;;;;;;;;AAEA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;AACA;;;;;;;;;;;;IAEMK,U;;;AACJ,sBAAalc,KAAb,EAAoB;AAAA;;AAAA,wHACZA,KADY;;AAGlB,UAAK2L,KAAL,GAAa;AACXyI,kBAAY,IADD;AAEX+H,0BAAoB;AAFT,KAAb;AAHkB;AAOnB;;;;wCAEoB;AACnB;AACA,WAAKhO,UAAL;AACD;;;8CAE0BlD,S,EAAW;AACpC,wIAAgCA,SAAhC;AACA,WAAKkD,UAAL;AACD;;;iCAEa;AAAA;;AACZ,sBAAMzQ,QAAN,CAAe,aAAf,EAA8B,EAACmD,MAAM,KAAKuC,aAAL,EAAP,EAA9B,EAA4D,IAA5D,yBACGnB,IADH,CACQ,UAACgK,IAAD,EAAU;AACd,eAAKD,QAAL,CAAc;AACZoI,sBAAYnI,IADA;AAEZkQ,8BAAoB,OAAKC,SAAL;AAFR,SAAd;AAID,OANH;AAOD;;;iCAEaxc,K,EAAO;AAAA;;AACnB,UAAMiB,OAAO,KAAKuC,aAAL,EAAb;AACA,UAAMiZ,SAAS,gBAAM/e,eAAN,CAAsBuD,IAAtB,CAAf;AACA,UAAIyb,mBAAJ;AACA,UAAID,WAAW,IAAf,EAAqB;AACnBC,qBAAa,MAAb;AACD,OAFD,MAEO;AACLA,qBAAa,KAAK7P,uBAAL,CAA6B4P,MAA7B,CAAb;AACD;;AAED,sBAAM/d,UAAN,CAAiB,eAAjB,EAAkC,EAACL,MAAM;AACvC4C,gBAAMA,IADiC;AAEvCoC,eAAK,KAAKI,YAAL,EAFkC;AAGvCkZ,yBAAe,KAAK5Q,KAAL,CAAWwQ,kBAAX,GAAgC,GAAhC,GAAsC;AAHd,SAAP;AAKhC;AACAje,gBAAQ,MANwB,EAAlC,yBAOG+D,IAPH,CAOQ,UAACgK,IAAD,EAAU;AACd,YAAI,OAAKN,KAAL,CAAWyI,UAAX,CAAsB3C,aAA1B,EAAyC;AACvC,wBAAIhP,IAAJ,CAAS,oCAA4B;AACnC8B,wBAAY,OAAKiY,mBAAL,EADuB;AAEnC9X,gCAAoB,CAAC,OAAKiH,KAAL,CAAWyI,UAAX,CAAsB5Q,EAAvB;AAFe,WAA5B,CAAT;AAID;AACD,eAAK+J,qBAAL,CAA2B,OAA3B,EAAoC,EAAC1M,MAAMyb,UAAP,EAApC;AACD,OAfH;AAgBD;;;iCAEa1c,K,EAAO;AACnB,UAAMZ,UAAU,KAAKyN,uBAAL,EAAhB;AACA,WAAKc,qBAAL,CAA2B,OAA3B,EAAoC,EAAC1M,MAAM7B,OAAP,EAApC;AACD;;;0CAEsBY,K,EAAO;AAC5B,WAAKoM,QAAL,CAAc;AACZmQ,4BAAoBvc,MAAMwL,MAAN,CAAazO,KAAb,KAAuB;AAD/B,OAAd;AAGD;;;gCAEY;AACX,aAAO,KAAK0G,YAAL,OAAwB,UAA/B;AACD;;;6BAES;AACR,UAAMoZ,KAAK,KAAK9Q,KAAL,CAAWyI,UAAtB;;AAEA,UAAI,CAACqI,EAAD,IAAO,CAACA,GAAG/K,cAAf,EAA+B;AAC7B,eAAO,IAAP;AACD;;AAED,UAAMgL,WAAW,EAAjB;AACA,UAAIzW,WAAW,EAAf;AACA,UAAMiL,OAAO,EAAb;AACA,UAAIK,cAAc,EAAlB;AACA,UAAIoL,UAAU,IAAd;AACA,UAAIC,WAAW,CAAf;;AAEA,WAAK,IAAIxhB,IAAI,CAAb,EAAgBA,IAAIqhB,GAAGvL,IAAH,CAAQpW,MAA5B,EAAoCM,GAApC,EAAyC;AACvC,YAAIqhB,GAAGvL,IAAH,CAAQ9V,CAAR,EAAW6H,GAAX,KAAmB,KAAKI,YAAL,EAAvB,EAA4C;AAC1CsZ,oBAAUF,GAAGvL,IAAH,CAAQ9V,CAAR,CAAV;AACD;AACD,YAAIqhB,GAAGvL,IAAH,CAAQ9V,CAAR,EAAWsR,MAAf,EAAuB;AACrBkQ;AACD;AACF;;AAED,UAAIH,GAAGhL,aAAP,EAAsB;AACpBiL,iBAAS1hB,IAAT,CACE;AAAA;AAAA,YAAG,KAAI,YAAP;AACG,eAAKohB,SAAL,KAAmB,eAAKriB,KAAL,CAAW,0BAAX,CAAnB,GACG,eAAKA,KAAL,CAAW,8BAAX,CAFN;AAEkD;AAFlD,SADF;AAMD,OAPD,MAOO;AACL2iB,iBAAS1hB,IAAT,CACE;AAAA;AAAA,YAAG,KAAI,YAAP;AACG,eAAKohB,SAAL,KAAmB,eAAKriB,KAAL,CAAW,oBAAX,CAAnB,GACG,eAAKA,KAAL,CAAW,wBAAX,CAFN;AAE4C,aAF5C;AAGG0iB,aAAGxW,QAAH,CAAYnL,MAAZ,GAAqB,CAArB,IAA0B,KAAKshB,SAAL,EAA1B,GACG,eAAKriB,KAAL,CAAW,8BAAX,CADH,GACgD;AAJnD,SADF;;AASA,YAAI0iB,GAAGxW,QAAH,CAAYnL,MAAZ,GAAqB,CAAzB,EAA4B;AAC1BmL,qBAAWwW,GAAGxW,QAAH,CAAYxF,GAAZ,CAAgB,UAAC8R,KAAD,EAAW;AACpC,mBACE;AAAA;AAAA,gBAAI,KAAKA,MAAM/O,EAAf;AAAoB,6BAAKzJ,KAAL,CAAWwY,MAAMhK,UAAjB;AAApB,aADF;AAGD,WAJU,CAAX;AAKA,cAAIkU,GAAGI,WAAH,GAAiB5W,SAASnL,MAA9B,EAAsC;AACpCmL,qBAASjL,IAAT,CAAc;AAAA;AAAA,gBAAI,KAAI,KAAR;AAAA;AAAA,aAAd;AACD;AACF;;AAEDuW,sBAAckL,GAAGlL,WAAH,CAAe9Q,GAAf,CAAmB,UAACgS,IAAD,EAAU;AACzC,iBACE;AAAA;AAAA,cAAI,KAAKA,KAAKjP,EAAd;AAAmBiP,iBAAKjP,EAAxB;AAAA;AAA8BiP,iBAAK3O,IAAnC;AAAA;AAAA,WADF;AAGD,SAJa,CAAd;AAKD;;AAED,UAAI8Y,WAAW,CAAX,IAAgB,KAAKvZ,YAAL,OAAwB,UAA5C,EAAwD;AACtDoZ,WAAGvL,IAAH,CAAQhY,OAAR,CAAgB,UAAC4Q,IAAD,EAAU;AACxB,cAAI,CAACA,KAAK4C,MAAV,EAAkB;AAChB;AACD;AACD,cAAIjJ,QAAQ,eAAK1J,KAAL,CAAW+P,KAAKiF,SAAhB,CAAZ;AACA,cAAIjF,KAAKuH,UAAT,EAAqB;AACnB5N,qBAAS,OAAO,eAAK1J,KAAL,CAAW,aAAX,CAAP,GAAmC,GAA5C;AACD,WAFD,MAEO,IAAI+P,KAAKmI,eAAT,EAA0B;AAC/BxO,qBAAS,OAAO,eAAK1J,KAAL,CAAW,iBAAX,CAAP,GAAuC,GAAhD;AACD;AACDmX,eAAKlW,IAAL,CAAU;AAAA;AAAA,cAAI,KAAK8O,KAAK7G,GAAd;AAAoBQ;AAApB,WAAV;AACD,SAXD;AAYAiZ,iBAAS1hB,IAAT,CACE;AAAA;AAAA,YAAG,KAAI,aAAP;AAAsB,yBAAKjB,KAAL,CAAW,yBAAX;AAAtB,SADF;AAGA2iB,iBAAS1hB,IAAT,CACE;AAAA;AAAA,YAAI,KAAI,iBAAR;AACE;AAAA;AAAA;AACE,qDAAO,MAAK,OAAZ,EAAoB,IAAG,iBAAvB,EAAyC,OAAM,GAA/C,EAAmD,MAAK,sBAAxD,EAA+E,SAC7E,KAAK2Q,KAAL,CAAWwQ,kBADb,EACiC,UAAU,KAAKW,qBAAL,CAA2Bzb,IAA3B,CAAgC,IAAhC,CAD3C,GADF;AAEuF,eAFvF;AAGE;AAAA;AAAA,gBAAO,SAAQ,iBAAf;AAAkC,6BAAKtH,KAAL,CAChC0iB,GAAGhL,aAAH,GAAmB,4BAAnB,GAAkD,sBADlB;AAAlC;AAHF,WADF;AAOE;AAAA;AAAA;AACE,qDAAO,MAAK,OAAZ,EAAoB,IAAG,sBAAvB,EAA8C,OAAM,GAApD,EAAwD,MAAK,sBAA7D,EAAoF,SAClF,CAAC,KAAK9F,KAAL,CAAWwQ,kBADd,EACkC,UAAU,KAAKW,qBAAL,CAA2Bzb,IAA3B,CAAgC,IAAhC,CAD5C,GADF;AAEwF,eAFxF;AAGE;AAAA;AAAA,gBAAO,SAAQ,sBAAf;AAAuC,6BAAKtH,KAAL,CACrC0iB,GAAGhL,aAAH,GAAmB,oCAAnB,GAA0D,8BADrB;AAAvC;AAHF;AAPF,SADF;AAgBD;;AAED,UAAItH,QAAQsS,GAAGlU,UAAH,GAAgB,eAAKxO,KAAL,CAAW0iB,GAAGlU,UAAd,CAAhB,GAA4CkU,GAAGjZ,EAA3D;AACA,UAAI,KAAKH,YAAL,OAAwB,UAAxB,IAAsCsZ,WAAW,IAArD,EAA2D;AACzDxS,iBAAS,OAAO,eAAKpQ,KAAL,CAAW4iB,QAAQ5N,SAAnB,CAAP,GAAuC,GAAhD;AACD;;AAED,aACE;AAAA;AAAA;AACE;AAAA;AAAA;AAAK,yBAAKhV,KAAL,CAAW,eAAX,EAA4B0B,OAA5B,CAAoC,IAApC,EAA0C0O,KAA1C;AAAL,SADF;AAEGuS,gBAFH;AAGE;AAAA;AAAA,YAAK,OAAO,EAACtE,SAAS,KAAKzM,KAAL,CAAWwQ,kBAAX,IAAiCjL,KAAKpW,MAAL,GAAc,CAA/C,GAAmD,OAAnD,GAA6D,MAAvE,EAAZ;AACE;AAAA;AAAA;AAAK,2BAAKf,KAAL,CAAW,oBAAX;AAAL,WADF;AAEE;AAAA;AAAA;AACGmX;AADH;AAFF,SAHF;AASE;AAAA;AAAA,YAAK,OAAO,EAACkH,SAAS,KAAKzM,KAAL,CAAWwQ,kBAAX,IAAiClW,SAASnL,MAAT,GAAkB,CAAnD,GAAuD,OAAvD,GAAiE,MAA3E,EAAZ;AACE;AAAA;AAAA;AAAK,2BAAKf,KAAL,CAAW,2BAAX;AAAL,WADF;AAEE;AAAA;AAAA;AACGkM;AADH;AAFF,SATF;AAeE;AAAA;AAAA,YAAK,OAAO,EAACmS,SAAS,KAAKzM,KAAL,CAAWwQ,kBAAX,IAAiC5K,YAAYzW,MAAZ,GAAqB,CAAtD,GAA0D,OAA1D,GAAoE,MAA9E,EAAZ;AACE;AAAA;AAAA;AAAK,2BAAKf,KAAL,CAAW,2BAAX;AAAL,WADF;AAEE;AAAA;AAAA;AACGwX;AADH;AAFF,SAfF;AAqBE;AAAA;AAAA,YAAK,WAAU,SAAf;AACE;AAAA;AAAA,cAAQ,WAAU,iBAAlB;AACE,uBAAS,KAAKkE,YAAL,CAAkBpU,IAAlB,CAAuB,IAAvB,CADX;AAC0C,2BAAKtH,KAAL,CAAW,YAAX;AAD1C,WADF;AAGE;AAAA;AAAA,cAAQ,WAAU,iBAAlB;AACE,uBAAS,KAAKgjB,YAAL,CAAkB1b,IAAlB,CAAuB,IAAvB,CADX;AAC0C,2BAAKtH,KAAL,CAAW,WAAX;AAD1C;AAHF;AArBF,OADF;AA8BD;;;;;;kBAGYmiB,U;;;;;;;ACrNf;;;;;;;;;;AAEA;;;;AACA;;;;AACA;;;;AACA;;;;;;;;;;;;IAEMc,W;;;AACJ,uBAAahd,KAAb,EAAoB;AAAA;;AAAA,0HACZA,KADY;;AAElB,UAAK2L,KAAL,GAAa;AACXsR,eAAS,IADE;AAEXC,kBAAY;AAFD,KAAb;AAFkB;AAMnB;;;;8CAE0BjS,S,EAAW;AACpC,0IAAgCA,SAAhC;AACA,WAAKe,QAAL,CAAc,EAAd,EAAkB,KAAKmR,SAAL,CAAe9b,IAAf,CAAoB,IAApB,CAAlB;AACD;;;wCAEoB;AACnB;AACA,WAAK8b,SAAL;AACD;;;4CAEwB;AACvB,aAAO,KAAK1Q,uBAAL,OAAmC,KAAKd,KAAL,CAAWuR,UAArD;AACD;;;gCAEY;AAAA;;AACX,UAAMja,MAAM,KAAKI,YAAL,EAAZ;AACA,UAAMxC,OAAO,KAAKuC,aAAL,EAAb;AACA,UAAIvC,SAAS,IAAb,EAAmB;AACjB,aAAKmL,QAAL,CAAc,KAAKoR,eAAL,EAAd;AACA;AACD;;AAED,UAAMC,YAAY,KAAK5Q,uBAAL,EAAlB;AACA,sBAAM/O,QAAN,CAAe,cAAf,EAA+B,EAACmD,MAAMA,IAAP,EAAaoC,KAAKA,GAAlB,EAA/B,EAAuD,IAAvD,yBACGhB,IADH,CACQ,UAACgK,IAAD,EAAU;AACd,eAAKD,QAAL,CAAc;AACZiR,mBAAShR,KAAK7P,GADF;AAEZ8gB,sBAAYG;AAFA,SAAd;AAID,OANH;AAOD;;;sCAEkB;AACjB,UAAI,KAAK1R,KAAL,CAAWuR,UAAX,KAA0B,KAAKzQ,uBAAL,EAA9B,EAA8D;AAC5D,eAAO,KAAKd,KAAL,CAAWsR,OAAlB;AACD;AACD,aAAO,IAAP;AACD;;;yCAEqB;AAAA;;AACpB,UAAMK,QAAQ,KAAKrQ,IAAL,CAAUsQ,MAAxB;AACA,UAAMC,eAAe,KAAKC,eAAL,EAArB;AACA,UAAID,iBAAiB,IAArB,EAA2B;AACzB,YAAME,YAAY,KAAKC,YAAL,EAAlB;;AAEA,YAAI,CAAC,gBAAMzgB,uBAAN,CAA8BsgB,YAA9B,EAA4CE,SAA5C,CAAL,EAA6D;AAC3DJ,gBAAMM,GAAN,GAAY,gBAAM9hB,eAAN,CAAsB0hB,YAAtB,CAAZ;AACD;;AAEDF,cAAMO,MAAN,GAAe,UAACje,KAAD,EAAW;AACxB,iBAAKke,gBAAL;AACD,SAFD;AAGD;AACF;;;mCAEe;AACd,UAAMC,gBAAgB,KAAK9Q,IAAL,CAAUsQ,MAAV,CAAiBS,aAAjB,CAA+B7d,QAArD;AACA,UAAI4d,cAAc7R,IAAd,KAAuB,aAA3B,EAA0C;AACxC,eAAO6R,cAAc7R,IAArB;AACD;AACD,aAAO,gBAAM/O,2BAAN,CACL4gB,cAAcE,QADT,CAAP;AAED;;;uCAEmB;AAAA;;AAClB,UAAM1gB,SAAS,KAAKogB,YAAL,EAAf;AACA,UAAIpgB,WAAW,IAAf,EAAqB;AACnB;AACD;AACD,sBAAMG,QAAN,CAAe,WAAf,EAA4B,EAACwgB,UAAU3gB,MAAX,EAA5B,EAAgD,IAAhD,yBACG0E,IADH,CACQ,UAACgK,IAAD,EAAU;AACd,YAAIA,KAAKS,MAAT,EAAiB;AACf,cAAM1N,UAAU,OAAKyN,uBAAL,CAA6BR,KAAKpL,IAAlC,EAAwCoL,KAAKhJ,GAA7C,CAAhB;AACA,iBAAKsK,qBAAL,CAA2B,UAA3B,EAAuC,EAAC1M,MAAM7B,OAAP,EAAvC;AACD;AACF,OANH;AAOD;;;6BAES;AACR,aACE;AAAA;AAAA,UAAK,WAAU,SAAf;AACE,kDAAQ,KAAI,QAAZ;AADF,OADF;AAKD;;;;;;kBAGYge,W;;;;;;;ACvGf;;AAEA;;;;;;;;;;AAEA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;;;;;;;;;AAEA,IAAMmB,sBAAsB,SAAtBA,mBAAsB,CAACC,MAAD,EAAY;AACtC,MAAIA,OAAOtO,IAAP,KAAgBhW,SAApB,EAA+B;AAC7B,WAAO,MAAP;AACD;AACD,MAAM+e,UAAUle,OAAO1B,IAAP,CAAYmlB,MAAZ,CAAhB;AACAvF,UAAQ1H,IAAR;AACA,SAAO0H,QAAQ,CAAR,CAAP;AACD,CAPD;;IASMwF,Y;;;AACJ,wBAAare,KAAb,EAAoB;AAAA;;AAAA,4HACZA,KADY;;AAElB,UAAK2L,KAAL,GAAa;AACX2S,oBAAc,IADH;AAEX9a,UAAI1J,SAFO;AAGXykB,qBAAe;AAHJ,KAAb;AAFkB;AAOnB;;;;wCAEoB;AACnB;AACA,WAAKpQ,UAAL;AACD;;;8CAE0BlD,S,EAAW;AACpC,4IAAgCA,SAAhC;AACA,WAAKkD,UAAL;AACD;;;iCAEa;AAAA;;AACZ,sBAAMzQ,QAAN,CAAe,YAAf,EAA6B,EAACmD,MAAM,KAAKuC,aAAL,EAAP,EAA7B,EAA2D,IAA3D,yBACGnB,IADH,CACQ,UAACgK,IAAD,EAAU;AACd,YAAIsS,gBAAgBtS,KAAKuS,aAAzB;AACA,YAAI,CAACD,aAAL,EAAoB;AAClBA,0BAAgBJ,oBAAoBlS,KAAKwS,gBAAzB,CAAhB;AACD;;AAED,eAAKzS,QAAL,CAAc;AACZsS,wBAAcrS,IADF;AAEZzI,cAAI1J,SAFQ;AAGZ4kB,mBAAS5kB,SAHG;AAIZykB,yBAAeA;AAJH,SAAd;AAMD,OAbH;AAcD;;;kCAEc/a,E,EAAI7G,K,EAAO;AACxB,UAAMgiB,MAAM,EAAZ;AACAA,UAAInb,EAAJ,IAAU7G,KAAV;AACA,WAAKqP,QAAL,CAAc2S,GAAd;AACD;;;yCAEqB;AACpB,UAAM3lB,KAAK,EAAX;AACA,WAAK,IAAMG,GAAX,IAAkB,KAAKwS,KAAL,CAAW2S,YAAX,CAAwBG,gBAA1C,EAA4D;AAC1D,YAAMG,QAAQ,KAAKjT,KAAL,CAAW2S,YAAX,CAAwBG,gBAAxB,CAAyCtlB,GAAzC,CAAd;AACAH,WAAGgC,IAAH,CAAQ4jB,KAAR;AACD;AACD5lB,SAAGmY,IAAH,CAAQ,UAAC5U,CAAD,EAAIC,CAAJ,EAAU;AAChB,eAAOD,EAAEgE,IAAF,CAAO1G,WAAP,GAAqBglB,aAArB,CAAmCriB,EAAE+D,IAAF,CAAO1G,WAAP,EAAnC,CAAP;AACD,OAFD;AAGA,aAAOb,EAAP;AACD;;;oCAEgB4G,K,EAAO;AACtB,WAAKoM,QAAL,CAAc;AACZuS,uBAAe3e,MAAMwL,MAAN,CAAazO;AADhB,OAAd;AAGD;;;mCAEe;AACd,aAAO,gBAAMd,OAAN,CAAc,KAAK8P,KAAL,CAAW+S,OAAX,IAAsB,EAApC,EAAwC7kB,WAAxC,EAAP;AACD;;;sCAEkB;AACjB,UAAM+kB,QAAQ,KAAKjT,KAAL,CAAW4S,aAAzB;AACA,aAAO,KAAK5S,KAAL,CAAW2S,YAAX,CAAwBG,gBAAxB,CAAyCG,KAAzC,EAAgDE,aAAvD;AACD;;;mCAEe;AAAA;;AACd,UAAMC,SAAS,SAATA,MAAS,CAACC,IAAD,EAAU;AACvBnN,cAAM,eAAK9X,KAAL,CAAW,cAAX,IAA6BilB,IAAnC;AACD,OAFD;;AAIA,UAAMxb,KAAK,KAAKmI,KAAL,CAAWnI,EAAX,IAAiB,KAAKyb,YAAL,EAA5B;AACA,UAAI,CAACzb,EAAL,EAAS;AACPub,eAAO,eAAKhlB,KAAL,CAAW,sBAAX,CAAP;AACA;AACD;;AAED,UAAMkE,OAAO,EAAb;AACA,UAAMN,SAAS,EAAC6F,IAAIA,EAAL,EAAS3C,MAAM,KAAKuC,aAAL,EAAf,EAAqCnF,MAAMA,IAA3C,EAAf;AACA,UAAI,CAAC,KAAK0N,KAAL,CAAW2S,YAAX,CAAwBE,aAA7B,EAA4C;AAC1CvgB,aAAK,QAAL,IAAiB,KAAK0N,KAAL,CAAW4S,aAA5B;AACD;AACD,UAAMW,eAAe,KAAKC,eAAL,EAArB;AACA,UAAID,YAAJ,EAAkB;AAChBjhB,aAAKihB,aAAa3e,IAAlB,IAA0B,KAAKoL,KAAL,CAAW+S,OAArC;AACD;;AAED,sBAAMpgB,UAAN,CAAiB,YAAjB,EAA+B,EAACC,MAAMZ,MAAP,EAAeO,QAAQ,MAAvB,EAA/B,yBACG+D,IADH,CACQ,UAACgK,IAAD,EAAU;AACd,YAAIA,KAAKS,MAAT,EAAiB;AACfqS,iBAAO,eAAKhlB,KAAL,CAAW,yBAAX,EAAsC0B,OAAtC,CAA8C,IAA9C,EAAoD+H,EAApD,CAAP;AACD,SAFD,MAEO,IAAI,CAACyI,KAAKmT,QAAV,EAAoB;AACzBL,iBAAO,eAAKhlB,KAAL,CAAW,kBAAX,EAA+B0B,OAA/B,CAAuC,IAAvC,EAA6C+H,EAA7C,CAAP;AACD,SAFM,MAEA;AACL,cAAMxE,UAAU,OAAKyN,uBAAL,CAA6BR,KAAKpL,IAAlC,CAAhB;AACA,iBAAK0M,qBAAL,CAA2B,OAA3B,EAAoC,EAAC1M,MAAM7B,OAAP,EAApC;AACD;AACF,OAVH;AAWD;;;mCAEe;AAAA;;AACd,UAAMgK,SAAS,EAAf;;AAEA,UAAI,CAAC,KAAK2C,KAAL,CAAW2S,YAAX,CAAwBE,aAA7B,EAA4C;AAC1C,YAAM3F,UAAU,KAAKwG,kBAAL,GAA0B5e,GAA1B,CAA8B,UAACme,KAAD,EAAW;AACvD,iBACE;AAAA;AAAA,cAAQ,OAAOA,MAAMpb,EAArB,EAAyB,KAAKob,MAAMpb,EAApC;AAAyC,2BAAKzJ,KAAL,CAAW6kB,MAAM7P,SAAjB;AAAzC,WADF;AAGD,SAJe,CAAhB;AAKA/F,eAAOhO,IAAP,CACE;AAAA;AAAA,YAAK,WAAU,KAAf,EAAqB,KAAI,QAAzB;AACE;AAAA;AAAA,cAAK,WAAU,qBAAf;AACE;AAAA;AAAA,gBAAI,WAAU,OAAd;AACE;AAAA;AAAA;AAAK,+BAAKjB,KAAL,CAAW,OAAX;AAAL,eADF;AAEE;AAAA;AAAA;AAAI;AAAA;AAAA,oBAAQ,OAAO,KAAK4R,KAAL,CAAW4S,aAA1B;AACF,+BAAU,cADR;AAEF,8BAAU,KAAKe,eAAL,CAAqBje,IAArB,CAA0B,IAA1B,CAFR;AAGDwX;AAHC;AAAJ;AAFF;AADF;AADF,SADF;AAcD;;AAED,UAAM0G,WAAW,SAAXA,QAAW,CAAC/b,EAAD,EAAKoE,KAAL,EAAY1C,WAAZ,EAA4B;AAC3C,YAAIvI,QAAQ,OAAKgP,KAAL,CAAWnI,EAAX,CAAZ;AACA,YAAMyE,SAAS,kBAAQC,8BAAR,CAAuCN,MAAM9D,IAA7C,CAAf;AACA,YAAImE,OAAO8M,gBAAX,EAA6B;AAC3BpY,kBAAQsL,OAAO8M,gBAAP,CAAwBpY,KAAxB,EAA+BiL,MAAM9D,IAArC,CAAR;AACD;AACDkF,eAAOhO,IAAP,CACE;AAAA;AAAA,YAAK,WAAU,eAAf,EAA+B,KAAK4M,MAAMrH,IAA1C;AACE;AAAA;AAAA,cAAK,WAAU,qBAAf;AACE;AAAA;AAAA,gBAAI,WAAU,OAAd;AACE;AAAA;AAAA;AAAK,oCAAU0J,MAAV,CAAiBrC,MAAMW,UAAN,IAAoBX,MAAMuC,KAA3C;AAAL,eADF;AAEE;AAAA;AAAA;AAAI,8CAAC,MAAD;AACF,yBAAOxN,KADL;AAEF,+BAAauI,WAFX;AAGF,4BAAU,OAAKmQ,aAAL,CAAmBhU,IAAnB,SAA8BmC,EAA9B,CAHR;AAIF,wBAAMoE,MAAM9D;AAJV;AAAJ;AAFF;AADF;AADF,SADF;AAeD,OArBD;;AAuBA,UAAMob,eAAe,KAAKC,eAAL,EAArB;AACA,UAAID,YAAJ,EAAkB;AAChBK,iBAAS,SAAT,EAAoBL,YAApB;AACD;;AAEDK,eAAS,IAAT,EAAe;AACbhf,cAAM,KADO;AAEb4J,eAAO,eAAKpQ,KAAL,CAAW,IAAX,CAFM;AAGb+J,cAAM,EAACvD,MAAM,MAAP,EAAemH,QAAQ,MAAvB;AAHO,OAAf,EAIG,KAAKuX,YAAL,EAJH;;AAMA,aAAOjW,MAAP;AACD;;;6BAES;AACR,UAAMwW,MAAM,KAAK7T,KAAL,CAAW2S,YAAvB;;AAEA,UAAI,CAACkB,GAAL,EAAU;AACR,eAAO,IAAP;AACD;;AAED,aACE;AAAA;AAAA,UAAK,WAAU,WAAf;AACE;AAAA;AAAA;AAAK,yBAAKzlB,KAAL,CAAW,mBAAX,EAAgC0B,OAAhC,CACH,IADG,EACG,KAAKkQ,KAAL,CAAW2S,YAAX,CAAwBnU,KAD3B;AAAL,SADF;AAGE;AAAA;AAAA;AAAI,yBAAKpQ,KAAL,CAAW,qBAAX;AAAJ,SAHF;AAIG,aAAK0lB,YAAL,EAJH;AAKE;AAAA;AAAA,YAAK,WAAU,SAAf;AACE;AAAA;AAAA,cAAQ,WAAU,iBAAlB,EAAoC,SAClC,KAAKC,YAAL,CAAkBre,IAAlB,CAAuB,IAAvB,CADF;AACiC,2BAAKtH,KAAL,CAAW,mBAAX;AADjC;AADF;AALF,OADF;AAYD;;;;;;kBAGYskB,Y;;;;;;;ACjNf;;AAEA;;;;;;;;AAEA;;;;AACA;;;;AACA;;;;AACA;;AACA;;;;AACA;;;;AACA;;;;;;;;;;;;IAEMsB,iB;;;AACJ,6BAAa3f,KAAb,EAAoB;AAAA;;AAAA,sIACZA,KADY;;AAElB,UAAK2L,KAAL,GAAa;AACXiU,yBAAmB,IADR;AAEXC,oBAAc,EAFH;AAGXC,mBAAa,KAHF;AAIXC,uBAAiB;AAJN,KAAb;AAFkB;AAQnB;;;;wCAEoB;AACnB,WAAK5R,UAAL;AACD;;;8CAE0BlD,S,EAAW;AACpC,WAAKkD,UAAL;AACD;;;iCAEa;AAAA;;AACZ,sBAAMzQ,QAAN,CAAe,gBAAf,EAAiC,EAACmD,MAAM,KAAKuC,aAAL,EAAP,EAAjC,EAA+D,IAA/D,yBACGnB,IADH,CACQ,UAACgK,IAAD,EAAU;AACd,eAAKD,QAAL,CAAc;AACZ4T,6BAAmB3T;AADP,SAAd;AAGD,OALH;AAMD;;;+BAEWrM,K,EAAO;AACjB,WAAKqN,IAAL,CAAU+S,IAAV,CAAe7U,KAAf;AACD;;;qCAEiBvL,K,EAAO;AACvB,UAAMqgB,cAActX,KAAKuX,KAAL,CAAYtgB,MAAMugB,MAAN,GAAe,GAAhB,GAAuBvgB,MAAMwgB,KAAxC,CAApB;AACA,UAAIH,gBAAgB,KAAKtU,KAAL,CAAWoU,eAA/B,EAAgD;AAC9C,aAAK/T,QAAL,CAAc;AACZ+T,2BAAiBE;AADL,SAAd;AAGD;AACF;;;qCAEiBhU,I,EAAMrM,K,EAAO;AAAA;;AAC7B,WAAKoM,QAAL,CAAc;AACZ8T,qBAAa,KADD;AAEZG,qBAAa;AAFD,OAAd,EAGG,YAAM;AACP,sBAAIxd,IAAJ,CAAS,oCAA4B;AACnC8B,sBAAY,OAAKnB,aAAL,EADuB;AAEnCqB,4BAAkBwH,KAAKoU,OAAL,CAAa5f,GAAb,CAAiB,UAAC6f,MAAD,EAAY;AAC7C,mBAAOA,OAAOC,eAAd;AACD,WAFiB;AAFiB,SAA5B,CAAT;AAMD,OAVD;AAWD;;;mCAEe3gB,K,EAAO;AAAA;;AACrB,UAAI,KAAK+L,KAAL,CAAWmU,WAAf,EAA4B;AAC1B;AACD;;AAED,UAAMU,QAAQ,KAAKvT,IAAL,CAAU+S,IAAV,CAAeQ,KAA7B;AACA,WAAKxU,QAAL,CAAc;AACZ6T,sBAAc3E,MAAMuF,SAAN,CAAgB1jB,KAAhB,CAAsBsF,IAAtB,CAA2Bme,KAA3B,EAAkC,CAAlC,CADF;AAEZV,qBAAa;AAFD,OAAd;;AAKA,UAAMY,WAAW,IAAIC,QAAJ,EAAjB;AACAD,eAASE,MAAT,CAAgB,MAAhB,EAAwB,KAAKxd,aAAL,EAAxB;;AAEA,WAAK,IAAIhI,IAAI,CAAb,EAAgBA,IAAIolB,MAAM1lB,MAA1B,EAAkCM,GAAlC,EAAuC;AACrCslB,iBAASE,MAAT,CAAgB,MAAhB,EAAwBJ,MAAMplB,CAAN,CAAxB,EAAkColB,MAAMplB,CAAN,EAASmF,IAA3C;AACD;;AAED,UAAMsgB,MAAM,IAAIC,cAAJ,EAAZ;AACAD,UAAIE,IAAJ,CAAS,MAAT,EAAiB,gBAAMvjB,SAAN,CAAgB,gBAAhB,CAAjB;AACAqjB,UAAIhD,MAAJ,GAAa,UAACje,KAAD,EAAW;AACtB,eAAKohB,gBAAL,CAAsBxiB,KAAKkQ,KAAL,CAAWmS,IAAII,YAAf,CAAtB,EAAoDrhB,KAApD;AACD,OAFD;AAGAihB,UAAIK,MAAJ,CAAWC,UAAX,GAAwB,UAACvhB,KAAD,EAAW;AACjC,eAAKwhB,gBAAL,CAAsBxhB,KAAtB;AACD,OAFD;AAGAihB,UAAIQ,IAAJ,CAASX,QAAT;AACD;;;yCAEqB;AACpB,UAAMF,QAAQ,KAAK7U,KAAL,CAAWkU,YAAX,CAAwBpf,GAAxB,CAA4B,UAACuf,IAAD,EAAU;AAClD,eACE;AAAA;AAAA,YAAI,KAAKA,KAAKzf,IAAd;AAAqByf,eAAKzf,IAA1B;AAAA;AAAkCyf,eAAKlc,IAAvC;AAAA;AAAA,SADF;AAGD,OAJa,CAAd;AAKA,aAAO;AAAA;AAAA;AAAK0c;AAAL,OAAP;AACD;;;6BAES;AACR,UAAMc,MAAM,KAAK3V,KAAL,CAAWiU,iBAAvB;;AAEA,UAAI,CAAC0B,GAAL,EAAU;AACR,eAAO,IAAP;AACD;;AAED,aACE;AAAA;AAAA;AACE;AAAA;AAAA;AAAK,yBAAKvnB,KAAL,CAAW,mBAAX,EAAgC0B,OAAhC,CAAwC,IAAxC,EAA8C6lB,IAAInX,KAAlD;AAAL,SADF;AAEE;AAAA;AAAA;AAAI,yBAAKpQ,KAAL,CAAW,qBAAX;AAAJ,SAFF;AAGG,aAAKwnB,kBAAL,EAHH;AAIE;AAAA;AAAA;AAAI,yBAAKxnB,KAAL,CAAW,UAAX,CAAJ;AAAA;AAA8B,eAAK4R,KAAL,CAAWoU,eAAzC;AAAA;AAAA,SAJF;AAKE,iDAAO,MAAK,MAAZ,EAAmB,KAAI,MAAvB,EAA8B,cAA9B;AACE,iBAAO,EAAC3H,SAAS,MAAV,EADT,EAC4B,UAAU,KAAKoJ,cAAL,CAAoBngB,IAApB,CAAyB,IAAzB,CADtC,GALF;AAOE;AAAA;AAAA,YAAK,WAAU,SAAf;AACE;AAAA;AAAA,cAAQ,WAAU,iBAAlB,EAAoC,SAAS,KAAKogB,UAAL,CAAgBpgB,IAAhB,CAAqB,IAArB,CAA7C;AACE,2BAAKtH,KAAL,CAAW,QAAX;AADF;AADF;AAPF,OADF;AAcD;;;;;;kBAGY4lB,iB","file":"app.js","sourcesContent":["const loadTranslations = () => {\n const ctx = require.context('../../../translations', true, /\\.json$/)\n const rv = {}\n ctx.keys().forEach((key) => {\n const langIdMatch = key.match(/([a-z]+)/)\n rv[langIdMatch[1]] = ctx(key)\n })\n return rv\n}\n\nconst i18n = {\n translations: loadTranslations(),\n\n currentLanguage: 'en',\n\n setLanguageFromLocale (locale) {\n if (locale) {\n let lang = locale.split(/[-_]/)[0].toLowerCase()\n if (this.translations[lang] !== undefined) {\n this.currentLanguage = lang\n }\n }\n },\n\n trans (key) {\n let rv\n if (typeof key === 'object') {\n rv = key[i18n.currentLanguage]\n if (rv === undefined) {\n rv = key.en\n }\n return rv\n }\n return i18n.translations[i18n.currentLanguage][key] || key\n }\n}\n\nexport default i18n\n\n\n\n// WEBPACK FOOTER //\n// ./js/i18n.jsx","import jQuery from 'jquery'\n\nconst slug = (string, opts) => {\n opts = opts || {}\n string = string.toString()\n if (typeof opts === 'string') { opts = {replacement: opts} }\n opts.mode = opts.mode || slug.defaults.mode\n const defaults = slug.defaults.modes[opts.mode];\n ['replacement', 'multicharmap', 'charmap', 'remove'].forEach((key) => {\n opts[key] = opts[key] || defaults[key]\n })\n if (typeof opts.symbols === 'undefined') { opts.symbols = defaults.symbols }\n const lengths = []\n Object.keys(opts.multicharmap).forEach((key) => {\n const len = key.length\n if (lengths.indexOf(len) === -1) { lengths.push(len) }\n })\n let result = ''\n for (let char, i = 0, l = string.length; i < l; i++) {\n char = string[i]\n if (!lengths.some((len) => {\n const str = string.substr(i, len)\n if (opts.multicharmap[str]) {\n i += len - 1\n char = opts.multicharmap[str]\n return true\n } else return false\n })) {\n if (opts.charmap[char]) {\n char = opts.charmap[char]\n }\n }\n char = char.replace(/[^\\w\\s\\-._~]/g, '') // allowed\n if (opts.remove) char = char.replace(opts.remove, '') // add flavour\n result += char\n }\n result = result.replace(/^\\s+|\\s+$/g, '') // trim leading/trailing spaces\n result = result.replace(/[-\\s]+/g, opts.replacement) // convert spaces\n return result.replace(opts.replacement + '$', '') // remove trailing separator\n}\n\nslug.defaults = {\n mode: 'pretty'\n}\n\nslug.multicharmap = slug.defaults.multicharmap = {\n '<3': 'love', '&&': 'and', '||': 'or', 'w/': 'with'\n}\n\n// https://code.djangoproject.com/browser/django/trunk/django/contrib/admin/media/js/urlify.js\nslug.charmap = slug.defaults.charmap = {\n // latin\n 'À': 'A',\n 'Á': 'A',\n 'Â': 'A',\n 'Ã': 'A',\n 'Ä': 'Ae',\n 'Å': 'A',\n 'Æ': 'AE',\n 'Ç': 'C',\n 'È': 'E',\n 'É': 'E',\n 'Ê': 'E',\n 'Ë': 'E',\n 'Ì': 'I',\n 'Í': 'I',\n 'Î': 'I',\n 'Ï': 'I',\n 'Ð': 'D',\n 'Ñ': 'N',\n 'Ò': 'O',\n 'Ó': 'O',\n 'Ô': 'O',\n 'Õ': 'O',\n 'Ö': 'Oe',\n 'Ő': 'O',\n 'Ø': 'O',\n 'Ù': 'U',\n 'Ú': 'U',\n 'Û': 'U',\n 'Ü': 'Ue',\n 'Ű': 'U',\n 'Ý': 'Y',\n 'Þ': 'TH',\n 'ß': 'ss',\n 'à': 'a',\n 'á': 'a',\n 'â': 'a',\n 'ã': 'a',\n 'ä': 'ae',\n 'å': 'a',\n 'æ': 'ae',\n 'ç': 'c',\n 'è': 'e',\n 'é': 'e',\n 'ê': 'e',\n 'ë': 'e',\n 'ì': 'i',\n 'í': 'i',\n 'î': 'i',\n 'ï': 'i',\n 'ð': 'd',\n 'ñ': 'n',\n 'ò': 'o',\n 'ó': 'o',\n 'ô': 'o',\n 'õ': 'o',\n 'ö': 'oe',\n 'ő': 'o',\n 'ø': 'o',\n 'ù': 'u',\n 'ú': 'u',\n 'û': 'u',\n 'ü': 'ue',\n 'ű': 'u',\n 'ý': 'y',\n 'þ': 'th',\n 'ÿ': 'y',\n 'ẞ': 'SS',\n // greek\n 'α': 'a',\n 'β': 'b',\n 'γ': 'g',\n 'δ': 'd',\n 'ε': 'e',\n 'ζ': 'z',\n 'η': 'h',\n 'θ': '8',\n 'ι': 'i',\n 'κ': 'k',\n 'λ': 'l',\n 'μ': 'm',\n 'ν': 'n',\n 'ξ': '3',\n 'ο': 'o',\n 'π': 'p',\n 'ρ': 'r',\n 'σ': 's',\n 'τ': 't',\n 'υ': 'y',\n 'φ': 'f',\n 'χ': 'x',\n 'ψ': 'ps',\n 'ω': 'w',\n 'ά': 'a',\n 'έ': 'e',\n 'ί': 'i',\n 'ό': 'o',\n 'ύ': 'y',\n 'ή': 'h',\n 'ώ': 'w',\n 'ς': 's',\n 'ϊ': 'i',\n 'ΰ': 'y',\n 'ϋ': 'y',\n 'ΐ': 'i',\n 'Α': 'A',\n 'Β': 'B',\n 'Γ': 'G',\n 'Δ': 'D',\n 'Ε': 'E',\n 'Ζ': 'Z',\n 'Η': 'H',\n 'Θ': '8',\n 'Ι': 'I',\n 'Κ': 'K',\n 'Λ': 'L',\n 'Μ': 'M',\n 'Ν': 'N',\n 'Ξ': '3',\n 'Ο': 'O',\n 'Π': 'P',\n 'Ρ': 'R',\n 'Σ': 'S',\n 'Τ': 'T',\n 'Υ': 'Y',\n 'Φ': 'F',\n 'Χ': 'X',\n 'Ψ': 'PS',\n 'Ω': 'W',\n 'Ά': 'A',\n 'Έ': 'E',\n 'Ί': 'I',\n 'Ό': 'O',\n 'Ύ': 'Y',\n 'Ή': 'H',\n 'Ώ': 'W',\n 'Ϊ': 'I',\n 'Ϋ': 'Y',\n // turkish\n 'ş': 's',\n 'Ş': 'S',\n 'ı': 'i',\n 'İ': 'I',\n 'ğ': 'g',\n 'Ğ': 'G',\n // russian\n 'а': 'a',\n 'б': 'b',\n 'в': 'v',\n 'г': 'g',\n 'д': 'd',\n 'е': 'e',\n 'ё': 'yo',\n 'ж': 'zh',\n 'з': 'z',\n 'и': 'i',\n 'й': 'j',\n 'к': 'k',\n 'л': 'l',\n 'м': 'm',\n 'н': 'n',\n 'о': 'o',\n 'п': 'p',\n 'р': 'r',\n 'с': 's',\n 'т': 't',\n 'у': 'u',\n 'ф': 'f',\n 'х': 'h',\n 'ц': 'c',\n 'ч': 'ch',\n 'ш': 'sh',\n 'щ': 'sh',\n 'ъ': 'u',\n 'ы': 'y',\n 'ь': '',\n 'э': 'e',\n 'ю': 'yu',\n 'я': 'ya',\n 'А': 'A',\n 'Б': 'B',\n 'В': 'V',\n 'Г': 'G',\n 'Д': 'D',\n 'Е': 'E',\n 'Ё': 'Yo',\n 'Ж': 'Zh',\n 'З': 'Z',\n 'И': 'I',\n 'Й': 'J',\n 'К': 'K',\n 'Л': 'L',\n 'М': 'M',\n 'Н': 'N',\n 'О': 'O',\n 'П': 'P',\n 'Р': 'R',\n 'С': 'S',\n 'Т': 'T',\n 'У': 'U',\n 'Ф': 'F',\n 'Х': 'H',\n 'Ц': 'C',\n 'Ч': 'Ch',\n 'Ш': 'Sh',\n 'Щ': 'Sh',\n 'Ъ': 'U',\n 'Ы': 'Y',\n 'Ь': '',\n 'Э': 'E',\n 'Ю': 'Yu',\n 'Я': 'Ya',\n // ukranian\n 'Є': 'Ye',\n 'І': 'I',\n 'Ї': 'Yi',\n 'Ґ': 'G',\n 'є': 'ye',\n 'і': 'i',\n 'ї': 'yi',\n 'ґ': 'g',\n // czech\n 'č': 'c',\n 'ď': 'd',\n 'ě': 'e',\n 'ň': 'n',\n 'ř': 'r',\n 'š': 's',\n 'ť': 't',\n 'ů': 'u',\n 'ž': 'z',\n 'Č': 'C',\n 'Ď': 'D',\n 'Ě': 'E',\n 'Ň': 'N',\n 'Ř': 'R',\n 'Š': 'S',\n 'Ť': 'T',\n 'Ů': 'U',\n 'Ž': 'Z',\n // polish\n 'ą': 'a',\n 'ć': 'c',\n 'ę': 'e',\n 'ł': 'l',\n 'ń': 'n',\n 'ś': 's',\n 'ź': 'z',\n 'ż': 'z',\n 'Ą': 'A',\n 'Ć': 'C',\n 'Ę': 'E',\n 'Ł': 'L',\n 'Ń': 'N',\n 'Ś': 'S',\n 'Ź': 'Z',\n 'Ż': 'Z',\n // latvian\n 'ā': 'a',\n 'ē': 'e',\n 'ģ': 'g',\n 'ī': 'i',\n 'ķ': 'k',\n 'ļ': 'l',\n 'ņ': 'n',\n 'ū': 'u',\n 'Ā': 'A',\n 'Ē': 'E',\n 'Ģ': 'G',\n 'Ī': 'I',\n 'Ķ': 'K',\n 'Ļ': 'L',\n 'Ņ': 'N',\n 'Ū': 'U',\n // lithuanian\n 'ė': 'e',\n 'į': 'i',\n 'ų': 'u',\n 'Ė': 'E',\n 'Į': 'I',\n 'Ų': 'U',\n // romanian\n 'ț': 't',\n 'Ț': 'T',\n 'ţ': 't',\n 'Ţ': 'T',\n 'ș': 's',\n 'Ș': 'S',\n 'ă': 'a',\n 'Ă': 'A',\n // currency\n '€': 'euro',\n '₢': 'cruzeiro',\n '₣': 'french franc',\n '£': 'pound',\n '₤': 'lira',\n '₥': 'mill',\n '₦': 'naira',\n '₧': 'peseta',\n '₨': 'rupee',\n '₩': 'won',\n '₪': 'new shequel',\n '₫': 'dong',\n '₭': 'kip',\n '₮': 'tugrik',\n '₯': 'drachma',\n '₰': 'penny',\n '₱': 'peso',\n '₲': 'guarani',\n '₳': 'austral',\n '₴': 'hryvnia',\n '₵': 'cedi',\n '¢': 'cent',\n '¥': 'yen',\n '元': 'yuan',\n '円': 'yen',\n '﷼': 'rial',\n '₠': 'ecu',\n '¤': 'currency',\n '฿': 'baht',\n '$': 'dollar',\n '₹': 'indian rupee',\n // symbols\n '©': '(c)',\n 'œ': 'oe',\n 'Œ': 'OE',\n '∑': 'sum',\n '®': '(r)',\n '†': '+',\n '“': '\"',\n '”': '\"',\n '‘': \"'\",\n '’': \"'\",\n '∂': 'd',\n 'ƒ': 'f',\n '™': 'tm',\n '℠': 'sm',\n '…': '...',\n '˚': 'o',\n 'º': 'o',\n 'ª': 'a',\n '•': '*',\n '∆': 'delta',\n '∞': 'infinity',\n '♥': 'love',\n '&': 'and',\n '|': 'or',\n '<': 'less',\n '>': 'greater',\n '=': 'equals'\n}\n\nslug.defaults.modes = {\n pretty: {\n replacement: '-',\n symbols: true,\n remove: /[.]/g,\n charmap: slug.defaults.charmap,\n multicharmap: slug.defaults.multicharmap\n }\n}\n\nconst utils = {\n slugify: slug,\n\n getCanonicalUrl (localPath) {\n return $LEKTOR_CONFIG.site_root.match(/^(.*?)\\/*$/)[1] +\n '/' + utils.stripLeadingSlash(localPath)\n },\n\n isValidUrl (url) {\n return !!url.match(/^(https?|ftp):\\/\\/\\S+$/)\n },\n\n stripLeadingSlash (string) {\n return string.match(/^\\/*(.*?)$/)[1]\n },\n\n stripTrailingSlash (string) {\n return string.match(/^(.*?)\\/*$/)[1]\n },\n\n joinFsPath (a, b) {\n return utils.stripTrailingSlash(a) + '/' + utils.stripLeadingSlash(b)\n },\n\n flipSetValue (originalSet, value, isActive) {\n if (isActive) {\n return utils.addToSet(originalSet || [], value)\n } else {\n return utils.removeFromSet(originalSet || [], value)\n }\n },\n\n addToSet (originalSet, value) {\n for (let i = 0; i < originalSet.length; i++) {\n if (originalSet[i] === value) {\n return originalSet\n }\n }\n const rv = originalSet.slice()\n rv.push(value)\n return rv\n },\n\n removeFromSet (originalSet, value) {\n let rv = null\n let off = 0\n for (let i = 0; i < originalSet.length; i++) {\n if (originalSet[i] === value) {\n if (rv === null) {\n rv = originalSet.slice()\n }\n rv.splice(i - (off++), 1)\n }\n }\n return (rv === null) ? originalSet : rv\n },\n\n urlPathsConsideredEqual (a, b) {\n if ((a == null) || (b == null)) {\n return false\n }\n return utils.stripTrailingSlash(a) === utils.stripTrailingSlash(b)\n },\n\n fsPathFromAdminObservedPath (adminPath) {\n const base = $LEKTOR_CONFIG.site_root.match(/^(.*?)\\/*$/)[1]\n if (adminPath.substr(0, base.length) !== base) {\n return null\n }\n return '/' + adminPath.substr(base.length).match(/^\\/*(.*?)\\/*$/)[1]\n },\n\n getParentFsPath (fsPath) {\n return fsPath.match(/^(.*?)\\/([^/]*)$/)[1]\n },\n\n getApiUrl (url) {\n return $LEKTOR_CONFIG.admin_root + '/api' + url\n },\n\n loadData (url, params, options, createPromise) {\n options = options || {}\n return createPromise((resolve, reject) => {\n jQuery.ajax({\n url: utils.getApiUrl(url),\n data: params,\n method: options.method || 'GET'\n }).done((data) => {\n resolve(data)\n }).fail(() => {\n reject({\n code: 'REQUEST_FAILED'\n })\n })\n })\n },\n\n apiRequest (url, options, createPromise) {\n options = options || {}\n options.url = utils.getApiUrl(url)\n if (options.json !== undefined) {\n options.data = JSON.stringify(options.json)\n options.contentType = 'application/json'\n delete options.json\n }\n if (!options.method) {\n options.method = 'GET'\n }\n\n return createPromise((resolve, reject) => {\n jQuery.ajax(options)\n .done((data) => {\n resolve(data)\n })\n .fail(() => {\n reject({\n code: 'REQUEST_FAILED'\n })\n })\n })\n },\n\n fsToUrlPath (fsPath) {\n let segments = fsPath.match(/^\\/*(.*?)\\/*$/)[1].split('/')\n if (segments.length === 1 && segments[0] === '') {\n segments = []\n }\n segments.unshift('root')\n return segments.join(':')\n },\n\n urlToFsPath (urlPath) {\n const segments = urlPath.match(/^:*(.*?):*$/)[1].split(':')\n if (segments.length < 1 || segments[0] !== 'root') {\n return null\n }\n segments[0] = ''\n return segments.join('/')\n },\n\n urlPathToSegments (urlPath) {\n if (!urlPath) {\n return null\n }\n const rv = urlPath.match(/^:*(.*?):*$/)[1].split('/')\n if (rv.length >= 1 && rv[0] === 'root') {\n return rv.slice(1)\n }\n return null\n },\n\n scrolledToBottom () {\n return document.body.offsetHeight + document.body.scrollTop >=\n document.body.scrollHeight\n },\n\n getPlatform () {\n if (navigator.appVersion.indexOf('Win') !== -1) {\n return 'windows'\n } else if (navigator.appVersion.indexOf('Mac') !== -1) {\n return 'mac'\n } else if (navigator.appVersion.indexOf('X11') !== -1 ||\n navigator.appVersion.indexOf('Linux') !== -1) {\n return 'linux'\n }\n return 'other'\n },\n\n isMetaKey (event) {\n if (utils.getPlatform() === 'mac') {\n return event.metaKey\n } else {\n return event.ctrlKey\n }\n }\n}\n\nexport default utils\n\n\n\n// WEBPACK FOOTER //\n// ./js/utils.jsx","'use strict'\nimport dialogSystem from '../dialogSystem'\nimport BaseComponent from './BaseComponent'\n\nclass Component extends BaseComponent {\n constructor (props) {\n super(props)\n this._unlistenBeforeLeavingRoute = null\n }\n\n /* helper function for forwarding props down the tree */\n getRoutingProps () {\n return {\n history: this.props.history,\n location: this.props.location,\n params: this.props.params,\n route: this.props.route,\n routeParams: this.props.routeParams,\n routes: this.props.routes\n }\n }\n\n /* helper that can generate a path to a rule */\n getPathToAdminPage (name, params) {\n let parts = this.props.routes.map((x) => x.name)\n if (name !== null) {\n if (name.substr(0, 1) === '.') {\n parts[parts.length - 1] = name.substr(1)\n } else {\n parts = name.split('.')\n }\n }\n\n const rv = []\n let node = this.props.routes[0]\n if (node.name !== parts.shift()) {\n return null\n }\n rv.push(node.path)\n\n parts.forEach((part) => {\n for (let i = 0; i < node.childRoutes.length; i++) {\n if (node.childRoutes[i].name === part) {\n node = node.childRoutes[i]\n rv.push(node.path)\n return\n }\n }\n node = null\n })\n\n return rv.join('/').replace(/:[a-zA-Z]+/g, (m) => {\n const key = m.substr(1)\n return params[key] || this.props.params[key]\n })\n }\n\n /* helper to transition to a specific page */\n transitionToAdminPage (name, params) {\n this.props.history.pushState(null, this.getPathToAdminPage(name, params))\n }\n\n componentDidMount () {\n super.componentDidMount()\n if (this.props.history !== undefined) {\n this._unlistenBeforeLeavingRoute = this.props.history.listenBeforeLeavingRoute(\n this.props.route, this.routerWillLeave.bind(this))\n }\n }\n\n componentWillUnmount () {\n super.componentWillUnmount()\n if (this._unlistenBeforeLeavingRoute) {\n this._unlistenBeforeLeavingRoute()\n }\n }\n\n routerWillLeave (nextLocation) {\n if (dialogSystem.preventNavigation()) {\n return false\n } else {\n dialogSystem.dismissDialog()\n }\n }\n}\nexport default Component\n\n\n\n// WEBPACK FOOTER //\n// ./js/components/Component.jsx","import ErrorDialog from './dialogs/errorDialog'\nimport dialogSystem from './dialogSystem'\n\nconst bringUpDialog = (error) => {\n if (!dialogSystem.dialogIsOpen()) {\n dialogSystem.showDialog(ErrorDialog, {\n error: error\n })\n }\n}\n\nconst makeRichPromise = (callback, fallback = bringUpDialog) => {\n const rv = new Promise(callback)\n const then = rv.then\n let hasRejectionHandler = false\n\n rv.then(null, (value) => {\n if (!hasRejectionHandler) {\n return fallback(value)\n }\n })\n\n rv.then = (onFulfilled, onRejected) => {\n if (onRejected) {\n hasRejectionHandler = true\n }\n return then.call(rv, onFulfilled, onRejected)\n }\n\n return rv\n}\n\nexport default makeRichPromise\n\n\n\n// WEBPACK FOOTER //\n// ./js/richPromise.jsx","'use strict'\n\nimport hub from './hub'\nimport {DialogChangedEvent} from './events'\n\nclass DialogSystem {\n constructor () {\n this._dialogInstance = null\n }\n\n // invoked by the application once the dialog has been created.\n notifyDialogInstance (dialog) {\n this._dialogInstance = dialog\n }\n\n // given a dialog class this will instruct the application to bring up\n // the dialog and display it.\n showDialog (dialog, options) {\n // if the current dialog prevents navigation, then we just silently\n // will not show the dialog.\n if (!this.preventNavigation()) {\n hub.emit(new DialogChangedEvent({\n dialog: dialog,\n dialogOptions: options || {}\n }))\n }\n }\n\n // tells the application to dismiss the current dialog.\n dismissDialog () {\n if (!this.preventNavigation()) {\n hub.emit(new DialogChangedEvent({\n currentDialog: null\n }))\n }\n }\n\n // indicates if a dialog is shown\n dialogIsOpen () {\n return !!this._dialogInstance\n }\n\n // returns true if the current dialog prevents navigation.\n preventNavigation () {\n return (\n this._dialogInstance &&\n this._dialogInstance.preventNavigation !== undefined &&\n this._dialogInstance.preventNavigation()\n )\n }\n}\n\nconst dialogSystem = new DialogSystem()\n\nexport default dialogSystem\n\n\n\n// WEBPACK FOOTER //\n// ./js/dialogSystem.jsx","/**\n * Copyright 2013-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\nif (process.env.NODE_ENV !== 'production') {\n var REACT_ELEMENT_TYPE = (typeof Symbol === 'function' &&\n Symbol.for &&\n Symbol.for('react.element')) ||\n 0xeac7;\n\n var isValidElement = function(object) {\n return typeof object === 'object' &&\n object !== null &&\n object.$$typeof === REACT_ELEMENT_TYPE;\n };\n\n // By explicitly using `prop-types` you are opting into new development behavior.\n // http://fb.me/prop-types-in-prod\n var throwOnDirectAccess = true;\n module.exports = require('./factoryWithTypeCheckers')(isValidElement, throwOnDirectAccess);\n} else {\n // By explicitly using `prop-types` you are opting into new production behavior.\n // http://fb.me/prop-types-in-prod\n module.exports = require('./factoryWithThrowingShims')();\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/prop-types/index.js\n// module id = 23\n// module chunks = 0","'use strict'\n\nimport Component from './Component'\nimport utils from '../utils'\n\n/* a react component baseclass that has some basic knowledge about\n the record it works with. */\nclass RecordComponent extends Component {\n /* checks if the record preview is active. */\n isRecordPreviewActive () {\n const routes = this.props.routes\n return (\n routes.length > 0 &&\n routes[routes.length - 1].component.name === 'PreviewPage'\n )\n }\n\n /* this returns the current record path segments as array */\n getRecordPathSegments () {\n const path = this.props.params.path\n return path ? utils.urlPathToSegments(path) : []\n }\n\n _getRecordPathAndAlt () {\n const path = this.props.params.path\n if (!path) {\n return [null, null]\n }\n const items = path.split(/\\+/, 2)\n return [utils.urlToFsPath(items[0]), items[1]]\n }\n\n /* this returns the path of the current record. If the current page does\n * not have a path component then null is returned. */\n getRecordPath () {\n const [path] = this._getRecordPathAndAlt()\n return path\n }\n\n /* returns the current alt */\n getRecordAlt () {\n const [, alt] = this._getRecordPathAndAlt()\n return !alt ? '_primary' : alt\n }\n\n /* return the url path for the current record path (or a modified one)\n by preserving or overriding the alt */\n getUrlRecordPathWithAlt (newPath, newAlt) {\n if (newPath === undefined || newPath === null) {\n newPath = this.getRecordPath()\n }\n if (newAlt === undefined || newAlt === null) {\n newAlt = this.getRecordAlt()\n }\n let rv = utils.fsToUrlPath(newPath)\n if (newAlt !== '_primary') {\n rv += '+' + newAlt\n }\n return rv\n }\n\n /* returns the parent path if available */\n getParentRecordPath () {\n return utils.getParentFsPath(this.getRecordPath())\n }\n\n /* returns true if this is the root record */\n isRootRecord () {\n return this.getRecordPath() === ''\n }\n\n /* returns the breadcrumbs for the current record path */\n getRecordCrumbs () {\n const segments = this.getRecordPathSegments()\n if (segments === null) {\n return []\n }\n\n segments.unshift('root')\n\n const rv = []\n for (let i = 0; i < segments.length; i++) {\n const curpath = segments.slice(0, i + 1).join(':')\n rv.push({\n id: 'path:' + curpath,\n urlPath: curpath,\n segments: segments.slice(1, i + 1),\n title: segments[i]\n })\n }\n\n return rv\n }\n}\n\nexport default RecordComponent\n\n\n\n// WEBPACK FOOTER //\n// ./js/components/RecordComponent.jsx","//import warning from 'warning'\n\n\"use strict\";\n\nexports.__esModule = true;\nfunction deprecate(fn) {\n return fn;\n //return function () {\n // warning(false, '[history] ' + message)\n // return fn.apply(this, arguments)\n //}\n}\n\nexports[\"default\"] = deprecate;\nmodule.exports = exports[\"default\"];\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/history/lib/deprecate.js\n// module id = 31\n// module chunks = 0","'use strict';\n\nexports.__esModule = true;\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar _warning = require('warning');\n\nvar _warning2 = _interopRequireDefault(_warning);\n\nvar _extractPath = require('./extractPath');\n\nvar _extractPath2 = _interopRequireDefault(_extractPath);\n\nfunction parsePath(path) {\n var pathname = _extractPath2['default'](path);\n var search = '';\n var hash = '';\n\n process.env.NODE_ENV !== 'production' ? _warning2['default'](path === pathname, 'A path must be pathname + search + hash only, not a fully qualified URL like \"%s\"', path) : undefined;\n\n var hashIndex = pathname.indexOf('#');\n if (hashIndex !== -1) {\n hash = pathname.substring(hashIndex);\n pathname = pathname.substring(0, hashIndex);\n }\n\n var searchIndex = pathname.indexOf('?');\n if (searchIndex !== -1) {\n search = pathname.substring(searchIndex);\n pathname = pathname.substring(0, searchIndex);\n }\n\n if (pathname === '') pathname = '/';\n\n return {\n pathname: pathname,\n search: search,\n hash: hash\n };\n}\n\nexports['default'] = parsePath;\nmodule.exports = exports['default'];\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/history/lib/parsePath.js\n// module id = 32\n// module chunks = 0","/**\n * Copyright 2014-2015, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n'use strict';\n\n/**\n * Similar to invariant but only logs a warning if the condition is not met.\n * This can be used to log issues in development environments in critical\n * paths. Removing the logging code for production environments will keep the\n * same logic and follow the same code paths.\n */\n\nvar warning = function() {};\n\nif (process.env.NODE_ENV !== 'production') {\n warning = function(condition, format, args) {\n var len = arguments.length;\n args = new Array(len > 2 ? len - 2 : 0);\n for (var key = 2; key < len; key++) {\n args[key - 2] = arguments[key];\n }\n if (format === undefined) {\n throw new Error(\n '`warning(condition, format, ...args)` requires a warning ' +\n 'message argument'\n );\n }\n\n if (format.length < 10 || (/^[s\\W]*$/).test(format)) {\n throw new Error(\n 'The warning format should be able to uniquely identify this ' +\n 'warning. Please, use a more descriptive format than: ' + format\n );\n }\n\n if (!condition) {\n var argIndex = 0;\n var message = 'Warning: ' +\n format.replace(/%s/g, function() {\n return args[argIndex++];\n });\n if (typeof console !== 'undefined') {\n console.error(message);\n }\n try {\n // This error was thrown as a convenience so that you can use this stack\n // to find the callsite that caused this warning to fire.\n throw new Error(message);\n } catch(x) {}\n }\n };\n}\n\nmodule.exports = warning;\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/warning/browser.js\n// module id = 33\n// module chunks = 0","/**\n * Indicates that navigation was caused by a call to history.push.\n */\n'use strict';\n\nexports.__esModule = true;\nvar PUSH = 'PUSH';\n\nexports.PUSH = PUSH;\n/**\n * Indicates that navigation was caused by a call to history.replace.\n */\nvar REPLACE = 'REPLACE';\n\nexports.REPLACE = REPLACE;\n/**\n * Indicates that navigation was caused by some other action such\n * as using a browser's back/forward buttons and/or manually manipulating\n * the URL in a browser's location bar. This is the default.\n *\n * See https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate\n * for more information.\n */\nvar POP = 'POP';\n\nexports.POP = POP;\nexports['default'] = {\n PUSH: PUSH,\n REPLACE: REPLACE,\n POP: POP\n};\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/history/lib/Actions.js\n// module id = 40\n// module chunks = 0","'use strict'\n\nclass Hub {\n constructor () {\n this._subscriptions = {}\n }\n\n /* subscribes a callback to an event */\n subscribe (event, callback) {\n if (typeof event !== 'string') {\n event = event.getEventType()\n }\n\n let subs = this._subscriptions[event]\n if (subs === undefined) {\n this._subscriptions[event] = subs = []\n }\n\n for (let i = 0; i < subs.length; i++) {\n if (subs[i] === callback) {\n return false\n }\n }\n\n subs.push(callback)\n return true\n }\n\n /* unsubscribes a callback from an event */\n unsubscribe (event, callback) {\n if (typeof event !== 'string') {\n event = event.getEventType()\n }\n\n const subs = this._subscriptions[event]\n if (subs === undefined) {\n return false\n }\n\n for (let i = 0; i < subs.length; i++) {\n if (subs[i] === callback) {\n subs.splice(i, 1)\n return true\n }\n }\n return false\n }\n\n /* emits an event with some parameters */\n emit (event) {\n const subs = this._subscriptions[event.type]\n if (subs !== undefined) {\n subs.forEach((callback) => {\n try {\n callback(event)\n } catch (e) {\n console.log('Event callback failed: ', e, 'callback=',\n callback, 'event=', event)\n }\n })\n }\n }\n}\n\nconst hub = new Hub()\n\nexport default hub\n\n\n\n// WEBPACK FOOTER //\n// ./js/hub.jsx","'use strict'\n\nclass Event {\n get type () {\n return Object.getPrototypeOf(this).constructor.getEventType()\n }\n\n toString () {\n return '[Event ' + this.type + ']'\n }\n}\n\nEvent.getEventType = function () {\n return this.name\n}\n\nclass RecordEvent extends Event {\n constructor (options) {\n super(options = options || {})\n this.recordPath = options.recordPath\n }\n}\n\nclass AttachmentsChangedEvent extends RecordEvent {\n constructor (options) {\n super(options = options || {})\n this.attachmentsAdded = options.attachmentsAdded || []\n this.attachmentsRemoved = options.attachmentsRemoved || []\n }\n}\n\nclass DialogChangedEvent extends Event {\n constructor (options) {\n super(options = options || {})\n this.dialog = options.dialog\n this.dialogOptions = options.dialogOptions\n }\n}\n\nexport {\n Event,\n RecordEvent,\n AttachmentsChangedEvent,\n DialogChangedEvent\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/events.jsx","'use strict';\n\nexports.__esModule = true;\nvar canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement);\nexports.canUseDOM = canUseDOM;\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/history/lib/ExecutionEnvironment.js\n// module id = 47\n// module chunks = 0","import PropTypes from 'prop-types'\nimport i18n from '../i18n'\n\nfunction ValidationFailure (options) {\n this.message = options.message || i18n.trans('INVALID_INPUT')\n this.type = options.type || 'error'\n}\n\nconst BasicWidgetMixin = {\n propTypes: {\n value: PropTypes.any,\n type: PropTypes.object,\n placeholder: PropTypes.any,\n onChange: PropTypes.func\n },\n\n getInputClass () {\n let rv = 'form-control'\n if (this.props.type.size === 'small') {\n rv = 'input-sm ' + rv\n } else if (this.props.type.size === 'large') {\n rv = 'input-lg ' + rv\n }\n return rv\n },\n\n getValidationFailure () {\n if (this.getValidationFailureImpl) {\n return this.getValidationFailureImpl()\n }\n return null\n }\n}\n\nexport {\n ValidationFailure,\n BasicWidgetMixin\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/widgets/mixins.jsx","'use strict';\n\nexports.__esModule = true;\nexports.addEventListener = addEventListener;\nexports.removeEventListener = removeEventListener;\nexports.getHashPath = getHashPath;\nexports.replaceHashPath = replaceHashPath;\nexports.getWindowPath = getWindowPath;\nexports.go = go;\nexports.getUserConfirmation = getUserConfirmation;\nexports.supportsHistory = supportsHistory;\nexports.supportsGoWithoutReloadUsingHash = supportsGoWithoutReloadUsingHash;\n\nfunction addEventListener(node, event, listener) {\n if (node.addEventListener) {\n node.addEventListener(event, listener, false);\n } else {\n node.attachEvent('on' + event, listener);\n }\n}\n\nfunction removeEventListener(node, event, listener) {\n if (node.removeEventListener) {\n node.removeEventListener(event, listener, false);\n } else {\n node.detachEvent('on' + event, listener);\n }\n}\n\nfunction getHashPath() {\n // We can't use window.location.hash here because it's not\n // consistent across browsers - Firefox will pre-decode it!\n return window.location.href.split('#')[1] || '';\n}\n\nfunction replaceHashPath(path) {\n window.location.replace(window.location.pathname + window.location.search + '#' + path);\n}\n\nfunction getWindowPath() {\n return window.location.pathname + window.location.search + window.location.hash;\n}\n\nfunction go(n) {\n if (n) window.history.go(n);\n}\n\nfunction getUserConfirmation(message, callback) {\n callback(window.confirm(message));\n}\n\n/**\n * Returns true if the HTML5 history API is supported. Taken from Modernizr.\n *\n * https://github.com/Modernizr/Modernizr/blob/master/LICENSE\n * https://github.com/Modernizr/Modernizr/blob/master/feature-detects/history.js\n * changed to avoid false negatives for Windows Phones: https://github.com/rackt/react-router/issues/586\n */\n\nfunction supportsHistory() {\n var ua = navigator.userAgent;\n if ((ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) && ua.indexOf('Mobile Safari') !== -1 && ua.indexOf('Chrome') === -1 && ua.indexOf('Windows Phone') === -1) {\n return false;\n }\n // FIXME: Work around our browser history not working correctly on Chrome\n // iOS: https://github.com/rackt/react-router/issues/2565\n if (ua.indexOf('CriOS') !== -1) {\n return false;\n }\n return window.history && 'pushState' in window.history;\n}\n\n/**\n * Returns false if using go(n) with hash history causes a full page reload.\n */\n\nfunction supportsGoWithoutReloadUsingHash() {\n var ua = navigator.userAgent;\n return ua.indexOf('Firefox') === -1;\n}\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/history/lib/DOMUtils.js\n// module id = 61\n// module chunks = 0","'use strict'\n\nimport PropTypes from 'prop-types'\nimport React from 'react'\nimport Component from '../components/Component'\nimport dialogSystem from '../dialogSystem'\nimport i18n from '../i18n'\n\nclass SlideDialog extends Component {\n constructor (props) {\n super(props)\n this._onKeyPress = this._onKeyPress.bind(this)\n }\n\n componentDidMount () {\n super.componentDidMount()\n if (this.props.closeOnEscape) {\n window.addEventListener('keydown', this._onKeyPress)\n }\n }\n\n componentWillUnmount () {\n window.removeEventListener('keydown', this._onKeyPress)\n super.componentWillUnmount()\n }\n\n _onKeyPress (event) {\n if (event.which === 27 && this.props.closeOnEscape) {\n event.preventDefault()\n dialogSystem.dismissDialog()\n }\n }\n\n _onCloseClick (event) {\n event.preventDefault()\n dialogSystem.dismissDialog()\n }\n\n render () {\n let {children, title, hasCloseButton, className, ...props} = this.props\n className = (className || '') + ' sliding-panel container'\n return (\n

\n
\n {\n hasCloseButton &&\n \n { i18n.trans('CLOSE') }\n \n }\n

{title}

\n {children}\n
\n
\n )\n }\n}\n\nSlideDialog.propTypes = {\n title: PropTypes.string,\n hasCloseButton: PropTypes.bool,\n closeOnEscape: PropTypes.bool\n}\n\nexport default SlideDialog\n\n\n\n// WEBPACK FOOTER //\n// ./js/components/SlideDialog.jsx","'use strict';\n\nexports.__esModule = true;\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar _warning = require('warning');\n\nvar _warning2 = _interopRequireDefault(_warning);\n\nfunction runTransitionHook(hook, location, callback) {\n var result = hook(location, callback);\n\n if (hook.length < 2) {\n // Assume the hook runs synchronously and automatically\n // call the callback with the return value.\n callback(result);\n } else {\n process.env.NODE_ENV !== 'production' ? _warning2['default'](result === undefined, 'You should not \"return\" in a transition hook with a callback argument; call the callback instead') : undefined;\n }\n}\n\nexports['default'] = runTransitionHook;\nmodule.exports = exports['default'];\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/history/lib/runTransitionHook.js\n// module id = 88\n// module chunks = 0","'use strict'\n\nimport PropTypes from 'prop-types'\nimport React from 'react'\nimport primitiveWidgets from './widgets/primitiveWidgets'\nimport multiWidgets from './widgets/multiWidgets'\nimport flowWidget from './widgets/flowWidget'\nimport fakeWidgets from './widgets/fakeWidgets'\nimport {BasicWidgetMixin} from './widgets/mixins'\nimport Component from './components/Component'\nimport ToggleGroup from './components/ToggleGroup'\nimport i18n from './i18n'\n\nconst widgetComponents = {\n 'singleline-text': primitiveWidgets.SingleLineTextInputWidget,\n 'multiline-text': primitiveWidgets.MultiLineTextInputWidget,\n 'datepicker': primitiveWidgets.DateInputWidget,\n 'integer': primitiveWidgets.IntegerInputWidget,\n 'float': primitiveWidgets.FloatInputWidget,\n 'checkbox': primitiveWidgets.BooleanInputWidget,\n 'url': primitiveWidgets.UrlInputWidget,\n 'slug': primitiveWidgets.SlugInputWidget,\n 'flow': flowWidget.FlowWidget,\n 'checkboxes': multiWidgets.CheckboxesInputWidget,\n 'select': multiWidgets.SelectInputWidget,\n 'f-line': fakeWidgets.LineWidget,\n 'f-spacing': fakeWidgets.SpacingWidget,\n 'f-info': fakeWidgets.InfoWidget,\n 'f-heading': fakeWidgets.HeadingWidget\n}\n\nconst FallbackWidget = React.createClass({\n mixins: [BasicWidgetMixin],\n render () {\n return (\n
\n \n Widget \"{this.props.type.widget}\" not implemented\n (used by type \"{this.props.type.name}\")\n \n
\n )\n }\n})\n\nclass FieldBox extends Component {\n render () {\n const {field, value, onChange, placeholder, disabled} = this.props\n const className = 'col-md-' + getFieldColumns(field) + ' field-box'\n let innerClassName = 'field'\n let inner\n\n if (field.name.substr(0, 1) === '_') {\n innerClassName += ' system-field'\n }\n\n const Widget = getWidgetComponentWithFallback(field.type)\n if (Widget.isFakeWidget) {\n inner = \n } else {\n let description = null\n if (field.description_i18n) {\n description = (\n
\n {i18n.trans(field.description_i18n)}\n
\n )\n }\n inner = (\n
\n {!field.hide_label ?
{i18n.trans(field.label_i18n)}
: null}\n
{description}
\n
\n )\n }\n\n return (\n
\n {inner}\n
\n )\n }\n}\n\nFieldBox.propTypes = {\n value: PropTypes.any,\n onChange: PropTypes.func,\n field: PropTypes.any,\n placeholder: PropTypes.any\n}\n\nconst getWidgetComponent = (type) => {\n return widgetComponents[type.widget] || null\n}\n\nconst getWidgetComponentWithFallback = (type) => {\n return widgetComponents[type.widget] || FallbackWidget\n}\n\nconst getFieldColumns = (field) => {\n const widthSpec = (field.type.width || '1/1').split('/')\n return Math.min(12, Math.max(2, parseInt(\n 12 * +widthSpec[0] / +widthSpec[1])))\n}\n\nconst getFieldRows = (fields, isIllegalField) => {\n const normalFields = []\n const systemFields = []\n\n if (!isIllegalField) {\n isIllegalField = (x) => { return false }\n }\n\n fields.forEach((field) => {\n if (!isIllegalField(field)) {\n if (field.name.substr(0, 1) === '_') {\n systemFields.push(field)\n } else {\n normalFields.push(field)\n }\n }\n })\n\n const processFields = (rv, rowType, fields) => {\n let currentColumns = 0\n let row = []\n\n fields.forEach((field) => {\n const columns = getFieldColumns(field)\n if (columns + currentColumns > 12) {\n rv.push([rowType, row])\n currentColumns = 0\n row = []\n }\n row.push(field)\n currentColumns += columns\n })\n\n if (row.length > 0) {\n rv.push([rowType, row])\n }\n }\n\n const rv = []\n processFields(rv, 'normal', normalFields)\n processFields(rv, 'system', systemFields)\n return rv\n}\n\nconst renderFieldRows = (fields, isIllegalField, renderFunc) => {\n const rv = {\n normal: [],\n system: []\n }\n\n const rows = getFieldRows(fields, isIllegalField)\n\n rows.forEach((item, idx) => {\n const [rowType, row] = item\n rv[rowType].push(\n
\n {row.map(renderFunc)}\n
\n )\n })\n\n return [\n rv.normal,\n rv.system.length > 1\n ? {rv.system} : null\n ]\n}\n\nexport default {\n getWidgetComponent: getWidgetComponent,\n getWidgetComponentWithFallback: getWidgetComponentWithFallback,\n getFieldRows: getFieldRows,\n renderFieldRows: renderFieldRows,\n getFieldColumns: getFieldColumns,\n FallbackWidget: FallbackWidget,\n FieldBox: FieldBox\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/widgets.jsx","'use strict'\n\nimport React from 'react'\nimport i18n from './i18n'\n\nconst userLabel = {\n\n // formats a user label appropriately\n format (inputConfig) {\n let label = null\n if (typeof inputConfig === 'string') {\n label = inputConfig\n } else {\n label = i18n.trans(inputConfig)\n }\n if (!label) {\n return \n }\n\n let iconData = label.match(/^\\[\\[\\s*(.*?)\\s*(;\\s*(.*?))?\\s*\\]\\]$/) // eslint-disable-line no-useless-escape\n if (iconData) {\n let className = 'fa fa-' + iconData[1]\n if ((iconData[3] || '').match(/90|180|270/)) {\n className += ' fa-rotate-' + iconData[3]\n }\n return \n }\n\n return {label}\n }\n}\n\nexport default userLabel\n\n\n\n// WEBPACK FOOTER //\n// ./js/userLabel.jsx","//import warning from 'warning'\n'use strict';\n\nexports.__esModule = true;\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar _Actions = require('./Actions');\n\nvar _parsePath = require('./parsePath');\n\nvar _parsePath2 = _interopRequireDefault(_parsePath);\n\nfunction createLocation() {\n var location = arguments.length <= 0 || arguments[0] === undefined ? '/' : arguments[0];\n var action = arguments.length <= 1 || arguments[1] === undefined ? _Actions.POP : arguments[1];\n var key = arguments.length <= 2 || arguments[2] === undefined ? null : arguments[2];\n\n var _fourthArg = arguments.length <= 3 || arguments[3] === undefined ? null : arguments[3];\n\n if (typeof location === 'string') location = _parsePath2['default'](location);\n\n if (typeof action === 'object') {\n //warning(\n // false,\n // 'The state (2nd) argument to createLocation is deprecated; use a ' +\n // 'location descriptor instead'\n //)\n\n location = _extends({}, location, { state: action });\n\n action = key || _Actions.POP;\n key = _fourthArg;\n }\n\n var pathname = location.pathname || '/';\n var search = location.search || '';\n var hash = location.hash || '';\n var state = location.state || null;\n\n return {\n pathname: pathname,\n search: search,\n hash: hash,\n state: state,\n action: action,\n key: key\n };\n}\n\nexports['default'] = createLocation;\nmodule.exports = exports['default'];\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/history/lib/createLocation.js\n// module id = 138\n// module chunks = 0","\"use strict\";\n\nexports.__esModule = true;\nfunction extractPath(string) {\n var match = string.match(/^https?:\\/\\/[^\\/]*/);\n\n if (match == null) return string;\n\n return string.substring(match[0].length);\n}\n\nexports[\"default\"] = extractPath;\nmodule.exports = exports[\"default\"];\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/history/lib/extractPath.js\n// module id = 139\n// module chunks = 0","'use strict';\n\nexports.__esModule = true;\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar _invariant = require('invariant');\n\nvar _invariant2 = _interopRequireDefault(_invariant);\n\nvar _Actions = require('./Actions');\n\nvar _ExecutionEnvironment = require('./ExecutionEnvironment');\n\nvar _DOMUtils = require('./DOMUtils');\n\nvar _DOMStateStorage = require('./DOMStateStorage');\n\nvar _createDOMHistory = require('./createDOMHistory');\n\nvar _createDOMHistory2 = _interopRequireDefault(_createDOMHistory);\n\nvar _parsePath = require('./parsePath');\n\nvar _parsePath2 = _interopRequireDefault(_parsePath);\n\n/**\n * Creates and returns a history object that uses HTML5's history API\n * (pushState, replaceState, and the popstate event) to manage history.\n * This is the recommended method of managing history in browsers because\n * it provides the cleanest URLs.\n *\n * Note: In browsers that do not support the HTML5 history API full\n * page reloads will be used to preserve URLs.\n */\nfunction createBrowserHistory() {\n var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];\n\n !_ExecutionEnvironment.canUseDOM ? process.env.NODE_ENV !== 'production' ? _invariant2['default'](false, 'Browser history needs a DOM') : _invariant2['default'](false) : undefined;\n\n var forceRefresh = options.forceRefresh;\n\n var isSupported = _DOMUtils.supportsHistory();\n var useRefresh = !isSupported || forceRefresh;\n\n function getCurrentLocation(historyState) {\n historyState = historyState || window.history.state || {};\n\n var path = _DOMUtils.getWindowPath();\n var _historyState = historyState;\n var key = _historyState.key;\n\n var state = undefined;\n if (key) {\n state = _DOMStateStorage.readState(key);\n } else {\n state = null;\n key = history.createKey();\n\n if (isSupported) window.history.replaceState(_extends({}, historyState, { key: key }), null, path);\n }\n\n var location = _parsePath2['default'](path);\n\n return history.createLocation(_extends({}, location, { state: state }), undefined, key);\n }\n\n function startPopStateListener(_ref) {\n var transitionTo = _ref.transitionTo;\n\n function popStateListener(event) {\n if (event.state === undefined) return; // Ignore extraneous popstate events in WebKit.\n\n transitionTo(getCurrentLocation(event.state));\n }\n\n _DOMUtils.addEventListener(window, 'popstate', popStateListener);\n\n return function () {\n _DOMUtils.removeEventListener(window, 'popstate', popStateListener);\n };\n }\n\n function finishTransition(location) {\n var basename = location.basename;\n var pathname = location.pathname;\n var search = location.search;\n var hash = location.hash;\n var state = location.state;\n var action = location.action;\n var key = location.key;\n\n if (action === _Actions.POP) return; // Nothing to do.\n\n _DOMStateStorage.saveState(key, state);\n\n var path = (basename || '') + pathname + search + hash;\n var historyState = {\n key: key\n };\n\n if (action === _Actions.PUSH) {\n if (useRefresh) {\n window.location.href = path;\n return false; // Prevent location update.\n } else {\n window.history.pushState(historyState, null, path);\n }\n } else {\n // REPLACE\n if (useRefresh) {\n window.location.replace(path);\n return false; // Prevent location update.\n } else {\n window.history.replaceState(historyState, null, path);\n }\n }\n }\n\n var history = _createDOMHistory2['default'](_extends({}, options, {\n getCurrentLocation: getCurrentLocation,\n finishTransition: finishTransition,\n saveState: _DOMStateStorage.saveState\n }));\n\n var listenerCount = 0,\n stopPopStateListener = undefined;\n\n function listenBefore(listener) {\n if (++listenerCount === 1) stopPopStateListener = startPopStateListener(history);\n\n var unlisten = history.listenBefore(listener);\n\n return function () {\n unlisten();\n\n if (--listenerCount === 0) stopPopStateListener();\n };\n }\n\n function listen(listener) {\n if (++listenerCount === 1) stopPopStateListener = startPopStateListener(history);\n\n var unlisten = history.listen(listener);\n\n return function () {\n unlisten();\n\n if (--listenerCount === 0) stopPopStateListener();\n };\n }\n\n // deprecated\n function registerTransitionHook(hook) {\n if (++listenerCount === 1) stopPopStateListener = startPopStateListener(history);\n\n history.registerTransitionHook(hook);\n }\n\n // deprecated\n function unregisterTransitionHook(hook) {\n history.unregisterTransitionHook(hook);\n\n if (--listenerCount === 0) stopPopStateListener();\n }\n\n return _extends({}, history, {\n listenBefore: listenBefore,\n listen: listen,\n registerTransitionHook: registerTransitionHook,\n unregisterTransitionHook: unregisterTransitionHook\n });\n}\n\nexports['default'] = createBrowserHistory;\nmodule.exports = exports['default'];\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/history/lib/createBrowserHistory.js\n// module id = 140\n// module chunks = 0","/*eslint-disable no-empty */\n'use strict';\n\nexports.__esModule = true;\nexports.saveState = saveState;\nexports.readState = readState;\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar _warning = require('warning');\n\nvar _warning2 = _interopRequireDefault(_warning);\n\nvar KeyPrefix = '@@History/';\nvar QuotaExceededError = 'QuotaExceededError';\nvar SecurityError = 'SecurityError';\n\nfunction createKey(key) {\n return KeyPrefix + key;\n}\n\nfunction saveState(key, state) {\n try {\n window.sessionStorage.setItem(createKey(key), JSON.stringify(state));\n } catch (error) {\n if (error.name === SecurityError) {\n // Blocking cookies in Chrome/Firefox/Safari throws SecurityError on any\n // attempt to access window.sessionStorage.\n process.env.NODE_ENV !== 'production' ? _warning2['default'](false, '[history] Unable to save state; sessionStorage is not available due to security settings') : undefined;\n\n return;\n }\n\n if (error.name === QuotaExceededError && window.sessionStorage.length === 0) {\n // Safari \"private mode\" throws QuotaExceededError.\n process.env.NODE_ENV !== 'production' ? _warning2['default'](false, '[history] Unable to save state; sessionStorage is not available in Safari private mode') : undefined;\n\n return;\n }\n\n throw error;\n }\n}\n\nfunction readState(key) {\n var json = undefined;\n try {\n json = window.sessionStorage.getItem(createKey(key));\n } catch (error) {\n if (error.name === SecurityError) {\n // Blocking cookies in Chrome/Firefox/Safari throws SecurityError on any\n // attempt to access window.sessionStorage.\n process.env.NODE_ENV !== 'production' ? _warning2['default'](false, '[history] Unable to read state; sessionStorage is not available due to security settings') : undefined;\n\n return null;\n }\n }\n\n if (json) {\n try {\n return JSON.parse(json);\n } catch (error) {\n // Ignore invalid JSON.\n }\n }\n\n return null;\n}\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/history/lib/DOMStateStorage.js\n// module id = 141\n// module chunks = 0","'use strict';\n\nexports.__esModule = true;\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar _invariant = require('invariant');\n\nvar _invariant2 = _interopRequireDefault(_invariant);\n\nvar _ExecutionEnvironment = require('./ExecutionEnvironment');\n\nvar _DOMUtils = require('./DOMUtils');\n\nvar _createHistory = require('./createHistory');\n\nvar _createHistory2 = _interopRequireDefault(_createHistory);\n\nfunction createDOMHistory(options) {\n var history = _createHistory2['default'](_extends({\n getUserConfirmation: _DOMUtils.getUserConfirmation\n }, options, {\n go: _DOMUtils.go\n }));\n\n function listen(listener) {\n !_ExecutionEnvironment.canUseDOM ? process.env.NODE_ENV !== 'production' ? _invariant2['default'](false, 'DOM history needs a DOM') : _invariant2['default'](false) : undefined;\n\n return history.listen(listener);\n }\n\n return _extends({}, history, {\n listen: listen\n });\n}\n\nexports['default'] = createDOMHistory;\nmodule.exports = exports['default'];\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/history/lib/createDOMHistory.js\n// module id = 142\n// module chunks = 0","//import warning from 'warning'\n'use strict';\n\nexports.__esModule = true;\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar _deepEqual = require('deep-equal');\n\nvar _deepEqual2 = _interopRequireDefault(_deepEqual);\n\nvar _AsyncUtils = require('./AsyncUtils');\n\nvar _Actions = require('./Actions');\n\nvar _createLocation2 = require('./createLocation');\n\nvar _createLocation3 = _interopRequireDefault(_createLocation2);\n\nvar _runTransitionHook = require('./runTransitionHook');\n\nvar _runTransitionHook2 = _interopRequireDefault(_runTransitionHook);\n\nvar _parsePath = require('./parsePath');\n\nvar _parsePath2 = _interopRequireDefault(_parsePath);\n\nvar _deprecate = require('./deprecate');\n\nvar _deprecate2 = _interopRequireDefault(_deprecate);\n\nfunction createRandomKey(length) {\n return Math.random().toString(36).substr(2, length);\n}\n\nfunction locationsAreEqual(a, b) {\n return a.pathname === b.pathname && a.search === b.search &&\n //a.action === b.action && // Different action !== location change.\n a.key === b.key && _deepEqual2['default'](a.state, b.state);\n}\n\nvar DefaultKeyLength = 6;\n\nfunction createHistory() {\n var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];\n var getCurrentLocation = options.getCurrentLocation;\n var finishTransition = options.finishTransition;\n var saveState = options.saveState;\n var go = options.go;\n var keyLength = options.keyLength;\n var getUserConfirmation = options.getUserConfirmation;\n\n if (typeof keyLength !== 'number') keyLength = DefaultKeyLength;\n\n var transitionHooks = [];\n\n function listenBefore(hook) {\n transitionHooks.push(hook);\n\n return function () {\n transitionHooks = transitionHooks.filter(function (item) {\n return item !== hook;\n });\n };\n }\n\n var allKeys = [];\n var changeListeners = [];\n var location = undefined;\n\n function getCurrent() {\n if (pendingLocation && pendingLocation.action === _Actions.POP) {\n return allKeys.indexOf(pendingLocation.key);\n } else if (location) {\n return allKeys.indexOf(location.key);\n } else {\n return -1;\n }\n }\n\n function updateLocation(newLocation) {\n var current = getCurrent();\n\n location = newLocation;\n\n if (location.action === _Actions.PUSH) {\n allKeys = [].concat(allKeys.slice(0, current + 1), [location.key]);\n } else if (location.action === _Actions.REPLACE) {\n allKeys[current] = location.key;\n }\n\n changeListeners.forEach(function (listener) {\n listener(location);\n });\n }\n\n function listen(listener) {\n changeListeners.push(listener);\n\n if (location) {\n listener(location);\n } else {\n var _location = getCurrentLocation();\n allKeys = [_location.key];\n updateLocation(_location);\n }\n\n return function () {\n changeListeners = changeListeners.filter(function (item) {\n return item !== listener;\n });\n };\n }\n\n function confirmTransitionTo(location, callback) {\n _AsyncUtils.loopAsync(transitionHooks.length, function (index, next, done) {\n _runTransitionHook2['default'](transitionHooks[index], location, function (result) {\n if (result != null) {\n done(result);\n } else {\n next();\n }\n });\n }, function (message) {\n if (getUserConfirmation && typeof message === 'string') {\n getUserConfirmation(message, function (ok) {\n callback(ok !== false);\n });\n } else {\n callback(message !== false);\n }\n });\n }\n\n var pendingLocation = undefined;\n\n function transitionTo(nextLocation) {\n if (location && locationsAreEqual(location, nextLocation)) return; // Nothing to do.\n\n pendingLocation = nextLocation;\n\n confirmTransitionTo(nextLocation, function (ok) {\n if (pendingLocation !== nextLocation) return; // Transition was interrupted.\n\n if (ok) {\n // treat PUSH to current path like REPLACE to be consistent with browsers\n if (nextLocation.action === _Actions.PUSH) {\n var prevPath = createPath(location);\n var nextPath = createPath(nextLocation);\n\n if (nextPath === prevPath) nextLocation.action = _Actions.REPLACE;\n }\n\n if (finishTransition(nextLocation) !== false) updateLocation(nextLocation);\n } else if (location && nextLocation.action === _Actions.POP) {\n var prevIndex = allKeys.indexOf(location.key);\n var nextIndex = allKeys.indexOf(nextLocation.key);\n\n if (prevIndex !== -1 && nextIndex !== -1) go(prevIndex - nextIndex); // Restore the URL.\n }\n });\n }\n\n function push(location) {\n transitionTo(createLocation(location, _Actions.PUSH, createKey()));\n }\n\n function replace(location) {\n transitionTo(createLocation(location, _Actions.REPLACE, createKey()));\n }\n\n function goBack() {\n go(-1);\n }\n\n function goForward() {\n go(1);\n }\n\n function createKey() {\n return createRandomKey(keyLength);\n }\n\n function createPath(location) {\n if (location == null || typeof location === 'string') return location;\n\n var pathname = location.pathname;\n var search = location.search;\n var hash = location.hash;\n\n var result = pathname;\n\n if (search) result += search;\n\n if (hash) result += hash;\n\n return result;\n }\n\n function createHref(location) {\n return createPath(location);\n }\n\n function createLocation(location, action) {\n var key = arguments.length <= 2 || arguments[2] === undefined ? createKey() : arguments[2];\n\n if (typeof action === 'object') {\n //warning(\n // false,\n // 'The state (2nd) argument to history.createLocation is deprecated; use a ' +\n // 'location descriptor instead'\n //)\n\n if (typeof location === 'string') location = _parsePath2['default'](location);\n\n location = _extends({}, location, { state: action });\n\n action = key;\n key = arguments[3] || createKey();\n }\n\n return _createLocation3['default'](location, action, key);\n }\n\n // deprecated\n function setState(state) {\n if (location) {\n updateLocationState(location, state);\n updateLocation(location);\n } else {\n updateLocationState(getCurrentLocation(), state);\n }\n }\n\n function updateLocationState(location, state) {\n location.state = _extends({}, location.state, state);\n saveState(location.key, location.state);\n }\n\n // deprecated\n function registerTransitionHook(hook) {\n if (transitionHooks.indexOf(hook) === -1) transitionHooks.push(hook);\n }\n\n // deprecated\n function unregisterTransitionHook(hook) {\n transitionHooks = transitionHooks.filter(function (item) {\n return item !== hook;\n });\n }\n\n // deprecated\n function pushState(state, path) {\n if (typeof path === 'string') path = _parsePath2['default'](path);\n\n push(_extends({ state: state }, path));\n }\n\n // deprecated\n function replaceState(state, path) {\n if (typeof path === 'string') path = _parsePath2['default'](path);\n\n replace(_extends({ state: state }, path));\n }\n\n return {\n listenBefore: listenBefore,\n listen: listen,\n transitionTo: transitionTo,\n push: push,\n replace: replace,\n go: go,\n goBack: goBack,\n goForward: goForward,\n createKey: createKey,\n createPath: createPath,\n createHref: createHref,\n createLocation: createLocation,\n\n setState: _deprecate2['default'](setState, 'setState is deprecated; use location.key to save state instead'),\n registerTransitionHook: _deprecate2['default'](registerTransitionHook, 'registerTransitionHook is deprecated; use listenBefore instead'),\n unregisterTransitionHook: _deprecate2['default'](unregisterTransitionHook, 'unregisterTransitionHook is deprecated; use the callback returned from listenBefore instead'),\n pushState: _deprecate2['default'](pushState, 'pushState is deprecated; use push instead'),\n replaceState: _deprecate2['default'](replaceState, 'replaceState is deprecated; use replace instead')\n };\n}\n\nexports['default'] = createHistory;\nmodule.exports = exports['default'];\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/history/lib/createHistory.js\n// module id = 143\n// module chunks = 0","'use strict';\n\nexports.__esModule = true;\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar _warning = require('warning');\n\nvar _warning2 = _interopRequireDefault(_warning);\n\nvar _ExecutionEnvironment = require('./ExecutionEnvironment');\n\nvar _DOMUtils = require('./DOMUtils');\n\nvar _deprecate = require('./deprecate');\n\nvar _deprecate2 = _interopRequireDefault(_deprecate);\n\nfunction startBeforeUnloadListener(getBeforeUnloadPromptMessage) {\n function listener(event) {\n var message = getBeforeUnloadPromptMessage();\n\n if (typeof message === 'string') {\n (event || window.event).returnValue = message;\n return message;\n }\n }\n\n _DOMUtils.addEventListener(window, 'beforeunload', listener);\n\n return function () {\n _DOMUtils.removeEventListener(window, 'beforeunload', listener);\n };\n}\n\n/**\n * Returns a new createHistory function that can be used to create\n * history objects that know how to use the beforeunload event in web\n * browsers to cancel navigation.\n */\nfunction useBeforeUnload(createHistory) {\n return function (options) {\n var history = createHistory(options);\n\n var stopBeforeUnloadListener = undefined;\n var beforeUnloadHooks = [];\n\n function getBeforeUnloadPromptMessage() {\n var message = undefined;\n\n for (var i = 0, len = beforeUnloadHooks.length; message == null && i < len; ++i) {\n message = beforeUnloadHooks[i].call();\n }return message;\n }\n\n function listenBeforeUnload(hook) {\n beforeUnloadHooks.push(hook);\n\n if (beforeUnloadHooks.length === 1) {\n if (_ExecutionEnvironment.canUseDOM) {\n stopBeforeUnloadListener = startBeforeUnloadListener(getBeforeUnloadPromptMessage);\n } else {\n process.env.NODE_ENV !== 'production' ? _warning2['default'](false, 'listenBeforeUnload only works in DOM environments') : undefined;\n }\n }\n\n return function () {\n beforeUnloadHooks = beforeUnloadHooks.filter(function (item) {\n return item !== hook;\n });\n\n if (beforeUnloadHooks.length === 0 && stopBeforeUnloadListener) {\n stopBeforeUnloadListener();\n stopBeforeUnloadListener = null;\n }\n };\n }\n\n // deprecated\n function registerBeforeUnloadHook(hook) {\n if (_ExecutionEnvironment.canUseDOM && beforeUnloadHooks.indexOf(hook) === -1) {\n beforeUnloadHooks.push(hook);\n\n if (beforeUnloadHooks.length === 1) stopBeforeUnloadListener = startBeforeUnloadListener(getBeforeUnloadPromptMessage);\n }\n }\n\n // deprecated\n function unregisterBeforeUnloadHook(hook) {\n if (beforeUnloadHooks.length > 0) {\n beforeUnloadHooks = beforeUnloadHooks.filter(function (item) {\n return item !== hook;\n });\n\n if (beforeUnloadHooks.length === 0) stopBeforeUnloadListener();\n }\n }\n\n return _extends({}, history, {\n listenBeforeUnload: listenBeforeUnload,\n\n registerBeforeUnloadHook: _deprecate2['default'](registerBeforeUnloadHook, 'registerBeforeUnloadHook is deprecated; use listenBeforeUnload instead'),\n unregisterBeforeUnloadHook: _deprecate2['default'](unregisterBeforeUnloadHook, 'unregisterBeforeUnloadHook is deprecated; use the callback returned from listenBeforeUnload instead')\n });\n };\n}\n\nexports['default'] = useBeforeUnload;\nmodule.exports = exports['default'];\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/history/lib/useBeforeUnload.js\n// module id = 144\n// module chunks = 0","'use strict';\n\nexports.__esModule = true;\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nfunction _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }\n\nvar _warning = require('warning');\n\nvar _warning2 = _interopRequireDefault(_warning);\n\nvar _queryString = require('query-string');\n\nvar _runTransitionHook = require('./runTransitionHook');\n\nvar _runTransitionHook2 = _interopRequireDefault(_runTransitionHook);\n\nvar _parsePath = require('./parsePath');\n\nvar _parsePath2 = _interopRequireDefault(_parsePath);\n\nvar _deprecate = require('./deprecate');\n\nvar _deprecate2 = _interopRequireDefault(_deprecate);\n\nvar SEARCH_BASE_KEY = '$searchBase';\n\nfunction defaultStringifyQuery(query) {\n return _queryString.stringify(query).replace(/%20/g, '+');\n}\n\nvar defaultParseQueryString = _queryString.parse;\n\nfunction isNestedObject(object) {\n for (var p in object) {\n if (object.hasOwnProperty(p) && typeof object[p] === 'object' && !Array.isArray(object[p]) && object[p] !== null) return true;\n }return false;\n}\n\n/**\n * Returns a new createHistory function that may be used to create\n * history objects that know how to handle URL queries.\n */\nfunction useQueries(createHistory) {\n return function () {\n var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];\n var stringifyQuery = options.stringifyQuery;\n var parseQueryString = options.parseQueryString;\n\n var historyOptions = _objectWithoutProperties(options, ['stringifyQuery', 'parseQueryString']);\n\n var history = createHistory(historyOptions);\n\n if (typeof stringifyQuery !== 'function') stringifyQuery = defaultStringifyQuery;\n\n if (typeof parseQueryString !== 'function') parseQueryString = defaultParseQueryString;\n\n function addQuery(location) {\n if (location.query == null) {\n var search = location.search;\n\n location.query = parseQueryString(search.substring(1));\n location[SEARCH_BASE_KEY] = { search: search, searchBase: '' };\n }\n\n // TODO: Instead of all the book-keeping here, this should just strip the\n // stringified query from the search.\n\n return location;\n }\n\n function appendQuery(location, query) {\n var _extends2;\n\n var queryString = undefined;\n if (!query || (queryString = stringifyQuery(query)) === '') return location;\n\n process.env.NODE_ENV !== 'production' ? _warning2['default'](stringifyQuery !== defaultStringifyQuery || !isNestedObject(query), 'useQueries does not stringify nested query objects by default; ' + 'use a custom stringifyQuery function') : undefined;\n\n if (typeof location === 'string') location = _parsePath2['default'](location);\n\n var searchBaseSpec = location[SEARCH_BASE_KEY];\n var searchBase = undefined;\n if (searchBaseSpec && location.search === searchBaseSpec.search) {\n searchBase = searchBaseSpec.searchBase;\n } else {\n searchBase = location.search || '';\n }\n\n var search = searchBase + (searchBase ? '&' : '?') + queryString;\n\n return _extends({}, location, (_extends2 = {\n search: search\n }, _extends2[SEARCH_BASE_KEY] = { search: search, searchBase: searchBase }, _extends2));\n }\n\n // Override all read methods with query-aware versions.\n function listenBefore(hook) {\n return history.listenBefore(function (location, callback) {\n _runTransitionHook2['default'](hook, addQuery(location), callback);\n });\n }\n\n function listen(listener) {\n return history.listen(function (location) {\n listener(addQuery(location));\n });\n }\n\n // Override all write methods with query-aware versions.\n function push(location) {\n history.push(appendQuery(location, location.query));\n }\n\n function replace(location) {\n history.replace(appendQuery(location, location.query));\n }\n\n function createPath(location, query) {\n //warning(\n // !query,\n // 'the query argument to createPath is deprecated; use a location descriptor instead'\n //)\n return history.createPath(appendQuery(location, query || location.query));\n }\n\n function createHref(location, query) {\n //warning(\n // !query,\n // 'the query argument to createHref is deprecated; use a location descriptor instead'\n //)\n return history.createHref(appendQuery(location, query || location.query));\n }\n\n function createLocation() {\n return addQuery(history.createLocation.apply(history, arguments));\n }\n\n // deprecated\n function pushState(state, path, query) {\n if (typeof path === 'string') path = _parsePath2['default'](path);\n\n push(_extends({ state: state }, path, { query: query }));\n }\n\n // deprecated\n function replaceState(state, path, query) {\n if (typeof path === 'string') path = _parsePath2['default'](path);\n\n replace(_extends({ state: state }, path, { query: query }));\n }\n\n return _extends({}, history, {\n listenBefore: listenBefore,\n listen: listen,\n push: push,\n replace: replace,\n createPath: createPath,\n createHref: createHref,\n createLocation: createLocation,\n\n pushState: _deprecate2['default'](pushState, 'pushState is deprecated; use push instead'),\n replaceState: _deprecate2['default'](replaceState, 'replaceState is deprecated; use replace instead')\n });\n };\n}\n\nexports['default'] = useQueries;\nmodule.exports = exports['default'];\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/history/lib/useQueries.js\n// module id = 145\n// module chunks = 0","'use strict'\n\nimport PropTypes from 'prop-types'\nimport React from 'react'\nimport { Link } from 'react-router'\nimport Component from './Component'\n\nclass LektorLink extends Component {\n render () {\n let path = this.props.to\n if (path.substr(0, 1) !== '/') {\n path = $LEKTOR_CONFIG.admin_root + '/' + path\n }\n return (\n \n {this.props.children}\n \n )\n }\n}\n\nLektorLink.propTypes = {\n to: PropTypes.string\n}\n\nmodule.exports = LektorLink\n\n\n\n// WEBPACK FOOTER //\n// ./js/components/Link.jsx","'use strict'\n\nimport RecordComponent from './RecordComponent'\nimport i18n from '../i18n'\n\nclass RecordEditComponent extends RecordComponent {\n hasPendingChanges () {\n return false\n }\n\n routerWillLeave (nextLocation) {\n const rv = super.routerWillLeave(nextLocation)\n if (rv !== undefined) {\n return rv\n }\n if (this.hasPendingChanges()) {\n return i18n.trans('UNLOAD_ACTIVE_TAB')\n }\n }\n}\n\nexport default RecordEditComponent\n\n\n\n// WEBPACK FOOTER //\n// ./js/components/RecordEditComponent.jsx","'use strict'\n\nimport PropTypes from 'prop-types'\nimport React from 'react'\nimport ReactDOM from 'react-dom'\nimport {Router, Route, IndexRoute} from 'react-router'\nimport Component from './components/Component'\nimport i18n from './i18n'\nimport {useBeforeUnload} from 'history'\nimport createBrowserHistory from 'history/lib/createBrowserHistory'\n\n/* eslint-disable no-unused-vars */\nimport Bootstrap from 'bootstrap'\nimport BootstrapExtras from './bootstrap-extras'\nimport FACss from 'font-awesome/css/font-awesome.css'\n\n// polyfill for internet explorer\nimport PromiseOnly from 'native-promise-only'\nimport EventSource from 'event-source-polyfill'\n/* eslint-enable no-unused-vars */\n\n// route targets\nimport App from './views/App'\nimport Dash from './views/Dash'\nimport EditPage from './views/EditPage'\nimport DeletePage from './views/DeletePage'\nimport PreviewPage from './views/PreviewPage'\nimport AddChildPage from './views/AddChildPage'\nimport AddAttachmentPage from './views/AddAttachmentPage'\n\ni18n.currentLanguage = $LEKTOR_CONFIG.lang\n\nclass BadRoute extends Component {\n render () {\n return (\n
\n

Nothing to see here

\n

There is really nothing to see here.

\n
\n )\n }\n}\n\nBadRoute.contextTypes = {\n router: PropTypes.func\n}\n\nconst routes = (() => {\n // route setup\n return (\n \n \n \n \n \n \n \n \n \n )\n})()\n\nconst dash = document.getElementById('dash')\n\nif (dash) {\n ReactDOM.render((\n \n {routes}\n \n ), dash)\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/main.jsx","/**\n * Copyright 2013-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n\n'use strict';\n\nvar emptyFunction = require('fbjs/lib/emptyFunction');\nvar invariant = require('fbjs/lib/invariant');\nvar ReactPropTypesSecret = require('./lib/ReactPropTypesSecret');\n\nmodule.exports = function() {\n function shim(props, propName, componentName, location, propFullName, secret) {\n if (secret === ReactPropTypesSecret) {\n // It is still safe when called from React.\n return;\n }\n invariant(\n false,\n 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' +\n 'Use PropTypes.checkPropTypes() to call them. ' +\n 'Read more at http://fb.me/use-check-prop-types'\n );\n };\n shim.isRequired = shim;\n function getShim() {\n return shim;\n };\n // Important!\n // Keep this list in sync with production version in `./factoryWithTypeCheckers.js`.\n var ReactPropTypes = {\n array: shim,\n bool: shim,\n func: shim,\n number: shim,\n object: shim,\n string: shim,\n symbol: shim,\n\n any: shim,\n arrayOf: getShim,\n element: shim,\n instanceOf: getShim,\n node: shim,\n objectOf: getShim,\n oneOf: getShim,\n oneOfType: getShim,\n shape: getShim\n };\n\n ReactPropTypes.checkPropTypes = emptyFunction;\n ReactPropTypes.PropTypes = ReactPropTypes;\n\n return ReactPropTypes;\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/prop-types/factoryWithThrowingShims.js\n// module id = 154\n// module chunks = 0","// the base component. This really should not exist in the first place\n// but react is a bit meh when it comes to what's on the base component\n// which breaks super. This is why we do this here. Note that this is\n// also used by the standalone admin UI app.\n\n'use strict'\n\nimport React from 'react'\n\nclass BaseComponent extends React.Component {\n componentDidMount () {\n }\n\n componentWillUnmount () {\n }\n\n componentDidUpdate () {\n }\n\n componentWillReceiveProps (nextProps) {\n }\n}\n\nexport default BaseComponent\n\n\n\n// WEBPACK FOOTER //\n// ./js/components/BaseComponent.jsx","var map = {\n\t\"./ca.json\": 285,\n\t\"./de.json\": 286,\n\t\"./en.json\": 287,\n\t\"./es.json\": 288,\n\t\"./fr.json\": 289,\n\t\"./it.json\": 290,\n\t\"./ja.json\": 291,\n\t\"./ko.json\": 292,\n\t\"./nl.json\": 293,\n\t\"./pl.json\": 294,\n\t\"./pt.json\": 295,\n\t\"./ru.json\": 296,\n\t\"./zh.json\": 297\n};\nfunction webpackContext(req) {\n\treturn __webpack_require__(webpackContextResolve(req));\n};\nfunction webpackContextResolve(req) {\n\tvar id = map[req];\n\tif(!(id + 1)) // check for number or string\n\t\tthrow new Error(\"Cannot find module '\" + req + \"'.\");\n\treturn id;\n};\nwebpackContext.keys = function webpackContextKeys() {\n\treturn Object.keys(map);\n};\nwebpackContext.resolve = webpackContextResolve;\nmodule.exports = webpackContext;\nwebpackContext.id = 284;\n\n\n//////////////////\n// WEBPACK FOOTER\n// /home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations \\.json$\n// module id = 284\n// module chunks = 0","module.exports = {\"RETURN_TO_WEBSITE\":\"Tornar al Lloc Web\",\"UNLOAD_ACTIVE_TAB\":\"Hi ha informació sense desar, està segur que vol abandonar aquesta pàgina?\",\"EDIT_METADATA\":\"Editar Metadades\",\"EDIT\":\"Editar\",\"DELETE\":\"Esborrar\",\"PREVIEW\":\"Previsualitzar\",\"ALTS\":\"Alternatives\",\"PRIMARY_ALT\":\"Primària\",\"PRIMARY_OVERLAY\":\"Overlaid\",\"ADD_CHILD_PAGE\":\"Afegir Pàgina\",\"ADD_ATTACHMENT\":\"Afegir Adjunt\",\"ATTACHMENT_ACTIONS\":\"Accions sobre els Adjunts\",\"PAGE_ACTIONS\":\"Accions sobre la Pàgina\",\"NO_CHILD_PAGES\":\"Sense Subpàgines\",\"CHILD_PAGES\":\"Subpàgines\",\"NO_ATTACHMENTS\":\"Sense Adjunts\",\"ATTACHMENTS\":\"Adjunts\",\"ADD_ATTACHMENT_TO\":\"Afegir Adjunt a “%s”\",\"ADD_ATTACHMENT_NOTE\":\"Pot pujar un nou adjunt aquí.\",\"UPLOAD\":\"Pujar\",\"PROGRESS\":\"Avenç\",\"ERROR_PREFIX\":\"Error: \",\"ERROR_NO_ID_PROVIDED\":\"No s'ha proporcionat un ID.\",\"ERROR_PAGE_ID_DUPLICATE\":\"Ja existeix una pàgina amb aquest ID (%s).\",\"ERROR_INVALID_ID\":\"ID invàlid\",\"ERROR_INVALID_DATE\":\"Data invàlida\",\"ERROR_INVALID_NUMBER\":\"Número no vàlid\",\"ERROR_INVALID_URL\":\"URL no vàlida\",\"ERROR\":\"Error\",\"ERROR_OCURRED\":\"Ha ocorregut un Error\",\"ERROR_REQUEST_FAILED\":\"No s'ha pogut enviar la tasca al servidor. Potser el servidor està apagat o és inaccessible\",\"ERROR_SERVER_UNAVAILABLE\":\"Servidor No Disponible\",\"ERROR_SERVER_UNAVAILABLE_MESSAGE\":\"El servidor no respon. Ha estat apagat o hi ha hagut un error crític que ha fet que estigui inoperatiu i hagi de ser reiniciat.\",\"MODEL\":\"Model\",\"ADD_CHILD_PAGE_TO\":\"Afegir Subpàgina a “%s”\",\"ADD_CHILD_PAGE_NOTE\":\"Pot afegir una nova subpàgina aquí. Tingui en compte que el model o el ID no podrà ser canviat fàcilment més endavant.\",\"CREATE_CHILD_PAGE\":\"Afegir pàgina filla\",\"DELETE_ATTACHMENT_PROMPT\":\"Realment vol esborrar aquest adjunt?\",\"DELETE_ATTACHMENT_ALT_PROMPT\":\"Realment vol esborrar les metadades d'aquest adjunt alternatiu?\",\"DELETE_PAGE_PROMPT\":\"Vol realment esborrar aquesta pàgina?\",\"DELETE_PAGE_ALT_PROMPT\":\"Realment desitja esborrar aquesta alternativa?\",\"DELETE_PAGE_CHILDREN_WARNING\":\"També s'esborraran les subpàgines que pengin d'aquesta pàgina.\",\"DELETE_RECORD\":\"Esborrar “%s”\",\"DELETE_ALL_PAGE_ALTS\":\"Esborrar també totes les alternatives i fitxers adjunts.\",\"DELETE_ALL_ATTACHMENT_ALTS\":\"Esborrar totes les alternatives de l'annex i el fitxer adjunt.\",\"DELETE_ONLY_PRIMARY_PAGE_ALT\":\"Esborrar només el registre principal. Els adjunts, les alternatives i les subpàgines no seran esborrades.\",\"DELETE_ONLY_PRIMARY_ATTACHMENT_ALT\":\"Esborrar només les metadades del registre principal.\",\"DELETE_PRIMARY_ALT_INFO\":\"Com aquest registre és una alternativa principal, pot ser esborrat per separat o conjuntament a la resta de continguts.\",\"CHILD_PAGES_TO_BE_DELETED\":\"Subpàgines que seran esborrares:\",\"ALTS_TO_BE_DELETED\":\"Alternatives que seran eliminades:\",\"ATTACHMENTS_TO_BE_DELETED\":\"Adjunts que seran eliminats:\",\"YES_DELETE\":\"Sí, esborrar\",\"NO_CANCEL\":\"No, cancel·lar\",\"SYSTEM_FIELDS\":\"Camps del Sistema\",\"EDIT_ATTACHMENT_METADATA_OF\":\"Editar les Metadades de l'Adjunt “%s”\",\"EDIT_PAGE_NAME\":\"Editar “%s”\",\"SAVE_CHANGES\":\"Desar els canvis\",\"BROWSE_FS\":\"Veure al Sistema de fitxers\",\"BROWSE_FS_MAC\":\"Mostrar al Finder\",\"BROWSE_FS_WINDOWS\":\"Mostrar a l'Explorador\",\"ERROR_CANNOT_BROWSE_FS\":\"Error: el fitxer no existeix encara.\",\"REMOVE_FLOWBLOCK_PROMPT\":\"¿Realment vol esborrar aquest block?\",\"ADD_FLOWBLOCK\":\"Afegir Block\",\"INVALID_INPUT\":\"Entrada invàlida\",\"UP\":\"Amunt\",\"DOWN\":\"Abaix\",\"REMOVE\":\"Esborrar\",\"ID\":\"ID\",\"CLOSE\":\"Tancar\",\"CANCEL\":\"Cancel·lar\",\"BACK_TO_OVERVIEW\":\"Tornar a la Revisió\",\"PUBLISH\":\"Publicar\",\"PUBLISH_NOTE\":\"Des d'aquí pot publicar la versió actual del lloc web.\",\"PUBLISH_SERVER\":\"Servidor Destinació\",\"CURRENTLY_PUBLISHING\":\"Publicannt ...\",\"STATE\":\"Estat\",\"PUBLISH_DONE\":\"Publicat\",\"PUBLISH_STATE_BUILDING\":\"Els canvis s'estan generant ...\",\"PUBLISH_STATE_PUBLISH\":\"Els canvis s'estan publicant ...\",\"PUBLISH_STATE_DONE\":\"Publicació finalitzada.\",\"FIND_FILES\":\"Buscar Fitxers\",\"FIND_FILES_PLACEHOLDER\":\"Introdueixi el nom de la pàgina ...\",\"ATTACHMENT_TYPE\":\"Tipus d'adjunt\",\"URL_SLUG\":\"URL personalitzada\",\"TEMPLATE\":\"Plantilla\",\"HIDE_PAGE\":\"Amagar pàgina\",\"HIDE_PAGE_EXPLANATION\":\"Hauria d'estar oculta aquesta pàgina?\",\"PAGE_IS_DISCOVERABLE\":\"La Pàgina és detectable\",\"PAGE_IS_DISCOVERABLE_EXPLANATION\":\"Si s'habilita, la pàgina pot ser detectada, en cas contrari la URL del contingut ha de ser coneguda.\",\"REFRESH_BUILD\":\"Regenerar Lloc Web\",\"REFRESH_BUILD_NOTE\":\"Això esborra tots els resultats generats i llença una nova generació des de zero. Això és útil en algunes situacions on els errors de sincronització o a les plantilles han causat un resultat corrupte.\",\"CURRENTLY_REFRESHING_BUILD\":\"Regenerant ...\",\"REFRESHING_BUILD_DONE\":\"Actualització finalitzada!\",\"FAILED_TO_LAUNCH_LEKTOR\":\"Ha fallat l'execució de Lektor.\",\"PROJECT\":\"Projecte\",\"CLOSE_PROJECT\":\"Tancar Projecte\",\"OPEN_PROJECT\":\"Obrir Projecte\",\"BROWSE_WEBSITE\":\"Anar al Lloc Web\",\"VIEW_ADMIN_PANEL\":\"Anar al Panell d'Administració\",\"QUIT\":\"Sortir\",\"FAILED_TO_LOAD_PROJECT\":\"Ha fallat la càrrega del projecte :(\",\"LOADING_PROJECT\":\"Carregant projecte ...\",\"INITIALIZING_LEKTOR\":\"Inicialitzant Lektor ...\",\"QUIT_LEKTOR\":\"Sortir de Lektor\",\"FILE\":\"Arxiu\",\"UNDO\":\"Desfer\",\"REDO\":\"Tornar a fer\",\"CUT\":\"Tallar\",\"COPY\":\"Copiar\",\"PASTE\":\"Enganxar\",\"SELECT_ALL\":\"Seleccionar-ho Tot\",\"HELP\":\"Ajuda\",\"VISIT_WEBSITE\":\"Visitar Web\",\"INSTALL_SHELL_COMMAND\":\"Instalar Eina\",\"INSTALL_SHELL_COMMAND_QUESTION\":\"Vol instal·lar la eina 'lektor'? Es requereixen permisos d'administració.\",\"FAILED_TO_INSTALL_SHELL_COMMANDS\":\"Ha fallat la instal·lació de l'eina.\",\"INSTALL_SHELL_COMMAND_SUCCESS\":\"L'eina ha estat instal·lada amb èxit.\",\"OPERATION_SUCCESS\":\"Amb èxit\",\"YES\":\"Sí\",\"NO\":\"No\",\"OK\":\"OK\",\"FAILED_TO_OPEN_CONTENT_FILE\":\"Error al intentar obrir el fitxer de contingut\",\"OPEN_OTHER_PROJECT\":\"Obrir un altre Projecte\",\"OPEN_OTHER_PROJECT_QUESTION\":\"Obrir aquest fitxer implica obrir un altre projecte (%s). El projecte actual serà tancat. Vol continuar?\"}\n\n\n//////////////////\n// WEBPACK FOOTER\n// /home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/ca.json\n// module id = 285\n// module chunks = 0","module.exports = {\"RETURN_TO_WEBSITE\":\"Zur Webseite\",\"UNLOAD_ACTIVE_TAB\":\"Du hast ungespeicherte Änderungen, willst du die Seite wirklich verlassen?\",\"EDIT_METADATA\":\"Metadaten bearbeiten\",\"EDIT\":\"Bearbeiten\",\"DELETE\":\"Löschen\",\"PREVIEW\":\"Vorschau\",\"ALTS\":\"Alternativen\",\"PRIMARY_ALT\":\"Primär\",\"PRIMARY_OVERLAY\":\"Überlagert\",\"ADD_CHILD_PAGE\":\"Seite hinzufügen\",\"ADD_ATTACHMENT\":\"Anhang hinzufügen\",\"ATTACHMENT_ACTIONS\":\"Anhang-Aktionen\",\"PAGE_ACTIONS\":\"Seiten-Aktionen\",\"NO_CHILD_PAGES\":\"Keine Unterseiten\",\"CHILD_PAGES\":\"Unterseiten\",\"NO_ATTACHMENTS\":\"Keine Anhänge\",\"ATTACHMENTS\":\"Anhänge\",\"ADD_ATTACHMENT_TO\":\"Anhang zu “%s” hinzufügen\",\"ADD_ATTACHMENT_NOTE\":\"Hier kannst du neue Anhänge hochladen.\",\"UPLOAD\":\"Hochladen\",\"PROGRESS\":\"Fortschritt\",\"ERROR_PREFIX\":\"Fehler: \",\"ERROR_NO_ID_PROVIDED\":\"Es wurde keine ID eingegeben.\",\"ERROR_PAGE_ID_DUPLICATE\":\"Eine Seite mit dieser ID (%s) existiert bereits.\",\"ERROR_INVALID_ID\":\"Ungültige ID\",\"ERROR_INVALID_DATE\":\"Ungültiges Datum\",\"ERROR_INVALID_NUMBER\":\"Ungültige Zahl\",\"ERROR_INVALID_URL\":\"Ungültige URL\",\"ERROR\":\"Fehler\",\"ERROR_OCURRED\":\"Ein Fehler ist aufgetreten\",\"ERROR_REQUEST_FAILED\":\"Ein Befehl konnte nicht an den Server gesendet werden. Eventuell reagiert der Server nicht oder wurde gestoppt.\",\"ERROR_SERVER_UNAVAILABLE\":\"Server unerreichbar\",\"ERROR_SERVER_UNAVAILABLE_MESSAGE\":\"Der Server reagiert nicht. Entweder er wurde gestoppt oder ein kritischer Fehler ist aufgetreten und er muss neu gestartet werden.\",\"MODEL\":\"Modell\",\"ADD_CHILD_PAGE_TO\":\"Unterseite zu “%s” hinzufügen\",\"ADD_CHILD_PAGE_NOTE\":\"Du kannst hier eine neue Unterseite hinzufügen. Beachte, dass die ID und as Modell später nicht mehr verändert werden kann.\",\"CREATE_CHILD_PAGE\":\"Unterseite hinzufügen\",\"DELETE_ATTACHMENT_PROMPT\":\"Willst du den Anhang wirklich löschen?\",\"DELETE_ATTACHMENT_ALT_PROMPT\":\"Willst du die Metadaten dieser Anhang-Alternative wirklich löschen?\",\"DELETE_PAGE_PROMPT\":\"Willst du diese Seite wirklich löschen?\",\"DELETE_PAGE_ALT_PROMPT\":\"Willst du diese Alternative wirklich löschen?\",\"DELETE_PAGE_CHILDREN_WARNING\":\"Dies wird auch die Unterseiten der Seite löschen.\",\"DELETE_RECORD\":\"“%s” Löschen\",\"DELETE_ALL_PAGE_ALTS\":\"Alle Alternativen und angehängten Dateien mitlöschen.\",\"DELETE_ALL_ATTACHMENT_ALTS\":\"Alle Alternativen und die angehängte Datei löschen.\",\"DELETE_ONLY_PRIMARY_PAGE_ALT\":\"Nur den Primäreintrag löschen. Anhänge, andere Alternativen und Unterseiten werden nicht gelöscht.\",\"DELETE_ONLY_PRIMARY_ATTACHMENT_ALT\":\"Nur die Metadaten des Primäreintrages löschen.\",\"DELETE_PRIMARY_ALT_INFO\":\"Da dieser Eintrag eine Primäralternative ist, kann diese auch separat gelöscht werden oder zusammen mit allen anderen Inhalten.\",\"CHILD_PAGES_TO_BE_DELETED\":\"Unterseiten, die gelöscht werden:\",\"ALTS_TO_BE_DELETED\":\"Alternativen, die gelöscht werden:\",\"ATTACHMENTS_TO_BE_DELETED\":\"Anhänge, die gelöscht werden:\",\"YES_DELETE\":\"Ja, löschen\",\"NO_CANCEL\":\"Nein, abbrechen\",\"SYSTEM_FIELDS\":\"Systemfelder\",\"EDIT_ATTACHMENT_METADATA_OF\":\"Bearbeite Metadaten von Anhang “%s”\",\"EDIT_PAGE_NAME\":\"Bearbeite “%s”\",\"SAVE_CHANGES\":\"Änderungen speichern\",\"BROWSE_FS\":\"Im Dateisystem öffnen\",\"BROWSE_FS_MAC\":\"In Finder anzeigen\",\"BROWSE_FS_WINDOWS\":\"Im Explorer öffnen\",\"ERROR_CANNOT_BROWSE_FS\":\"Fehler: Datei existiert noch nicht\",\"REMOVE_FLOWBLOCK_PROMPT\":\"Willst du diesen Block wirklich entfernen?\",\"ADD_FLOWBLOCK\":\"Block hinzufügen\",\"INVALID_INPUT\":\"Ungültige Eingabe\",\"UP\":\"Nach oben\",\"DOWN\":\"Nach unten\",\"REMOVE\":\"Entfernen\",\"ID\":\"ID\",\"CLOSE\":\"Schließen\",\"CANCEL\":\"Abbrechen\",\"BACK_TO_OVERVIEW\":\"Übersicht\",\"PUBLISH\":\"Veröffentlichen\",\"PUBLISH_NOTE\":\"Von hier aus kann der aktuelle Stand der Webseite publiziert werden.\",\"PUBLISH_SERVER\":\"Ziel-Server\",\"CURRENTLY_PUBLISHING\":\"Veröffentlichung …\",\"STATE\":\"Status\",\"PUBLISH_DONE\":\"Veröffentlicht\",\"PUBLISH_STATE_BUILDING\":\"Änderungen werden gebaut ...\",\"PUBLISH_STATE_PUBLISH\":\"Änderungen werden publiziert ...\",\"PUBLISH_STATE_DONE\":\"Veröffentlichung fertiggestellt.\",\"FIND_FILES\":\"Seiten Finden\",\"FIND_FILES_PLACEHOLDER\":\"Seitenname eingeben ...\",\"ATTACHMENT_TYPE\":\"Attachment type\",\"URL_SLUG\":\"URL-Slug\",\"TEMPLATE\":\"Vorlage\",\"HIDE_PAGE\":\"Seite verstecken\",\"HIDE_PAGE_EXPLANATION\":\"Soll diese Seite versteckt werden?\",\"PAGE_IS_DISCOVERABLE\":\"Seite ist erkundbar\",\"PAGE_IS_DISCOVERABLE_EXPLANATION\":\"Wenn dies aktiviert ist, wird Seite von Vorlagen verlinkt. Ansonsten muss die URL bekannt sein.\",\"REFRESH_BUILD\":\"Änderungen regenerieren\",\"REFRESH_BUILD_NOTE\":\"In machen Situationen kann es nützlich sein, alle Änderungen zu regenerieren. Zum Beispiel können Synchronisationsfehler und kaputte Vorlagen manchmal dazu führen, dass Seiten fehlerhaft gebaut wurden. Dies bringt Lektor dazu, alle Seiten neu zu bauen.\",\"CURRENTLY_REFRESHING_BUILD\":\"Änderungen werden regeneriert ...\",\"REFRESHING_BUILD_DONE\":\"Änderungen wurden regeneriert!\",\"FAILED_TO_LAUNCH_LEKTOR\":\"Lektor konnte nicht gestartet werden.\",\"PROJECT\":\"Projekt\",\"CLOSE_PROJECT\":\"Projekt schließen\",\"OPEN_PROJECT\":\"Projekt öffnen\",\"BROWSE_WEBSITE\":\"Webseite anzeigen\",\"VIEW_ADMIN_PANEL\":\"Admin-Panel öffnen\",\"QUIT\":\"Beenden\",\"FAILED_TO_LOAD_PROJECT\":\"Projekt konnte nicht geladen werden :(\",\"LOADING_PROJECT\":\"Projekt wird geöffnet ...\",\"INITIALIZING_LEKTOR\":\"Initialisiere Lektor ...\",\"QUIT_LEKTOR\":\"Lektor beenden\",\"FILE\":\"Datei\",\"UNDO\":\"Rückgängig\",\"REDO\":\"Wiederholen\",\"CUT\":\"Ausschneiden\",\"COPY\":\"Kopieren\",\"PASTE\":\"Einfügen\",\"SELECT_ALL\":\"Alles Markieren\",\"HELP\":\"Hilfe\",\"VISIT_WEBSITE\":\"Webseite öffnen\",\"INSTALL_SHELL_COMMAND\":\"Shell-Befehl installieren\",\"INSTALL_SHELL_COMMAND_QUESTION\":\"Möchtest du den 'lektor' Shell-Befehl installieren? Dies erfordert Admin-Rechte.\",\"FAILED_TO_INSTALL_SHELL_COMMANDS\":\"Konnte Shell-Befehl nicht installieren.\",\"INSTALL_SHELL_COMMAND_SUCCESS\":\"Shell-Befehl wurde erfolgreich installiert.\",\"OPERATION_SUCCESS\":\"Operation erfolgreich\",\"YES\":\"Ja\",\"NO\":\"Nein\",\"OK\":\"OK\",\"FAILED_TO_OPEN_CONTENT_FILE\":\"Konnte Datei nicht öffnen\",\"OPEN_OTHER_PROJECT\":\"Anderes Projekt öffnen\",\"OPEN_OTHER_PROJECT_QUESTION\":\"Um diese Datei zu öffnen, muss ein anderes Projekt (%s) geöffnet werden. Das aktuelle Projekt wird dadurch geschlossen. Fortfahren?\"}\n\n\n//////////////////\n// WEBPACK FOOTER\n// /home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/de.json\n// module id = 286\n// module chunks = 0","module.exports = {\"RETURN_TO_WEBSITE\":\"Return to Website\",\"UNLOAD_ACTIVE_TAB\":\"You have unsaved information, are you sure you want to leave this page?\",\"EDIT_METADATA\":\"Edit Metadata\",\"EDIT\":\"Edit\",\"DELETE\":\"Delete\",\"PREVIEW\":\"Preview\",\"ALTS\":\"Alternatives\",\"PRIMARY_ALT\":\"Primary\",\"PRIMARY_OVERLAY\":\"Overlaid\",\"ADD_CHILD_PAGE\":\"Add Page\",\"ADD_ATTACHMENT\":\"Add Attachment\",\"ATTACHMENT_ACTIONS\":\"Attachment Actions\",\"PAGE_ACTIONS\":\"Page Actions\",\"NO_CHILD_PAGES\":\"No Subpages\",\"CHILD_PAGES\":\"Subpages\",\"NO_ATTACHMENTS\":\"No attachments\",\"ATTACHMENTS\":\"Attachments\",\"ADD_ATTACHMENT_TO\":\"Add Attachment to “%s”\",\"ADD_ATTACHMENT_NOTE\":\"You can upload a new attachment here.\",\"UPLOAD\":\"Upload\",\"PROGRESS\":\"Progress\",\"ERROR_PREFIX\":\"Error: \",\"ERROR_NO_ID_PROVIDED\":\"No ID provided.\",\"ERROR_PAGE_ID_DUPLICATE\":\"A page with this ID (%s) exists already.\",\"ERROR_INVALID_ID\":\"Invalid ID\",\"ERROR_INVALID_DATE\":\"Invalid date\",\"ERROR_INVALID_NUMBER\":\"Not a valid number\",\"ERROR_INVALID_URL\":\"Not a valid URL\",\"ERROR\":\"Error\",\"ERROR_OCURRED\":\"An Error ocurred\",\"ERROR_REQUEST_FAILED\":\"Could not send command to server. Maybe the server was stopped or is unresponsive?\",\"ERROR_SERVER_UNAVAILABLE\":\"Server Unavailable\",\"ERROR_SERVER_UNAVAILABLE_MESSAGE\":\"The server is not responding. Either it was stopped or a critical error made it not operable and it needs to be restarted.\",\"MODEL\":\"Model\",\"ADD_CHILD_PAGE_TO\":\"Add Subpage to “%s”\",\"ADD_CHILD_PAGE_NOTE\":\"You can add a new subpage to the page here. Note that the model or ID cannot be easily changed afterwards.\",\"CREATE_CHILD_PAGE\":\"Add Child Page\",\"DELETE_ATTACHMENT_PROMPT\":\"Do you really want to delete this attachment?\",\"DELETE_ATTACHMENT_ALT_PROMPT\":\"Do you really want to delete the metadata of this attachment alternative?\",\"DELETE_PAGE_PROMPT\":\"Do you really want to delete this page?\",\"DELETE_PAGE_ALT_PROMPT\":\"Do you really want to delete this alternative?\",\"DELETE_PAGE_CHILDREN_WARNING\":\"This will also delete the child subpages of this page.\",\"DELETE_RECORD\":\"Delete “%s”\",\"DELETE_ALL_PAGE_ALTS\":\"Also delete all alternatives and attached files.\",\"DELETE_ALL_ATTACHMENT_ALTS\":\"Delete all alternatives and the attached file.\",\"DELETE_ONLY_PRIMARY_PAGE_ALT\":\"Delete only the primary record. Attachments, alternatives and subpages will not be deleted.\",\"DELETE_ONLY_PRIMARY_ATTACHMENT_ALT\":\"Only delete the Metadata of the primary record.\",\"DELETE_PRIMARY_ALT_INFO\":\"Because this record is a primary alternative it can be deleted separately or together with all other contents.\",\"CHILD_PAGES_TO_BE_DELETED\":\"Subpages that will be deleted:\",\"ALTS_TO_BE_DELETED\":\"Alternatives that will be deleted:\",\"ATTACHMENTS_TO_BE_DELETED\":\"Attachments that will be deleted:\",\"YES_DELETE\":\"Yes, delete\",\"NO_CANCEL\":\"No, cancel\",\"SYSTEM_FIELDS\":\"System Fields\",\"EDIT_ATTACHMENT_METADATA_OF\":\"Edit Metadata of Attachment “%s”\",\"EDIT_PAGE_NAME\":\"Edit “%s”\",\"SAVE_CHANGES\":\"Save Changes\",\"BROWSE_FS\":\"Browse in Filesystem\",\"BROWSE_FS_MAC\":\"Reveal in Finder\",\"BROWSE_FS_WINDOWS\":\"Open in Explorer\",\"ERROR_CANNOT_BROWSE_FS\":\"Error: File does not exist yet.\",\"REMOVE_FLOWBLOCK_PROMPT\":\"Do you really want to remove this block?\",\"ADD_FLOWBLOCK\":\"Add Block\",\"INVALID_INPUT\":\"Invalid Input\",\"UP\":\"Up\",\"DOWN\":\"Down\",\"REMOVE\":\"Remove\",\"ID\":\"ID\",\"CLOSE\":\"Close\",\"CANCEL\":\"Cancel\",\"BACK_TO_OVERVIEW\":\"Back to Overview\",\"PUBLISH\":\"Publish\",\"PUBLISH_NOTE\":\"From here you can publish the current version of the website.\",\"PUBLISH_SERVER\":\"Target Server\",\"CURRENTLY_PUBLISHING\":\"Publishing …\",\"STATE\":\"Status\",\"PUBLISH_DONE\":\"Published\",\"PUBLISH_STATE_BUILDING\":\"Changes are being built ...\",\"PUBLISH_STATE_PUBLISH\":\"Changes are being published ...\",\"PUBLISH_STATE_DONE\":\"Publishing done.\",\"FIND_FILES\":\"Find Files\",\"FIND_FILES_PLACEHOLDER\":\"Enter page name ...\",\"ATTACHMENT_TYPE\":\"Attachment type\",\"URL_SLUG\":\"URL slug\",\"TEMPLATE\":\"Template\",\"HIDE_PAGE\":\"Hide page\",\"HIDE_PAGE_EXPLANATION\":\"Should this page be hidden?\",\"PAGE_IS_DISCOVERABLE\":\"Page is discoverable\",\"PAGE_IS_DISCOVERABLE_EXPLANATION\":\"If this is enabled the page can be discovered, otherwise the URL has to be known.\",\"REFRESH_BUILD\":\"Refresh Build\",\"REFRESH_BUILD_NOTE\":\"This deletes all cached build results which triggers a rebuilt from scratch. This is useful in certain situations where sync errors or mistakes in templates caused corrupted output.\",\"CURRENTLY_REFRESHING_BUILD\":\"Currently refreshing build ...\",\"REFRESHING_BUILD_DONE\":\"Done refreshing build!\",\"FAILED_TO_LAUNCH_LEKTOR\":\"Failed to launch Lektor.\",\"PROJECT\":\"Project\",\"CLOSE_PROJECT\":\"Close Project\",\"OPEN_PROJECT\":\"Open Project\",\"BROWSE_WEBSITE\":\"Browse Website\",\"VIEW_ADMIN_PANEL\":\"View Admin Panel\",\"QUIT\":\"Quit\",\"FAILED_TO_LOAD_PROJECT\":\"Failed to load the project :(\",\"LOADING_PROJECT\":\"Loading project ...\",\"INITIALIZING_LEKTOR\":\"Initializing Lektor ...\",\"QUIT_LEKTOR\":\"Quit Lektor\",\"FILE\":\"File\",\"UNDO\":\"Undo\",\"REDO\":\"Redo\",\"CUT\":\"Cut\",\"COPY\":\"Copy\",\"PASTE\":\"Paste\",\"SELECT_ALL\":\"Select All\",\"HELP\":\"Help\",\"VISIT_WEBSITE\":\"Visit Website\",\"INSTALL_SHELL_COMMAND\":\"Install Shell Command\",\"INSTALL_SHELL_COMMAND_QUESTION\":\"Do you want to install the 'lektor' shell command? This requires admin rights.\",\"FAILED_TO_INSTALL_SHELL_COMMANDS\":\"Failed to install shell commands.\",\"INSTALL_SHELL_COMMAND_SUCCESS\":\"Shell command was successfully installed.\",\"OPERATION_SUCCESS\":\"Success\",\"YES\":\"Yes\",\"NO\":\"No\",\"OK\":\"OK\",\"FAILED_TO_OPEN_CONTENT_FILE\":\"Failed to open content file\",\"OPEN_OTHER_PROJECT\":\"Open other Project\",\"OPEN_OTHER_PROJECT_QUESTION\":\"Opening this file requires opening another project (%s). The current project will be closed. Do you want to continue?\"}\n\n\n//////////////////\n// WEBPACK FOOTER\n// /home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/en.json\n// module id = 287\n// module chunks = 0","module.exports = {\"RETURN_TO_WEBSITE\":\"Volver al Sitio Web\",\"UNLOAD_ACTIVE_TAB\":\"Tiene información sin guardar, está seguro de que quiere abandonar esta página?\",\"EDIT_METADATA\":\"Editar Metadatos\",\"EDIT\":\"Editar\",\"DELETE\":\"Borrar\",\"PREVIEW\":\"Previsualizar\",\"ALTS\":\"Alternativas\",\"PRIMARY_ALT\":\"Primaria\",\"PRIMARY_OVERLAY\":\"Overlaid\",\"ADD_CHILD_PAGE\":\"Añadir Página\",\"ADD_ATTACHMENT\":\"Añadir Adjunto\",\"ATTACHMENT_ACTIONS\":\"Acciones de Adjunto\",\"PAGE_ACTIONS\":\"Acciones de Página\",\"NO_CHILD_PAGES\":\"Sin Subpáginas\",\"CHILD_PAGES\":\"Subpáginas\",\"NO_ATTACHMENTS\":\"Sin Adjuntos\",\"ATTACHMENTS\":\"Adjuntos\",\"ADD_ATTACHMENT_TO\":\"Añadir Adjunto a “%s”\",\"ADD_ATTACHMENT_NOTE\":\"Puede cargar un nuevo adjunto aquí.\",\"UPLOAD\":\"Cargar\",\"PROGRESS\":\"Avance\",\"ERROR_PREFIX\":\"Error: \",\"ERROR_NO_ID_PROVIDED\":\"No se proporcionó un ID.\",\"ERROR_PAGE_ID_DUPLICATE\":\"Ya existe una página con este ID (%s).\",\"ERROR_INVALID_ID\":\"ID inválido\",\"ERROR_INVALID_DATE\":\"Fecha inválida\",\"ERROR_INVALID_NUMBER\":\"Número no válido\",\"ERROR_INVALID_URL\":\"URL no válida\",\"ERROR\":\"Error\",\"ERROR_OCURRED\":\"Ocurrió un Error\",\"ERROR_REQUEST_FAILED\":\"No se pudo enviar el comando al servidor. ¿Es posible que el servidor esté apagado o no responda?\",\"ERROR_SERVER_UNAVAILABLE\":\"Servidor No Disponible\",\"ERROR_SERVER_UNAVAILABLE_MESSAGE\":\"El servidor no responde. Fue apagado o hubo un error crítico que lo hace inoperativo y necesita ser reiniciado.\",\"MODEL\":\"Modelo\",\"ADD_CHILD_PAGE_TO\":\"Añada Subpágina a “%s”\",\"ADD_CHILD_PAGE_NOTE\":\"Puede añadir una nueva subpágina aquí. Tenga en cuenta que el modelo o el ID no puede ser cambiado fácilmente más tarde.\",\"CREATE_CHILD_PAGE\":\"Añada Página Hijo\",\"DELETE_ATTACHMENT_PROMPT\":\"¿Quiere realmente borrar este anexo?\",\"DELETE_ATTACHMENT_ALT_PROMPT\":\"¿Quiere realmente borrar los metadatos de esta alternativa de anexo?\",\"DELETE_PAGE_PROMPT\":\"¿Quiere realmente borrar esta página?\",\"DELETE_PAGE_ALT_PROMPT\":\"¿Quiere realmente borrar esta alternativa?\",\"DELETE_PAGE_CHILDREN_WARNING\":\"Esto también borrará las subpáginas hijo de esta página.\",\"DELETE_RECORD\":\"Borrar “%s”\",\"DELETE_ALL_PAGE_ALTS\":\"Borrar también todas las alternativas y ficheros adjuntos.\",\"DELETE_ALL_ATTACHMENT_ALTS\":\"Borrar todas las alternativas y el fichero adjunto.\",\"DELETE_ONLY_PRIMARY_PAGE_ALT\":\"Borra sólo el registro principal. Los adjuntos, las alternativas y las subpáginas no serán borradas.\",\"DELETE_ONLY_PRIMARY_ATTACHMENT_ALT\":\"Borra sólo los metadatos del registro principal.\",\"DELETE_PRIMARY_ALT_INFO\":\"Como este registro es una alternativa principal, puede ser borrado por separado o junto al resto de contenidos.\",\"CHILD_PAGES_TO_BE_DELETED\":\"Subpáginas que serán borradas:\",\"ALTS_TO_BE_DELETED\":\"Alternativas que serán borradas:\",\"ATTACHMENTS_TO_BE_DELETED\":\"Adjuntos que serán borrados:\",\"YES_DELETE\":\"Sí, borrar\",\"NO_CANCEL\":\"No, cancelar\",\"SYSTEM_FIELDS\":\"Campos de Sistema\",\"EDIT_ATTACHMENT_METADATA_OF\":\"Editar los Metadatos del Adjunto “%s”\",\"EDIT_PAGE_NAME\":\"Editar “%s”\",\"SAVE_CHANGES\":\"Guardar los cambios\",\"BROWSE_FS\":\"Navegar en el Sistema de ficheros\",\"BROWSE_FS_MAC\":\"Mostrar en el Finder\",\"BROWSE_FS_WINDOWS\":\"Abrir en el Explorador\",\"ERROR_CANNOT_BROWSE_FS\":\"Error: el fichero no existe todavía.\",\"REMOVE_FLOWBLOCK_PROMPT\":\"¿Quiere realmente borrar este bloque?\",\"ADD_FLOWBLOCK\":\"Añadir Bloque\",\"INVALID_INPUT\":\"Entrada inválida\",\"UP\":\"Arriba\",\"DOWN\":\"Abajo\",\"REMOVE\":\"Eliminar\",\"ID\":\"ID\",\"CLOSE\":\"Cerrar\",\"CANCEL\":\"Cancelar\",\"BACK_TO_OVERVIEW\":\"Vuelve a Revisión\",\"PUBLISH\":\"Publicar\",\"PUBLISH_NOTE\":\"Desde aquí puede publicar la versión actual del sitio web.\",\"PUBLISH_SERVER\":\"Servidor Destino\",\"CURRENTLY_PUBLISHING\":\"Publicando …\",\"STATE\":\"Estado\",\"PUBLISH_DONE\":\"Publicado\",\"PUBLISH_STATE_BUILDING\":\"Los cambios se están generando ...\",\"PUBLISH_STATE_PUBLISH\":\"Los cambios están siendo publicados ...\",\"PUBLISH_STATE_DONE\":\"Publicación finalizada.\",\"FIND_FILES\":\"Encontrar Ficheros\",\"FIND_FILES_PLACEHOLDER\":\"Introduzca el nombre de la página ...\",\"ATTACHMENT_TYPE\":\"Tipo de adjunto\",\"URL_SLUG\":\"URL personalizada\",\"TEMPLATE\":\"Plantilla\",\"HIDE_PAGE\":\"Ocultar página\",\"HIDE_PAGE_EXPLANATION\":\"¿Debería estar oculta esta página?\",\"PAGE_IS_DISCOVERABLE\":\"La Página es detectable\",\"PAGE_IS_DISCOVERABLE_EXPLANATION\":\"Si esto está habilitado la página puede ser detectada, en caso contrario la URL ha de ser conocida.\",\"REFRESH_BUILD\":\"Refrescar la Generación\",\"REFRESH_BUILD_NOTE\":\"Esto borra todos los resultados generados y lanza una nueva generación desde cero. Esto es útil en ciertas situaciones donde errores de sincronización o en las plantillas causaron un resultado corrupto.\",\"CURRENTLY_REFRESHING_BUILD\":\"Regenerando ...\",\"REFRESHING_BUILD_DONE\":\"¡Acabó la regeneración!\",\"FAILED_TO_LAUNCH_LEKTOR\":\"Falló la ejecución de Lektor.\",\"PROJECT\":\"Proyecto\",\"CLOSE_PROJECT\":\"Cerrar Proyecto\",\"OPEN_PROJECT\":\"Abrir Proyecto\",\"BROWSE_WEBSITE\":\"Navegar Sitio Web\",\"VIEW_ADMIN_PANEL\":\"Ver Panel de Administración\",\"QUIT\":\"Salir\",\"FAILED_TO_LOAD_PROJECT\":\"Falló la carga del proyecto :(\",\"LOADING_PROJECT\":\"Cargando proyecto ...\",\"INITIALIZING_LEKTOR\":\"Inicializando Lektor ...\",\"QUIT_LEKTOR\":\"Salir de Lektor\",\"FILE\":\"Archivo\",\"UNDO\":\"Deshacer\",\"REDO\":\"Rehacer\",\"CUT\":\"Cortar\",\"COPY\":\"Copiar\",\"PASTE\":\"Pegar\",\"SELECT_ALL\":\"Seleccionar Todo\",\"HELP\":\"Ayuda\",\"VISIT_WEBSITE\":\"Visitar Web\",\"INSTALL_SHELL_COMMAND\":\"Instalar Comando\",\"INSTALL_SHELL_COMMAND_QUESTION\":\"¿Quiere instalar el comando 'lektor'? Son necesarios privilegios de administrador.\",\"FAILED_TO_INSTALL_SHELL_COMMANDS\":\"Falló la instalación de los comandos.\",\"INSTALL_SHELL_COMMAND_SUCCESS\":\"El comando se instaló con éxito.\",\"OPERATION_SUCCESS\":\"Con éxito\",\"YES\":\"Sí\",\"NO\":\"No\",\"OK\":\"OK\",\"FAILED_TO_OPEN_CONTENT_FILE\":\"Falló al abrir el fichero de contenido\",\"OPEN_OTHER_PROJECT\":\"Abrir otro Proyecto\",\"OPEN_OTHER_PROJECT_QUESTION\":\"Abrir este fichero requiere abrir otro proyecto (%s). El proyecto actual será cerrado. ¿Quiere continuar?\"}\n\n\n//////////////////\n// WEBPACK FOOTER\n// /home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/es.json\n// module id = 288\n// module chunks = 0","module.exports = {\"RETURN_TO_WEBSITE\":\"Retour au site Web\",\"UNLOAD_ACTIVE_TAB\":\"Des informations ne sont pas enregistrées, voulez-vous vraiment quitter cette page ?\",\"EDIT_METADATA\":\"Modifier les métadonnées\",\"EDIT\":\"Modifier\",\"DELETE\":\"Supprimer\",\"PREVIEW\":\"Aperçu\",\"ALTS\":\"Alternatives\",\"PRIMARY_ALT\":\"Primaire\",\"PRIMARY_OVERLAY\":\"Superposée\",\"ADD_CHILD_PAGE\":\"Ajouter une page\",\"ADD_ATTACHMENT\":\"Joindre un fichier\",\"ATTACHMENT_ACTIONS\":\"Actions sur les fichiers joints\",\"PAGE_ACTIONS\":\"Action sur les pages\",\"NO_CHILD_PAGES\":\"Aucune sous-page\",\"CHILD_PAGES\":\"Sous-pages\",\"NO_ATTACHMENTS\":\"Aucun fichier joint\",\"ATTACHMENTS\":\"Fichiers joints\",\"ADD_ATTACHMENT_TO\":\"Joindre un fichier à « %s »\",\"ADD_ATTACHMENT_NOTE\":\"Vous pouvez téléverser un nouveau fichier joint ici.\",\"UPLOAD\":\"Téléverser\",\"PROGRESS\":\"Progression\",\"ERROR_PREFIX\":\"Erreur : \",\"ERROR_NO_ID_PROVIDED\":\"Erreur : aucun ID fourni.\",\"ERROR_PAGE_ID_DUPLICATE\":\"Une page avec cet ID (%s) existe déjà.\",\"ERROR_INVALID_ID\":\"ID non valide\",\"ERROR_INVALID_DATE\":\"Date non valide\",\"ERROR_INVALID_NUMBER\":\"Nombre non valide\",\"ERROR_INVALID_URL\":\"URL non valide\",\"ERROR\":\"Erreur\",\"ERROR_OCURRED\":\"Une erreur a été rencontrée\",\"ERROR_REQUEST_FAILED\":\"La commande n'a pas pu être envoyée au serveur. Le serveur a peut-être été arrêté ou ne répond plus ?\",\"ERROR_SERVER_UNAVAILABLE\":\"Serveur indisponible\",\"ERROR_SERVER_UNAVAILABLE_MESSAGE\":\"Le serveur ne répond pas. Il a dû être arrêté ou une erreur critique l'a rendu inopérant et il doit être redémarré.\",\"MODEL\":\"Modèle\",\"ADD_CHILD_PAGE_TO\":\"Ajouter une sous-page à « %s »\",\"ADD_CHILD_PAGE_NOTE\":\"Vous pouvez ajouter une nouvelle sous-page à la page ici. Veuillez noter que le modèle ou l'ID ne peut pas être changé facilement ultérieurement.\",\"CREATE_CHILD_PAGE\":\"Ajouter une sous-page\",\"DELETE_ATTACHMENT_PROMPT\":\"Voulez-vous vraiment supprimer ce fichier joint ?\",\"DELETE_ATTACHMENT_ALT_PROMPT\":\"Voulez-vous vraiment supprimer les métadonnées de ce fichier joint alternatif ?\",\"DELETE_PAGE_PROMPT\":\"Voulez-vous vraiment supprimer cette page ?\",\"DELETE_PAGE_ALT_PROMPT\":\"Voulez-vous vraiment supprimer cette version alternative ?\",\"DELETE_PAGE_CHILDREN_WARNING\":\"Cela supprimera aussi les sous-pages de cette page.\",\"DELETE_RECORD\":\"Supprimer « %s »\",\"DELETE_ALL_PAGE_ALTS\":\"Supprimer aussi toutes les versions alternatives et les fichiers joints.\",\"DELETE_ALL_ATTACHMENT_ALTS\":\"Supprimer toutes les versions alternatives et les fichiers joints.\",\"DELETE_ONLY_PRIMARY_PAGE_ALT\":\"Supprimer seulement le premier enregistrement. Les fichiers joints, versions alternatives et sous-pages ne seront pas supprimées.\",\"DELETE_ONLY_PRIMARY_ATTACHMENT_ALT\":\"Supprimer seulement les métadonnées de la pièce jointe primaire.\",\"DELETE_PRIMARY_ALT_INFO\":\"Cet enregistrement étant l'alternative primaire, il peut être supprimé séparément ou avec tous les autres contenus.\",\"CHILD_PAGES_TO_BE_DELETED\":\"Les sous-pages qui seront supprimées :\",\"ALTS_TO_BE_DELETED\":\"Les versions alternatives qui seront supprimées :\",\"ATTACHMENTS_TO_BE_DELETED\":\"Les fichiers joints qui seront supprimés :\",\"YES_DELETE\":\"Oui, supprimer\",\"NO_CANCEL\":\"Non, annuler\",\"SYSTEM_FIELDS\":\"Champs système\",\"EDIT_ATTACHMENT_METADATA_OF\":\"Modifier les métadonnées du fichier joint « %s »\",\"EDIT_PAGE_NAME\":\"Modifier « %s »\",\"SAVE_CHANGES\":\"Enregistrer les changements\",\"BROWSE_FS\":\"Parcourir le système de fichiers\",\"BROWSE_FS_MAC\":\"Révéler dans le Finder\",\"BROWSE_FS_WINDOWS\":\"Ouvrir dans l'Explorateur\",\"ERROR_CANNOT_BROWSE_FS\":\"Erreur : le fichier n'existe pas encore.\",\"REMOVE_FLOWBLOCK_PROMPT\":\"Voulez-vous vraiment supprimer ce bloc ?\",\"ADD_FLOWBLOCK\":\"Ajouter un bloc\",\"INVALID_INPUT\":\"Saisie non valide\",\"UP\":\"Haut\",\"DOWN\":\"Bas\",\"REMOVE\":\"Enlever\",\"ID\":\"ID\",\"CLOSE\":\"Fermer\",\"CANCEL\":\"Annuler\",\"BACK_TO_OVERVIEW\":\"Retour à l'aperçu\",\"PUBLISH\":\"Publier\",\"PUBLISH_NOTE\":\"À partir de maintenant, vous pouvez publier la version actuelle de votre site Web.\",\"PUBLISH_SERVER\":\"Serveur cible\",\"CURRENTLY_PUBLISHING\":\"Publication en cours…\",\"STATE\":\"Statut\",\"PUBLISH_DONE\":\"Publié\",\"PUBLISH_STATE_BUILDING\":\"Les changements sont en cours de construction…\",\"PUBLISH_STATE_PUBLISH\":\"Les changements sont en cours de publication…\",\"PUBLISH_STATE_DONE\":\"Publication effectuée.\",\"FIND_FILES\":\"Trouver les fichiers\",\"FIND_FILES_PLACEHOLDER\":\"Saisir le nom de la page…\",\"ATTACHMENT_TYPE\":\"Type de fichier joint\",\"URL_SLUG\":\"Motif d'URL (slug)\",\"TEMPLATE\":\"Modèle\",\"HIDE_PAGE\":\"Masquer la page\",\"HIDE_PAGE_EXPLANATION\":\"Est-ce que cette page devrait être masquée ?\",\"PAGE_IS_DISCOVERABLE\":\"La page est « découvrable »\",\"PAGE_IS_DISCOVERABLE_EXPLANATION\":\"Si activé, la page pourra être retrouvée car elle sera indexée, sinon l'URL devra être connue pour y accéder.\",\"REFRESH_BUILD\":\"Actualiser la construction\",\"REFRESH_BUILD_NOTE\":\"Cela supprime tous les résultats de la construction et entraîne une reconstruction complète. C'est utile dans certaines situations où le résultat est corrompu suite à des erreurs de synchronisation ou de modèles.\",\"CURRENTLY_REFRESHING_BUILD\":\"Actualisation de la construction en cours…\",\"REFRESHING_BUILD_DONE\":\"Actualisation de la construction terminée\",\"FAILED_TO_LAUNCH_LEKTOR\":\"Impossible de lancer Lektor.\",\"PROJECT\":\"Projet\",\"CLOSE_PROJECT\":\"Fermer le projet\",\"OPEN_PROJECT\":\"Ouvrir le projet\",\"BROWSE_WEBSITE\":\"Ouvrir le site Web\",\"VIEW_ADMIN_PANEL\":\"Voir le panneau administrateur\",\"QUIT\":\"Quitter\",\"FAILED_TO_LOAD_PROJECT\":\"Impossible de charger le projet :(\",\"LOADING_PROJECT\":\"Chargement du projet…\",\"INITIALIZING_LEKTOR\":\"Initialisation de Lektor…\",\"QUIT_LEKTOR\":\"Quitter Lektor\",\"FILE\":\"Fichier\",\"UNDO\":\"Annuler\",\"REDO\":\"Rétablir\",\"CUT\":\"Couper\",\"COPY\":\"Copier\",\"PASTE\":\"Coller\",\"SELECT_ALL\":\"Sélectionner tout\",\"HELP\":\"Aide\",\"VISIT_WEBSITE\":\"Visiter le site Web\",\"INSTALL_SHELL_COMMAND\":\"Installer la commande shell\",\"INSTALL_SHELL_COMMAND_QUESTION\":\"Voulez-vous installer la commande shell « lektor » ? Cela nécessite des droits administrateurs.\",\"FAILED_TO_INSTALL_SHELL_COMMANDS\":\"Impossible d'installer les commandes shell.\",\"INSTALL_SHELL_COMMAND_SUCCESS\":\"La commande shell a été correctement installée.\",\"OPERATION_SUCCESS\":\"Succès\",\"YES\":\"Oui\",\"NO\":\"Non\",\"OK\":\"OK\",\"FAILED_TO_OPEN_CONTENT_FILE\":\"Impossible d'ouvir le contenu du fichier\",\"OPEN_OTHER_PROJECT\":\"Ouvrir un autre projet\",\"OPEN_OTHER_PROJECT_QUESTION\":\"Ouvrir ce fichier nécessite d'ouvrir un autre projet (%s). Le projet actuel sera fermé. Voulez-vous vraiment continuer ?\"}\n\n\n//////////////////\n// WEBPACK FOOTER\n// /home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/fr.json\n// module id = 289\n// module chunks = 0","module.exports = {\"RETURN_TO_WEBSITE\":\"Torna al sito web\",\"UNLOAD_ACTIVE_TAB\":\"Hai informazioni non salvate, sei sicuro di voler abbandonare questa pagina?\",\"EDIT_METADATA\":\"Modifica metadati\",\"EDIT\":\"Modifica\",\"DELETE\":\"Cancella\",\"PREVIEW\":\"Anteprima\",\"ALTS\":\"Alternative\",\"PRIMARY_ALT\":\"Primaria\",\"PRIMARY_OVERLAY\":\"Sovrascritta\",\"ADD_CHILD_PAGE\":\"Aggiungi pagina\",\"ADD_ATTACHMENT\":\"Aggiungi allegato\",\"ATTACHMENT_ACTIONS\":\"Azioni sull'allegato\",\"PAGE_ACTIONS\":\"Azioni sulla pagina\",\"NO_CHILD_PAGES\":\"Nessuna sottopagina\",\"CHILD_PAGES\":\"Sottopagine\",\"NO_ATTACHMENTS\":\"Nessun alleagto\",\"ATTACHMENTS\":\"Allegati\",\"ADD_ATTACHMENT_TO\":\"Aggiungi allegato a “%s”\",\"ADD_ATTACHMENT_NOTE\":\"Puoi caricare un allegato qui.\",\"UPLOAD\":\"Carica\",\"PROGRESS\":\"Avanzamento\",\"ERROR_PREFIX\":\"Errore: \",\"ERROR_NO_ID_PROVIDED\":\"Nessun ID fornito.\",\"ERROR_PAGE_ID_DUPLICATE\":\"Una pagina con questo ID (%s) esiste già.\",\"ERROR_INVALID_ID\":\"ID non valido\",\"ERROR_INVALID_DATE\":\"Data non valida\",\"ERROR_INVALID_NUMBER\":\"Non è un numero valido\",\"ERROR_INVALID_URL\":\"Non è un indirizzo valido\",\"ERROR\":\"Errore\",\"ERROR_OCURRED\":\"È capitato un errore\",\"ERROR_REQUEST_FAILED\":\"Impossibile inviare comandi al server. Magari il server è stato spento o è sovraccarico?\",\"ERROR_SERVER_UNAVAILABLE\":\"Server non disponibile\",\"ERROR_SERVER_UNAVAILABLE_MESSAGE\":\"Il server non risponde. Può essere spento o un errore critico l'ha reso non operativo ed è necessario riavviarlo.\",\"MODEL\":\"Modello\",\"ADD_CHILD_PAGE_TO\":\"Aggiungi sottopagina a “%s”\",\"ADD_CHILD_PAGE_NOTE\":\"Puoi aggiungere una nuova sottopagina qui. Tieni presente che il modello o l'ID non potranno essere cambiati facilmente in futuro.\",\"CREATE_CHILD_PAGE\":\"Aggiungi sottopagina\",\"DELETE_ATTACHMENT_PROMPT\":\"Vuoi veramente cancellare questo allegato?\",\"DELETE_ATTACHMENT_ALT_PROMPT\":\"Vuoi veramente cancellare i metadati di questa alternativa all'allegato?\",\"DELETE_PAGE_PROMPT\":\"Vuoi veramente cancellare questa pagina?\",\"DELETE_PAGE_ALT_PROMPT\":\"Vuoi veramente cancellare questa alternativa?\",\"DELETE_PAGE_CHILDREN_WARNING\":\"Questo cancellerà anche le sottopagine di questa pagina.\",\"DELETE_RECORD\":\"Cancella “%s”\",\"DELETE_ALL_PAGE_ALTS\":\"Cancella anche tutte le alternative ed i file allegati.\",\"DELETE_ALL_ATTACHMENT_ALTS\":\"Cancella tutte le alternative ed il file allegato.\",\"DELETE_ONLY_PRIMARY_PAGE_ALT\":\"Cancella solo la pagina principale. Allegati, alternative e sottopagine nnon verranno cancellate.\",\"DELETE_ONLY_PRIMARY_ATTACHMENT_ALT\":\"Cancella solo i metadati dell'allegato principale.\",\"DELETE_PRIMARY_ALT_INFO\":\"Dato che questo oggetto è l'alternativa primaria, può essere cancellato separatamente o insieme al resto del contenuto.\",\"CHILD_PAGES_TO_BE_DELETED\":\"Sottopagine che verranno cancellate:\",\"ALTS_TO_BE_DELETED\":\"Alternative che verranno cancellate:\",\"ATTACHMENTS_TO_BE_DELETED\":\"Allegati che verranno cancellati:\",\"YES_DELETE\":\"Si, cancella\",\"NO_CANCEL\":\"No, annulla\",\"SYSTEM_FIELDS\":\"Campi di sistema\",\"EDIT_ATTACHMENT_METADATA_OF\":\"Modifica i metadati dell'allegato “%s”\",\"EDIT_PAGE_NAME\":\"Modifica “%s”\",\"SAVE_CHANGES\":\"Salva modifiche\",\"BROWSE_FS\":\"Apri nel filesystem\",\"BROWSE_FS_MAC\":\"Apri in Finder\",\"BROWSE_FS_WINDOWS\":\"Apri in Esplora risorse\",\"ERROR_CANNOT_BROWSE_FS\":\"Errore: il file non esiste.\",\"REMOVE_FLOWBLOCK_PROMPT\":\"Vuoi davvero cancellare questo blocco?\",\"ADD_FLOWBLOCK\":\"Aggiungi blocco\",\"INVALID_INPUT\":\"Input invalido\",\"UP\":\"Su\",\"DOWN\":\"Giù\",\"REMOVE\":\"Rimuovi\",\"ID\":\"ID\",\"CLOSE\":\"Chiudi\",\"CANCEL\":\"Annulla\",\"BACK_TO_OVERVIEW\":\"Torna alla panoramica\",\"PUBLISH\":\"Pubblica\",\"PUBLISH_NOTE\":\"Da qui puoi pubblicare la versione corrente del sito web.\",\"PUBLISH_SERVER\":\"Server di destinazione\",\"CURRENTLY_PUBLISHING\":\"Pubblicazione in corso...\",\"STATE\":\"Stato\",\"PUBLISH_DONE\":\"Pubblicato\",\"PUBLISH_STATE_BUILDING\":\"Costruendo le pagine modificate...\",\"PUBLISH_STATE_PUBLISH\":\"Pubblicando le pagine modificate...\",\"PUBLISH_STATE_DONE\":\"Pubblicazione completata.\",\"FIND_FILES\":\"Trova i file\",\"FIND_FILES_PLACEHOLDER\":\"Inserisci il nome della pagina...\",\"ATTACHMENT_TYPE\":\"Tipo dell'allegato\",\"URL_SLUG\":\"Alias della pagina\",\"TEMPLATE\":\"Template\",\"HIDE_PAGE\":\"Nascondi pagina\",\"HIDE_PAGE_EXPLANATION\":\"Questa pagina deve essere nascosta?\",\"PAGE_IS_DISCOVERABLE\":\"La pagina può essere scoperta?\",\"PAGE_IS_DISCOVERABLE_EXPLANATION\":\"Se è abilitato la pagina può essere scoperta, altrimenti l'indirizzo deve essere noto.\",\"REFRESH_BUILD\":\"Esegui build completa\",\"REFRESH_BUILD_NOTE\":\"Questo cancella tutti i risultati precedenti, eseguendo una build completa. Questo è utile in casi in cui errori di sincronizzazione o errori nei template rendono il risultato corrotto.\",\"CURRENTLY_REFRESHING_BUILD\":\"Eseguendo build completa...\",\"REFRESHING_BUILD_DONE\":\"Build completa eseguita!\",\"FAILED_TO_LAUNCH_LEKTOR\":\"Impossibile eseguire Lektor.\",\"PROJECT\":\"Progetto\",\"CLOSE_PROJECT\":\"Chiudi progetto\",\"OPEN_PROJECT\":\"Apri progetto\",\"BROWSE_WEBSITE\":\"Naviga nel sito web\",\"VIEW_ADMIN_PANEL\":\"Mostra pannello di amministrazione\",\"QUIT\":\"Esci\",\"FAILED_TO_LOAD_PROJECT\":\"Impossibile caricare il progetto :(\",\"LOADING_PROJECT\":\"Caricamento del progetto...\",\"INITIALIZING_LEKTOR\":\"Preparazione di Lektor...\",\"QUIT_LEKTOR\":\"Esci da Lektor\",\"FILE\":\"File\",\"UNDO\":\"Annulla\",\"REDO\":\"Ripeti\",\"CUT\":\"Taglia\",\"COPY\":\"Copia\",\"PASTE\":\"Incolla\",\"SELECT_ALL\":\"Seleziona tutto\",\"HELP\":\"Aiuto\",\"VISIT_WEBSITE\":\"Visita il sito web\",\"INSTALL_SHELL_COMMAND\":\"Installa comando shell\",\"INSTALL_SHELL_COMMAND_QUESTION\":\"Vuoi installare il comando shell 'lektor'? Questo richiede privilegi di amministrazione.\",\"FAILED_TO_INSTALL_SHELL_COMMANDS\":\"Impossibile installare il comando shell.\",\"INSTALL_SHELL_COMMAND_SUCCESS\":\"Il comando shell è stato installato con successo.\",\"OPERATION_SUCCESS\":\"Successo\",\"YES\":\"Si\",\"NO\":\"No\",\"OK\":\"OK\",\"FAILED_TO_OPEN_CONTENT_FILE\":\"Impossibile aprire il file di contenuto\",\"OPEN_OTHER_PROJECT\":\"Apri un altro progetto\",\"OPEN_OTHER_PROJECT_QUESTION\":\"Aprire questo file richiede l'apertura di un altro progetto (%s). Il progetto corrente verrà chiuso. Vuoi proseguire?\"}\n\n\n//////////////////\n// WEBPACK FOOTER\n// /home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/it.json\n// module id = 290\n// module chunks = 0","module.exports = {\"RETURN_TO_WEBSITE\":\"Websiteに戻る\",\"UNLOAD_ACTIVE_TAB\":\"保存していない編集があります、本当にページを離れますか?\",\"EDIT_METADATA\":\"メタデータの編集\",\"EDIT\":\"編集\",\"DELETE\":\"削除\",\"PREVIEW\":\"プレビュー\",\"ALTS\":\"代替\",\"PRIMARY_ALT\":\"プライマリー\",\"PRIMARY_OVERLAY\":\"上書き\",\"ADD_CHILD_PAGE\":\"ページの追加\",\"ADD_ATTACHMENT\":\"アタッチメントの追加\",\"ATTACHMENT_ACTIONS\":\"アタッチメントのアクション\",\"PAGE_ACTIONS\":\"ページアクション\",\"NO_CHILD_PAGES\":\"サブページはありません\",\"CHILD_PAGES\":\"サブページ\",\"NO_ATTACHMENTS\":\"アタッチメントはありません\",\"ATTACHMENTS\":\"アタッチメント\",\"ADD_ATTACHMENT_TO\":\"“%s”にアタッチメントを追加する\",\"ADD_ATTACHMENT_NOTE\":\"ここに新しいアタッチメントをアップロードできます\",\"UPLOAD\":\"アップロード\",\"PROGRESS\":\"プログレス\",\"ERROR_PREFIX\":\"エラー: \",\"ERROR_NO_ID_PROVIDED\":\"IDがありません\",\"ERROR_PAGE_ID_DUPLICATE\":\"このID (%s) のページはすでに存在します\",\"ERROR_INVALID_ID\":\"IDが不正です\",\"ERROR_INVALID_DATE\":\"日付が不正です\",\"ERROR_INVALID_NUMBER\":\"不正な番号です\",\"ERROR_INVALID_URL\":\"URLが不正です\",\"ERROR\":\"エラー\",\"ERROR_OCURRED\":\"エラーが発生しました\",\"ERROR_REQUEST_FAILED\":\"サーバーにコマンドが送れませんでした、サーバーが止まっているか応答がないのかもしれません\",\"ERROR_SERVER_UNAVAILABLE\":\"サーバーアンアベイラブル\",\"ERROR_SERVER_UNAVAILABLE_MESSAGE\":\"サーバーが応答しません、中断されたかクリティカルなエラーが発生したたためオペレーションが完了しなかったためリスタートが必要です。\",\"MODEL\":\"モデル\",\"ADD_CHILD_PAGE_TO\":\"“%s”にサブページを追加する\",\"ADD_CHILD_PAGE_NOTE\":\"このページにサブページが作れます。注意: モデルまたはIDはその後簡単には変更できません。\",\"CREATE_CHILD_PAGE\":\"チャイルドページを作る\",\"DELETE_ATTACHMENT_PROMPT\":\"本当にこの添付を削除しますか?\",\"DELETE_ATTACHMENT_ALT_PROMPT\":\"本当にこの添付代替のメタデータを削除しますか?\",\"DELETE_PAGE_PROMPT\":\"このページを本当に削除しますか?\",\"DELETE_PAGE_ALT_PROMPT\":\"この代替を本能に削除しますか?\",\"DELETE_PAGE_CHILDREN_WARNING\":\"このページのサブページも削除されます\",\"DELETE_RECORD\":\"“%s”を削除\",\"DELETE_ALL_PAGE_ALTS\":\"すべての代替と添付も削除\",\"DELETE_ALL_ATTACHMENT_ALTS\":\"すべての代替と添付を削除\",\"DELETE_ONLY_PRIMARY_PAGE_ALT\":\"プライマリレコードのメタデータのみ削除。添付、代替、サブページは削除されません。\",\"DELETE_ONLY_PRIMARY_ATTACHMENT_ALT\":\"プライマリレコードのメタデータのみ削除\",\"DELETE_PRIMARY_ALT_INFO\":\"このレコードはプライマリの代替のため、別に削除することも、他のすべてのコンポーネントともに削除することもできます。\",\"CHILD_PAGES_TO_BE_DELETED\":\"サブページは削除されます:\",\"ALTS_TO_BE_DELETED\":\"代替は削除されます:\",\"ATTACHMENTS_TO_BE_DELETED\":\"添付は削除されます:\",\"YES_DELETE\":\"はい、削除します\",\"NO_CANCEL\":\"いいえ、キャンセルします\",\"SYSTEM_FIELDS\":\"システムフィールド\",\"EDIT_ATTACHMENT_METADATA_OF\":\"添付 “%s”のメタデータを編集\",\"EDIT_PAGE_NAME\":\"“%s”を編集\",\"SAVE_CHANGES\":\"編集を保存\",\"BROWSE_FS\":\"ファイルシステムで閲覧する\",\"BROWSE_FS_MAC\":\"ファインダーで開く\",\"BROWSE_FS_WINDOWS\":\"エクスプローラで開く\",\"ERROR_CANNOT_BROWSE_FS\":\"エラー: ファイルは存在しません\",\"REMOVE_FLOWBLOCK_PROMPT\":\"このブロックを本当に削除しますか?\",\"ADD_FLOWBLOCK\":\"ブロックを追加\",\"INVALID_INPUT\":\"不正な入力\",\"UP\":\"アップ\",\"DOWN\":\"ダウン\",\"REMOVE\":\"取り除く\",\"ID\":\"ID\",\"CLOSE\":\"閉じる\",\"CANCEL\":\"キャンセル\",\"BACK_TO_OVERVIEW\":\"オーバービューに戻る\",\"PUBLISH\":\"公開\",\"PUBLISH_NOTE\":\"ここから現行のウェブサイトを公開できます。\",\"PUBLISH_SERVER\":\"ターゲットサーバー\",\"CURRENTLY_PUBLISHING\":\"公開 …\",\"STATE\":\"状態\",\"PUBLISH_DONE\":\"公開中\",\"PUBLISH_STATE_BUILDING\":\"変更がをビルドしています...\",\"PUBLISH_STATE_PUBLISH\":\"変更が公開されました ...\",\"PUBLISH_STATE_DONE\":\"公開完了\",\"FIND_FILES\":\"ファイルを見つける\",\"FIND_FILES_PLACEHOLDER\":\"ページ名を入力...\",\"ATTACHMENT_TYPE\":\"添付タイプ\",\"URL_SLUG\":\"URLストリング\",\"TEMPLATE\":\"テンプレート\",\"HIDE_PAGE\":\"ヘージを隠す\",\"HIDE_PAGE_EXPLANATION\":\"このページを非表示にしますか?\",\"PAGE_IS_DISCOVERABLE\":\"このページは外部から見ることが可能です\",\"PAGE_IS_DISCOVERABLE_EXPLANATION\":\"有効にすることで、ページは発見可能になります、そうしない場合はアクセスするのにそのURLを知っている必要があります。\",\"REFRESH_BUILD\":\"ビルドを更新\",\"REFRESH_BUILD_NOTE\":\"これは、キャッシュ済みのビルド結果をすべて削除し、最初からの構築を開始します。同期のエラーやテンプレート内のミスにより出力が不正な場合に有効です。\",\"CURRENTLY_REFRESHING_BUILD\":\"ビルドを更新中...\",\"REFRESHING_BUILD_DONE\":\"ビルドを更新が完了しました!\",\"FAILED_TO_LAUNCH_LEKTOR\":\"Lektorを開けるのに失敗しました\",\"PROJECT\":\"プロジェクト\",\"CLOSE_PROJECT\":\"プロジェクトを閉じる\",\"OPEN_PROJECT\":\"プロジェクトを開ける\",\"BROWSE_WEBSITE\":\"ブラウザで開く\",\"VIEW_ADMIN_PANEL\":\"アドミンパネルを開く\",\"QUIT\":\"終了\",\"FAILED_TO_LOAD_PROJECT\":\"Failed to load the project :(\",\"LOADING_PROJECT\":\"プロジェクトを読み込んでいます ...\",\"INITIALIZING_LEKTOR\":\"Lektorを初期化しています ...\",\"QUIT_LEKTOR\":\"Lektorを終了する\",\"FILE\":\"ファイル\",\"UNDO\":\"アンドゥー\",\"REDO\":\"リドゥー\",\"CUT\":\"カット\",\"COPY\":\"コピー\",\"PASTE\":\"ペースト\",\"SELECT_ALL\":\"全てを選択\",\"HELP\":\"ヘルプ\",\"VISIT_WEBSITE\":\"Websiteを訪ねる\",\"INSTALL_SHELL_COMMAND\":\"シェルコマンドをインストール\",\"INSTALL_SHELL_COMMAND_QUESTION\":\"「lektor」のシェルコマンドをインストールしますか?。インストールするには管理権限が必要です。\",\"FAILED_TO_INSTALL_SHELL_COMMANDS\":\"シェルコマンドのインストールに失敗しました。\",\"INSTALL_SHELL_COMMAND_SUCCESS\":\"シェルコマンドのインストールに成功しました。\",\"OPERATION_SUCCESS\":\"成功\",\"YES\":\"はい\",\"NO\":\"いいえ\",\"OK\":\"了解\",\"FAILED_TO_OPEN_CONTENT_FILE\":\"コンテンツファイルを開くのに失敗しました\",\"OPEN_OTHER_PROJECT\":\"他のプロジェクトを開く\",\"OPEN_OTHER_PROJECT_QUESTION\":\"このファイルを開くには、他のプロジェクト(%s)を開く必要があります。現在のプロジェクトは閉じられます、処理を継続しますか?\"}\n\n\n//////////////////\n// WEBPACK FOOTER\n// /home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/ja.json\n// module id = 291\n// module chunks = 0","module.exports = {\"RETURN_TO_WEBSITE\":\"사이트로 되돌아가기\",\"UNLOAD_ACTIVE_TAB\":\"저장되지 않은 정보가 있습니다. 페이지를 떠나시겠습니까?\",\"EDIT_METADATA\":\"메타데이터 수정\",\"EDIT\":\"수정\",\"DELETE\":\"삭제\",\"PREVIEW\":\"미리보기\",\"ALTS\":\"다른 언어\",\"PRIMARY_ALT\":\"기본\",\"PRIMARY_OVERLAY\":\"겹친\",\"ADD_CHILD_PAGE\":\"페이지 추가\",\"ADD_ATTACHMENT\":\"첨부 파일 추가\",\"ATTACHMENT_ACTIONS\":\"첨부 파일 작업\",\"PAGE_ACTIONS\":\"페이지 작업\",\"NO_CHILD_PAGES\":\"하위 페이지 없음\",\"CHILD_PAGES\":\"하위 페이지\",\"NO_ATTACHMENTS\":\"첨부 파일 없음\",\"ATTACHMENTS\":\"첨부 파일\",\"ADD_ATTACHMENT_TO\":\"“%s“에서 첨부 파일 추가\",\"ADD_ATTACHMENT_NOTE\":\"여기서 새로운 첨부 파일을 업로드할 수 있습니다.\",\"UPLOAD\":\"업로드\",\"PROGRESS\":\"진행\",\"ERROR_PREFIX\":\"에러: \",\"ERROR_NO_ID_PROVIDED\":\"제공된 ID가 없습니다.\",\"ERROR_PAGE_ID_DUPLICATE\":\"이 ID (%s) 페이지는 이미 존재합니다.\",\"ERROR_INVALID_ID\":\"잘못된 ID\",\"ERROR_INVALID_DATE\":\"잘못된 날짜\",\"ERROR_INVALID_NUMBER\":\"유효한 숫자 아님\",\"ERROR_INVALID_URL\":\"유효한 URL 아님\",\"ERROR\":\"에러\",\"ERROR_OCURRED\":\"오류 발생\",\"ERROR_REQUEST_FAILED\":\"서버에 명령을 보내지 못했습니다. 서버가 중지되었거나 응답하지 않을 수도 있네요?\",\"ERROR_SERVER_UNAVAILABLE\":\"서버를 사용할 수 없음\",\"ERROR_SERVER_UNAVAILABLE_MESSAGE\":\"서버가 응답하지 않습니다. 서버가 중지되었거나, 재시작을 필요로 하는 치명적인 오류가 발생했습니다.\",\"MODEL\":\"모델\",\"ADD_CHILD_PAGE_TO\":\"“%s”에 하위 페이지 추가\",\"ADD_CHILD_PAGE_NOTE\":\"이 페이지에서 새로운 하위 페이지를 추가할 수 있습니다. 중요, 나중에 모델이나 ID를 변경하기 어렵습니다.\",\"CREATE_CHILD_PAGE\":\"하위 페이지 추가\",\"DELETE_ATTACHMENT_PROMPT\":\"정말로 첨부 파일을 삭제하실 건가요?\",\"DELETE_ATTACHMENT_ALT_PROMPT\":\"정말로 첨부 파일의 다른 언어에 대한 메타데이터를 삭제하실 건가요?\",\"DELETE_PAGE_PROMPT\":\"정말로 이 페이지를 삭제하실 건가요?\",\"DELETE_PAGE_ALT_PROMPT\":\"정말로 이 다른 언어를 삭제하실 건가요?\",\"DELETE_PAGE_CHILDREN_WARNING\":\"이 페이지의 하위 페이지 또한 삭제됩니다.\",\"DELETE_RECORD\":\"“%s” 삭제\",\"DELETE_ALL_PAGE_ALTS\":\"또한, 모든 다른 언어와 첨부 파일을 삭제합니다.\",\"DELETE_ALL_ATTACHMENT_ALTS\":\"모든 다른 언어와 첨부 파일을 삭제합니다.\",\"DELETE_ONLY_PRIMARY_PAGE_ALT\":\"오직 주 레코드만 삭제됩니다. 첨부 파일, 다른 언어, 하위 페이지는 삭제되지 않습니다.\",\"DELETE_ONLY_PRIMARY_ATTACHMENT_ALT\":\"오직 주 레코드의 메타데이터만 삭제됩니다.\",\"DELETE_PRIMARY_ALT_INFO\":\"이 레코드는 기본 언어이기 때문에 별도로 삭제하거나 다른 콘텐츠 전부와 같이 삭제할 수 있습니다.\",\"CHILD_PAGES_TO_BE_DELETED\":\"하위 페이지를 삭제합니다:\",\"ALTS_TO_BE_DELETED\":\"다른 언어를 삭제합니다:\",\"ATTACHMENTS_TO_BE_DELETED\":\"첨부 파일을 삭제합니다:\",\"YES_DELETE\":\"네, 삭제\",\"NO_CANCEL\":\"아니요, 취소\",\"SYSTEM_FIELDS\":\"시스템 필드\",\"EDIT_ATTACHMENT_METADATA_OF\":\"첨부 파일 “%s”의 메타데이터 수정\",\"EDIT_PAGE_NAME\":\"“%s” 수정\",\"SAVE_CHANGES\":\"변경 저장\",\"BROWSE_FS\":\"파일 시스템 검색\",\"BROWSE_FS_MAC\":\"파인더에서 검색\",\"BROWSE_FS_WINDOWS\":\"탐색기에서 열기\",\"ERROR_CANNOT_BROWSE_FS\":\"오류: 파일이 존재하지 않습니다.\",\"REMOVE_FLOWBLOCK_PROMPT\":\"이 블록을 제거하시겠습니까?\",\"ADD_FLOWBLOCK\":\"블록 추가\",\"INVALID_INPUT\":\"잘못된 입력\",\"UP\":\"위로\",\"DOWN\":\"아래로\",\"REMOVE\":\"제거\",\"ID\":\"ID\",\"CLOSE\":\"닫기\",\"CANCEL\":\"취소\",\"BACK_TO_OVERVIEW\":\"개요로 되돌아가기\",\"PUBLISH\":\"발행\",\"PUBLISH_NOTE\":\"여기서 웹사이트 현재 버전을 발행할 수 있습니다.\",\"PUBLISH_SERVER\":\"대상 서버\",\"CURRENTLY_PUBLISHING\":\"발행 중 ...\",\"STATE\":\"상태\",\"PUBLISH_DONE\":\"발행됨\",\"PUBLISH_STATE_BUILDING\":\"변경 사항 빌드 중 ...\",\"PUBLISH_STATE_PUBLISH\":\"변경 사항 발행 중 ...\",\"PUBLISH_STATE_DONE\":\"발행 완료.\",\"FIND_FILES\":\"파일 찾기\",\"FIND_FILES_PLACEHOLDER\":\"페이지 이름 입력 ...\",\"ATTACHMENT_TYPE\":\"첨부 파일 형식\",\"URL_SLUG\":\"URL slug\",\"TEMPLATE\":\"템플릿\",\"HIDE_PAGE\":\"페이지 숨기기\",\"HIDE_PAGE_EXPLANATION\":\"이 페이지를 숨길까요?\",\"PAGE_IS_DISCOVERABLE\":\"페이지 다시보이기\",\"PAGE_IS_DISCOVERABLE_EXPLANATION\":\"이 설정이 활성화되어있으면 페이지를 확인할 수 있습니다. 그렇지 않으면 URL만 확인할 수 있습니다.\",\"REFRESH_BUILD\":\"새로운 빌드\",\"REFRESH_BUILD_NOTE\":\"이 트리거는 처음부터 다시 빌드합니다. 그러면서 이전 빌드하면서 캐시된 결과를 삭제합니다. 이 기능은 동기화 오류나 템플릿에서 잘못된 설정으로 출력물에 문제가 있을 때 유용합니다.\",\"CURRENTLY_REFRESHING_BUILD\":\"지금 새롭게 빌드 중 ...\",\"REFRESHING_BUILD_DONE\":\"새로운 빌드를 완료하였습니다!\",\"FAILED_TO_LAUNCH_LEKTOR\":\"실행하지 못하였습니다.\",\"PROJECT\":\"프로젝트\",\"CLOSE_PROJECT\":\"프로젝트 닫기\",\"OPEN_PROJECT\":\"프로젝트 열기\",\"BROWSE_WEBSITE\":\"웹사이트 찾아보기\",\"VIEW_ADMIN_PANEL\":\"관리자 판넬 보기\",\"QUIT\":\"나가기\",\"FAILED_TO_LOAD_PROJECT\":\"프로젝트를 불러오지 못하였습니다. :(\",\"LOADING_PROJECT\":\"프로젝트 불러오는 중 ...\",\"INITIALIZING_LEKTOR\":\"Lektor 초기화 중 ...\",\"QUIT_LEKTOR\":\"Lektor 나가기\",\"FILE\":\"파일\",\"UNDO\":\"실행 취소\",\"REDO\":\"다시 실행\",\"CUT\":\"잘라내기\",\"COPY\":\"복사\",\"PASTE\":\"붙여넣기\",\"SELECT_ALL\":\"전부 선택\",\"HELP\":\"도움말\",\"VISIT_WEBSITE\":\"웹사이트 방문\",\"INSTALL_SHELL_COMMAND\":\"쉘 커멘드 설치\",\"INSTALL_SHELL_COMMAND_QUESTION\":\"'lektor' 쉘 명령을 설치하시겠습니까? 관리자 권한이 필요합니다.\",\"FAILED_TO_INSTALL_SHELL_COMMANDS\":\"쉘 명령을 설치하지 못하였습니다.\",\"INSTALL_SHELL_COMMAND_SUCCESS\":\"쉘 명령이 성공적으로 설치되었습니다.\",\"OPERATION_SUCCESS\":\"완료\",\"YES\":\"예\",\"NO\":\"아니오\",\"OK\":\"OK\",\"FAILED_TO_OPEN_CONTENT_FILE\":\"현재 파일을 열지 못하였습니다.\",\"OPEN_OTHER_PROJECT\":\"다른 프로젝트 열기\",\"OPEN_OTHER_PROJECT_QUESTION\":\"열려는 파일은 다른 프로젝트 (%s)를 열어야합니다. 현재 프로젝트는 종료됩니다. 계속 하시겠습니까?\"}\n\n\n//////////////////\n// WEBPACK FOOTER\n// /home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/ko.json\n// module id = 292\n// module chunks = 0","module.exports = {\"RETURN_TO_WEBSITE\":\"Terug naar Website\",\"UNLOAD_ACTIVE_TAB\":\"U hebt niet-opgeslagen data, weet je zeker dat je deze pagina wil verlaten?\",\"EDIT_METADATA\":\"Bewerk Metadata\",\"EDIT\":\"Bewerk\",\"DELETE\":\"Verwijderen\",\"PREVIEW\":\"Voorbeeld\",\"ALTS\":\"Alternatieven\",\"PRIMARY_ALT\":\"Primair\",\"PRIMARY_OVERLAY\":\"Overlapt\",\"ADD_CHILD_PAGE\":\"Pagina toevoegen\",\"ADD_ATTACHMENT\":\"Bijlage toevoegen\",\"ATTACHMENT_ACTIONS\":\"Bijlage Acties\",\"PAGE_ACTIONS\":\"Pagina Acties\",\"NO_CHILD_PAGES\":\"Geen Subpagina's\",\"CHILD_PAGES\":\"Subpagina's\",\"NO_ATTACHMENTS\":\"Geen bijlages\",\"ATTACHMENTS\":\"Bijlages\",\"ADD_ATTACHMENT_TO\":\"Voeg bijlage toe aan “%s”\",\"ADD_ATTACHMENT_NOTE\":\"Je kan hier een nieuwe bijlage uploaden.\",\"UPLOAD\":\"Upload\",\"PROGRESS\":\"Vooruitgang\",\"ERROR_PREFIX\":\"Fout: \",\"ERROR_NO_ID_PROVIDED\":\"Geen ID gegeven.\",\"ERROR_PAGE_ID_DUPLICATE\":\"Een pagina met deze ID (%s) bestaat al.\",\"ERROR_INVALID_ID\":\"Ongeldige ID\",\"ERROR_INVALID_DATE\":\"Ongeldige datum\",\"ERROR_INVALID_NUMBER\":\"Geen geldig getal\",\"ERROR_INVALID_URL\":\"Geen geldige URL\",\"ERROR\":\"Fout\",\"ERROR_OCURRED\":\"Er is een fout opgetreden\",\"ERROR_REQUEST_FAILED\":\"Kon het commando niet naar de server sturen. Misschien is de server gestopt of reageert deze niet?\",\"ERROR_SERVER_UNAVAILABLE\":\"Server niet beschikbaar\",\"ERROR_SERVER_UNAVAILABLE_MESSAGE\":\"De server reageert niet. Deze was gestopt of door een kritieke fout niet langer operationeel en moet worden herstart.\",\"MODEL\":\"Model\",\"ADD_CHILD_PAGE_TO\":\"Voeg Subpagina toe aan “%s”\",\"ADD_CHILD_PAGE_NOTE\":\"U kan hier een nieuwe subpagina toevoegen. Merk op dat het model of de ID achteraf niet makkelijk gewijzigd kunnen worden.\",\"CREATE_CHILD_PAGE\":\"Subpagina Toevoegen\",\"DELETE_ATTACHMENT_PROMPT\":\"Weet je zeker dat je deze bijlage wilt verwijderen?\",\"DELETE_ATTACHMENT_ALT_PROMPT\":\"Weet je zeker dat je de metadata van dit bijlage alternatief wilt verwijderen?\",\"DELETE_PAGE_PROMPT\":\"Weet je zeker dat je deze pagina wilt verwijderen?\",\"DELETE_PAGE_ALT_PROMPT\":\"Weet je zeker dat je dit alternatief wilt verwijderen?\",\"DELETE_PAGE_CHILDREN_WARNING\":\"Dit zal ook de subpagina's van deze pagina verwijderen.\",\"DELETE_RECORD\":\"Verwijder “%s”\",\"DELETE_ALL_PAGE_ALTS\":\"Verwijder ook de alternatieven en bijlages.\",\"DELETE_ALL_ATTACHMENT_ALTS\":\"Verwijder alle alternatieven en bijlages.\",\"DELETE_ONLY_PRIMARY_PAGE_ALT\":\"Verwijder enkel de primaire record. Bijlages, alternatieven en subpagina's zullen niet verwijderd worden.\",\"DELETE_ONLY_PRIMARY_ATTACHMENT_ALT\":\"Verwijder enkel de metadata van de primaire record.\",\"DELETE_PRIMARY_ALT_INFO\":\"Omdat dit record een primair alternatief is, kan het apart verwijderd worden of samen met alle andere inhoud.\",\"CHILD_PAGES_TO_BE_DELETED\":\"Subpagina's die verwijderd zullen worden:\",\"ALTS_TO_BE_DELETED\":\"Alternatieven die verwijderd zullen worden:\",\"ATTACHMENTS_TO_BE_DELETED\":\"Bijlages die verwijderd zullen worden:\",\"YES_DELETE\":\"Ja, verwijder\",\"NO_CANCEL\":\"Nee, annuleer\",\"SYSTEM_FIELDS\":\"Systeem Velden\",\"EDIT_ATTACHMENT_METADATA_OF\":\"Bewerk Metadata van Bijlage “%s”\",\"EDIT_PAGE_NAME\":\"Bewerk “%s”\",\"SAVE_CHANGES\":\"Wijzigingen opslaan\",\"BROWSE_FS\":\"Blader in Bestandsysteem\",\"BROWSE_FS_MAC\":\"Bekijk in Finder\",\"BROWSE_FS_WINDOWS\":\"Open in Explorer\",\"ERROR_CANNOT_BROWSE_FS\":\"Fout: Bestand bestaat nog niet.\",\"REMOVE_FLOWBLOCK_PROMPT\":\"Weet je zeker dat je dit blok wilt verwijderen?\",\"ADD_FLOWBLOCK\":\"Blok Toevoegen\",\"INVALID_INPUT\":\"Ongeldige Invoer\",\"UP\":\"Omhoog\",\"DOWN\":\"Omlaag\",\"REMOVE\":\"Verwijderen\",\"ID\":\"ID\",\"CLOSE\":\"Sluiten\",\"CANCEL\":\"Annuleren\",\"BACK_TO_OVERVIEW\":\"Terug naar Overzicht\",\"PUBLISH\":\"Publiceren\",\"PUBLISH_NOTE\":\"Van hieruit kan je de huidige versie van je website publiceren.\",\"PUBLISH_SERVER\":\"Doelserver\",\"CURRENTLY_PUBLISHING\":\"Publiceren …\",\"STATE\":\"Status\",\"PUBLISH_DONE\":\"Gepubliceerd\",\"PUBLISH_STATE_BUILDING\":\"De wijzigingen worden gebouwd ...\",\"PUBLISH_STATE_PUBLISH\":\"De wijzigingen worden gepuliceerd ...\",\"PUBLISH_STATE_DONE\":\"Klaar met publiceren.\",\"FIND_FILES\":\"Zoek bestanden\",\"FIND_FILES_PLACEHOLDER\":\"Vul paginanaam in ...\",\"ATTACHMENT_TYPE\":\"Type Bijlage\",\"URL_SLUG\":\"URL slug\",\"TEMPLATE\":\"Template\",\"HIDE_PAGE\":\"Verberg pagina\",\"HIDE_PAGE_EXPLANATION\":\"Moet deze pagina verborgen zijn?\",\"PAGE_IS_DISCOVERABLE\":\"Deze pagina is vindbaar\",\"PAGE_IS_DISCOVERABLE_EXPLANATION\":\"Als dit ingeschakeld is, is de pagina vindbaar. Anders moet de URL bekend zijn.\",\"REFRESH_BUILD\":\"Ververs Build\",\"REFRESH_BUILD_NOTE\":\"Dit verwijdert alle buildresultaten in de cache en veroorzaakt een volledige rebuild. Dit is nuttig in bepaalde situaties waar synchonisatiefouten of fouten in de templates de uitvoer corrupt hebben gemaakt.\",\"CURRENTLY_REFRESHING_BUILD\":\"Bezig met verversen van de build ...\",\"REFRESHING_BUILD_DONE\":\"Klaar met de build te verversen!\",\"FAILED_TO_LAUNCH_LEKTOR\":\"Het starten van Lektor is mislukt.\",\"PROJECT\":\"Project\",\"CLOSE_PROJECT\":\"Sluit Project\",\"OPEN_PROJECT\":\"Open Project\",\"BROWSE_WEBSITE\":\"Bekijk Website\",\"VIEW_ADMIN_PANEL\":\"Bekijk Admin Paneel\",\"QUIT\":\"Afsluiten\",\"FAILED_TO_LOAD_PROJECT\":\"Laden van het project is mislukt :(\",\"LOADING_PROJECT\":\"Project laden ...\",\"INITIALIZING_LEKTOR\":\"Lektor Initializeren ...\",\"QUIT_LEKTOR\":\"Lektor Afsluiten\",\"FILE\":\"Bestand\",\"UNDO\":\"Ongedaan maken\",\"REDO\":\"Opnieuw\",\"CUT\":\"Knippen\",\"COPY\":\"Kopiëren\",\"PASTE\":\"Plakken\",\"SELECT_ALL\":\"Selecteer alles\",\"HELP\":\"Help\",\"VISIT_WEBSITE\":\"Bezoek Website\",\"INSTALL_SHELL_COMMAND\":\"Installeer Shell Commando\",\"INSTALL_SHELL_COMMAND_QUESTION\":\"Weet je zeker dat je het 'lektor' shell commando wil installeren? Dit vereist admin rechten.\",\"FAILED_TO_INSTALL_SHELL_COMMANDS\":\"Installeren van de shell commando's mislukt.\",\"INSTALL_SHELL_COMMAND_SUCCESS\":\"Shell commando's zijn geïnstalleerd.\",\"OPERATION_SUCCESS\":\"Success\",\"YES\":\"Ja\",\"NO\":\"Nee\",\"OK\":\"OK\",\"FAILED_TO_OPEN_CONTENT_FILE\":\"Kon het inhoudbestand niet openen\",\"OPEN_OTHER_PROJECT\":\"Open ander Project\",\"OPEN_OTHER_PROJECT_QUESTION\":\"Om deze file te openen moet een ander project geopend worden (%s). Het huidige project zal gesloten worden. Wil je verdergaan?\"}\n\n\n//////////////////\n// WEBPACK FOOTER\n// /home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/nl.json\n// module id = 293\n// module chunks = 0","module.exports = {\"RETURN_TO_WEBSITE\":\"Wróć do strony\",\"UNLOAD_ACTIVE_TAB\":\"Masz niezapisane dane, czy na pewno chcesz opuścić tą stronę ?\",\"EDIT_METADATA\":\"Edytuj dane\",\"EDIT\":\"Edycja\",\"DELETE\":\"Usuń\",\"PREVIEW\":\"Podgląd\",\"ALTS\":\"Wersje językowe\",\"PRIMARY_ALT\":\"Podstawowy język\",\"PRIMARY_OVERLAY\":\"(Nałożony)\",\"ADD_CHILD_PAGE\":\"Dodaj podstronę\",\"ADD_ATTACHMENT\":\"Dodaj załącznik\",\"ATTACHMENT_ACTIONS\":\"Operacje na załącznikach\",\"PAGE_ACTIONS\":\"Operacje na stronach\",\"NO_CHILD_PAGES\":\"Brak podstron\",\"CHILD_PAGES\":\"Podstrony\",\"NO_ATTACHMENTS\":\"Brak załączników\",\"ATTACHMENTS\":\"Załączniki\",\"ADD_ATTACHMENT_TO\":\"Dodaj załącznik do “%s”\",\"ADD_ATTACHMENT_NOTE\":\"Możesz wgrać nowy załącznik tutaj.\",\"UPLOAD\":\"Wgraj\",\"PROGRESS\":\"Postęp\",\"ERROR_PREFIX\":\"Błąd: \",\"ERROR_NO_ID_PROVIDED\":\"Nie podano ID.\",\"ERROR_PAGE_ID_DUPLICATE\":\"Strona z ID: (%s) już istnieje.\",\"ERROR_INVALID_ID\":\"Błędny ID\",\"ERROR_INVALID_DATE\":\"Błędna data\",\"ERROR_INVALID_NUMBER\":\"Błędny numer\",\"ERROR_INVALID_URL\":\"Błędny adres URL\",\"ERROR\":\"Błąd\",\"ERROR_OCURRED\":\"Wystąpił błąd\",\"ERROR_REQUEST_FAILED\":\"Nie można wysłać żądania do serwera. Może został zatrzymany, albo nie odpowiada?\",\"ERROR_SERVER_UNAVAILABLE\":\"Serwer niedostępny\",\"ERROR_SERVER_UNAVAILABLE_MESSAGE\":\"Serwer nie odpowiada. Został zatrzymany, albo wystąpił błąd krytyczny, który spowodował brak działania. Być może musi zostać zrestartowany.\",\"MODEL\":\"Model\",\"ADD_CHILD_PAGE_TO\":\"Dodaj podstronę do “%s”\",\"ADD_CHILD_PAGE_NOTE\":\"Możesz dodać podstronę tutaj. Pamiętaj, że Model oraz ID nie mogą być zmienione później w prosty sposób.\",\"CREATE_CHILD_PAGE\":\"Dodaj podstronę\",\"DELETE_ATTACHMENT_PROMPT\":\"Czy na pewno chcesz usunąć ten załącznik?\",\"DELETE_ATTACHMENT_ALT_PROMPT\":\"Czy na pewno chcesz usunąć dane załącznika dla tego języka?\",\"DELETE_PAGE_PROMPT\":\"Czy na pewno chcesz usunąć tą stronę?\",\"DELETE_PAGE_ALT_PROMPT\":\"Czy na pewno chcesz usunąć ten język?\",\"DELETE_PAGE_CHILDREN_WARNING\":\"To spowoduje także usunięcie wszystkich podstron.\",\"DELETE_RECORD\":\"Skasuj “%s”\",\"DELETE_ALL_PAGE_ALTS\":\"Usuń również wszystkie wersje językowe oraz załączniki.\",\"DELETE_ALL_ATTACHMENT_ALTS\":\"Usuń wszystkie wersje językowe oraz załączony plik.\",\"DELETE_ONLY_PRIMARY_PAGE_ALT\":\"Usuń tylko podstawowy rekord. Załączniki, wersje językowe oraz podstrony nie będę usunięte.\",\"DELETE_ONLY_PRIMARY_ATTACHMENT_ALT\":\"Usuń tylko dane podstawowego rekordu.\",\"DELETE_PRIMARY_ALT_INFO\":\"Ponieważ ten rekord zawiera podstawową wersję językową może zostać usunięty osobno jak i razem z pozostałą zawartością.\",\"CHILD_PAGES_TO_BE_DELETED\":\"Podstrony, które zostaną usunięte:\",\"ALTS_TO_BE_DELETED\":\"Wersje językowe, które zostaną usunięte:\",\"ATTACHMENTS_TO_BE_DELETED\":\"Załączniki, które zostaną usunięte:\",\"YES_DELETE\":\"Tak, usuń\",\"NO_CANCEL\":\"Nie, anuluj\",\"SYSTEM_FIELDS\":\"Pola Systemowe\",\"EDIT_ATTACHMENT_METADATA_OF\":\"Edytuj dane załącznika “%s”\",\"EDIT_PAGE_NAME\":\"Edytuj “%s”\",\"SAVE_CHANGES\":\"Zapisz zmiany\",\"BROWSE_FS\":\"Otwórz w przeglądarce plików\",\"BROWSE_FS_MAC\":\"Otwórz w Finderze\",\"BROWSE_FS_WINDOWS\":\"Otwórz w eksploratorze plików\",\"ERROR_CANNOT_BROWSE_FS\":\"Błąd: Plik jeszcze nie istnieje.\",\"REMOVE_FLOWBLOCK_PROMPT\":\"Czy na pewno chcesz usunąć ten blok ?\",\"ADD_FLOWBLOCK\":\"Dodaj blok\",\"INVALID_INPUT\":\"Błędne dane wejściowe\",\"UP\":\"W górę\",\"DOWN\":\"W dół\",\"REMOVE\":\"Usuń\",\"ID\":\"ID\",\"CLOSE\":\"Zamknij\",\"CANCEL\":\"Anuluj\",\"BACK_TO_OVERVIEW\":\"Powrót do przeglądu\",\"PUBLISH\":\"Publikuj\",\"PUBLISH_NOTE\":\"Stąd możesz opublikować aktualną wersję strony.\",\"PUBLISH_SERVER\":\"Serwer Docelowy\",\"CURRENTLY_PUBLISHING\":\"Publikowanie …\",\"STATE\":\"Status\",\"PUBLISH_DONE\":\"Opublikowany\",\"PUBLISH_STATE_BUILDING\":\"Zmiany są wprowadzane ...\",\"PUBLISH_STATE_PUBLISH\":\"Zmiany są publikowane ...\",\"PUBLISH_STATE_DONE\":\"Publikowanie zakończone.\",\"FIND_FILES\":\"Znadź Pliki\",\"FIND_FILES_PLACEHOLDER\":\"Podaj nazwę strony ...\",\"ATTACHMENT_TYPE\":\"Typ załącznika\",\"URL_SLUG\":\"Przyjazny URL\",\"TEMPLATE\":\"Szablon\",\"HIDE_PAGE\":\"Ukryj stronę\",\"HIDE_PAGE_EXPLANATION\":\"Czy ta strona powinna być ukryta?\",\"PAGE_IS_DISCOVERABLE\":\"Strona jest 'widoczna'\",\"PAGE_IS_DISCOVERABLE_EXPLANATION\":\"Jeśli włączone, strona jest widoczna na liście stron oraz w listingu dla danego rekordu. W przeciwnym razie, adres URL musi być znany\",\"REFRESH_BUILD\":\"Zbuduj odświeżoną wersję\",\"REFRESH_BUILD_NOTE\":\"To spowoduje usunięcie pamięci podręcznej i stworzenie wersji końcowej od nowa. Ta opcja jest przydatna w sytuacjach, gdzie błędy albo pomyłki synchronizacji w szablonach spowodowały uszkodzenie danych wyjściowych.\",\"CURRENTLY_REFRESHING_BUILD\":\"Aktualnie odświeżam pakiet wyjściowy ...\",\"REFRESHING_BUILD_DONE\":\"Zakończono odświeżanie pakietu wyjściowego!\",\"FAILED_TO_LAUNCH_LEKTOR\":\"Nie udało się uruchomić Lektor.\",\"PROJECT\":\"Projekt\",\"CLOSE_PROJECT\":\"Zamknij projekt\",\"OPEN_PROJECT\":\"Otwórz projekt\",\"BROWSE_WEBSITE\":\"Przeglądaj stronę\",\"VIEW_ADMIN_PANEL\":\"Przejdź do panelu administracyjnego\",\"QUIT\":\"Wyjdź\",\"FAILED_TO_LOAD_PROJECT\":\"Nie udało się załadować projektu :(\",\"LOADING_PROJECT\":\"Ładowanie projektu ...\",\"INITIALIZING_LEKTOR\":\"Inicjalizacja Lektor ...\",\"QUIT_LEKTOR\":\"Opuść Lektor\",\"FILE\":\"Plik\",\"UNDO\":\"Cofnij\",\"REDO\":\"Ponów\",\"CUT\":\"Wytnij\",\"COPY\":\"Kopiuj\",\"PASTE\":\"Wklej\",\"SELECT_ALL\":\"Zaznacz wszystko\",\"HELP\":\"Pomoc\",\"VISIT_WEBSITE\":\"Odwiedź stronę\",\"INSTALL_SHELL_COMMAND\":\"Zainstaluj komendę powłoki\",\"INSTALL_SHELL_COMMAND_QUESTION\":\"Czy chcesz zainstalować komendę 'lektor' w powłoce systemowej? Wygamane są uprawnienia administracyjne.\",\"FAILED_TO_INSTALL_SHELL_COMMANDS\":\"Nie udało się zainstalować komend w powłoce systemowej.\",\"INSTALL_SHELL_COMMAND_SUCCESS\":\"Komenda została pomyślnie zainstalowana w powłoce systemowej.\",\"OPERATION_SUCCESS\":\"Sukces\",\"YES\":\"Tak\",\"NO\":\"Nie\",\"OK\":\"OK\",\"FAILED_TO_OPEN_CONTENT_FILE\":\"Nie udało się otworzyć zawartości pliku\",\"OPEN_OTHER_PROJECT\":\"Otwórz inny projekt\",\"OPEN_OTHER_PROJECT_QUESTION\":\"Otwarcie tego pliku wymaga otwarcia kolejnego projektu (%s). Obecny projekt zostanie zamknięty. Czy chcesz kontynuować?\"}\n\n\n//////////////////\n// WEBPACK FOOTER\n// /home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/pl.json\n// module id = 294\n// module chunks = 0","module.exports = {\"RETURN_TO_WEBSITE\":\"Retornar ao Site\",\"UNLOAD_ACTIVE_TAB\":\"Você tem modificações não salvas, tem certeza que deseja deixar a página?\",\"EDIT_METADATA\":\"Editar Metadado\",\"EDIT\":\"Editar\",\"DELETE\":\"Deletar\",\"PREVIEW\":\"Pré-visualizar\",\"ALTS\":\"Alternativas\",\"PRIMARY_ALT\":\"Primária\",\"PRIMARY_OVERLAY\":\"Revestida\",\"ADD_CHILD_PAGE\":\"Add Página\",\"ADD_ATTACHMENT\":\"Add Anexo\",\"ATTACHMENT_ACTIONS\":\"Ações de Anexos\",\"PAGE_ACTIONS\":\"Ações de Páginas\",\"NO_CHILD_PAGES\":\"Sem sub-páginas\",\"CHILD_PAGES\":\"Sub-páginas\",\"NO_ATTACHMENTS\":\"Sem anexos\",\"ATTACHMENTS\":\"Anexos\",\"ADD_ATTACHMENT_TO\":\"Add anexo para “%s”\",\"ADD_ATTACHMENT_NOTE\":\"Você pode subir um novo anexo aqui.\",\"UPLOAD\":\"Upload\",\"PROGRESS\":\"Progresso\",\"ERROR_PREFIX\":\"Erro: \",\"ERROR_NO_ID_PROVIDED\":\"Nenhuma ID fornecida.\",\"ERROR_PAGE_ID_DUPLICATE\":\"Uma página com este ID (%s) já existe.\",\"ERROR_INVALID_ID\":\"ID inválido\",\"ERROR_INVALID_DATE\":\"Data inválida\",\"ERROR_INVALID_NUMBER\":\"Não é um número válido\",\"ERROR_INVALID_URL\":\"Não é uma URL válida\",\"ERROR\":\"Erro\",\"ERROR_OCURRED\":\"Ocorreu um Erro\",\"ERROR_REQUEST_FAILED\":\"Não foi possível enviar o comando ao servidor. Talvez o servidor foi parado ou não está respondendo\",\"ERROR_SERVER_UNAVAILABLE\":\"Servidor Não Disponível\",\"ERROR_SERVER_UNAVAILABLE_MESSAGE\":\"O servidor não está respondendo. Ou foi parado ou um erro sério o fez parar e precisa ser reiniciado.\",\"MODEL\":\"Modelo\",\"ADD_CHILD_PAGE_TO\":\"Add Sub-página para “%s”\",\"ADD_CHILD_PAGE_NOTE\":\"Você pode adicionar uma nova sub-página aqui. Note que o modelo ou o ID não podem ser mudados facilmente depois.\",\"CREATE_CHILD_PAGE\":\"Add Página Filha\",\"DELETE_ATTACHMENT_PROMPT\":\"Você tem certeza que deseja deletar este anexo?\",\"DELETE_ATTACHMENT_ALT_PROMPT\":\"Você tem certeza que deseja deletar o metadado deste anexo alternativo?\",\"DELETE_PAGE_PROMPT\":\"Você tem certeza que deseja deletar esta página\",\"DELETE_PAGE_ALT_PROMPT\":\"Você tem certeza que deseja deletar esta alternativa?\",\"DELETE_PAGE_CHILDREN_WARNING\":\"Isto também deletará as sub-páginas filhas desta página.\",\"DELETE_RECORD\":\"Deletar “%s”\",\"DELETE_ALL_PAGE_ALTS\":\"Também delete todas alternativas e arquivos de anexo.\",\"DELETE_ALL_ATTACHMENT_ALTS\":\"Delete todas alternativas e arquivo de anexo\",\"DELETE_ONLY_PRIMARY_PAGE_ALT\":\"Delete somente o registro primário. Anexos, alternativas e sub-páginas não serão deletadas.\",\"DELETE_ONLY_PRIMARY_ATTACHMENT_ALT\":\"Delete somente o Metadado do registro primário.\",\"DELETE_PRIMARY_ALT_INFO\":\"Porque este registro é uma alternativa primária ele pode ser deletado separadamente ou junto com todos os outros conteúdos.\",\"CHILD_PAGES_TO_BE_DELETED\":\"Sub-páginas que serão deletadas:\",\"ALTS_TO_BE_DELETED\":\"Alternativas que serão deletadas:\",\"ATTACHMENTS_TO_BE_DELETED\":\"Anexos que serão deletados:\",\"YES_DELETE\":\"Sim, deletar\",\"NO_CANCEL\":\"Não, cancelar\",\"SYSTEM_FIELDS\":\"Campos do Sistema\",\"EDIT_ATTACHMENT_METADATA_OF\":\"Editar Metadado do Anexo “%s”\",\"EDIT_PAGE_NAME\":\"Editar “%s”\",\"SAVE_CHANGES\":\"Salvar Alterações\",\"BROWSE_FS\":\"Navegar no Sistema\",\"BROWSE_FS_MAC\":\"Mostrar no Finder\",\"BROWSE_FS_WINDOWS\":\"Abrir no Explorer\",\"ERROR_CANNOT_BROWSE_FS\":\"Erro: Arquivo não existe ainda.\",\"REMOVE_FLOWBLOCK_PROMPT\":\"Você realmente deseja remover este bloco?\",\"ADD_FLOWBLOCK\":\"Add Bloco\",\"INVALID_INPUT\":\"Entrada Inválida\",\"UP\":\"Cima\",\"DOWN\":\"Baixo\",\"REMOVE\":\"Remover\",\"ID\":\"ID\",\"CLOSE\":\"Fechar\",\"CANCEL\":\"Cancelar\",\"BACK_TO_OVERVIEW\":\"Voltar para Overview\",\"PUBLISH\":\"Publicar\",\"PUBLISH_NOTE\":\"Daqui você pode publicar a versão atual do website.\",\"PUBLISH_SERVER\":\"Servidor Alvo\",\"CURRENTLY_PUBLISHING\":\"Publicando …\",\"STATE\":\"Status\",\"PUBLISH_DONE\":\"Publicado\",\"PUBLISH_STATE_BUILDING\":\"Mudanças estão sendo construídas ...\",\"PUBLISH_STATE_PUBLISH\":\"Mudanças estão sendo publicadas ...\",\"PUBLISH_STATE_DONE\":\"Publicação feita.\",\"FIND_FILES\":\"Procurar Arquivos\",\"FIND_FILES_PLACEHOLDER\":\"Entrar com o nome da página ...\",\"ATTACHMENT_TYPE\":\"Tipo de anexo\",\"URL_SLUG\":\"URL slug\",\"TEMPLATE\":\"Template\",\"HIDE_PAGE\":\"Esconder página\",\"HIDE_PAGE_EXPLANATION\":\"Isto deveria ser escondido?\",\"PAGE_IS_DISCOVERABLE\":\"Página é descobrível\",\"PAGE_IS_DISCOVERABLE_EXPLANATION\":\"Se isto estiver ativo a página pode ser descoberta, caso contrário será necessário saber a URL.\",\"REFRESH_BUILD\":\"Atualizar Build\",\"REFRESH_BUILD_NOTE\":\"Isto deleta todos os resultados de builds em cache ativando uma build do zero. Isto é útil em situações onde erros de sincronização ou erros no template causam saídas corrompidas.\",\"CURRENTLY_REFRESHING_BUILD\":\"No momento atualizando a build ...\",\"REFRESHING_BUILD_DONE\":\"Atualização da build feita!\",\"FAILED_TO_LAUNCH_LEKTOR\":\"Falha ao iniciar o Lektor.\",\"PROJECT\":\"Projeto\",\"CLOSE_PROJECT\":\"Fechar Projeto\",\"OPEN_PROJECT\":\"Abrir Projeto\",\"BROWSE_WEBSITE\":\"Navegar no Website\",\"VIEW_ADMIN_PANEL\":\"Ver Admin Painel\",\"QUIT\":\"Sair\",\"FAILED_TO_LOAD_PROJECT\":\"Falha ao carregar o projeto :(\",\"LOADING_PROJECT\":\"Carregando o projeto ...\",\"INITIALIZING_LEKTOR\":\"Iniciando o Lektor ...\",\"QUIT_LEKTOR\":\"Sair do Lektor\",\"FILE\":\"Arquivo\",\"UNDO\":\"Desfazer\",\"REDO\":\"Refazer\",\"CUT\":\"Cortar\",\"COPY\":\"Copiar\",\"PASTE\":\"Colar\",\"SELECT_ALL\":\"Selecionar Todos\",\"HELP\":\"Ajuda\",\"VISIT_WEBSITE\":\"Visitar Website\",\"INSTALL_SHELL_COMMAND\":\"Instalar Shell Command\",\"INSTALL_SHELL_COMMAND_QUESTION\":\"Você deseja instalar 'lektor' shell command? Isto requer permissões de administrador.\",\"FAILED_TO_INSTALL_SHELL_COMMANDS\":\"Falha ao instalar shell commands.\",\"INSTALL_SHELL_COMMAND_SUCCESS\":\"Shell command foi instalado com sucesso.\",\"OPERATION_SUCCESS\":\"Sucesso\",\"YES\":\"Sim\",\"NO\":\"Não\",\"OK\":\"OK\",\"FAILED_TO_OPEN_CONTENT_FILE\":\"Falha ao abrir o conteúdo do arquivo\",\"OPEN_OTHER_PROJECT\":\"Abrir outro Projeto\",\"OPEN_OTHER_PROJECT_QUESTION\":\"Abrir este arquivo requer abrir outro projeto (%s). O projeto atual será fechado. Deseja continuar?\"}\n\n\n//////////////////\n// WEBPACK FOOTER\n// /home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/pt.json\n// module id = 295\n// module chunks = 0","module.exports = {\"RETURN_TO_WEBSITE\":\"Вернуться на вебсайт\",\"UNLOAD_ACTIVE_TAB\":\"Ваши изменения не сохранены. Вы уверены, что хотите покинуть страницу?\",\"EDIT_METADATA\":\"Редактировать метаданные\",\"EDIT\":\"Редактировать\",\"DELETE\":\"Удалить\",\"PREVIEW\":\"Предпросмотр\",\"ALTS\":\"Варианты\",\"PRIMARY_ALT\":\"Основной\",\"PRIMARY_OVERLAY\":\"Оверлей\",\"ADD_CHILD_PAGE\":\"Добавить страницу\",\"ADD_ATTACHMENT\":\"Приложить файл\",\"ATTACHMENT_ACTIONS\":\"Действия с вложением\",\"PAGE_ACTIONS\":\"Действия со страницей\",\"NO_CHILD_PAGES\":\"Вложенные страницы отсутствуют\",\"CHILD_PAGES\":\"Вложенные страницы\",\"NO_ATTACHMENTS\":\"Вложенные файлы отсутствуют\",\"ATTACHMENTS\":\"Вложенные файлы\",\"ADD_ATTACHMENT_TO\":\"Приложить файл к странице “%s”\",\"ADD_ATTACHMENT_NOTE\":\"Здесь вы можете загрузить новый файл.\",\"UPLOAD\":\"Загрузить\",\"PROGRESS\":\"Прогресс\",\"ERROR_PREFIX\":\"Ошибка: \",\"ERROR_NO_ID_PROVIDED\":\"Ошибка: Отсутсует ID.\",\"ERROR_PAGE_ID_DUPLICATE\":\"Страница с ID (%s) уже существует.\",\"ERROR_INVALID_ID\":\"Некорректный ID\",\"ERROR_INVALID_DATE\":\"Некорректная дата\",\"ERROR_INVALID_NUMBER\":\"Некорректное число\",\"ERROR_INVALID_URL\":\"Некорректный URL\",\"ERROR\":\"Ошибка\",\"ERROR_OCURRED\":\"Произошла ошибка\",\"ERROR_REQUEST_FAILED\":\"Ошибка при отправке команды на сервер. Возможно, сервер остановлен или не отвечает.\",\"ERROR_SERVER_UNAVAILABLE\":\"Сервер недоступен\",\"ERROR_SERVER_UNAVAILABLE_MESSAGE\":\"Сервер не отвечает. Возможно, сервер остановлен или произошла критическая ошибка. Перезапустите сервер.\",\"MODEL\":\"Модель\",\"ADD_CHILD_PAGE_TO\":\"Создать вложенную страницу для “%s”\",\"ADD_CHILD_PAGE_NOTE\":\"Здесь вы можете создать новую вложенную страницу. Имейте в виду, что вы не сможете легко изменить модель и ID после создания страницы.\",\"CREATE_CHILD_PAGE\":\"Создать вложенную страницу\",\"DELETE_ATTACHMENT_PROMPT\":\"Вы действительно хотите удалить это вложение?\",\"DELETE_ATTACHMENT_ALT_PROMPT\":\"Вы действительно хотите удалить этот вариант вложения?\",\"DELETE_PAGE_PROMPT\":\"Вы действительно хотите удалить эту страницу?\",\"DELETE_PAGE_ALT_PROMPT\":\"Вы действительно хотите удалить этот вариант страницы?\",\"DELETE_PAGE_CHILDREN_WARNING\":\"Страница будет удалена вместе со всеми вложенными страницами.\",\"DELETE_RECORD\":\"Удалить “%s”\",\"DELETE_ALL_PAGE_ALTS\":\"Удалить все варианты страницы и вложенные файлы.\",\"DELETE_ALL_ATTACHMENT_ALTS\":\"Удалить все варианты вложенного файла\",\"DELETE_ONLY_PRIMARY_PAGE_ALT\":\"Удалить только основную версию. Вложеннные страницы, файлы и другие варианты страницы не будут удалены.\",\"DELETE_ONLY_PRIMARY_ATTACHMENT_ALT\":\"Удалить только основную версию.\",\"DELETE_PRIMARY_ALT_INFO\":\"Данная версия является основной и может быть удалена как отдельно, так и вместе со всем содержимым.\",\"CHILD_PAGES_TO_BE_DELETED\":\"Вложенные страницы, которые будут удалены:\",\"ALTS_TO_BE_DELETED\":\"Версии, которые будут удалены:\",\"ATTACHMENTS_TO_BE_DELETED\":\"Вложенные файлы, которые будут удалены:\",\"YES_DELETE\":\"Да, удалить\",\"NO_CANCEL\":\"Отмена\",\"SYSTEM_FIELDS\":\"Системные поля\",\"EDIT_ATTACHMENT_METADATA_OF\":\"Редактировать метаданные вложения “%s”\",\"EDIT_PAGE_NAME\":\"Редактировать “%s”\",\"SAVE_CHANGES\":\"Сохранить изменения\",\"BROWSE_FS\":\"Посмотреть в файловой системе\",\"BROWSE_FS_MAC\":\"Открыть в Finder\",\"BROWSE_FS_WINDOWS\":\"Открыть в Обозревателе\",\"ERROR_CANNOT_BROWSE_FS\":\"Ошибка: Файл не существует.\",\"REMOVE_FLOWBLOCK_PROMPT\":\"Вы действительно хотите удалить этот блок?\",\"ADD_FLOWBLOCK\":\"Добавить блок\",\"INVALID_INPUT\":\"Некорректный ввод\",\"UP\":\"Вверх\",\"DOWN\":\"Вниз\",\"REMOVE\":\"Удалить\",\"ID\":\"Идентификатор (ID)\",\"CLOSE\":\"Закрыть\",\"CANCEL\":\"Отмена\",\"BACK_TO_OVERVIEW\":\"На стартовую страницу\",\"PUBLISH\":\"Опубликовать\",\"PUBLISH_NOTE\":\"Здесь вы можете опубликовать текущую версию вебсайта.\",\"PUBLISH_SERVER\":\"Сервер\",\"CURRENTLY_PUBLISHING\":\"Публикация …\",\"STATE\":\"Статус\",\"PUBLISH_DONE\":\"Публикация завершена\",\"PUBLISH_STATE_BUILDING\":\"Сборка изменений ...\",\"PUBLISH_STATE_PUBLISH\":\"Публикация изменений ...\",\"PUBLISH_STATE_DONE\":\"Публикация завершена.\",\"FIND_FILES\":\"Поиск файла\",\"FIND_FILES_PLACEHOLDER\":\"Введите имя страницы ...\",\"ATTACHMENT_TYPE\":\"Тип вложения\",\"URL_SLUG\":\"Краткий заголовок для URL\",\"TEMPLATE\":\"Шаблон\",\"HIDE_PAGE\":\"Скрыть страницу\",\"HIDE_PAGE_EXPLANATION\":\"Скрыть данную страницу?\",\"REFRESH_BUILD\":\"Обновить сборку\",\"REFRESH_BUILD_NOTE\":\"В некоторых ситуациях бывает полезно заново пересобрать страницы вебсайта: например, когда произошёл сбой синхронизации или ошибка в шаблоне привела к некорректному отображению вебсайта.\",\"CURRENTLY_REFRESHING_BUILD\":\"Обновление сборки ...\",\"REFRESHING_BUILD_DONE\":\"Сборка обновлена!\",\"FAILED_TO_LAUNCH_LEKTOR\":\"Не удалось запустить Lektor.\",\"PROJECT\":\"Проект\",\"CLOSE_PROJECT\":\"Закрыть проект\",\"OPEN_PROJECT\":\"Открыть проект\",\"BROWSE_WEBSITE\":\"Открыть вебсайт\",\"VIEW_ADMIN_PANEL\":\"Открыть админ-панель\",\"QUIT\":\"Выйти\",\"FAILED_TO_LOAD_PROJECT\":\"Не удалось загрузить проект :(\",\"LOADING_PROJECT\":\"Загрузка проекта ...\",\"INITIALIZING_LEKTOR\":\"Инициализация Lektor ...\",\"QUIT_LEKTOR\":\"Выйти из Lektor\",\"FILE\":\"Файл\",\"UNDO\":\"Отменить\",\"REDO\":\"Повторить\",\"CUT\":\"Вырезать\",\"COPY\":\"Копировать\",\"PASTE\":\"Вставить\",\"SELECT_ALL\":\"Выделить всё\",\"HELP\":\"Помощь\",\"VISIT_WEBSITE\":\"Открыть вебсайт\",\"INSTALL_SHELL_COMMAND\":\"Установить команду для терминала\",\"INSTALL_SHELL_COMMAND_QUESTION\":\"Вы хотите установить команду 'lektor' для терминала? Для этого необходимы права администратора.\",\"FAILED_TO_INSTALL_SHELL_COMMANDS\":\"Не удалось установить команду для терминала.\",\"INSTALL_SHELL_COMMAND_SUCCESS\":\"Команда для терминала была успешно установлена.\",\"OPERATION_SUCCESS\":\"Операция завершена успешно\",\"YES\":\"Да\",\"NO\":\"Нет\",\"OK\":\"ОК\"}\n\n\n//////////////////\n// WEBPACK FOOTER\n// /home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/ru.json\n// module id = 296\n// module chunks = 0","module.exports = {\"RETURN_TO_WEBSITE\":\"回到網頁\",\"UNLOAD_ACTIVE_TAB\":\"你還有未儲存的資訊,確定要離開這個頁面?\",\"EDIT_METADATA\":\"編輯元資料\",\"EDIT\":\"編輯\",\"DELETE\":\"刪除\",\"PREVIEW\":\"預覽\",\"ALTS\":\"副語\",\"PRIMARY_ALT\":\"主語\",\"PRIMARY_OVERLAY\":\"Overlaid\",\"ADD_CHILD_PAGE\":\"新增頁面\",\"ADD_ATTACHMENT\":\"新增附件\",\"ATTACHMENT_ACTIONS\":\"附件行為\",\"PAGE_ACTIONS\":\"頁面行為\",\"NO_CHILD_PAGES\":\"沒有附件\",\"CHILD_PAGES\":\"子頁面\",\"NO_ATTACHMENTS\":\"沒有附件\",\"ATTACHMENTS\":\"附件\",\"ADD_ATTACHMENT_TO\":\"新增附件到「%s」\",\"ADD_ATTACHMENT_NOTE\":\"你可以在這裡上傳新的附件。\",\"UPLOAD\":\"上傳\",\"PROGRESS\":\"進度\",\"ERROR_PREFIX\":\"錯誤:\",\"ERROR_NO_ID_PROVIDED\":\"錯誤:沒有提供ID。\",\"ERROR_PAGE_ID_DUPLICATE\":\"已經有頁面的ID跟這個ID(%s)一樣了。\",\"ERROR_INVALID_ID\":\"無效的ID\",\"ERROR_INVALID_DATE\":\"無效的日期\",\"ERROR_INVALID_NUMBER\":\"無效的數字\",\"ERROR_INVALID_URL\":\"無效的URL\",\"ERROR\":\"錯誤\",\"ERROR_OCURRED\":\"發生錯誤\",\"ERROR_REQUEST_FAILED\":\"無法傳送指令到伺服器,可能它被關了或沒回應?\",\"ERROR_SERVER_UNAVAILABLE\":\"伺服器掛掉了\",\"ERROR_SERVER_UNAVAILABLE_MESSAGE\":\"伺服器目前沒回應,它可能已被關閉或是遇到嚴重錯誤導致無法運作,伺服器需要重新啟動。\",\"MODEL\":\"模型\",\"ADD_CHILD_PAGE_TO\":\"新增子面頁到 「%s」\",\"ADD_CHILD_PAGE_NOTE\":\"你可以在這裡加入新的子頁面,注意模型及ID之後無法輕易更改。\",\"CREATE_CHILD_PAGE\":\"新增子頁面\",\"DELETE_ATTACHMENT_PROMPT\":\"真的要刪除這個附件?\",\"DELETE_ATTACHMENT_ALT_PROMPT\":\"你真的想刪除這個副語附件的元資料嗎?\",\"DELETE_PAGE_PROMPT\":\"真的要刪除這個頁面?\",\"DELETE_PAGE_ALT_PROMPT\":\"你真的想刪除這個分支嗎?\",\"DELETE_PAGE_CHILDREN_WARNING\":\"這也會把這個頁面的子頁面刪除。\",\"DELETE_RECORD\":\"刪除「%s」\",\"DELETE_ALL_PAGE_ALTS\":\"順便刪除所有副語及附加檔案。\",\"DELETE_ALL_ATTACHMENT_ALTS\":\"刪除所有副語及附加檔案。\",\"DELETE_ONLY_PRIMARY_PAGE_ALT\":\"只刪除主語的紀錄,附件、副語、及子頁面不會被刪除。\",\"DELETE_ONLY_PRIMARY_ATTACHMENT_ALT\":\"只刪除主語紀錄的元資料。\",\"DELETE_PRIMARY_ALT_INFO\":\"主語可以被單獨刪除,或是連同副語一起刪除。\",\"CHILD_PAGES_TO_BE_DELETED\":\"即將被刪除的子頁面:\",\"ALTS_TO_BE_DELETED\":\"即將被刪除的副語:\",\"ATTACHMENTS_TO_BE_DELETED\":\"即將被刪除的附件:\",\"YES_DELETE\":\"對,就是要把它刪掉!\",\"NO_CANCEL\":\"還是不要好了...\",\"SYSTEM_FIELDS\":\"系統欄位\",\"EDIT_ATTACHMENT_METADATA_OF\":\"編輯附件「%s」的元資料\",\"EDIT_PAGE_NAME\":\"編輯「%s」\",\"SAVE_CHANGES\":\"儲存變更\",\"BROWSE_FS\":\"用文件系統開啟\",\"BROWSE_FS_MAC\":\"用Finder開啟\",\"BROWSE_FS_WINDOWS\":\"用檔案總管開啟\",\"ERROR_CANNOT_BROWSE_FS\":\"錯誤:檔案還沒有存在。\",\"REMOVE_FLOWBLOCK_PROMPT\":\"你真的要刪掉這個區塊?\",\"ADD_FLOWBLOCK\":\"新增區塊\",\"INVALID_INPUT\":\"無效的輸入\",\"UP\":\"上\",\"DOWN\":\"下\",\"REMOVE\":\"移除\",\"ID\":\"ID\",\"CLOSE\":\"關閉\",\"CANCEL\":\"取消\",\"BACK_TO_OVERVIEW\":\"回到總覽\",\"PUBLISH\":\"發佈\",\"PUBLISH_NOTE\":\"你可以在這裡發佈網站目前的版本。\",\"PUBLISH_SERVER\":\"目標伺服器\",\"CURRENTLY_PUBLISHING\":\"發佈中...\",\"STATE\":\"狀態\",\"PUBLISH_DONE\":\"已發佈\",\"PUBLISH_STATE_BUILDING\":\"正在建置變更...\",\"PUBLISH_STATE_PUBLISH\":\"正在發佈變更...\",\"PUBLISH_STATE_DONE\":\"發佈完成。\",\"FIND_FILES\":\"搜尋檔案\",\"FIND_FILES_PLACEHOLDER\":\"輸入頁面名稱...\",\"ATTACHMENT_TYPE\":\"附件類型\",\"URL_SLUG\":\"URL縮略名\",\"TEMPLATE\":\"模板\",\"HIDE_PAGE\":\"隱藏頁面\",\"HIDE_PAGE_EXPLANATION\":\"要隱藏這個頁面嗎?\",\"PAGE_IS_DISCOVERABLE\":\"網頁可以被發現\",\"PAGE_IS_DISCOVERABLE_EXPLANATION\":\"若啟用則這個頁面可以被發現,否則必須知道URL才能連結到這裡。\",\"REFRESH_BUILD\":\"重新整理建置\",\"REFRESH_BUILD_NOTE\":\"這會刪掉所有緩存的建置結果並導致重新置建。這在特殊情況(如同步錯誤、模板出錯等)下會有用。\",\"CURRENTLY_REFRESHING_BUILD\":\"刷新建置中...\",\"REFRESHING_BUILD_DONE\":\"完成刷新建置!\",\"FAILED_TO_LAUNCH_LEKTOR\":\"啟動Lektor失敗。\",\"PROJECT\":\"專案\",\"CLOSE_PROJECT\":\"關閉專案\",\"OPEN_PROJECT\":\"開啟專案\",\"BROWSE_WEBSITE\":\"瀏覽網站\",\"VIEW_ADMIN_PANEL\":\"查看管理員面板\",\"QUIT\":\"離開\",\"FAILED_TO_LOAD_PROJECT\":\"讀取專案失敗 QAQ\",\"LOADING_PROJECT\":\"讀取專案中...\",\"INITIALIZING_LEKTOR\":\"初始化Lektor中...\",\"QUIT_LEKTOR\":\"離開Lektor\",\"FILE\":\"檔案\",\"UNDO\":\"復原\",\"REDO\":\"重做\",\"CUT\":\"剪下\",\"COPY\":\"複製\",\"PASTE\":\"貼上\",\"SELECT_ALL\":\"全選\",\"HELP\":\"說明\",\"VISIT_WEBSITE\":\"參觀網站\",\"INSTALL_SHELL_COMMAND\":\"安裝命令列模式\",\"INSTALL_SHELL_COMMAND_QUESTION\":\"你想安裝lektor命令列模式嗎? 這需要管理員權限。\",\"FAILED_TO_INSTALL_SHELL_COMMANDS\":\"安裝命令列模式失敗。\",\"INSTALL_SHELL_COMMAND_SUCCESS\":\"命令列模式安裝成功\",\"OPERATION_SUCCESS\":\"成功\",\"YES\":\"是\",\"NO\":\"否\",\"OK\":\"好\",\"FAILED_TO_OPEN_CONTENT_FILE\":\"開啟檔案失敗\",\"OPEN_OTHER_PROJECT\":\"開啟其它專案\",\"OPEN_OTHER_PROJECT_QUESTION\":\"開啟這份檔案需要連同開啟另一個專案(%s),目前的專案將會被關閉,確定要繼續?\"}\n\n\n//////////////////\n// WEBPACK FOOTER\n// /home/nemo/wrkspc/lktr-prjcts/lektor/lektor/translations/zh.json\n// module id = 297\n// module chunks = 0","'use strict';\n\nexports.__esModule = true;\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar _deprecate = require('./deprecate');\n\nvar _deprecate2 = _interopRequireDefault(_deprecate);\n\nvar _createLocation2 = require('./createLocation');\n\nvar _createLocation3 = _interopRequireDefault(_createLocation2);\n\nvar _createBrowserHistory = require('./createBrowserHistory');\n\nvar _createBrowserHistory2 = _interopRequireDefault(_createBrowserHistory);\n\nexports.createHistory = _createBrowserHistory2['default'];\n\nvar _createHashHistory2 = require('./createHashHistory');\n\nvar _createHashHistory3 = _interopRequireDefault(_createHashHistory2);\n\nexports.createHashHistory = _createHashHistory3['default'];\n\nvar _createMemoryHistory2 = require('./createMemoryHistory');\n\nvar _createMemoryHistory3 = _interopRequireDefault(_createMemoryHistory2);\n\nexports.createMemoryHistory = _createMemoryHistory3['default'];\n\nvar _useBasename2 = require('./useBasename');\n\nvar _useBasename3 = _interopRequireDefault(_useBasename2);\n\nexports.useBasename = _useBasename3['default'];\n\nvar _useBeforeUnload2 = require('./useBeforeUnload');\n\nvar _useBeforeUnload3 = _interopRequireDefault(_useBeforeUnload2);\n\nexports.useBeforeUnload = _useBeforeUnload3['default'];\n\nvar _useQueries2 = require('./useQueries');\n\nvar _useQueries3 = _interopRequireDefault(_useQueries2);\n\nexports.useQueries = _useQueries3['default'];\n\nvar _Actions2 = require('./Actions');\n\nvar _Actions3 = _interopRequireDefault(_Actions2);\n\nexports.Actions = _Actions3['default'];\n\n// deprecated\n\nvar _enableBeforeUnload2 = require('./enableBeforeUnload');\n\nvar _enableBeforeUnload3 = _interopRequireDefault(_enableBeforeUnload2);\n\nexports.enableBeforeUnload = _enableBeforeUnload3['default'];\n\nvar _enableQueries2 = require('./enableQueries');\n\nvar _enableQueries3 = _interopRequireDefault(_enableQueries2);\n\nexports.enableQueries = _enableQueries3['default'];\nvar createLocation = _deprecate2['default'](_createLocation3['default'], 'Using createLocation without a history instance is deprecated; please use history.createLocation instead');\nexports.createLocation = createLocation;\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/history/lib/index.js\n// module id = 298\n// module chunks = 0","\"use strict\";\n\nexports.__esModule = true;\nexports.loopAsync = loopAsync;\n\nfunction loopAsync(turns, work, callback) {\n var currentTurn = 0;\n var isDone = false;\n\n function done() {\n isDone = true;\n callback.apply(this, arguments);\n }\n\n function next() {\n if (isDone) return;\n\n if (currentTurn < turns) {\n work.call(this, currentTurn++, next, done);\n } else {\n done.apply(this, arguments);\n }\n }\n\n next();\n}\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/history/lib/AsyncUtils.js\n// module id = 299\n// module chunks = 0","'use strict';\n\nexports.__esModule = true;\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar _warning = require('warning');\n\nvar _warning2 = _interopRequireDefault(_warning);\n\nvar _invariant = require('invariant');\n\nvar _invariant2 = _interopRequireDefault(_invariant);\n\nvar _Actions = require('./Actions');\n\nvar _ExecutionEnvironment = require('./ExecutionEnvironment');\n\nvar _DOMUtils = require('./DOMUtils');\n\nvar _DOMStateStorage = require('./DOMStateStorage');\n\nvar _createDOMHistory = require('./createDOMHistory');\n\nvar _createDOMHistory2 = _interopRequireDefault(_createDOMHistory);\n\nvar _parsePath = require('./parsePath');\n\nvar _parsePath2 = _interopRequireDefault(_parsePath);\n\nfunction isAbsolutePath(path) {\n return typeof path === 'string' && path.charAt(0) === '/';\n}\n\nfunction ensureSlash() {\n var path = _DOMUtils.getHashPath();\n\n if (isAbsolutePath(path)) return true;\n\n _DOMUtils.replaceHashPath('/' + path);\n\n return false;\n}\n\nfunction addQueryStringValueToPath(path, key, value) {\n return path + (path.indexOf('?') === -1 ? '?' : '&') + (key + '=' + value);\n}\n\nfunction stripQueryStringValueFromPath(path, key) {\n return path.replace(new RegExp('[?&]?' + key + '=[a-zA-Z0-9]+'), '');\n}\n\nfunction getQueryStringValueFromPath(path, key) {\n var match = path.match(new RegExp('\\\\?.*?\\\\b' + key + '=(.+?)\\\\b'));\n return match && match[1];\n}\n\nvar DefaultQueryKey = '_k';\n\nfunction createHashHistory() {\n var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];\n\n !_ExecutionEnvironment.canUseDOM ? process.env.NODE_ENV !== 'production' ? _invariant2['default'](false, 'Hash history needs a DOM') : _invariant2['default'](false) : undefined;\n\n var queryKey = options.queryKey;\n\n if (queryKey === undefined || !!queryKey) queryKey = typeof queryKey === 'string' ? queryKey : DefaultQueryKey;\n\n function getCurrentLocation() {\n var path = _DOMUtils.getHashPath();\n\n var key = undefined,\n state = undefined;\n if (queryKey) {\n key = getQueryStringValueFromPath(path, queryKey);\n path = stripQueryStringValueFromPath(path, queryKey);\n\n if (key) {\n state = _DOMStateStorage.readState(key);\n } else {\n state = null;\n key = history.createKey();\n _DOMUtils.replaceHashPath(addQueryStringValueToPath(path, queryKey, key));\n }\n } else {\n key = state = null;\n }\n\n var location = _parsePath2['default'](path);\n\n return history.createLocation(_extends({}, location, { state: state }), undefined, key);\n }\n\n function startHashChangeListener(_ref) {\n var transitionTo = _ref.transitionTo;\n\n function hashChangeListener() {\n if (!ensureSlash()) return; // Always make sure hashes are preceeded with a /.\n\n transitionTo(getCurrentLocation());\n }\n\n ensureSlash();\n _DOMUtils.addEventListener(window, 'hashchange', hashChangeListener);\n\n return function () {\n _DOMUtils.removeEventListener(window, 'hashchange', hashChangeListener);\n };\n }\n\n function finishTransition(location) {\n var basename = location.basename;\n var pathname = location.pathname;\n var search = location.search;\n var state = location.state;\n var action = location.action;\n var key = location.key;\n\n if (action === _Actions.POP) return; // Nothing to do.\n\n var path = (basename || '') + pathname + search;\n\n if (queryKey) {\n path = addQueryStringValueToPath(path, queryKey, key);\n _DOMStateStorage.saveState(key, state);\n } else {\n // Drop key and state.\n location.key = location.state = null;\n }\n\n var currentHash = _DOMUtils.getHashPath();\n\n if (action === _Actions.PUSH) {\n if (currentHash !== path) {\n window.location.hash = path;\n } else {\n process.env.NODE_ENV !== 'production' ? _warning2['default'](false, 'You cannot PUSH the same path using hash history') : undefined;\n }\n } else if (currentHash !== path) {\n // REPLACE\n _DOMUtils.replaceHashPath(path);\n }\n }\n\n var history = _createDOMHistory2['default'](_extends({}, options, {\n getCurrentLocation: getCurrentLocation,\n finishTransition: finishTransition,\n saveState: _DOMStateStorage.saveState\n }));\n\n var listenerCount = 0,\n stopHashChangeListener = undefined;\n\n function listenBefore(listener) {\n if (++listenerCount === 1) stopHashChangeListener = startHashChangeListener(history);\n\n var unlisten = history.listenBefore(listener);\n\n return function () {\n unlisten();\n\n if (--listenerCount === 0) stopHashChangeListener();\n };\n }\n\n function listen(listener) {\n if (++listenerCount === 1) stopHashChangeListener = startHashChangeListener(history);\n\n var unlisten = history.listen(listener);\n\n return function () {\n unlisten();\n\n if (--listenerCount === 0) stopHashChangeListener();\n };\n }\n\n function push(location) {\n process.env.NODE_ENV !== 'production' ? _warning2['default'](queryKey || location.state == null, 'You cannot use state without a queryKey it will be dropped') : undefined;\n\n history.push(location);\n }\n\n function replace(location) {\n process.env.NODE_ENV !== 'production' ? _warning2['default'](queryKey || location.state == null, 'You cannot use state without a queryKey it will be dropped') : undefined;\n\n history.replace(location);\n }\n\n var goIsSupportedWithoutReload = _DOMUtils.supportsGoWithoutReloadUsingHash();\n\n function go(n) {\n process.env.NODE_ENV !== 'production' ? _warning2['default'](goIsSupportedWithoutReload, 'Hash history go(n) causes a full page reload in this browser') : undefined;\n\n history.go(n);\n }\n\n function createHref(path) {\n return '#' + history.createHref(path);\n }\n\n // deprecated\n function registerTransitionHook(hook) {\n if (++listenerCount === 1) stopHashChangeListener = startHashChangeListener(history);\n\n history.registerTransitionHook(hook);\n }\n\n // deprecated\n function unregisterTransitionHook(hook) {\n history.unregisterTransitionHook(hook);\n\n if (--listenerCount === 0) stopHashChangeListener();\n }\n\n // deprecated\n function pushState(state, path) {\n process.env.NODE_ENV !== 'production' ? _warning2['default'](queryKey || state == null, 'You cannot use state without a queryKey it will be dropped') : undefined;\n\n history.pushState(state, path);\n }\n\n // deprecated\n function replaceState(state, path) {\n process.env.NODE_ENV !== 'production' ? _warning2['default'](queryKey || state == null, 'You cannot use state without a queryKey it will be dropped') : undefined;\n\n history.replaceState(state, path);\n }\n\n return _extends({}, history, {\n listenBefore: listenBefore,\n listen: listen,\n push: push,\n replace: replace,\n go: go,\n createHref: createHref,\n\n registerTransitionHook: registerTransitionHook, // deprecated - warning is in createHistory\n unregisterTransitionHook: unregisterTransitionHook, // deprecated - warning is in createHistory\n pushState: pushState, // deprecated - warning is in createHistory\n replaceState: replaceState // deprecated - warning is in createHistory\n });\n}\n\nexports['default'] = createHashHistory;\nmodule.exports = exports['default'];\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/history/lib/createHashHistory.js\n// module id = 300\n// module chunks = 0","'use strict';\n\nexports.__esModule = true;\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar _warning = require('warning');\n\nvar _warning2 = _interopRequireDefault(_warning);\n\nvar _invariant = require('invariant');\n\nvar _invariant2 = _interopRequireDefault(_invariant);\n\nvar _Actions = require('./Actions');\n\nvar _createHistory = require('./createHistory');\n\nvar _createHistory2 = _interopRequireDefault(_createHistory);\n\nvar _parsePath = require('./parsePath');\n\nvar _parsePath2 = _interopRequireDefault(_parsePath);\n\nfunction createStateStorage(entries) {\n return entries.filter(function (entry) {\n return entry.state;\n }).reduce(function (memo, entry) {\n memo[entry.key] = entry.state;\n return memo;\n }, {});\n}\n\nfunction createMemoryHistory() {\n var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];\n\n if (Array.isArray(options)) {\n options = { entries: options };\n } else if (typeof options === 'string') {\n options = { entries: [options] };\n }\n\n var history = _createHistory2['default'](_extends({}, options, {\n getCurrentLocation: getCurrentLocation,\n finishTransition: finishTransition,\n saveState: saveState,\n go: go\n }));\n\n var _options = options;\n var entries = _options.entries;\n var current = _options.current;\n\n if (typeof entries === 'string') {\n entries = [entries];\n } else if (!Array.isArray(entries)) {\n entries = ['/'];\n }\n\n entries = entries.map(function (entry) {\n var key = history.createKey();\n\n if (typeof entry === 'string') return { pathname: entry, key: key };\n\n if (typeof entry === 'object' && entry) return _extends({}, entry, { key: key });\n\n !false ? process.env.NODE_ENV !== 'production' ? _invariant2['default'](false, 'Unable to create history entry from %s', entry) : _invariant2['default'](false) : undefined;\n });\n\n if (current == null) {\n current = entries.length - 1;\n } else {\n !(current >= 0 && current < entries.length) ? process.env.NODE_ENV !== 'production' ? _invariant2['default'](false, 'Current index must be >= 0 and < %s, was %s', entries.length, current) : _invariant2['default'](false) : undefined;\n }\n\n var storage = createStateStorage(entries);\n\n function saveState(key, state) {\n storage[key] = state;\n }\n\n function readState(key) {\n return storage[key];\n }\n\n function getCurrentLocation() {\n var entry = entries[current];\n var key = entry.key;\n var basename = entry.basename;\n var pathname = entry.pathname;\n var search = entry.search;\n\n var path = (basename || '') + pathname + (search || '');\n\n var state = undefined;\n if (key) {\n state = readState(key);\n } else {\n state = null;\n key = history.createKey();\n entry.key = key;\n }\n\n var location = _parsePath2['default'](path);\n\n return history.createLocation(_extends({}, location, { state: state }), undefined, key);\n }\n\n function canGo(n) {\n var index = current + n;\n return index >= 0 && index < entries.length;\n }\n\n function go(n) {\n if (n) {\n if (!canGo(n)) {\n process.env.NODE_ENV !== 'production' ? _warning2['default'](false, 'Cannot go(%s) there is not enough history', n) : undefined;\n return;\n }\n\n current += n;\n\n var currentLocation = getCurrentLocation();\n\n // change action to POP\n history.transitionTo(_extends({}, currentLocation, { action: _Actions.POP }));\n }\n }\n\n function finishTransition(location) {\n switch (location.action) {\n case _Actions.PUSH:\n current += 1;\n\n // if we are not on the top of stack\n // remove rest and push new\n if (current < entries.length) entries.splice(current);\n\n entries.push(location);\n saveState(location.key, location.state);\n break;\n case _Actions.REPLACE:\n entries[current] = location;\n saveState(location.key, location.state);\n break;\n }\n }\n\n return history;\n}\n\nexports['default'] = createMemoryHistory;\nmodule.exports = exports['default'];\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/history/lib/createMemoryHistory.js\n// module id = 301\n// module chunks = 0","'use strict';\n\nexports.__esModule = true;\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nfunction _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }\n\nvar _ExecutionEnvironment = require('./ExecutionEnvironment');\n\nvar _runTransitionHook = require('./runTransitionHook');\n\nvar _runTransitionHook2 = _interopRequireDefault(_runTransitionHook);\n\nvar _extractPath = require('./extractPath');\n\nvar _extractPath2 = _interopRequireDefault(_extractPath);\n\nvar _parsePath = require('./parsePath');\n\nvar _parsePath2 = _interopRequireDefault(_parsePath);\n\nvar _deprecate = require('./deprecate');\n\nvar _deprecate2 = _interopRequireDefault(_deprecate);\n\nfunction useBasename(createHistory) {\n return function () {\n var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];\n var basename = options.basename;\n\n var historyOptions = _objectWithoutProperties(options, ['basename']);\n\n var history = createHistory(historyOptions);\n\n // Automatically use the value of in HTML\n // documents as basename if it's not explicitly given.\n if (basename == null && _ExecutionEnvironment.canUseDOM) {\n var base = document.getElementsByTagName('base')[0];\n\n if (base) basename = _extractPath2['default'](base.href);\n }\n\n function addBasename(location) {\n if (basename && location.basename == null) {\n if (location.pathname.indexOf(basename) === 0) {\n location.pathname = location.pathname.substring(basename.length);\n location.basename = basename;\n\n if (location.pathname === '') location.pathname = '/';\n } else {\n location.basename = '';\n }\n }\n\n return location;\n }\n\n function prependBasename(location) {\n if (!basename) return location;\n\n if (typeof location === 'string') location = _parsePath2['default'](location);\n\n var pname = location.pathname;\n var normalizedBasename = basename.slice(-1) === '/' ? basename : basename + '/';\n var normalizedPathname = pname.charAt(0) === '/' ? pname.slice(1) : pname;\n var pathname = normalizedBasename + normalizedPathname;\n\n return _extends({}, location, {\n pathname: pathname\n });\n }\n\n // Override all read methods with basename-aware versions.\n function listenBefore(hook) {\n return history.listenBefore(function (location, callback) {\n _runTransitionHook2['default'](hook, addBasename(location), callback);\n });\n }\n\n function listen(listener) {\n return history.listen(function (location) {\n listener(addBasename(location));\n });\n }\n\n // Override all write methods with basename-aware versions.\n function push(location) {\n history.push(prependBasename(location));\n }\n\n function replace(location) {\n history.replace(prependBasename(location));\n }\n\n function createPath(location) {\n return history.createPath(prependBasename(location));\n }\n\n function createHref(location) {\n return history.createHref(prependBasename(location));\n }\n\n function createLocation() {\n return addBasename(history.createLocation.apply(history, arguments));\n }\n\n // deprecated\n function pushState(state, path) {\n if (typeof path === 'string') path = _parsePath2['default'](path);\n\n push(_extends({ state: state }, path));\n }\n\n // deprecated\n function replaceState(state, path) {\n if (typeof path === 'string') path = _parsePath2['default'](path);\n\n replace(_extends({ state: state }, path));\n }\n\n return _extends({}, history, {\n listenBefore: listenBefore,\n listen: listen,\n push: push,\n replace: replace,\n createPath: createPath,\n createHref: createHref,\n createLocation: createLocation,\n\n pushState: _deprecate2['default'](pushState, 'pushState is deprecated; use push instead'),\n replaceState: _deprecate2['default'](replaceState, 'replaceState is deprecated; use replace instead')\n });\n };\n}\n\nexports['default'] = useBasename;\nmodule.exports = exports['default'];\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/history/lib/useBasename.js\n// module id = 302\n// module chunks = 0","'use strict';\n\nexports.__esModule = true;\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar _deprecate = require('./deprecate');\n\nvar _deprecate2 = _interopRequireDefault(_deprecate);\n\nvar _useBeforeUnload = require('./useBeforeUnload');\n\nvar _useBeforeUnload2 = _interopRequireDefault(_useBeforeUnload);\n\nexports['default'] = _deprecate2['default'](_useBeforeUnload2['default'], 'enableBeforeUnload is deprecated, use useBeforeUnload instead');\nmodule.exports = exports['default'];\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/history/lib/enableBeforeUnload.js\n// module id = 303\n// module chunks = 0","'use strict';\n\nexports.__esModule = true;\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar _deprecate = require('./deprecate');\n\nvar _deprecate2 = _interopRequireDefault(_deprecate);\n\nvar _useQueries = require('./useQueries');\n\nvar _useQueries2 = _interopRequireDefault(_useQueries);\n\nexports['default'] = _deprecate2['default'](_useQueries2['default'], 'enableQueries is deprecated, use useQueries instead');\nmodule.exports = exports['default'];\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/history/lib/enableQueries.js\n// module id = 304\n// module chunks = 0","import $ from 'jquery'\n\n$(document).ready(function () {\n $('[data-toggle=offcanvas]').click(function () {\n const target = $($(this).attr('data-target') || '.block-offcanvas')\n const isActive = target.is('.active')\n target.toggleClass('active', !isActive)\n $(this).toggleClass('active', !isActive)\n })\n})\n\n\n\n// WEBPACK FOOTER //\n// ./js/bootstrap-extras.jsx","// removed by extract-text-webpack-plugin\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/font-awesome/css/font-awesome.css\n// module id = 318\n// module chunks = 0","/** @license\r\n * eventsource.js\r\n * Available under MIT License (MIT)\r\n * https://github.com/Yaffle/EventSource/\r\n */\r\n\r\n/*jslint indent: 2, vars: true, plusplus: true */\r\n/*global setTimeout, clearTimeout */\r\n\r\n(function (global) {\r\n \"use strict\";\r\n\r\n function Map() {\r\n this.data = {};\r\n }\r\n\r\n Map.prototype.get = function (key) {\r\n return this.data[key + \"~\"];\r\n };\r\n Map.prototype.set = function (key, value) {\r\n this.data[key + \"~\"] = value;\r\n };\r\n Map.prototype[\"delete\"] = function (key) {\r\n delete this.data[key + \"~\"];\r\n };\r\n\r\n function EventTarget() {\r\n this.listeners = new Map();\r\n }\r\n\r\n function throwError(e) {\r\n setTimeout(function () {\r\n throw e;\r\n }, 0);\r\n }\r\n\r\n EventTarget.prototype.dispatchEvent = function (event) {\r\n event.target = this;\r\n var type = event.type.toString();\r\n var listeners = this.listeners;\r\n var typeListeners = listeners.get(type);\r\n if (typeListeners == undefined) {\r\n return;\r\n }\r\n var length = typeListeners.length;\r\n var i = -1;\r\n var listener = undefined;\r\n while (++i < length) {\r\n listener = typeListeners[i];\r\n try {\r\n listener.call(this, event);\r\n } catch (e) {\r\n throwError(e);\r\n }\r\n }\r\n };\r\n EventTarget.prototype.addEventListener = function (type, callback) {\r\n type = type.toString();\r\n var listeners = this.listeners;\r\n var typeListeners = listeners.get(type);\r\n if (typeListeners == undefined) {\r\n typeListeners = [];\r\n listeners.set(type, typeListeners);\r\n }\r\n var i = typeListeners.length;\r\n while (--i >= 0) {\r\n if (typeListeners[i] === callback) {\r\n return;\r\n }\r\n }\r\n typeListeners.push(callback);\r\n };\r\n EventTarget.prototype.removeEventListener = function (type, callback) {\r\n type = type.toString();\r\n var listeners = this.listeners;\r\n var typeListeners = listeners.get(type);\r\n if (typeListeners == undefined) {\r\n return;\r\n }\r\n var length = typeListeners.length;\r\n var filtered = [];\r\n var i = -1;\r\n while (++i < length) {\r\n if (typeListeners[i] !== callback) {\r\n filtered.push(typeListeners[i]);\r\n }\r\n }\r\n if (filtered.length === 0) {\r\n listeners[\"delete\"](type);\r\n } else {\r\n listeners.set(type, filtered);\r\n }\r\n };\r\n\r\n function Event(type) {\r\n this.type = type;\r\n this.target = undefined;\r\n }\r\n\r\n function MessageEvent(type, options) {\r\n Event.call(this, type);\r\n this.data = options.data;\r\n this.lastEventId = options.lastEventId;\r\n }\r\n\r\n MessageEvent.prototype = Event.prototype;\r\n\r\n var XHR = global.XMLHttpRequest;\r\n var XDR = global.XDomainRequest;\r\n var isCORSSupported = XHR != undefined && (new XHR()).withCredentials != undefined;\r\n var isXHR = isCORSSupported;\r\n var Transport = isCORSSupported ? XHR : (XDR != undefined ? XDR : undefined);\r\n var WAITING = -1;\r\n var CONNECTING = 0;\r\n var OPEN = 1;\r\n var CLOSED = 2;\r\n var AFTER_CR = 3;\r\n var FIELD_START = 4;\r\n var FIELD = 5;\r\n var VALUE_START = 6;\r\n var VALUE = 7;\r\n var contentTypeRegExp = /^text\\/event\\-stream;?(\\s*charset\\=utf\\-8)?$/i;\r\n\r\n var MINIMUM_DURATION = 1000;\r\n var MAXIMUM_DURATION = 18000000;\r\n\r\n function getDuration(value, def) {\r\n var n = value;\r\n if (n !== n) {\r\n n = def;\r\n }\r\n return (n < MINIMUM_DURATION ? MINIMUM_DURATION : (n > MAXIMUM_DURATION ? MAXIMUM_DURATION : n));\r\n }\r\n\r\n function fire(that, f, event) {\r\n try {\r\n if (typeof f === \"function\") {\r\n f.call(that, event);\r\n }\r\n } catch (e) {\r\n throwError(e);\r\n }\r\n }\r\n\r\n function EventSource(url, options) {\r\n url = url.toString();\r\n\r\n var withCredentials = isCORSSupported && options != undefined && Boolean(options.withCredentials);\r\n var initialRetry = getDuration(1000, 0);\r\n var heartbeatTimeout = getDuration(45000, 0);\r\n\r\n var lastEventId = \"\";\r\n var that = this;\r\n var retry = initialRetry;\r\n var wasActivity = false;\r\n var xhr = options != undefined && options.Transport != undefined ? new options.Transport() : new Transport();\r\n var timeout = 0;\r\n var timeout0 = 0;\r\n var charOffset = 0;\r\n var currentState = WAITING;\r\n var dataBuffer = [];\r\n var lastEventIdBuffer = \"\";\r\n var eventTypeBuffer = \"\";\r\n var onTimeout = undefined;\r\n\r\n var state = FIELD_START;\r\n var field = \"\";\r\n var value = \"\";\r\n\r\n function close() {\r\n currentState = CLOSED;\r\n if (xhr != undefined) {\r\n xhr.abort();\r\n xhr = undefined;\r\n }\r\n if (timeout !== 0) {\r\n clearTimeout(timeout);\r\n timeout = 0;\r\n }\r\n if (timeout0 !== 0) {\r\n clearTimeout(timeout0);\r\n timeout0 = 0;\r\n }\r\n that.readyState = CLOSED;\r\n }\r\n\r\n function onEvent(type) {\r\n var responseText = currentState === OPEN || currentState === CONNECTING ? xhr.responseText : \"\";\r\n var event = undefined;\r\n var isWrongStatusCodeOrContentType = false;\r\n\r\n if (currentState === CONNECTING) {\r\n var status = 0;\r\n var statusText = \"\";\r\n var contentType = undefined;\r\n if (isXHR) {\r\n try {\r\n status = xhr.status;\r\n statusText = xhr.statusText;\r\n contentType = xhr.getResponseHeader(\"Content-Type\");\r\n } catch (error) {\r\n // https://bugs.webkit.org/show_bug.cgi?id=29121\r\n status = 0;\r\n statusText = \"\";\r\n contentType = undefined;\r\n // FF < 14, WebKit\r\n // https://bugs.webkit.org/show_bug.cgi?id=29658\r\n // https://bugs.webkit.org/show_bug.cgi?id=77854\r\n }\r\n } else if (type !== \"\" && type !== \"error\") {\r\n status = 200;\r\n statusText = \"OK\";\r\n contentType = xhr.contentType;\r\n }\r\n if (contentType == undefined) {\r\n contentType = \"\";\r\n }\r\n if (status === 0 && statusText === \"\" && type === \"load\" && responseText !== \"\") {\r\n status = 200;\r\n statusText = \"OK\";\r\n if (contentType === \"\") { // Opera 12\r\n var tmp = (/^data\\:([^,]*?)(?:;base64)?,[\\S]*$/).exec(url);\r\n if (tmp != undefined) {\r\n contentType = tmp[1];\r\n }\r\n }\r\n }\r\n if (status === 200 && contentTypeRegExp.test(contentType)) {\r\n currentState = OPEN;\r\n wasActivity = true;\r\n retry = initialRetry;\r\n that.readyState = OPEN;\r\n event = new Event(\"open\");\r\n that.dispatchEvent(event);\r\n fire(that, that.onopen, event);\r\n if (currentState === CLOSED) {\r\n return;\r\n }\r\n } else {\r\n // Opera 12\r\n if (status !== 0 && (status !== 200 || contentType !== \"\")) {\r\n var message = \"\";\r\n if (status !== 200) {\r\n message = \"EventSource's response has a status \" + status + \" \" + statusText.replace(/\\s+/g, \" \") + \" that is not 200. Aborting the connection.\";\r\n } else {\r\n message = \"EventSource's response has a Content-Type specifying an unsupported type: \" + contentType.replace(/\\s+/g, \" \") + \". Aborting the connection.\";\r\n }\r\n setTimeout(function () {\r\n throw new Error(message);\r\n }, 0);\r\n isWrongStatusCodeOrContentType = true;\r\n }\r\n }\r\n }\r\n\r\n if (currentState === OPEN) {\r\n if (responseText.length > charOffset) {\r\n wasActivity = true;\r\n }\r\n var i = charOffset - 1;\r\n var length = responseText.length;\r\n var c = \"\\n\";\r\n while (++i < length) {\r\n c = responseText.charAt(i);\r\n if (state === AFTER_CR && c === \"\\n\") {\r\n state = FIELD_START;\r\n } else {\r\n if (state === AFTER_CR) {\r\n state = FIELD_START;\r\n }\r\n if (c === \"\\r\" || c === \"\\n\") {\r\n if (field === \"data\") {\r\n dataBuffer.push(value);\r\n } else if (field === \"id\") {\r\n lastEventIdBuffer = value;\r\n } else if (field === \"event\") {\r\n eventTypeBuffer = value;\r\n } else if (field === \"retry\") {\r\n initialRetry = getDuration(Number(value), initialRetry);\r\n retry = initialRetry;\r\n } else if (field === \"heartbeatTimeout\") {\r\n heartbeatTimeout = getDuration(Number(value), heartbeatTimeout);\r\n if (timeout !== 0) {\r\n clearTimeout(timeout);\r\n timeout = setTimeout(onTimeout, heartbeatTimeout);\r\n }\r\n }\r\n value = \"\";\r\n field = \"\";\r\n if (state === FIELD_START) {\r\n if (dataBuffer.length !== 0) {\r\n lastEventId = lastEventIdBuffer;\r\n if (eventTypeBuffer === \"\") {\r\n eventTypeBuffer = \"message\";\r\n }\r\n event = new MessageEvent(eventTypeBuffer, {\r\n data: dataBuffer.join(\"\\n\"),\r\n lastEventId: lastEventIdBuffer\r\n });\r\n that.dispatchEvent(event);\r\n if (eventTypeBuffer === \"message\") {\r\n fire(that, that.onmessage, event);\r\n }\r\n if (currentState === CLOSED) {\r\n return;\r\n }\r\n }\r\n dataBuffer.length = 0;\r\n eventTypeBuffer = \"\";\r\n }\r\n state = c === \"\\r\" ? AFTER_CR : FIELD_START;\r\n } else {\r\n if (state === FIELD_START) {\r\n state = FIELD;\r\n }\r\n if (state === FIELD) {\r\n if (c === \":\") {\r\n state = VALUE_START;\r\n } else {\r\n field += c;\r\n }\r\n } else if (state === VALUE_START) {\r\n if (c !== \" \") {\r\n value += c;\r\n }\r\n state = VALUE;\r\n } else if (state === VALUE) {\r\n value += c;\r\n }\r\n }\r\n }\r\n }\r\n charOffset = length;\r\n }\r\n\r\n if ((currentState === OPEN || currentState === CONNECTING) &&\r\n (type === \"load\" || type === \"error\" || isWrongStatusCodeOrContentType || (charOffset > 1024 * 1024) || (timeout === 0 && !wasActivity))) {\r\n if (isWrongStatusCodeOrContentType) {\r\n close();\r\n } else {\r\n if (type === \"\" && timeout === 0 && !wasActivity) {\r\n setTimeout(function () {\r\n throw new Error(\"No activity within \" + heartbeatTimeout + \" milliseconds. Reconnecting.\");\r\n }, 0);\r\n }\r\n currentState = WAITING;\r\n xhr.abort();\r\n if (timeout !== 0) {\r\n clearTimeout(timeout);\r\n timeout = 0;\r\n }\r\n if (retry > initialRetry * 16) {\r\n retry = initialRetry * 16;\r\n }\r\n if (retry > MAXIMUM_DURATION) {\r\n retry = MAXIMUM_DURATION;\r\n }\r\n timeout = setTimeout(onTimeout, retry);\r\n retry = retry * 2 + 1;\r\n\r\n that.readyState = CONNECTING;\r\n }\r\n event = new Event(\"error\");\r\n that.dispatchEvent(event);\r\n fire(that, that.onerror, event);\r\n } else {\r\n if (timeout === 0) {\r\n wasActivity = false;\r\n timeout = setTimeout(onTimeout, heartbeatTimeout);\r\n }\r\n }\r\n }\r\n\r\n function onProgress() {\r\n onEvent(\"progress\");\r\n }\r\n\r\n function onLoad() {\r\n onEvent(\"load\");\r\n }\r\n\r\n function onError() {\r\n onEvent(\"error\");\r\n }\r\n\r\n if (isXHR && global.opera != undefined) {\r\n // workaround for Opera issue with \"progress\" events\r\n timeout0 = setTimeout(function f() {\r\n if (xhr.readyState === 3) {\r\n onEvent(\"progress\");\r\n }\r\n timeout0 = setTimeout(f, 500);\r\n }, 0);\r\n }\r\n\r\n onTimeout = function () {\r\n timeout = 0;\r\n if (currentState !== WAITING) {\r\n onEvent(\"\");\r\n return;\r\n }\r\n\r\n // loading indicator in Safari, Chrome < 14\r\n if (isXHR && !(\"onloadend\" in xhr) && global.document != undefined && global.document.readyState != undefined && global.document.readyState !== \"complete\") {\r\n timeout = setTimeout(onTimeout, 4);\r\n return;\r\n }\r\n\r\n // XDomainRequest#abort removes onprogress, onerror, onload\r\n xhr.onload = onLoad;\r\n xhr.onerror = onError;\r\n\r\n if (isXHR) {\r\n // improper fix to match Firefox behaviour, but it is better than just ignore abort\r\n // see https://bugzilla.mozilla.org/show_bug.cgi?id=768596\r\n // https://bugzilla.mozilla.org/show_bug.cgi?id=880200\r\n // https://code.google.com/p/chromium/issues/detail?id=153570\r\n xhr.onabort = onError;\r\n\r\n // Firefox 3.5 - 3.6 - ? < 9.0\r\n // onprogress is not fired sometimes or delayed\r\n xhr.onreadystatechange = onProgress;\r\n }\r\n\r\n // loading indicator in Firefox\r\n // https://bugzilla.mozilla.org/show_bug.cgi?id=736723\r\n if (xhr.sendAsBinary == undefined) {\r\n xhr.onprogress = onProgress;\r\n }\r\n\r\n wasActivity = false;\r\n timeout = setTimeout(onTimeout, heartbeatTimeout);\r\n\r\n charOffset = 0;\r\n currentState = CONNECTING;\r\n dataBuffer.length = 0;\r\n eventTypeBuffer = \"\";\r\n lastEventIdBuffer = lastEventId;\r\n value = \"\";\r\n field = \"\";\r\n state = FIELD_START;\r\n\r\n var s = url.slice(0, 5);\r\n if (s !== \"data:\" && s !== \"blob:\") {\r\n s = url + ((url.indexOf(\"?\", 0) === -1 ? \"?\" : \"&\") + \"lastEventId=\" + encodeURIComponent(lastEventId) + \"&r=\" + (Math.random() + 1).toString().slice(2));\r\n } else {\r\n s = url;\r\n }\r\n xhr.open(\"GET\", s, true);\r\n\r\n if (isXHR) {\r\n // withCredentials should be set after \"open\" for Safari and Chrome (< 19 ?)\r\n xhr.withCredentials = withCredentials;\r\n\r\n xhr.responseType = \"text\";\r\n\r\n // Request header field Cache-Control is not allowed by Access-Control-Allow-Headers.\r\n // \"Cache-control: no-cache\" are not honored in Chrome and Firefox\r\n // https://bugzilla.mozilla.org/show_bug.cgi?id=428916\r\n //xhr.setRequestHeader(\"Cache-Control\", \"no-cache\");\r\n xhr.setRequestHeader(\"Accept\", \"text/event-stream\");\r\n // Request header field Last-Event-ID is not allowed by Access-Control-Allow-Headers.\r\n //xhr.setRequestHeader(\"Last-Event-ID\", lastEventId);\r\n }\r\n\r\n xhr.send(undefined);\r\n };\r\n\r\n EventTarget.call(this);\r\n this.close = close;\r\n this.url = url;\r\n this.readyState = CONNECTING;\r\n this.withCredentials = withCredentials;\r\n\r\n this.onopen = undefined;\r\n this.onmessage = undefined;\r\n this.onerror = undefined;\r\n\r\n onTimeout();\r\n }\r\n\r\n function F() {\r\n this.CONNECTING = CONNECTING;\r\n this.OPEN = OPEN;\r\n this.CLOSED = CLOSED;\r\n }\r\n F.prototype = EventTarget.prototype;\r\n\r\n EventSource.prototype = new F();\r\n F.call(EventSource);\r\n\r\n var isEventSourceSupported = function () {\r\n if (global.EventSource != undefined) {\r\n try {\r\n var es = new global.EventSource(\"data:text/event-stream;charset=utf-8,\");\r\n es.close();\r\n return es.withCredentials === false &&\r\n es.url !== \"\"; // to filter out Opera 12 implementation\r\n } catch (error) {\r\n return false;\r\n }\r\n }\r\n return false;\r\n };\r\n\r\n if (Transport != undefined && !isEventSourceSupported()) {\r\n // Why replace a native EventSource ?\r\n // https://bugzilla.mozilla.org/show_bug.cgi?id=444328\r\n // https://bugzilla.mozilla.org/show_bug.cgi?id=831392\r\n // https://code.google.com/p/chromium/issues/detail?id=260144\r\n // https://code.google.com/p/chromium/issues/detail?id=225654\r\n // ...\r\n global.NativeEventSource = global.EventSource;\r\n global.EventSource = EventSource;\r\n }\r\n\r\n}(this));\r\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ../node_modules/event-source-polyfill/eventsource.js\n// module id = 322\n// module chunks = 0","'use strict'\n\nimport React from 'react'\nimport BreadCrumbs from '../components/BreadCrumbs'\nimport Sidebar from '../components/Sidebar'\nimport Component from '../components/Component'\nimport DialogSlot from '../components/DialogSlot'\nimport ServerStatus from '../components/ServerStatus'\n\nclass App extends Component {\n render () {\n return (\n
\n \n
\n \n \n \n
\n
\n \n
\n \n
\n {this.props.children}\n
\n
\n
\n
\n )\n }\n}\n\nexport default App\n\n\n\n// WEBPACK FOOTER //\n// ./js/views/App.jsx","'use strict'\n\nimport React from 'react'\nimport RecordComponent from './RecordComponent'\nimport Link from './Link'\nimport utils from '../utils'\nimport i18n from '../i18n'\nimport dialogSystem from '../dialogSystem'\nimport FindFiles from '../dialogs/findFiles'\nimport Publish from '../dialogs/publish'\nimport Refresh from '../dialogs/Refresh'\nimport makeRichPromise from '../richPromise'\n\nclass BreadCrumbs extends RecordComponent {\n constructor (props) {\n super(props)\n this.state = {\n recordPathInfo: null\n }\n this._onKeyPress = this._onKeyPress.bind(this)\n }\n\n componentDidMount () {\n super.componentDidMount()\n this.updateCrumbs()\n window.addEventListener('keydown', this._onKeyPress)\n }\n\n componentDidUpdate (prevProps, prevState) {\n super.componentDidUpdate(prevProps, prevState)\n if (prevProps.params.path !== this.props.params.path) {\n this.updateCrumbs()\n }\n }\n\n componentWillUnmount () {\n window.removeEventListener('keydown', this._onKeyPress)\n }\n\n updateCrumbs () {\n const path = this.getRecordPath()\n if (path === null) {\n this.setState({\n recordPathInfo: null\n })\n return\n }\n\n utils.loadData('/pathinfo', {path: path}, null, makeRichPromise)\n .then((resp) => {\n this.setState({\n recordPathInfo: {\n path: path,\n segments: resp.segments\n }\n })\n })\n }\n\n _onKeyPress (event) {\n // meta+g is open find files\n if (event.which === 71 && utils.isMetaKey(event)) {\n event.preventDefault()\n dialogSystem.showDialog(FindFiles)\n }\n }\n\n _onCloseClick (e) {\n utils.loadData('/previewinfo', {\n path: this.getRecordPath(),\n alt: this.getRecordAlt()\n }, null, makeRichPromise)\n .then((resp) => {\n if (resp.url === null) {\n window.location.href = utils.getCanonicalUrl('/')\n } else {\n window.location.href = utils.getCanonicalUrl(resp.url)\n }\n })\n }\n\n _onFindFiles (e) {\n dialogSystem.showDialog(FindFiles)\n }\n\n _onRefresh (e) {\n dialogSystem.showDialog(Refresh)\n }\n\n _onPublish (e) {\n dialogSystem.showDialog(Publish)\n }\n\n renderGlobalActions () {\n return (\n
\n \n \n \n \n
\n )\n }\n\n render () {\n let crumbs = []\n const target = this.isRecordPreviewActive() ? '.preview' : '.edit'\n let lastItem = null\n\n if (this.state.recordPathInfo != null) {\n crumbs = this.state.recordPathInfo.segments.map((item) => {\n const urlPath = this.getUrlRecordPathWithAlt(item.path)\n let label = item.label_i18n ? i18n.trans(item.label_i18n) : item.label\n let className = 'record-crumb'\n\n if (!item.exists) {\n label = item.id\n className += ' missing-record-crumb'\n }\n lastItem = item\n\n const adminPath = this.getPathToAdminPage(target, {path: urlPath})\n\n return (\n
  • \n {label}\n
  • \n )\n })\n } else {\n crumbs = (\n
  • \n {i18n.trans('BACK_TO_OVERVIEW')}
  • \n )\n }\n\n return (\n
    \n
      \n {this.props.children}\n {crumbs}\n {lastItem && lastItem.can_have_children ? (\n
    • \n +\n
    • \n ) : null}\n {' ' /* this space is needed for chrome ... */}\n
    • \n {this.renderGlobalActions()}\n
    • \n
    \n
    \n )\n }\n}\n\nexport default BreadCrumbs\n\n\n\n// WEBPACK FOOTER //\n// ./js/components/BreadCrumbs.jsx","'use strict'\n\nimport React from 'react'\n\nimport RecordComponent from '../components/RecordComponent'\nimport SlideDialog from '../components/SlideDialog'\nimport utils from '../utils'\nimport i18n from '../i18n'\nimport dialogSystem from '../dialogSystem'\nimport makeRichPromise from '../richPromise'\n\nclass FindFiles extends RecordComponent {\n constructor (props) {\n super(props)\n this.state = {\n query: '',\n currentSelection: -1,\n results: []\n }\n }\n\n componentDidMount () {\n super.componentDidMount()\n this.refs.q.focus()\n }\n\n onInputChange (e) {\n const q = e.target.value\n\n if (q === '') {\n this.setState({\n query: '',\n results: [],\n currentSelection: -1\n })\n } else {\n this.setState({\n query: q\n })\n\n utils.apiRequest('/find', {\n data: {\n q: q,\n alt: this.getRecordAlt(),\n lang: i18n.currentLanguage\n },\n method: 'POST'\n }, makeRichPromise).then((resp) => {\n this.setState({\n results: resp.results,\n currentSelection: Math.min(this.state.currentSelection,\n resp.results.length - 1)\n })\n })\n }\n }\n\n onInputKey (e) {\n let sel = this.state.currentSelection\n const max = this.state.results.length\n if (e.which === 40) {\n e.preventDefault()\n sel = (sel + 1) % max\n } else if (e.which === 38) {\n e.preventDefault()\n sel = (sel - 1 + max) % max\n } else if (e.which === 13) {\n this.onActiveItem(this.state.currentSelection)\n }\n this.setState({\n currentSelection: sel\n })\n }\n\n onActiveItem (index) {\n const item = this.state.results[index]\n if (item !== undefined) {\n const target = this.isRecordPreviewActive() ? '.preview' : '.edit'\n const urlPath = this.getUrlRecordPathWithAlt(item.path)\n dialogSystem.dismissDialog()\n this.transitionToAdminPage(target, {path: urlPath})\n }\n }\n\n selectItem (index) {\n this.setState({\n currentSelection: Math.min(index, this.state.results.length - 1)\n })\n }\n\n renderResults () {\n const rv = this.state.results.map((result, idx) => {\n const parents = result.parents.map((item, idx) => {\n return (\n \n {item.title}\n \n )\n })\n\n return (\n \n {parents}\n {result.title}\n \n )\n })\n\n return (\n
      {rv}
    \n )\n }\n\n render () {\n return (\n \n
    \n \n
    \n {this.renderResults()}\n \n )\n }\n}\n\nexport default FindFiles\n\n\n\n// WEBPACK FOOTER //\n// ./js/dialogs/findFiles.jsx","'use strict'\n\nimport PropTypes from 'prop-types'\nimport React from 'react'\nimport RecordComponent from '../components/RecordComponent'\nimport SlideDialog from '../components/SlideDialog'\nimport dialogSystem from '../dialogSystem'\nimport i18n from '../i18n'\n\nclass ErrorDialog extends RecordComponent {\n onClose () {\n dialogSystem.dismissDialog()\n }\n\n render () {\n return (\n \n

    \n {i18n.trans('ERROR_OCURRED')}{': '}\n {i18n.trans('ERROR_' + this.props.error.code)}\n

    \n
    \n \n
    \n \n )\n }\n}\n\nErrorDialog.propTypes = {\n error: PropTypes.object\n}\n\nexport default ErrorDialog\n\n\n\n// WEBPACK FOOTER //\n// ./js/dialogs/errorDialog.jsx","'use strict'\n\n/* eslint-env browser */\n\nimport React from 'react'\nimport Component from '../components/Component'\nimport SlideDialog from '../components/SlideDialog'\nimport utils from '../utils'\nimport i18n from '../i18n'\nimport dialogSystem from '../dialogSystem'\nimport makeRichPromise from '../richPromise'\n\nclass Publish extends Component {\n constructor (props) {\n super(props)\n\n this.state = {\n servers: [],\n activeTarget: null,\n log: [],\n currentState: 'IDLE'\n }\n }\n\n componentDidMount () {\n super.componentDidMount()\n this.syncDialog()\n }\n\n componentWillUnmount () {\n super.componentWillUnmount()\n }\n\n componentWillReceiveProps (nextProps) {\n this.syncDialog()\n }\n\n preventNavigation () {\n return !this.isSafeToPublish()\n }\n\n syncDialog () {\n utils.loadData('/servers', {}, null, makeRichPromise)\n .then(({ servers }) => {\n this.setState({\n servers: servers,\n activeTarget: servers && servers.length\n ? servers[0].id\n : null\n })\n })\n }\n\n isSafeToPublish () {\n return this.state.currentState === 'IDLE' ||\n this.state.currentState === 'DONE'\n }\n\n onPublish () {\n if (this.isSafeToPublish()) {\n this._beginBuild()\n }\n }\n\n onCancel () {\n dialogSystem.dismissDialog()\n }\n\n _beginBuild () {\n this.setState({\n log: [],\n currentState: 'BUILDING'\n })\n utils.apiRequest('/build', {\n method: 'POST'\n }, makeRichPromise).then((resp) => {\n this._beginPublish()\n })\n }\n\n _beginPublish () {\n this.setState({\n currentState: 'PUBLISH'\n })\n\n const es = new EventSource(utils.getApiUrl('/publish') +\n '?server=' + encodeURIComponent(this.state.activeTarget))\n es.addEventListener('message', (event) => {\n const data = JSON.parse(event.data)\n if (data === null) {\n this.setState({\n currentState: 'DONE'\n })\n es.close()\n } else {\n this.setState({\n log: this.state.log.concat(data.msg)\n })\n }\n })\n }\n\n onSelectServer (event) {\n this.setState({\n activeTarget: event.target.value\n })\n }\n\n componentDidUpdate () {\n super.componentDidUpdate()\n const node = this.refs.log\n if (node) {\n node.scrollTop = node.scrollHeight\n }\n }\n\n render () {\n const servers = this.state.servers.map((server) => {\n return (\n \n )\n })\n\n let progress = null\n if (this.state.currentState !== 'IDLE') {\n progress = (\n
    \n

    {this.state.currentState !== 'DONE'\n ? i18n.trans('CURRENTLY_PUBLISHING')\n : i18n.trans('PUBLISH_DONE')}

    \n
    {i18n.trans('STATE') + ': ' +\n            i18n.trans('PUBLISH_STATE_' + this.state.currentState)}
    \n
    {this.state.log.join('\\n')}
    \n
    \n )\n }\n\n return (\n \n

    {i18n.trans('PUBLISH_NOTE')}

    \n
    \n
    {i18n.trans('PUBLISH_SERVER')}
    \n
    \n
    \n \n {servers}\n \n
    \n
    \n
    \n
    \n \n \n
    \n {progress}\n \n )\n }\n}\n\nexport default Publish\n\n\n\n// WEBPACK FOOTER //\n// ./js/dialogs/publish.jsx","'use strict'\n\nimport React from 'react'\nimport Component from '../components/Component'\nimport SlideDialog from '../components/SlideDialog'\nimport utils from '../utils'\nimport i18n from '../i18n'\nimport dialogSystem from '../dialogSystem'\nimport makeRichPromise from '../richPromise'\n\nclass Refresh extends Component {\n constructor (props) {\n super(props)\n this.state = {\n currentState: 'IDLE'\n }\n }\n\n componentDidMount () {\n super.componentDidMount()\n this.syncDialog()\n }\n\n preventNavigation () {\n return !this.isSafeToNavigate()\n }\n\n isSafeToNavigate () {\n return this.state.currentState === 'IDLE' ||\n this.state.currentState === 'DONE'\n }\n\n onRefresh () {\n this.setState({\n currentState: 'CLEANING'\n })\n utils.apiRequest('/clean', {\n method: 'POST'\n }, makeRichPromise).then((resp) => {\n this.setState({\n currentState: 'DONE'\n })\n })\n }\n\n onCancel () {\n dialogSystem.dismissDialog()\n }\n\n render () {\n let progress = null\n if (this.state.currentState !== 'IDLE') {\n progress = (\n
    \n

    {this.state.currentState !== 'DONE'\n ? i18n.trans('CURRENTLY_REFRESHING_BUILD')\n : i18n.trans('REFRESHING_BUILD_DONE')}

    \n
    \n )\n }\n\n return (\n \n

    {i18n.trans('REFRESH_BUILD_NOTE')}

    \n {progress}\n
    \n \n \n
    \n \n )\n }\n}\n\nexport default Refresh\n\n\n\n// WEBPACK FOOTER //\n// ./js/dialogs/Refresh.jsx","'use strict'\n\n/* eslint-env browser */\n\nimport React from 'react'\nimport utils from '../utils'\nimport i18n from '../i18n'\nimport hub from '../hub'\nimport {AttachmentsChangedEvent} from '../events'\nimport RecordComponent from './RecordComponent'\nimport Link from '../components/Link'\nimport makeRichPromise from '../richPromise'\n\nconst getBrowseButtonTitle = () => {\n const platform = utils.getPlatform()\n if (platform === 'mac') {\n return i18n.trans('BROWSE_FS_MAC')\n } else if (platform === 'windows') {\n return i18n.trans('BROWSE_FS_WINDOWS')\n } else {\n return i18n.trans('BROWSE_FS')\n }\n}\n\nconst CHILDREN_PER_PAGE = 15\n\nclass ChildPosCache {\n constructor () {\n this.memo = []\n }\n\n rememberPosition (record, page) {\n for (let i = 0; i < this.memo.length; i++) {\n if (this.memo[i][0] === record) {\n this.memo[i][1] = page\n return\n }\n }\n this.memo.unshift([record, page])\n if (this.memo.length > 5) {\n this.memo.length = 5\n }\n }\n\n getPosition (record, childCount) {\n for (let i = 0; i < this.memo.length; i++) {\n if (this.memo[i][0] === record) {\n let rv = this.memo[i][1]\n if (childCount !== undefined) {\n rv = Math.min(rv, Math.ceil(childCount / CHILDREN_PER_PAGE))\n }\n return rv\n }\n }\n return 1\n }\n}\n\nclass Sidebar extends RecordComponent {\n constructor (props) {\n super(props)\n\n this.state = this._getInitialState()\n this.childPosCache = new ChildPosCache()\n this.onAttachmentsChanged = this.onAttachmentsChanged.bind(this)\n }\n\n _getInitialState () {\n return {\n recordAttachments: [],\n recordChildren: [],\n recordAlts: [],\n canHaveAttachments: false,\n canHaveChildren: false,\n isAttachment: false,\n canBeDeleted: false,\n recordExists: false,\n lastRecordRequest: null,\n childrenPage: 1\n }\n }\n\n componentDidMount () {\n super.componentDidMount()\n this._updateRecordInfo()\n\n hub.subscribe(AttachmentsChangedEvent, this.onAttachmentsChanged)\n }\n\n componentDidUpdate (prevProps, prevState) {\n super.componentDidUpdate(prevProps, prevState)\n if (prevProps.params.path !== this.props.params.path) {\n this._updateRecordInfo()\n }\n }\n\n componentWillUnmount () {\n super.componentWillUnmount()\n hub.unsubscribe(AttachmentsChangedEvent, this.onAttachmentsChanged)\n }\n\n onAttachmentsChanged (event) {\n if (event.recordPath === this.getRecordPath()) {\n this._updateRecordInfo()\n }\n }\n\n _updateRecordInfo () {\n const path = this.getRecordPath()\n if (path === null) {\n this.setState(this._getInitialState())\n return\n }\n\n this.setState({\n lastRecordRequest: path\n }, () => {\n utils.loadData('/recordinfo', {path: path}, null, makeRichPromise)\n .then((resp) => {\n // we're already fetching something else.\n if (path !== this.state.lastRecordRequest) {\n return\n }\n const alts = resp.alts\n alts.sort((a, b) => {\n const nameA = (a.is_primary ? 'A' : 'B') + i18n.trans(a.name_i18n)\n const nameB = (b.is_primary ? 'A' : 'B') + i18n.trans(b.name_i18n)\n return nameA === nameB ? 0 : nameA < nameB ? -1 : 1\n })\n this.setState({\n recordAttachments: resp.attachments,\n recordChildren: resp.children,\n recordAlts: alts,\n canHaveAttachments: resp.can_have_attachments,\n canHaveChildren: resp.can_have_children,\n isAttachment: resp.is_attachment,\n canBeDeleted: resp.can_be_deleted,\n recordExists: resp.exists,\n childrenPage: this.childPosCache.getPosition(\n path, resp.children.length)\n })\n })\n })\n }\n\n fsOpen (event) {\n event.preventDefault()\n utils.apiRequest('/browsefs', {data: {\n path: this.getRecordPath(),\n alt: this.getRecordAlt()\n },\n // eslint-disable-next-line indent\n method: 'POST'}, makeRichPromise)\n .then((resp) => {\n if (!resp.okay) {\n alert(i18n.trans('ERROR_CANNOT_BROWSE_FS'))\n }\n })\n }\n\n renderPageActions () {\n const urlPath = this.getUrlRecordPathWithAlt()\n const links = []\n const deleteLink = null\n\n links.push(\n
  • \n \n {this.state.isAttachment\n ? i18n.trans('EDIT_METADATA')\n : i18n.trans('EDIT')}\n \n
  • \n )\n\n if (this.state.canBeDeleted) {\n links.push(\n
  • \n {i18n.trans('DELETE')}
  • \n )\n }\n\n links.push(\n
  • \n {i18n.trans('PREVIEW')}
  • \n )\n\n if (this.state.recordExists) {\n links.push(\n
  • \n \n {getBrowseButtonTitle()}\n \n
  • \n )\n }\n\n if (this.state.canHaveChildren) {\n links.push(\n
  • \n {i18n.trans('ADD_CHILD_PAGE')}
  • \n )\n }\n\n if (this.state.canHaveAttachments) {\n links.push(\n
  • \n {i18n.trans('ADD_ATTACHMENT')}
  • \n )\n }\n\n const title = this.state.isAttachment\n ? i18n.trans('ATTACHMENT_ACTIONS')\n : i18n.trans('PAGE_ACTIONS')\n\n return (\n
    \n

    {title}

    \n
      \n {links}\n {deleteLink}\n
    \n
    \n )\n }\n\n renderAlts () {\n if (this.state.recordAlts.length < 2) {\n return null\n }\n\n const items = this.state.recordAlts.map((item) => {\n let title = i18n.trans(item.name_i18n)\n let className = 'alt'\n if (item.is_primary) {\n title += ' (' + i18n.trans('PRIMARY_ALT') + ')'\n } else if (item.primary_overlay) {\n title += ' (' + i18n.trans('PRIMARY_OVERLAY') + ')'\n }\n if (!item.exists) {\n className += ' alt-missing'\n }\n\n const path = this.getPathToAdminPage(null, {\n path: this.getUrlRecordPathWithAlt(null, item.alt)\n })\n return (\n
  • \n {title}\n
  • \n )\n })\n\n return (\n
    \n

    {i18n.trans('ALTS')}

    \n
      \n {items}\n
    \n
    \n )\n }\n\n renderChildPagination () {\n let pages = Math.ceil(this.state.recordChildren.length / CHILDREN_PER_PAGE)\n if (pages <= 1) {\n return null\n }\n let page = this.state.childrenPage\n let goToPage = (diff, event) => {\n event.preventDefault()\n let newPage = page + diff\n this.childPosCache.rememberPosition(this.getRecordPath(), newPage)\n this.setState({\n childrenPage: newPage\n })\n }\n\n return (\n
  • \n {page > 1\n ? «\n : «}\n {page + ' / ' + pages}\n {page < pages\n ? »\n : »}\n
  • \n )\n }\n\n renderChildActions () {\n const target = this.isRecordPreviewActive() ? 'preview' : 'edit'\n\n const children = this.state.recordChildren.slice(\n (this.state.childrenPage - 1) * CHILDREN_PER_PAGE,\n this.state.childrenPage * CHILDREN_PER_PAGE)\n\n const items = children.map((child) => {\n const urlPath = this.getUrlRecordPathWithAlt(child.path)\n return (\n
  • \n \n {i18n.trans(child.label_i18n)}\n
  • \n )\n })\n\n if (items.length === 0) {\n items.push(\n
  • \n {i18n.trans('NO_CHILD_PAGES')}\n
  • \n )\n }\n\n return (\n
    \n

    {i18n.trans('CHILD_PAGES')}

    \n
      \n {this.renderChildPagination()}\n {items}\n
    \n
    \n )\n }\n\n renderAttachmentActions () {\n const items = this.state.recordAttachments.map((atch) => {\n const urlPath = this.getUrlRecordPathWithAlt(atch.path)\n return (\n
  • \n \n {atch.id} ({atch.type})\n
  • \n )\n })\n\n if (items.length === 0) {\n items.push(\n
  • \n {i18n.trans('NO_ATTACHMENTS')}\n
  • \n )\n }\n\n return (\n
    \n

    {i18n.trans('ATTACHMENTS')}

    \n
      \n {items}\n
    \n
    \n )\n }\n\n render () {\n const sections = []\n\n if (this.getRecordPath() !== null) {\n sections.push(this.renderPageActions())\n }\n\n sections.push(this.renderAlts())\n\n if (this.state.canHaveChildren) {\n sections.push(this.renderChildActions())\n }\n\n if (this.state.canHaveAttachments) {\n sections.push(this.renderAttachmentActions())\n }\n\n return
    {sections}
    \n }\n}\n\nexport default Sidebar\n\n\n\n// WEBPACK FOOTER //\n// ./js/components/Sidebar.jsx","'use strict'\n\nimport React from 'react'\nimport Component from '../components/Component'\nimport dialogSystem from '../dialogSystem'\nimport { DialogChangedEvent } from '../events'\nimport hub from '../hub'\n\nclass DialogSlot extends Component {\n constructor (props) {\n super(props)\n this.state = {\n currentDialog: null,\n currentDialogOptions: null\n }\n this.onDialogChanged = this.onDialogChanged.bind(this)\n }\n\n componentDidMount () {\n super.componentDidMount()\n hub.subscribe(DialogChangedEvent, this.onDialogChanged)\n }\n\n componentWillUnmount () {\n super.componentWillUnmount()\n hub.unsubscribe(DialogChangedEvent, this.onDialogChanged)\n }\n\n onDialogChanged (event) {\n this.setState({\n currentDialog: event.dialog,\n currentDialogOptions: event.dialogOptions || {}\n })\n }\n\n initDialogInstance (dialog) {\n dialogSystem.notifyDialogInstance(dialog)\n window.scrollTo(0, 0)\n }\n\n render () {\n let dialog = null\n if (this.state.currentDialog) {\n dialog = this.initDialogInstance(ref)}\n {...this.getRoutingProps()}\n {...this.state.currentDialogOptions}\n />\n } else {\n dialogSystem.notifyDialogInstance(null)\n }\n\n if (!dialog) {\n return null\n }\n\n return (\n
    \n {dialog}\n
    \n
    \n )\n }\n}\n\nexport default DialogSlot\n\n\n\n// WEBPACK FOOTER //\n// ./js/components/DialogSlot.jsx","'use strict'\n\nimport React from 'react'\nimport Component from '../components/Component'\nimport utils from '../utils'\nimport i18n from '../i18n'\nimport makeRichPromise from '../richPromise'\n\nclass ServerStatus extends Component {\n constructor (props) {\n super(props)\n this.state = {\n serverIsUp: true,\n projectId: null\n }\n\n this.intervalId = null\n this.onInterval = this.onInterval.bind(this)\n }\n\n componentDidMount () {\n super.componentDidMount()\n this.intervalId = window.setInterval(this.onInterval, 2000)\n }\n\n componentWillUnmount () {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId)\n this.intervalId = null\n }\n super.componentWillUnmount()\n }\n\n onInterval () {\n utils.loadData('/ping', {}, null, makeRichPromise)\n .then((resp) => {\n if (this.state.projectId === null) {\n this.setState({\n projectId: resp.project_id\n })\n }\n this.setState({\n serverIsUp: this.state.projectId === resp.project_id\n })\n }, () => {\n this.setState({\n serverIsUp: false\n })\n })\n }\n\n render () {\n if (this.state.serverIsUp) {\n return null\n }\n return (\n
    \n
    \n

    {i18n.trans('ERROR_SERVER_UNAVAILABLE')}

    \n

    {i18n.trans('ERROR_SERVER_UNAVAILABLE_MESSAGE')}

    \n
    \n
    \n )\n }\n}\n\nexport default ServerStatus\n\n\n\n// WEBPACK FOOTER //\n// ./js/components/ServerStatus.jsx","'use strict'\n\nimport Component from '../components/Component'\n\nclass Dash extends Component {\n componentDidMount () {\n super.componentDidMount()\n const rootPreview = $LEKTOR_CONFIG.admin_root + '/root/preview'\n this.props.history.pushState(null, rootPreview)\n }\n\n render () {\n return null\n }\n}\n\nexport default Dash\n\n\n\n// WEBPACK FOOTER //\n// ./js/views/Dash.jsx","'use strict'\n\nimport React from 'react'\nimport update from 'react-addons-update'\nimport RecordEditComponent from '../components/RecordEditComponent'\nimport utils from '../utils'\nimport i18n from '../i18n'\nimport widgets from '../widgets'\nimport makeRichPromise from '../richPromise'\n\nclass EditPage extends RecordEditComponent {\n constructor (props) {\n super(props)\n\n this.state = {\n recordInitialData: null,\n recordData: null,\n recordDataModel: null,\n recordInfo: null,\n hasPendingChanges: false\n }\n this._onKeyPress = this._onKeyPress.bind(this)\n }\n\n componentDidMount () {\n super.componentDidMount()\n this.syncEditor()\n window.addEventListener('keydown', this._onKeyPress)\n }\n\n componentWillReceiveProps (nextProps) {\n /*\n if (nextProps.params.path !== this.props.params.path) {\n this.syncEditor();\n }\n */\n }\n\n componentDidUpdate (prevProps, prevState) {\n if (prevProps.params.path !== this.props.params.path) {\n this.syncEditor()\n }\n }\n\n componentWillUnmount () {\n window.removeEventListener('keydown', this._onKeyPress)\n }\n\n hasPendingChanges () {\n return this.state.hasPendingChanges\n }\n\n _onKeyPress (event) {\n // meta+s is open find files\n if (event.which === 83 && utils.isMetaKey(event)) {\n event.preventDefault()\n this.saveChanges()\n }\n }\n\n isIllegalField (field) {\n switch (field.name) {\n case '_id':\n case '_path':\n case '_gid':\n case '_alt':\n case '_source_alt':\n case '_model':\n case '_attachment_for':\n return true\n case '_attachment_type':\n return !this.state.recordInfo.is_attachment\n }\n return false\n }\n\n syncEditor () {\n utils.loadData('/rawrecord', {\n path: this.getRecordPath(),\n alt: this.getRecordAlt()\n }, null, makeRichPromise)\n .then((resp) => {\n this.setState({\n recordInitialData: resp.data,\n recordData: {},\n recordDataModel: resp.datamodel,\n recordInfo: resp.record_info,\n hasPendingChanges: false\n })\n })\n }\n\n onValueChange (field, value) {\n let updates = {}\n updates[field.name] = {$set: value || ''}\n const rd = update(this.state.recordData, updates)\n this.setState({\n recordData: rd,\n hasPendingChanges: true\n })\n }\n\n getValues () {\n let rv = {}\n this.state.recordDataModel.fields.forEach((field) => {\n if (this.isIllegalField(field)) {\n return\n }\n\n let value = this.state.recordData[field.name]\n\n if (value !== undefined) {\n const Widget = widgets.getWidgetComponentWithFallback(field.type)\n if (Widget.serializeValue) {\n value = Widget.serializeValue(value, field.type)\n }\n } else {\n value = this.state.recordInitialData[field.name]\n if (value === undefined) {\n value = null\n }\n }\n\n rv[field.name] = value\n })\n\n return rv\n }\n\n saveChanges () {\n const path = this.getRecordPath()\n const alt = this.getRecordAlt()\n const newData = this.getValues()\n utils.apiRequest('/rawrecord', {json: {\n data: newData, path: path, alt: alt},\n // eslint-disable-next-line indent\n method: 'PUT'}, makeRichPromise)\n .then((resp) => {\n this.setState({\n hasPendingChanges: false\n }, () => {\n this.transitionToAdminPage('.preview', {\n path: this.getUrlRecordPathWithAlt(path)\n })\n })\n })\n }\n\n deleteRecord (event) {\n this.transitionToAdminPage('.delete', {\n path: this.getUrlRecordPathWithAlt()\n })\n }\n\n getValueForField (widget, field) {\n let value = this.state.recordData[field.name]\n if (value === undefined) {\n value = this.state.recordInitialData[field.name] || ''\n if (widget.deserializeValue) {\n value = widget.deserializeValue(value, field.type)\n }\n }\n return value\n }\n\n getPlaceholderForField (widget, field) {\n if (field['default'] !== null) {\n if (widget.deserializeValue) {\n return widget.deserializeValue(field['default'], field.type)\n }\n return field['default']\n } else if (field.name === '_slug') {\n return this.state.recordInfo.slug_format\n } else if (field.name === '_template') {\n return this.state.recordInfo.default_template\n } else if (field.name === '_attachment_type') {\n return this.state.recordInfo.implied_attachment_type\n }\n return null\n }\n\n renderFormField (field, idx) {\n const widget = widgets.getWidgetComponentWithFallback(field.type)\n return (\n \n )\n }\n\n renderFormFields () {\n return widgets.renderFieldRows(\n this.state.recordDataModel.fields,\n this.isIllegalField.bind(this),\n this.renderFormField.bind(this)\n )\n }\n\n render () {\n // we have not loaded anything yet.\n if (this.state.recordInfo === null) {\n return null\n }\n\n let deleteButton = null\n if (this.state.recordInfo.can_be_deleted) {\n deleteButton = (\n \n )\n }\n\n const title = this.state.recordInfo.is_attachment\n ? i18n.trans('EDIT_ATTACHMENT_METADATA_OF')\n : i18n.trans('EDIT_PAGE_NAME')\n\n const label = this.state.recordInfo.label_i18n\n ? i18n.trans(this.state.recordInfo.label_i18n)\n : this.state.recordInfo.label\n\n return (\n
    \n

    {title.replace('%s', label)}

    \n {this.renderFormFields()}\n
    \n \n {deleteButton}\n
    \n
    \n )\n }\n}\n\nexport default EditPage\n\n\n\n// WEBPACK FOOTER //\n// ./js/views/EditPage.jsx","'use strict'\n\nimport React from 'react'\nimport jQuery from 'jquery'\nimport {BasicWidgetMixin, ValidationFailure} from './mixins'\nimport utils from '../utils'\nimport userLabel from '../userLabel'\nimport i18n from '../i18n'\n\nconst isTrue = (value) => {\n return value === 'true' || value === 'yes' || value === '1'\n}\n\nconst isValidDate = (year, month, day) => {\n year = parseInt(year, 10)\n month = parseInt(month, 10)\n day = parseInt(day, 10)\n const date = new Date(year, month - 1, day)\n if (date.getFullYear() === year &&\n date.getMonth() === month - 1 &&\n date.getDate() === day) {\n return true\n }\n return false\n}\n\nconst InputWidgetMixin = {\n mixins: [BasicWidgetMixin],\n\n onChange (event) {\n let value = event.target.value\n if (this.postprocessValue) {\n value = this.postprocessValue(value)\n }\n this.props.onChange(value)\n },\n\n render () {\n let {type, onChange, className, ...otherProps} = this.props\n let help = null\n const failure = this.getValidationFailure()\n className = (className || '')\n className += ' input-group'\n\n if (failure !== null) {\n className += ' has-feedback has-' + failure.type\n const valClassName = 'validation-block validation-block-' + failure.type\n help =
    {failure.message}
    \n }\n\n let addon = null\n const configuredAddon = type.addon_label_i18n\n if (configuredAddon) {\n addon = userLabel.format(configuredAddon)\n } else if (this.getInputAddon) {\n addon = this.getInputAddon()\n }\n\n return (\n
    \n
    \n \n {addon ? {addon} : null}\n
    \n {help}\n
    \n )\n }\n}\n\nconst SingleLineTextInputWidget = React.createClass({\n mixins: [InputWidgetMixin],\n\n getInputType () {\n return 'text'\n },\n\n getInputAddon () {\n return \n }\n})\n\nconst SlugInputWidget = React.createClass({\n mixins: [InputWidgetMixin],\n\n postprocessValue (value) {\n return value.replace(/\\s+/g, '-')\n },\n\n getInputType () {\n return 'text'\n },\n\n getInputAddon () {\n return \n }\n})\n\nconst IntegerInputWidget = React.createClass({\n mixins: [InputWidgetMixin],\n\n postprocessValue (value) {\n return value.match(/^\\s*(.*?)\\s*$/)[1]\n },\n\n getValidationFailureImpl () {\n if (this.props.value && !this.props.value.match(/^\\d+$/)) {\n return new ValidationFailure({\n message: i18n.trans('ERROR_INVALID_NUMBER')\n })\n }\n return null\n },\n\n getInputType () {\n return 'text'\n },\n\n getInputAddon () {\n return '0'\n }\n})\n\nconst FloatInputWidget = React.createClass({\n mixins: [InputWidgetMixin],\n\n postprocessValue (value) {\n return value.match(/^\\s*(.*?)\\s*$/)[1]\n },\n\n getValidationFailureImpl () {\n if (this.props.value && isNaN(parseFloat(this.props.value))) {\n return new ValidationFailure({\n message: i18n.trans('ERROR_INVALID_NUMBER')\n })\n }\n return null\n },\n\n getInputType () {\n return 'text'\n },\n\n getInputAddon () {\n return '0.0'\n }\n})\n\nconst DateInputWidget = React.createClass({\n mixins: [InputWidgetMixin],\n\n postprocessValue (value) {\n value = value.match(/^\\s*(.*?)\\s*$/)[1]\n const match = value.match(/^(\\d{1,2})\\.(\\d{1,2})\\.(\\d{4})\\s*$/)\n let day, month, year\n if (match) {\n day = parseInt(match[1], 10)\n month = parseInt(match[2], 10)\n year = parseInt(match[3], 10)\n return (\n year + '-' +\n (month < 10 ? '0' : '') + month + '-' +\n (day < 10 ? '0' : '') + day\n )\n }\n return value\n },\n\n getValidationFailureImpl () {\n if (!this.props.value) {\n return null\n }\n\n const match = this.props.value.match(/^\\s*(\\d{4})-(\\d{1,2})-(\\d{1,2})\\s*$/)\n if (match && isValidDate(match[1], match[2], match[3])) {\n return null\n }\n\n return new ValidationFailure({\n message: i18n.trans('ERROR_INVALID_DATE')\n })\n },\n\n getInputType () {\n return 'date'\n },\n\n getInputAddon () {\n return \n }\n})\n\nconst UrlInputWidget = React.createClass({\n mixins: [InputWidgetMixin],\n\n getValidationFailureImpl () {\n if (this.props.value && !utils.isValidUrl(this.props.value)) {\n return new ValidationFailure({\n message: i18n.trans('ERROR_INVALID_URL')\n })\n }\n return null\n },\n\n getInputType () {\n return 'text'\n },\n\n getInputAddon () {\n return \n }\n})\n\nconst MultiLineTextInputWidget = React.createClass({\n mixins: [BasicWidgetMixin],\n\n onChange (event) {\n this.recalculateSize()\n if (this.props.onChange) {\n this.props.onChange(event.target.value)\n }\n },\n\n componentDidMount () {\n this.recalculateSize()\n window.addEventListener('resize', this.recalculateSize)\n },\n\n componentWillUnmount () {\n window.removeEventListener('resize', this.recalculateSize)\n },\n\n componentDidUpdate (prevProps) {\n this.recalculateSize()\n },\n\n isInAutoResizeMode () {\n return this.props.rows === undefined\n },\n\n recalculateSize () {\n if (!this.isInAutoResizeMode()) {\n return\n }\n let diff\n let node = this.refs.ta\n\n if (window.getComputedStyle) {\n const s = window.getComputedStyle(node)\n if (s.getPropertyValue('box-sizing') === 'border-box' ||\n s.getPropertyValue('-moz-box-sizing') === 'border-box' ||\n s.getPropertyValue('-webkit-box-sizing') === 'border-box') {\n diff = 0\n } else {\n diff = (\n parseInt(s.getPropertyValue('padding-bottom') || 0, 10) +\n parseInt(s.getPropertyValue('padding-top') || 0, 10)\n )\n }\n } else {\n diff = 0\n }\n\n const updateScrollPosition = jQuery(node).is(':focus')\n // Cross-browser compatibility for scroll position\n const oldScrollTop = document.documentElement.scrollTop || document.body.scrollTop\n const oldHeight = jQuery(node).outerHeight()\n\n node.style.height = 'auto'\n const newHeight = (node.scrollHeight - diff)\n node.style.height = newHeight + 'px'\n\n if (updateScrollPosition) {\n window.scrollTo(\n document.body.scrollLeft, oldScrollTop + (newHeight - oldHeight))\n }\n },\n\n render () {\n let {className, type, onChange, style, ...otherProps} = this.props // eslint-disable-line no-unused-vars\n className = (className || '')\n\n style = style || {}\n if (this.isInAutoResizeMode()) {\n style.display = 'block'\n style.overflow = 'hidden'\n style.resize = 'none'\n }\n\n return (\n
    \n \n
    \n )\n }\n})\n\nconst BooleanInputWidget = React.createClass({\n mixins: [BasicWidgetMixin],\n\n onChange (event) {\n this.props.onChange(event.target.checked ? 'yes' : 'no')\n },\n\n componentDidMount () {\n const checkbox = this.refs.checkbox\n if (!this.props.value && this.props.placeholder) {\n checkbox.indeterminate = true\n checkbox.checked = isTrue(this.props.placeholder)\n } else {\n checkbox.indeterminate = false\n }\n },\n\n render () {\n let {className, type, placeholder, onChange, value, ...otherProps} = this.props // eslint-disable-line no-unused-vars\n className = (className || '') + ' checkbox'\n\n return (\n
    \n \n
    \n )\n }\n})\n\nexport default {\n SingleLineTextInputWidget: SingleLineTextInputWidget,\n SlugInputWidget: SlugInputWidget,\n IntegerInputWidget: IntegerInputWidget,\n FloatInputWidget: FloatInputWidget,\n DateInputWidget: DateInputWidget,\n UrlInputWidget: UrlInputWidget,\n MultiLineTextInputWidget: MultiLineTextInputWidget,\n BooleanInputWidget: BooleanInputWidget\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/widgets/primitiveWidgets.jsx","'use strict'\n\nimport React from 'react'\nimport utils from '../utils'\nimport i18n from '../i18n'\nimport {BasicWidgetMixin} from './mixins'\n\nconst CheckboxesInputWidget = React.createClass({\n mixins: [BasicWidgetMixin],\n\n statics: {\n deserializeValue: (value) => {\n if (value === '') {\n return null\n }\n let rv = value.split(',').map((x) => {\n return x.match(/^\\s*(.*?)\\s*$/)[1]\n })\n if (rv.length === 1 && rv[0] === '') {\n rv = []\n }\n return rv\n },\n\n serializeValue: (value) => {\n return (value || '').join(', ')\n }\n },\n\n onChange: function (field, event) {\n const newValue = utils.flipSetValue(this.props.value,\n field, event.target.checked)\n if (this.props.onChange) {\n this.props.onChange(newValue)\n }\n },\n\n isActive: function (field) {\n let value = this.props.value\n if (value == null) {\n value = this.props.placeholder\n if (value == null) {\n return false\n }\n }\n for (const item of value) {\n if (item === field) {\n return true\n }\n }\n return false\n },\n\n render () {\n let {className, value, placeholder, type, ...otherProps} = this.props // eslint-disable-line no-unused-vars\n className = (className || '') + ' checkbox'\n\n const choices = this.props.type.choices.map((item) => {\n return (\n
    \n \n
    \n )\n })\n return (\n
    \n {choices}\n
    \n )\n }\n})\n\nconst SelectInputWidget = React.createClass({\n mixins: [BasicWidgetMixin],\n\n onChange (event) {\n this.props.onChange(event.target.value)\n },\n\n render () {\n let {className, type, value, placeholder, onChange, ...otherProps} = this.props // eslint-disable-line no-unused-vars\n value = value || placeholder\n\n let choices = this.props.type.choices.map((item) => {\n return (\n \n )\n })\n choices.unshift(\n \n )\n\n return (\n
    \n
    \n \n {choices}\n \n
    \n
    \n )\n }\n})\n\nexport default {\n CheckboxesInputWidget: CheckboxesInputWidget,\n SelectInputWidget: SelectInputWidget\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/widgets/multiWidgets.jsx","'use strict'\n\n/* eslint-env browser */\n\nimport React from 'react'\nimport i18n from '../i18n'\nimport metaformat from '../metaformat'\nimport {BasicWidgetMixin} from './mixins'\nimport userLabel from '../userLabel'\nimport widgets from '../widgets'\n\n/* circular references require us to do this */\nconst getWidgetComponent = (type) => {\n return widgets.getWidgetComponent(type)\n}\n\nconst getWidgets = () => {\n return widgets\n}\n\nconst parseFlowFormat = (value) => {\n let blocks = []\n let buf = []\n let lines = value.split(/\\r?\\n/)\n let block = null\n\n for (const line of lines) {\n // leading whitespace is ignored.\n if (block === null && line.match(/^\\s*$/)) {\n continue\n }\n\n const blockStart = line.match(/^####\\s*([^#]*?)\\s*####\\s*$/)\n if (!blockStart) {\n if (block === null) {\n // bad format :(\n return null\n }\n } else {\n if (block !== null) {\n blocks.push([block, buf])\n buf = []\n }\n block = blockStart[1]\n continue\n }\n\n buf.push(line.replace(/^#####(.*?)#####$/, '####$1####'))\n }\n\n if (block !== null) {\n blocks.push([block, buf])\n }\n\n return blocks\n}\n\nconst serializeFlowFormat = (blocks) => {\n let rv = []\n blocks.forEach((block) => {\n const [blockName, lines] = block\n rv.push('#### ' + blockName + ' ####\\n')\n lines.forEach((line) => {\n rv.push(line.replace(/^(####(.*)####)(\\r?\\n)?$/, '#$1#$3'))\n })\n })\n\n rv = rv.join('')\n\n /* we need to chop of the last newline if it exists because this would\n otherwise add a newline to the last block. This is just a side effect\n of how we serialize the meta format internally */\n if (rv[rv.length - 1] === '\\n') {\n rv = rv.substr(0, rv.length - 1)\n }\n\n return rv\n}\n\nconst deserializeFlowBlock = (flowBlockModel, lines, localId) => {\n let data = {}\n let rawData = {}\n\n metaformat.tokenize(lines).forEach((item) => {\n const [key, lines] = item\n const value = lines.join('')\n rawData[key] = value\n })\n\n flowBlockModel.fields.forEach((field) => {\n let value = rawData[field.name] || ''\n const Widget = getWidgetComponent(field.type)\n if (!value && field['default']) {\n value = field['default']\n }\n if (Widget && Widget.deserializeValue) {\n value = Widget.deserializeValue(value, field.type)\n }\n data[field.name] = value\n })\n\n return {\n localId: localId || null,\n flowBlockModel: flowBlockModel,\n data: data\n }\n}\n\nconst serializeFlowBlock = (flockBlockModel, data) => {\n let rv = []\n flockBlockModel.fields.forEach((field) => {\n const Widget = getWidgetComponent(field.type)\n if (Widget === null) {\n return\n }\n\n let value = data[field.name]\n if (value === undefined || value === null) {\n return\n }\n\n if (Widget.serializeValue) {\n value = Widget.serializeValue(value, field.type)\n }\n\n rv.push([field.name, value])\n })\n return metaformat.serialize(rv)\n}\n\n// ever growing counter of block ids. Good enough for what we do I think.\nlet lastBlockId = 0\n\nconst FlowWidget = React.createClass({\n mixins: [BasicWidgetMixin],\n\n statics: {\n deserializeValue: (value, type) => {\n return parseFlowFormat(value).map((item) => {\n const [id, lines] = item\n const flowBlock = type.flowblocks[id]\n if (flowBlock !== undefined) {\n return deserializeFlowBlock(flowBlock, lines, ++lastBlockId)\n }\n return null\n })\n },\n\n serializeValue: (value) => {\n return serializeFlowFormat(value.map((item) => {\n return [\n item.flowBlockModel.id,\n serializeFlowBlock(item.flowBlockModel, item.data)\n ]\n }))\n }\n },\n\n // XXX: the modification of props is questionable\n\n moveBlock: function (idx, offset, event) {\n event.preventDefault()\n\n const newIndex = idx + offset\n if (newIndex < 0 || newIndex >= this.props.value.length) {\n return\n }\n\n const tmp = this.props.value[newIndex]\n this.props.value[newIndex] = this.props.value[idx]\n this.props.value[idx] = tmp\n\n if (this.props.onChange) {\n this.props.onChange(this.props.value)\n }\n },\n\n removeBlock: function (idx, event) {\n event.preventDefault()\n\n if (confirm(i18n.trans('REMOVE_FLOWBLOCK_PROMPT'))) {\n this.props.value.splice(idx, 1)\n if (this.props.onChange) {\n this.props.onChange(this.props.value)\n }\n }\n },\n\n addNewBlock: function (key, event) {\n event.preventDefault()\n\n const flowBlockModel = this.props.type.flowblocks[key]\n\n // this is a rather ugly way to do this, but hey, it works.\n this.props.value.push(deserializeFlowBlock(flowBlockModel, [],\n ++lastBlockId))\n if (this.props.onChange) {\n this.props.onChange(this.props.value)\n }\n },\n\n renderFormField: function (blockInfo, field, idx) {\n const widgets = getWidgets()\n const value = blockInfo.data[field.name]\n let placeholder = field['default']\n const Widget = widgets.getWidgetComponentWithFallback(field.type)\n if (Widget.deserializeValue && placeholder != null) {\n placeholder = Widget.deserializeValue(placeholder, field.type)\n }\n\n const onChange = !this.props.onChange ? null : (value) => {\n blockInfo.data[field.name] = value\n this.props.onChange(this.props.value)\n }\n\n return (\n \n )\n },\n\n renderBlocks () {\n const widgets = getWidgets()\n\n return this.props.value.map((blockInfo, idx) => {\n // bad block is no block\n if (blockInfo === null) {\n return null\n }\n\n const fields = widgets.renderFieldRows(\n blockInfo.flowBlockModel.fields,\n null,\n this.renderFormField.bind(this, blockInfo)\n )\n\n return (\n
    \n
    \n \n \n \n = this.props.value.length - 1}\n onClick={this.moveBlock.bind(this, idx, 1)}>\n \n \n \n \n \n
    \n

    {userLabel.format(blockInfo.flowBlockModel.name_i18n)}

    \n {fields}\n
    \n )\n })\n },\n\n renderAddBlockSection () {\n let choices = []\n\n this.props.type.flowblock_order.forEach((key) => {\n let flowBlockModel = this.props.type.flowblocks[key]\n let label = flowBlockModel.button_label\n ? userLabel.format(flowBlockModel.button_label)\n : userLabel.format(flowBlockModel.name_i18n)\n choices.push([flowBlockModel.id, label, i18n.trans(flowBlockModel.name_i18n)])\n })\n\n const buttons = choices.map((item) => {\n const [key, label, title] = item\n return (\n {label}\n )\n })\n\n return (\n
    \n \n
    \n {buttons}\n
    \n
    \n )\n },\n\n render () {\n let {className} = this.props\n className = (className || '') + ' flow'\n\n return (\n
    \n {this.renderBlocks()}\n {this.renderAddBlockSection()}\n
    \n )\n }\n})\n\nexport default {\n FlowWidget: FlowWidget\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/widgets/flowWidget.jsx","'use strict'\n\nconst lineIsDashes = (line) => {\n line = line.match(/^\\s*(.*?)\\s*$/)[1]\n return line.length >= 3 && line === (new Array(line.length + 1)).join('-')\n}\n\nconst processBuf = (buf) => {\n const lines = buf.map((line) => {\n if (lineIsDashes(line)) {\n line = line.substr(1)\n }\n return line\n })\n\n if (lines.length > 0) {\n const lastLine = lines[lines.length - 1]\n if (lastLine.substr(lastLine.length - 1) === '\\n') {\n lines[lines.length - 1] = lastLine.substr(0, lastLine.length - 1)\n }\n }\n\n return lines\n}\n\nconst tokenize = (lines) => {\n let key = null\n let buf = []\n let wantNewline = false\n const rv = []\n\n const flushItem = () => {\n rv.push([key, processBuf(buf)])\n key = null\n buf = []\n }\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].match(/^(.*?)(\\r?\\n)*$/m)[1] + '\\n'\n\n if (line.match(/^(.*?)\\s*$/m)[1] === '---') {\n wantNewline = false\n if (key !== null) {\n flushItem()\n }\n } else if (key !== null) {\n if (wantNewline) {\n wantNewline = false\n if (line.match(/^\\s*$/)) {\n continue\n }\n }\n buf.push(line)\n } else {\n const bits = line.split(':')\n if (bits.length >= 2) {\n key = bits.shift().match(/^\\s*(.*?)\\s*$/m)[1]\n const firstBit = bits.join(':').match(/^[\\t ]*(.*?)[\\t ]*$/m)[1]\n if (!firstBit.match(/^\\s*$/)) {\n buf = [firstBit]\n } else {\n buf = []\n wantNewline = true\n }\n }\n }\n }\n\n if (key !== null) {\n flushItem()\n }\n\n return rv\n}\n\nconst serialize = (blocks) => {\n const rv = []\n\n blocks.forEach((item, idx) => {\n const [key, value] = item\n if (idx > 0) {\n rv.push('---\\n')\n }\n if (value.match(/([\\r\\n]|(^[\\t ])|([\\t ]$))/m)) {\n rv.push(key + ':\\n')\n rv.push('\\n')\n const lines = value.split(/\\n/)\n if (lines[lines.length - 1] === '') {\n lines.pop()\n }\n lines.forEach((line, idx, arr) => {\n if (lineIsDashes(line)) {\n line = '-' + line\n }\n rv.push(line + '\\n')\n })\n } else {\n rv.push(key + ': ' + value + '\\n')\n }\n })\n\n return rv\n}\n\nexport default {\n tokenize: tokenize,\n serialize: serialize\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/metaformat.jsx","'use strict'\n\nimport PropTypes from 'prop-types'\nimport React from 'react'\nimport {BasicWidgetMixin} from './mixins'\nimport i18n from '../i18n'\n\nconst FakeWidgetMixin = {\n mixins: [BasicWidgetMixin],\n propTypes: {\n field: PropTypes.any\n },\n\n statics: {\n isFakeWidget: true\n }\n}\n\nconst LineWidget = React.createClass({\n mixins: [FakeWidgetMixin],\n\n render () {\n return
    \n }\n})\n\nconst SpacingWidget = React.createClass({\n mixins: [FakeWidgetMixin],\n\n render () {\n return
    \n }\n})\n\nconst InfoWidget = React.createClass({\n mixins: [FakeWidgetMixin],\n\n render () {\n const label = i18n.trans(this.props.field.label_i18n)\n return (\n
    \n

    \n {label ? {label + ': '} : null}\n {i18n.trans(this.props.field.description_i18n)}\n

    \n
    \n )\n }\n})\n\nconst HeadingWidget = React.createClass({\n mixins: [FakeWidgetMixin],\n\n render () {\n return (\n

    {i18n.trans(this.props.type.heading_i18n)}

    \n )\n }\n})\n\nexport default {\n LineWidget: LineWidget,\n SpacingWidget: SpacingWidget,\n InfoWidget: InfoWidget,\n HeadingWidget: HeadingWidget\n}\n\n\n\n// WEBPACK FOOTER //\n// ./js/widgets/fakeWidgets.jsx","'use strict'\n\nimport PropTypes from 'prop-types'\nimport React from 'react'\nimport Component from './Component'\n\nclass ToggleGroup extends Component {\n constructor (props) {\n super(props)\n this.state = {\n isVisible: props.defaultVisibility\n }\n }\n\n toggle (event) {\n event.preventDefault()\n this.setState({\n isVisible: !this.state.isVisible\n })\n }\n\n render () {\n let {className, groupTitle, children, defaultVisibility, ...otherProps} = this.props\n className = (className || '') + ' toggle-group'\n if (this.state.isVisible) {\n className += ' toggle-group-open'\n } else {\n className += ' toggle-group-closed'\n }\n\n return (\n
    \n
    \n

    {groupTitle}

    \n
    \n
    \n {children}\n
    \n
    \n )\n }\n}\n\nToggleGroup.propTypes = {\n groupTitle: PropTypes.string,\n defaultVisibility: PropTypes.bool\n}\n\nexport default ToggleGroup\n\n\n\n// WEBPACK FOOTER //\n// ./js/components/ToggleGroup.jsx","'use strict'\n\nimport React from 'react'\nimport RecordComponent from '../components/RecordEditComponent'\nimport utils from '../utils'\nimport i18n from '../i18n'\nimport hub from '../hub'\nimport {AttachmentsChangedEvent} from '../events'\nimport makeRichPromise from '../richPromise'\n\nclass DeletePage extends RecordComponent {\n constructor (props) {\n super(props)\n\n this.state = {\n recordInfo: null,\n deleteMasterRecord: true\n }\n }\n\n componentDidMount () {\n super.componentDidMount()\n this.syncDialog()\n }\n\n componentWillReceiveProps (nextProps) {\n super.componentWillReceiveProps(nextProps)\n this.syncDialog()\n }\n\n syncDialog () {\n utils.loadData('/recordinfo', {path: this.getRecordPath()}, null, makeRichPromise)\n .then((resp) => {\n this.setState({\n recordInfo: resp,\n deleteMasterRecord: this.isPrimary()\n })\n })\n }\n\n deleteRecord (event) {\n const path = this.getRecordPath()\n const parent = utils.getParentFsPath(path)\n let targetPath\n if (parent === null) {\n targetPath = 'root'\n } else {\n targetPath = this.getUrlRecordPathWithAlt(parent)\n }\n\n utils.apiRequest('/deleterecord', {data: {\n path: path,\n alt: this.getRecordAlt(),\n delete_master: this.state.deleteMasterRecord ? '1' : '0'\n },\n // eslint-disable-next-line indent\n method: 'POST'}, makeRichPromise)\n .then((resp) => {\n if (this.state.recordInfo.is_attachment) {\n hub.emit(new AttachmentsChangedEvent({\n recordPath: this.getParentRecordPath(),\n attachmentsRemoved: [this.state.recordInfo.id]\n }))\n }\n this.transitionToAdminPage('.edit', {path: targetPath})\n })\n }\n\n cancelDelete (event) {\n const urlPath = this.getUrlRecordPathWithAlt()\n this.transitionToAdminPage('.edit', {path: urlPath})\n }\n\n onDeleteAllAltsChange (event) {\n this.setState({\n deleteMasterRecord: event.target.value === '1'\n })\n }\n\n isPrimary () {\n return this.getRecordAlt() === '_primary'\n }\n\n render () {\n const ri = this.state.recordInfo\n\n if (!ri || !ri.can_be_deleted) {\n return null\n }\n\n const elements = []\n let children = []\n const alts = []\n let attachments = []\n let altInfo = null\n let altCount = 0\n\n for (let i = 0; i < ri.alts.length; i++) {\n if (ri.alts[i].alt === this.getRecordAlt()) {\n altInfo = ri.alts[i]\n }\n if (ri.alts[i].exists) {\n altCount++\n }\n }\n\n if (ri.is_attachment) {\n elements.push(\n

    \n {this.isPrimary() ? i18n.trans('DELETE_ATTACHMENT_PROMPT')\n : i18n.trans('DELETE_ATTACHMENT_ALT_PROMPT')}{' '}\n

    \n )\n } else {\n elements.push(\n

    \n {this.isPrimary() ? i18n.trans('DELETE_PAGE_PROMPT')\n : i18n.trans('DELETE_PAGE_ALT_PROMPT')}{' '}\n {ri.children.length > 0 && this.isPrimary()\n ? i18n.trans('DELETE_PAGE_CHILDREN_WARNING') : null}\n

    \n )\n\n if (ri.children.length > 0) {\n children = ri.children.map((child) => {\n return (\n
  • {i18n.trans(child.label_i18n)}
  • \n )\n })\n if (ri.child_count > children.length) {\n children.push(
  • ...
  • )\n }\n }\n\n attachments = ri.attachments.map((atch) => {\n return (\n
  • {atch.id} ({atch.type})
  • \n )\n })\n }\n\n if (altCount > 1 && this.getRecordAlt() === '_primary') {\n ri.alts.forEach((item) => {\n if (!item.exists) {\n return\n }\n let title = i18n.trans(item.name_i18n)\n if (item.is_primary) {\n title += ' (' + i18n.trans('PRIMARY_ALT') + ')'\n } else if (item.primary_overlay) {\n title += ' (' + i18n.trans('PRIMARY_OVERLAY') + ')'\n }\n alts.push(
  • {title}
  • )\n })\n elements.push(\n

    {i18n.trans('DELETE_PRIMARY_ALT_INFO')}

    \n )\n elements.push(\n
      \n
    • \n {' '}\n \n
    • \n
    • \n {' '}\n \n
    • \n
    \n )\n }\n\n let label = ri.label_i18n ? i18n.trans(ri.label_i18n) : ri.id\n if (this.getRecordAlt() !== '_primary' && altInfo != null) {\n label += ' (' + i18n.trans(altInfo.name_i18n) + ')'\n }\n\n return (\n
    \n

    {i18n.trans('DELETE_RECORD').replace('%s', label)}

    \n {elements}\n
    0 ? 'block' : 'none'}}>\n

    {i18n.trans('ALTS_TO_BE_DELETED')}

    \n
      \n {alts}\n
    \n
    \n
    0 ? 'block' : 'none'}}>\n

    {i18n.trans('CHILD_PAGES_TO_BE_DELETED')}

    \n
      \n {children}\n
    \n
    \n
    0 ? 'block' : 'none'}}>\n

    {i18n.trans('ATTACHMENTS_TO_BE_DELETED')}

    \n
      \n {attachments}\n
    \n
    \n
    \n \n \n
    \n
    \n )\n }\n}\n\nexport default DeletePage\n\n\n\n// WEBPACK FOOTER //\n// ./js/views/DeletePage.jsx","'use strict'\n\nimport React from 'react'\nimport utils from '../utils'\nimport RecordComponent from '../components/RecordComponent'\nimport makeRichPromise from '../richPromise'\n\nclass PreviewPage extends RecordComponent {\n constructor (props) {\n super(props)\n this.state = {\n pageUrl: null,\n pageUrlFor: null\n }\n }\n\n componentWillReceiveProps (nextProps) {\n super.componentWillReceiveProps(nextProps)\n this.setState({}, this.syncState.bind(this))\n }\n\n componentDidMount () {\n super.componentDidMount()\n this.syncState()\n }\n\n shouldComponentUpdate () {\n return this.getUrlRecordPathWithAlt() !== this.state.pageUrlFor\n }\n\n syncState () {\n const alt = this.getRecordAlt()\n const path = this.getRecordPath()\n if (path === null) {\n this.setState(this.getInitialState())\n return\n }\n\n const recordUrl = this.getUrlRecordPathWithAlt()\n utils.loadData('/previewinfo', {path: path, alt: alt}, null, makeRichPromise)\n .then((resp) => {\n this.setState({\n pageUrl: resp.url,\n pageUrlFor: recordUrl\n })\n })\n }\n\n getIntendedPath () {\n if (this.state.pageUrlFor === this.getUrlRecordPathWithAlt()) {\n return this.state.pageUrl\n }\n return null\n }\n\n componentDidUpdate () {\n const frame = this.refs.iframe\n const intendedPath = this.getIntendedPath()\n if (intendedPath !== null) {\n const framePath = this.getFramePath()\n\n if (!utils.urlPathsConsideredEqual(intendedPath, framePath)) {\n frame.src = utils.getCanonicalUrl(intendedPath)\n }\n\n frame.onload = (event) => {\n this.onFrameNavigated()\n }\n }\n }\n\n getFramePath () {\n const frameLocation = this.refs.iframe.contentWindow.location\n if (frameLocation.href === 'about:blank') {\n return frameLocation.href\n }\n return utils.fsPathFromAdminObservedPath(\n frameLocation.pathname)\n }\n\n onFrameNavigated () {\n const fsPath = this.getFramePath()\n if (fsPath === null) {\n return\n }\n utils.loadData('/matchurl', {url_path: fsPath}, null, makeRichPromise)\n .then((resp) => {\n if (resp.exists) {\n const urlPath = this.getUrlRecordPathWithAlt(resp.path, resp.alt)\n this.transitionToAdminPage('.preview', {path: urlPath})\n }\n })\n }\n\n render () {\n return (\n
    \n