libffado-2.4.5/ 0000755 0001750 0000144 00000000000 14206145613 012662 5 ustar jwoithe users libffado-2.4.5/SConstruct 0000644 0001750 0000144 00000115333 14206145570 014724 0 ustar jwoithe users # -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008, 2010 Arnold Krille
# Copyright (C) 2007, 2008 Pieter Palmers
# Copyright (C) 2008, 2012 Jonathan Woithe
#
# This file is part of FFADO
# FFADO = Free FireWire (pro-)audio drivers for Linux
#
# FFADO is based upon FreeBoB.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
from __future__ import print_function
FFADO_API_VERSION = "9"
FFADO_VERSION="2.4.5"
from subprocess import Popen, PIPE, check_output
import os
import re
import sys
from string import Template
import distutils.sysconfig
if not os.path.isdir( "cache" ):
os.makedirs( "cache" )
opts = Variables( "cache/options.cache" )
opts.AddVariables(
BoolVariable( "DEBUG", """\
Build with \"-g -Wall\" rather than \"-O2\", and include extra debugging
checks in the code.""", True ),
BoolVariable( "DEBUG_MESSAGES", "Enable support for debug messages", True ),
BoolVariable( "PROFILE", "Build with symbols, warnings and other profiling info", False ),
PathVariable( "PREFIX", "The prefix where ffado will be installed to.", "/usr/local", PathVariable.PathAccept ),
PathVariable( "BINDIR", "Overwrite the directory where apps are installed to.", "$PREFIX/bin", PathVariable.PathAccept ),
PathVariable( "LIBDIR", "Overwrite the directory where libs are installed to.", "$PREFIX/lib", PathVariable.PathAccept ),
PathVariable( "INCLUDEDIR", "Overwrite the directory where headers are installed to.", "$PREFIX/include", PathVariable.PathAccept ),
PathVariable( "SHAREDIR", "Overwrite the directory where misc shared files are installed to.", "$PREFIX/share/libffado", PathVariable.PathAccept ),
PathVariable( "LIBDATADIR", "Location for architecture-dependent data.", "$LIBDIR/libffado", PathVariable.PathAccept ),
PathVariable( "MANDIR", "Overwrite the directory where manpages are installed", "$PREFIX/man", PathVariable.PathAccept ),
PathVariable( "PYPKGDIR", "The directory where the python modules get installed.",
distutils.sysconfig.get_python_lib( prefix="$PREFIX" ), PathVariable.PathAccept ),
PathVariable( "UDEVDIR", "Overwrite the directory where udev rules are installed to.", "/lib/udev/rules.d/", PathVariable.PathAccept ),
BoolVariable( "ENABLE_BEBOB", "Enable/Disable support for the BeBoB platform.", True ),
BoolVariable( "ENABLE_FIREWORKS", "Enable/Disable support for the ECHO Audio FireWorks platform.", True ),
BoolVariable( "ENABLE_OXFORD", "Enable/Disable support for the Oxford Semiconductor FW platform.", True ),
BoolVariable( "ENABLE_MOTU", "Enable/Disable support for the MOTU platform.", True ),
BoolVariable( "ENABLE_DICE", "Enable/Disable support for the TCAT DICE platform.", True ),
BoolVariable( "ENABLE_METRIC_HALO", "Enable/Disable support for the Metric Halo platform.", False ),
BoolVariable( "ENABLE_RME", "Enable/Disable support for the RME platform.", True ),
BoolVariable( "ENABLE_DIGIDESIGN", "Enable/Disable support for Digidesign interfaces.", False ),
BoolVariable( "ENABLE_BOUNCE", "Enable/Disable the BOUNCE device.", False ),
BoolVariable( "ENABLE_GENERICAVC", """\
Enable/Disable the the generic avc part (mainly used by apple).
Note that disabling this option might be overwritten by other devices needing
this code.""", False ),
BoolVariable( "ENABLE_ALL", "Enable/Disable support for all devices.", False ),
BoolVariable( "SERIALIZE_USE_EXPAT", "Use libexpat for XML serialization.", False ),
EnumVariable( "BUILD_DOC", "Build API documentation", 'none', allowed_values=('all', 'user', 'none'), ignorecase=2),
EnumVariable( "BUILD_MIXER", "Build the ffado-mixer", 'auto', allowed_values=('auto', 'true', 'false'), ignorecase=2),
BoolVariable( "BUILD_TESTS", """\
Build the tests in their directory. As some contain quite some functionality,
this is on by default.
If you just want to use ffado with jack without the tools, you can disable this.\
""", True ),
BoolVariable( "BUILD_STATIC_TOOLS", "Build a statically linked version of the FFADO tools.", False ),
EnumVariable('DIST_TARGET', 'Build target for cross compiling packagers', 'auto', allowed_values=('auto', 'i386', 'i686', 'x86_64', 'powerpc', 'powerpc64', 'none' ), ignorecase=2),
BoolVariable( "ENABLE_OPTIMIZATIONS", "Enable optimizations and the use of processor specific extentions (MMX/SSE/...).", False ),
BoolVariable( "DETECT_USERSPACE_ENV", "Try to detect the user space environment and add necessary 32/64 bit machine flags.", True ),
BoolVariable( "PEDANTIC", "Enable -Werror and more pedantic options during compile.", False ),
BoolVariable( "CUSTOM_ENV", "Respect CC, CXX, CFLAGS, CXXFLAGS and LDFLAGS.\nOnly meant for distributors and gentoo-users who want to over-optimize their build.\n Using this is not supported by the ffado-devs!", False ),
( "COMPILE_FLAGS", "Deprecated (use CFLAGS and CXXFLAGS with CUSTOM_ENV=True instead). Add additional flags to the environment.\nOnly meant for distributors and gentoo-users who want to over-optimize their build.\n Using this is not supported by the ffado-devs!" ),
EnumVariable( "ENABLE_SETBUFFERSIZE_API_VER", "Report API version at runtime which includes support for dynamic buffer resizing (requires recent jack).", 'auto', allowed_values=('auto', 'true', 'false', 'force'), ignorecase=2),
("PYTHON_INTERPRETER", "Python interpreter to be used by FFADO installation.", "/usr/bin/python"),
)
## Load the builders in config
buildenv=os.environ
env = Environment( tools=['default','scanreplace','pyuic','pyuic4','pyuic5','dbus','doxygen','pkgconfig'], toolpath=['admin'], ENV = buildenv, options=opts )
custom_flags = False
if 'COMPILE_FLAGS' in env and len(env['COMPILE_FLAGS']) > 0:
print("The COMPILE_FLAGS option is deprecated. Use CFLAGS and CXXFLAGS with CUSTOM_ENV=True instead")
custom_flags = True
env.MergeFlags(env['COMPILE_FLAGS'])
if env['CUSTOM_ENV']:
custom_flags = True
# Honour the user choice of compiler (if any).
if 'CC' in os.environ and len(os.environ['CC']) > 0:
env['CC'] = os.environ['CC']
if 'CXX' in os.environ and len(os.environ['CXX']) > 0:
env['CXX'] = os.environ['CXX']
# Honour the user supplied flags (if any), but notify the user that this is not supported.
if 'CFLAGS' in os.environ and len(os.environ['CFLAGS']) > 0:
env.Append(CFLAGS = str(os.environ['CFLAGS'].replace('\"', '')))
if 'CXXFLAGS' in os.environ and len(os.environ['CXXFLAGS']) > 0:
env.Append(CXXFLAGS = str(os.environ['CXXFLAGS'].replace('\"', '')))
if 'LDFLAGS' in os.environ and len(os.environ['LDFLAGS']) > 0:
env.Append(LINKFLAGS = str(os.environ['LDFLAGS'].replace('\"', '')))
if custom_flags:
print('''
* Usage of additional flags is not supported by the ffado-devs.
* Use at own risk!
*
* Flags in use:
* CC = %s
* CXX = %s
* CFLAGS = %s
* CXXFLAGS = %s
* LDFLAGS = %s
''' % (env['CC'], env['CXX'], env['CFLAGS'], env['CXXFLAGS'], env['LINKFLAGS']))
Help( """
For building ffado you can set different options as listed below. You have to
specify them only once, scons will save the last value you used and re-use
that.
To really undo your settings and return to the factory defaults, remove the
"cache"-folder and the file ".sconsign.dblite" from this directory.
For example with: "rm -Rf .sconsign.dblite cache"
Note that this is a development version! Don't complain if its not working!
See www.ffado.org for stable releases.
""" )
Help( opts.GenerateHelpText( env ) )
# make sure the necessary dirs exist
if not os.path.isdir( "cache" ):
os.makedirs( "cache" )
if not os.path.isdir( 'cache/objects' ):
os.makedirs( 'cache/objects' )
CacheDir( 'cache/objects' )
opts.Save( 'cache/options.cache', env )
def ConfigGuess( context ):
context.Message( "Trying to find the system triple: " )
ret = check_output(("/bin/sh", "admin/config.guess")).rstrip()
context.Result( ret )
return ret.decode()
def CheckForApp( context, app ):
context.Message( "Checking whether '" + app + "' executes " )
ret = context.TryAction( app )
context.Result( ret[0] )
return ret[0]
def CheckForPyModule( context, module ):
context.Message( "Checking for the python module '" + module + "' " )
ret = context.TryAction( "$PYTHON_INTERPRETER $SOURCE", "import %s" % module, ".py" )
context.Result( ret[0] )
return ret[0]
def CompilerCheck( context ):
context.Message( "Checking for a working C-compiler " )
ret = context.TryRun( """
#include
int main() {
printf( "Hello World!" );
return 0;
}""", '.c' )[0]
context.Result( ret )
if ret == 0:
return False;
context.Message( "Checking for a working C++-compiler " )
ret = context.TryRun( """
#include
int main() {
std::cout << "Hello World!" << std::endl;
return 0;
}""", ".cpp" )[0]
context.Result( ret )
return ret
def CheckPKG(context, name):
context.Message( 'Checking for %s... ' % name )
ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0]
context.Result( ret )
return ret
tests = {
"ConfigGuess" : ConfigGuess,
"CheckForApp" : CheckForApp,
"CheckForPyModule": CheckForPyModule,
"CompilerCheck" : CompilerCheck,
"CheckPKG" : CheckPKG,
}
tests.update( env['PKGCONFIG_TESTS'] )
tests.update( env['PYUIC_TESTS'] )
tests.update( env['PYUIC4_TESTS'] )
conf = Configure( env,
custom_tests = tests,
conf_dir = "cache/",
log_file = 'cache/config.log' )
version_re = re.compile(r'^(\d+)\.(\d+)\.(\d+)')
def CheckJackdVer():
print('Checking jackd version...', end='')
popen = Popen(("which", 'jackd'), stdout=PIPE, stderr=PIPE)
stdout, stderr = popen.communicate()
assert popen.returncode in (0, 1), "which returned a unexpected status"
if popen.returncode == 1:
print("not installed")
return None
jackd = stdout.decode ().rstrip ()
ret = check_output ((jackd, '--version')).decode() .rstrip ()
ret = ret.split ('\n') [-1]; # Last line.
ret = ret.split () [2]; # Third field.
if not version_re.match (ret):
print("failed to parse version")
return None
print (ret)
# Trim off any "rc" (release candidate) components from the end of the
# version string
ret = ret.split ('rc')[0]
ret = ret.split ('.')
ret = map (int, ret)
return tuple (ret)
if env['SERIALIZE_USE_EXPAT']:
env['SERIALIZE_USE_EXPAT']=1
else:
env['SERIALIZE_USE_EXPAT']=0
if env['ENABLE_BOUNCE'] or env['ENABLE_ALL']:
env['REQUIRE_LIBAVC']=1
else:
env['REQUIRE_LIBAVC']=0
if not env.GetOption('clean'):
#
# Check for working gcc and g++ compilers and their environment.
#
if not conf.CompilerCheck():
print("\nIt seems as if your system isn't even able to compile any C-/C++-programs. Probably you don't have gcc and g++ installed. Compiling a package from source without a working compiler is very hard to do, please install the needed packages.\nHint: on *ubuntu you need both gcc- and g++-packages installed, easiest solution is to install build-essential which depends on gcc and g++.")
Exit( 1 )
# Check for pkg-config before using pkg-config to check for other dependencies.
if not conf.CheckForPKGConfig():
print("\nThe program 'pkg-config' could not be found.\nEither you have to install the corresponding package first or make sure that PATH points to the right directions.")
Exit( 1 )
#
# The following checks are for headers and libs and packages we need.
#
allpresent = 1;
# for cache-serialization.
if env['SERIALIZE_USE_EXPAT']:
allpresent &= conf.CheckHeader( "expat.h" )
allpresent &= conf.CheckLib( 'expat', 'XML_ExpatVersion', '#include ' )
pkgs = {
'libraw1394' : '2.0.5',
'libiec61883' : '1.1.0',
'libconfig++' : '0'
}
if env['REQUIRE_LIBAVC']:
pkgs['libavc1394'] = '0.5.3'
if not env['SERIALIZE_USE_EXPAT']:
if conf.CheckPKG('libxml++-3.0'):
pkgs['libxml++-3.0'] = '3.0.0'
if not('libxml++-3.0' in pkgs):
pkgs['libxml++-2.6'] = '2.13.0'
# Provide a way for users to compile newer libffado which will work
# against older jack installations which will not accept the new API
# version reported at runtime.
have_jack = conf.CheckPKG('jack')
if have_jack:
good_jack1 = conf.CheckPKG('jack < 1.9.0') and conf.CheckPKG('jack >= 0.121.4')
good_jack2 = conf.CheckPKG('jack >= 1.9.9')
else:
jackd_ver = CheckJackdVer()
if jackd_ver:
# If jackd is unknown to pkg-config but is never-the-less
# runnable, use the version number reported by it. This means
# users don't have to have jack development files present on
# their system for this to work.
have_jack = jackd_ver >= (0, 0, 0)
good_jack1 = jackd_ver < (1, 9, 0) and jackd_ver >= (0, 121, 4)
good_jack2 = jackd_ver >= (1, 9, 9)
if env['ENABLE_SETBUFFERSIZE_API_VER'] == 'auto':
if not(have_jack):
print("""
No Jack Audio Connection Kit (JACK) installed: assuming a FFADO
setbuffersize-compatible version will be used.
""")
elif not(good_jack1 or good_jack2):
FFADO_API_VERSION="8"
print("""
Installed Jack Audio Connection Kit (JACK) jack does not support FFADO
setbuffersize API: will report earlier API version at runtime. Consider
upgrading to jack1 >=0.122.0 or jack2 >=1.9.9 at some point, and then
recompile ffado to gain access to this added feature.
""")
else:
print("Installed Jack Audio Connection Kit (JACK) supports FFADO setbuffersize API")
elif env['ENABLE_SETBUFFERSIZE_API_VER'] == 'true':
if (have_jack and not(good_jack1) and not(good_jack2)):
print("""
SetBufferSize API version is enabled but no suitable version of Jack Audio
Connection Kit (JACK) has been found. The resulting FFADO would cause your
jackd to abort with "incompatible FFADO version". Please upgrade to
jack1 >=0.122.0 or jack2 >=1.9.9, or set ENABLE_SETBUFFERSIZE_API_VER to "auto"
or "false".
""")
# Although it's not strictly an error, in almost every case that
# this occurs the user will want to know about it and fix the
# problem, so we exit so they're guaranteed of seeing the above
# message.
Exit( 1 )
else:
print("Will report SetBufferSize API version at runtime")
elif env['ENABLE_SETBUFFERSIZE_API_VER'] == 'force':
print("Will report SetBufferSize API version at runtime")
else:
FFADO_API_VERSION="8"
print("Will not report SetBufferSize API version at runtime")
for pkg in pkgs:
name2 = pkg.replace("+","").replace(".","").replace("-","").upper()
env['%s_FLAGS' % name2] = conf.GetPKGFlags( pkg, pkgs[pkg] )
#print('%s_FLAGS' % name2)
if env['%s_FLAGS'%name2] == 0:
allpresent &= 0
if not allpresent:
print("""
(At least) One of the dependencies is missing. I can't go on without it, please
install the needed packages for each of the lines saying "no".
(Remember to also install the *-devel packages!)
And remember to remove the cache with "rm -Rf .sconsign.dblite cache" so the
results above get rechecked.
""")
Exit( 1 )
# libxml++-2.6 requires a c++11 compiler as of version 2.39.1. The
# gnu++11 standard seems to work both with these later libxml++ versions
# and ffado itself, although a significant number of warnings are
# produced. Add the necessary option to CXXFLAGS if required.
if conf.CheckPKG('libxml++-2.6 >= 2.39.1'):
env.Append(CXXFLAGS = '-std=gnu++11')
if conf.CheckPKG('libxml++-3.0 >= 3.0.0'):
env.Append(CXXFLAGS = '-std=gnu++11')
# Check for C99 lrint() and lrintf() functions used to convert from
# float to integer more efficiently via float_cast.h. If not
# present the standard slower methods will be used instead. This
# might not be the best way of testing for these but it's the only
# way which seems to work properly. CheckFunc() fails due to
# argument count problems.
if 'CFLAGS' in env:
oldcf = env['CFLAGS']
else:
oldcf = ""
env.Append(CFLAGS = '-std=c99')
if conf.CheckLibWithHeader( "m", "math.h", "c", "lrint(3.2);" ):
HAVE_LRINT = 1
else:
HAVE_LRINT = 0
if conf.CheckLibWithHeader( "m", "math.h", "c", "lrintf(3.2);" ):
HAVE_LRINTF = 1
else:
HAVE_LRINTF = 0
env['HAVE_LRINT'] = HAVE_LRINT;
env['HAVE_LRINTF'] = HAVE_LRINTF;
env.Replace(CFLAGS=oldcf)
#
# Optional checks follow:
#
# PyQT checks
if env['BUILD_MIXER'] != 'false':
if ( conf.CheckForApp( 'which pyuic4' ) \
and conf.CheckForPyModule( 'PyQt4' ) \
and conf.CheckForPyModule( 'dbus.mainloop.qt' )) \
or ( conf.CheckForApp( 'which pyuic5' ) \
and conf.CheckForPyModule( 'PyQt5' ) \
and conf.CheckForPyModule( 'dbus.mainloop.pyqt5' )):
env['BUILD_MIXER'] = 'true'
elif not env.GetOption('clean'):
if env['BUILD_MIXER'] == 'auto':
env['BUILD_MIXER'] = 'false'
print("""
The prerequisites ('pyuic4'/'pyuic5' and the python-modules 'dbus' and
'PyQt4'/'PyQt5', the packages could be named like dbus-python and PyQt) to
build the mixer were not found. Therefore the qt mixer will not be installed.""")
else: # env['BUILD_MIXER'] == 'true'
print("""
The prerequisites ('pyuic4'/'pyuic5' and the python-modules 'dbus' and
'PyQt4'/'PyQt5', the packages could be named like dbus-python and PyQt) to
build the mixer were not found, but BUILD_MIXER was requested.""")
Exit( 1 )
env['XDG_TOOLS'] = False
if env['BUILD_MIXER'] == 'true':
if conf.CheckForApp( 'xdg-desktop-menu --help' ) and conf.CheckForApp( 'xdg-icon-resource --help' ):
env['XDG_TOOLS'] = True
else:
print("""
I couldn't find the 'xdg-desktop-menu' and 'xdg-icon-resource' programs. These
are needed to add the fancy entry for the mixer to your menu, but you can still
start it by executing "ffado-mixer".""")
#
# Optional pkg-config
#
pkgs = {
'alsa': '0',
'dbus-1': '1.0',
'dbus-c++-1' : '0',
}
for pkg in pkgs:
name2 = pkg.replace("+","").replace(".","").replace("-","").upper()
env['%s_FLAGS' % name2] = conf.GetPKGFlags( pkg, pkgs[pkg] )
if not env['DBUS1_FLAGS'] or not env['DBUSC1_FLAGS'] or not conf.CheckForApp('which dbusxx-xml2cpp'):
env['DBUS1_FLAGS'] = b""
env['DBUSC1_FLAGS'] = b""
print("""
One of the dbus-headers, the dbus-c++-headers and/or the application
'dbusxx-xml2cpp' where not found. The dbus-server for ffado will therefore not
be built.
""")
else:
# Get the directory where dbus stores the service-files
env['dbus_service_dir'] = conf.GetPKGVariable( 'dbus-1', 'session_bus_services_dir' ).strip()
# this is required to indicate that the DBUS version we use has support
# for platform dependent threading init functions
# this is true for DBUS >= 0.96 or so. Since we require >= 1.0 it is
# always true
env['DBUS1_FLAGS'] += b" -DDBUS_HAS_THREADS_INIT_DEFAULT"
# The controlserver-glue.h file generated by dbusxx-xml2cpp generates
# a large number of instances where call.reader()'s return value is
# stored (in ri) but not used. This generates a compiler warning which
# we can do nothing about. Therefore when compiling dbus-related
# code, suppress the "set but not used" warning.
env['DBUS1_FLAGS'] += b" -Wno-unused-but-set-variable"
config_guess = conf.ConfigGuess()
conf.Finish()
if env['DEBUG']:
print("Doing a debug build")
env.MergeFlags( "-Wall -g -DDEBUG" )
env['DEBUG_MESSAGES'] = True
elif not custom_flags:
# Only merge -O2 to flags if the user has not specified custom flags.
env.MergeFlags( "-O2" )
if env['DEBUG_MESSAGES']:
env.MergeFlags( "-DDEBUG_MESSAGES" )
if env['PROFILE']:
print("Doing a PROFILE build")
env.MergeFlags( "-Wall -g" )
if env['PEDANTIC']:
env.MergeFlags( "-Werror" )
if env['ENABLE_ALL']:
env['ENABLE_BEBOB'] = True
env['ENABLE_FIREWORKS'] = True
env['ENABLE_OXFORD'] = True
env['ENABLE_MOTU'] = True
env['ENABLE_DICE'] = True
env['ENABLE_METRIC_HALO'] = True
env['ENABLE_RME'] = True
env['ENABLE_DIGIDESIGN'] = True
env['ENABLE_BOUNCE'] = True
env['BUILD_STATIC_LIB'] = False
if env['BUILD_STATIC_TOOLS']:
print("Building static versions of the tools...")
env['BUILD_STATIC_LIB'] = True
env['build_base']="#/"
#
# Get the DESTDIR (if wanted) from the commandline
#
env.destdir = ARGUMENTS.get( 'DESTDIR', "" )
#
# Uppercase variables are for usage in code, lowercase versions for usage in
# scons-files for installing.
#
env['BINDIR'] = Template( env['BINDIR'] ).safe_substitute( env )
env['LIBDIR'] = Template( env['LIBDIR'] ).safe_substitute( env )
env['INCLUDEDIR'] = Template( env['INCLUDEDIR'] ).safe_substitute( env )
env['SHAREDIR'] = Template( env['SHAREDIR'] ).safe_substitute( env )
env['LIBDATADIR'] = Template( env['LIBDATADIR'] ).safe_substitute( env )
env['UDEVDIR'] = Template( env['UDEVDIR'] ).safe_substitute( env )
env['PYTHON_INTERPRETER'] = Template( env['PYTHON_INTERPRETER'] ).safe_substitute( env )
env['prefix'] = Template( env.destdir + env['PREFIX'] ).safe_substitute( env )
env['bindir'] = Template( env.destdir + env['BINDIR'] ).safe_substitute( env )
env['libdir'] = Template( env.destdir + env['LIBDIR'] ).safe_substitute( env )
env['includedir'] = Template( env.destdir + env['INCLUDEDIR'] ).safe_substitute( env )
env['sharedir'] = Template( env.destdir + env['SHAREDIR'] ).safe_substitute( env )
env['libdatadir'] = Template( env.destdir + env['LIBDATADIR'] ).safe_substitute( env )
env['mandir'] = Template( env.destdir + env['MANDIR'] ).safe_substitute( env )
env['pypkgdir'] = Template( env.destdir + env['PYPKGDIR'] ).safe_substitute( env )
env['udevdir'] = Template( env.destdir + env['UDEVDIR'] ).safe_substitute( env )
env['PYPKGDIR'] = Template( env['PYPKGDIR'] ).safe_substitute( env )
env['metainfodir'] = Template( env.destdir + "/usr/share/metainfo" ).safe_substitute( env )
env.Command( target=env['sharedir'], source="", action=Mkdir( env['sharedir'] ) )
env.Alias( "install", env['libdir'] )
env.Alias( "install", env['includedir'] )
env.Alias( "install", env['sharedir'] )
env.Alias( "install", env['libdatadir'] )
env.Alias( "install", env['bindir'] )
env.Alias( "install", env['mandir'] )
if env['BUILD_MIXER'] == 'true':
env.Alias( "install", env['pypkgdir'] )
env.Alias( "install", env['metainfodir'] )
#
# shamelessly copied from the Ardour scons file
#
opt_flags = []
env['USE_SSE'] = 0
# guess at the platform, used to define compiler flags
config_cpu = 0
config_arch = 1
config_kernel = 2
config_os = 3
config = config_guess.split ("-")
needs_fPIC = False
#=== Begin Revised CXXFLAGS =========================================
def cpuinfo_kv():
"""generator which reads lines from Linux /proc/cpuinfo and splits them
into key:value tokens and yields (key, value) tuple.
"""
with open('/proc/cpuinfo', 'r') as f:
for line in f:
line = line.strip()
if line:
k,v = line.split(':', 1)
yield (k.strip(), v.strip())
class CpuInfo (object):
"""Collects information about the CPU, mainly from /proc/cpuinfo
"""
def __init__(self):
self.sysname, self.hostname, self.release, self.version, self.machine = os.uname()
# general CPU architecture
self.is_x86 = self.machine in ('i686', 'x86_64') or \
re.match("i[3-5]86", self.machine) or False
self.is_powerpc = self.machine in ('ppc64', 'ppc', 'powerpc', 'powerpc64', 'ppc64le')
#!!! probably not comprehensive
self.is_mips = self.machine == 'mips'
#!!! not a comprehensive list. uname -m on one android phone reports 'armv71'
# I have no other arm devices I can check
self.is_arm = self.machine in ('armv71', )
self.cpu_count = 0
if self.is_x86:
self.cpu_info_x86()
elif self.is_powerpc:
self.cpu_info_ppc()
elif self.is_mips:
self.cpu_info_mips()
# 64-bit (x86_64/AMD64/Intel64)
# Long Mode (x86-64: amd64, also known as Intel 64, i.e. 64-bit capable)
self.is_64bit = (self.is_x86 and 'lm' in self.x86_flags) or \
(self.is_powerpc and \
('970' in self.ppc_type or 'power8' in self.ppc_type.lower()))
# Hardware virtualization capable: vmx (Intel), svm (AMD, Hygon)
self.has_hwvirt = self.is_x86 and (
((self.is_amd or self.is_hygon) and
'svm' in self.x86_flags) or
(self.is_intel and 'vmx' in self.x86_flags))
# Physical Address Extensions (support for more than 4GB of RAM)
self.has_pae = self.is_x86 and 'pae' in self.x86_flags
def cpu_info_x86(self):
"parse /proc/cpuinfo for x86 kernels"
for k,v in cpuinfo_kv():
if k == 'processor':
self.cpu_count += 1
if self.cpu_count > 1:
# assume all CPUs are identical features, no need to
# parse all of them
continue
elif k == 'vendor_id': # AuthenticAMD, HygonGenuine, GenuineIntel
self.vendor_id = v
self.is_amd = v == 'AuthenticAMD'
self.is_hygon = v == 'HygonGenuine'
self.is_intel = v == 'GenuineIntel'
elif k == 'flags':
self.x86_flags = v.split()
elif k == 'model name':
self.model_name = v
elif k == 'cpu family':
self.cpu_family = v
elif k == 'model':
self.model = v
def cpu_info_ppc(self):
"parse /proc/cpuinfo for PowerPC kernels"
# http://en.wikipedia.org/wiki/List_of_PowerPC_processors
# PowerPC 7xx family
# PowerPC 740 and 750, 233-366 MHz
# 745/755, 300–466 MHz
# PowerPC G4 series
# 7400/7410 350 - 550 MHz, uses AltiVec, a SIMD extension of the original PPC specs
# 7450 micro-architecture family up to 1.5 GHz and 256 kB on-chip L2 cache and improved Altivec
# 7447/7457 micro-architecture family up to 1.8 GHz with 512 kB on-chip L2 cache
# 7448 micro-architecture family (1.5 GHz) in 90 nm with 1MB L2 cache and slightly
# improved AltiVec (out of order instructions).
# 8640/8641/8640D/8641D with one or two e600 (Formerly known as G4) cores, 1MB L2 cache
# PowerPC G5 series
# 970 (2003), 64-bit, derived from POWER4, enhanced with VMX, 512 kB L2 cache, 1.4 – 2 GHz
# 970FX (2004), manufactured at 90 nm, 1.8 - 2.7 GHz
# 970GX (2006), manufactured at 90 nm, 1MB L2 cache/core, 1.2 - 2.5 GHz
# 970MP (2005), dual core, 1 MB L2 cache/core, 1.6 - 2.5 GHz
for k,v in cpuinfo_kv():
if k == 'processor':
self.cpu_count += 1
elif k == 'cpu':
self.is_altivec_supported = 'altivec' in v
if ',' in v:
ppc_type, x = v.split(',')
else:
ppc_type = v
self.ppc_type = ppc_type.strip()
# older kernels might not have a 'processor' line
if self.cpu_count == 0:
self.cpu_count += 1
def cpu_info_mips(self):
"parse /proc/cpuinfo for MIPS kernels"
for k,v in cpuinfo_kv():
if k == 'processor':
self.cpu_count += 1
elif k == 'cpu model':
self.mips_cpu_model = v
def is_userspace_32bit(cpuinfo):
"""Even if `uname -m` reports a 64-bit architecture, userspace could still
be 32-bit, such as Debian on powerpc64. This function tries to figure out
if userspace is 32-bit, i.e. we might need to pass '-m32' or '-m64' to gcc.
"""
if not cpuinfo.is_64bit:
return True
# note that having a 64-bit CPU means nothing for these purposes. You could
# run a completely 32-bit system on a 64-bit capable CPU.
answer = None
# If setting DIST_TARGET to i686 on a 64-bit CPU to facilitate
# compilation of a multilib environment, force 32-bit.
if env['DIST_TARGET'] == 'i686':
return True
# Debian ppc64 returns machine 'ppc64', but userspace might be 32-bit
# We'll make an educated guess by examining a known executable
exe = '/bin/mount'
if os.path.isfile(exe):
#print('Found %s' % exe)
if os.path.islink(exe):
real_exe = os.path.join(os.path.dirname(exe), os.readlink(exe))
#print('%s is a symlink to %s' % (exe, real_exe))
else:
real_exe = exe
# presumably if a person is running this script, they should have
# a gcc toolchain installed...
x = check_output(('objdump', '-Wi', real_exe)).decode()
# should emit a line that looks like this:
# /bin/mount: file format elf32-i386
# or like this:
# /bin/mount: file format elf64-x86-64
# or like this:
# /bin/mount: file format elf32-powerpc
for line in x.split('\n'):
line = line.strip()
if line.startswith(real_exe):
x, fmt = line.rsplit(None, 1)
answer = 'elf32' in fmt
break
else:
print('!!! Not found %s' % exe)
return answer
def cc_flags_x86(cpuinfo, enable_optimizations):
"""add certain gcc -m flags based on CPU features
"""
# See http://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/i386-and-x86_002d64-Options.html
cc_opts = []
if cpuinfo.machine == 'i586':
cc_opts.append('-march=i586')
elif cpuinfo.machine == 'i686':
cc_opts.append('-march=i686')
if 'mmx' in cpuinfo.x86_flags:
cc_opts.append('-mmmx')
# map from proc/cpuinfo flags to gcc options
opt_flags = [
('sse', ('-mfpmath=sse', '-msse')),
('sse2', '-msse2'),
('ssse3', '-mssse3'),
('sse4', '-msse4'),
('sse4_1', '-msse4.1'),
('sse4_2', '-msse4.2'),
('sse4a', '-msse4a'),
('3dnow', '-m3dnow'),
]
if enable_optimizations:
for flag, gccopt in opt_flags:
if flag in cpuinfo.x86_flags:
if isinstance(gccopt, (tuple, list)):
cc_opts.extend(gccopt)
else:
cc_opts.append(gccopt)
return cc_opts
def cc_flags_powerpc(cpuinfo, enable_optimizations):
"""add certain gcc -m flags based on CPU model
"""
cc_opts = []
if cpuinfo.is_altivec_supported:
cc_opts.append ('-maltivec')
cc_opts.append ('-mabi=altivec')
if re.match('74[0145][0578]A?', cpuinfo.ppc_type) is not None:
cc_opts.append ('-mcpu=7400')
cc_opts.append ('-mtune=7400')
elif re.match('750', cpuinfo.ppc_type) is not None:
cc_opts.append ('-mcpu=750')
cc_opts.append ('-mtune=750')
elif re.match('PPC970', cpuinfo.ppc_type) is not None:
cc_opts.append ('-mcpu=970')
cc_opts.append ('-mtune=970')
elif re.match('Cell Broadband Engine', cpuinfo.ppc_type) is not None:
cc_opts.append('-mcpu=cell')
cc_opts.append('-mtune=cell')
return cc_opts
#=== End Revised CXXFLAGS =========================================
# Autodetect
if env['DIST_TARGET'] == 'auto':
if re.search ("x86_64", config[config_cpu]) is not None:
env['DIST_TARGET'] = 'x86_64'
elif re.search("i[0-5]86", config[config_cpu]) is not None:
env['DIST_TARGET'] = 'i386'
elif re.search("i686", config[config_cpu]) is not None:
env['DIST_TARGET'] = 'i686'
elif re.search("powerpc64", config[config_cpu]) is not None:
env['DIST_TARGET'] = 'powerpc64'
elif re.search("powerpc", config[config_cpu]) is not None:
env['DIST_TARGET'] = 'powerpc'
else:
env['DIST_TARGET'] = config[config_cpu]
print("Detected DIST_TARGET = " + env['DIST_TARGET'])
#=== Begin Revised CXXFLAGS =========================================
# comment on DIST_TARGET up top implies it can be used for cross-compiling
# but that's not true because even if it is not 'auto' the original
# script still reads /proc/cpuinfo to determine gcc arch flags.
# This script does the same as the original. Needs to be fixed someday.
cpuinfo = CpuInfo()
if cpuinfo.is_x86:
opt_flags.extend(cc_flags_x86(cpuinfo, env['ENABLE_OPTIMIZATIONS']))
if cpuinfo.is_powerpc:
opt_flags.extend(cc_flags_powerpc(cpuinfo, env['ENABLE_OPTIMIZATIONS']))
if '-msse' in opt_flags:
env['USE_SSE'] = 1
if '-msse2' in opt_flags:
env['USE_SSE2'] = 1
if env['DETECT_USERSPACE_ENV']:
m32 = is_userspace_32bit(cpuinfo)
print('User space is %s' % (m32 and '32-bit' or '64-bit'))
if cpuinfo.is_powerpc:
if m32:
print("Doing a 32-bit PowerPC build for %s CPU" % cpuinfo.ppc_type)
machineflags = { 'CXXFLAGS' : ['-m32'] }
else:
print("Doing a 64-bit PowerPC build for %s CPU" % cpuinfo.ppc_type)
machineflags = { 'CXXFLAGS' : ['-m64'] }
env.MergeFlags( machineflags )
elif cpuinfo.is_x86:
if m32:
print("Doing a 32-bit %s build for %s" % (cpuinfo.machine, cpuinfo.model_name))
if cpuinfo.machine == 'x86_64':
machineflags = { 'CXXFLAGS' : ['-mx32'] }
else:
machineflags = { 'CXXFLAGS' : ['-m32'] }
else:
print("Doing a 64-bit %s build for %s" % (cpuinfo.machine, cpuinfo.model_name))
machineflags = { 'CXXFLAGS' : ['-m64'] }
needs_fPIC = True
env.MergeFlags( machineflags )
#=== End Revised CXXFLAGS =========================================
if needs_fPIC or ( 'COMPILE_FLAGS' in env and '-fPIC' in env['COMPILE_FLAGS'] ):
env.MergeFlags( "-fPIC" )
# end of processor-specific section
if env['ENABLE_OPTIMIZATIONS']:
opt_flags.extend (["-fomit-frame-pointer","-ffast-math","-funroll-loops"])
env.MergeFlags( opt_flags )
print("Doing an optimized build...")
try:
env['REVISION'] = check_output(('svnversion', '.',)).decode().rstrip()
except:
env['REVISION'] = ''
# This may be as simple as '89' or as complex as '4123:4184M'.
# We'll just use the last bit.
env['REVISION'] = env['REVISION'].split(':')[-1]
# Assume an unversioned directory indicates a release.
if env['REVISION'].startswith ('Unversioned'):
env['REVISION'] = ''
# try to circumvent localized versions
if env['REVISION'].startswith ('export'):
env['REVISION'] = ''
# avoid the 1.999.41- type of version for exported versions
if env['REVISION'] != '':
env['REVISIONSTRING'] = '-' + env['REVISION']
else:
env['REVISIONSTRING'] = ''
env['FFADO_API_VERSION'] = FFADO_API_VERSION
env['PACKAGE'] = "libffado"
env['VERSION'] = FFADO_VERSION
env['LIBVERSION'] = "1.0.0"
env['CONFIGDIR'] = "~/.ffado"
env['CACHEDIR'] = "~/.ffado"
env['USER_CONFIG_FILE'] = env['CONFIGDIR'] + "/configuration"
env['SYSTEM_CONFIG_FILE'] = env['SHAREDIR'] + "/configuration"
env['REGISTRATION_URL'] = "http://ffado.org/deviceregistration/register.php?action=register"
#
# To have the top_srcdir as the doxygen-script is used from auto*
#
env['top_srcdir'] = env.Dir( "." ).abspath
#
# Start building
#
env.ScanReplace( "config.h.in" )
env.ScanReplace( "config_debug.h.in" )
env.ScanReplace( "version.h.in" )
# ensure that the config.h is updated
env.Depends( "config.h", "SConstruct" )
env.Depends( "config.h", 'cache/options.cache' )
# update version.h whenever the version or SVN revision changes
env.Depends( "version.h", env.Value(env['REVISION']))
env.Depends( "version.h", env.Value(env['VERSION']))
env.Depends( "libffado.pc", "SConstruct" )
pkgconfig = env.ScanReplace( "libffado.pc.in" )
env.Install( env['libdir'] + '/pkgconfig', pkgconfig )
env.Install( env['sharedir'], 'configuration' )
subdirs=['src','libffado','support','doc']
if env['BUILD_TESTS']:
subdirs.append('tests')
env.SConscript( dirs=subdirs, exports="env" )
if 'debian' in COMMAND_LINE_TARGETS:
env.SConscript("deb/SConscript", exports="env")
# By default only src is built but all is cleaned
if not env.GetOption('clean'):
Default( 'src' )
Default( 'support' )
if env['BUILD_TESTS']:
Default( 'tests' )
if env['BUILD_DOC'] != 'none':
Default( 'doc' )
env.Install( env['metainfodir'], "support/xdg/ffado-mixer.appdata.xml" )
#
# Deal with the DESTDIR vs. xdg-tools conflict (which is basicely that the
# xdg-tools can't deal with DESTDIR, so the packagers have to deal with this
# their own :-/
#
if len(env.destdir) > 0:
if not len( ARGUMENTS.get( "WILL_DEAL_WITH_XDG_MYSELF", "" ) ) > 0:
print("""
WARNING!
You are using the (packagers) option DESTDIR to install this package to a
different place than the real prefix. As the xdg-tools can't cope with
that, the .desktop-files are not installed by this build, you have to
deal with them your own.
(And you have to look into the SConstruct to learn how to disable this
message.)
""")
else:
def CleanAction( action ):
if env.GetOption( "clean" ):
env.Execute( action )
if env['BUILD_MIXER'] == 'true' and env['XDG_TOOLS']:
if not env.GetOption("clean"):
action = "install"
else:
action = "uninstall"
mixerdesktopaction = env.Action( "-xdg-desktop-menu %s support/xdg/ffado.org-ffadomixer.desktop" % action )
mixericonaction = env.Action( "-xdg-icon-resource %s --size 64 --novendor --context apps support/xdg/hi64-apps-ffado.png ffado" % action )
env.Command( "__xdgstuff1", None, mixerdesktopaction )
env.Command( "__xdgstuff2", None, mixericonaction )
env.Alias( "install", ["__xdgstuff1", "__xdgstuff2" ] )
CleanAction( mixerdesktopaction )
CleanAction( mixericonaction )
#
# Create a tags-file for easier emacs/vim-source-browsing
# I don't know if the dependency is right...
#
findcommand = "find . \( -path \"*.h\" -o -path \"*.cpp\" -o -path \"*.c\" \) \! -path \"*.svn*\" \! -path \"./doc*\" \! -path \"./cache*\""
env.Command( "tags", "", findcommand + " |xargs ctags" )
env.Command( "TAGS", "", findcommand + " |xargs etags" )
env.AlwaysBuild( "tags", "TAGS" )
if 'NoCache' in dir(env):
env.NoCache( "tags", "TAGS" )
# Another convinience target
if env.GetOption( "clean" ):
env.Execute( "rm cache/objects -Rf" )
#
# vim: ts=4 sw=4 et
libffado-2.4.5/README 0000644 0001750 0000144 00000033421 14206145246 013547 0 ustar jwoithe users FFADO v2.4
==========
The FFADO project aims to provide a free driver implementation for FireWire
(IEEE1394, iLink) based audio interfaces. The focus of the project are on
audio/music production rather than consumer audio. This means that although
we intend to supported all features at some point, consumer features are
considered less important. The most obvious example of a consumer feature
is AC3/DTS pass-through support, which is unsupported at the moment.
This package provides the libffado shared library that provides a unified
programming interface to configure and use all supported devices. Currently
this library is used by the "firewire" backends of the jack audio connection
kit sound server (jackaudio.org). This backend provides audio and midi
support, and is available both in jackd and its multiprocessor variant
jackdmp. At present there is no support for ALSA or pulseaudio, although
jack bridging solutions may help in some situations.
Access to the device internal configuration (the internal mixer and device
settings) is exposed using the ffado-dbus-server daemon. This daemon
exposes the configurable parameters of all detected devices through DBUS.
The ffado-mixer application in support/mixer/ presents a GUI to control these
parameters.
Features
--------
* 24-bit audio input/output (number of channels only limited by interface
hardware)
* supports for all sample rates a device supports
* MIDI input/output (unlimited number of channels)
* Support for S/PDIF and ADAT/SMUX I/O
* Internal mixer and device control support for all officially supported
devices (NOTE: no support for internal DSP)
* Support for device aggregation (limited to devices on the same bus)
Device Support
--------------
The "officially supported" label is only given to devices that fulfil the
following:
* at least one of the developers has the device
* the vendor provides development support (access to information)
* the device works
The devices which are officially supported are:
* ESI Quatafire 610
* Terratec Producer Phase 88
* Focusrite Saffire (original/white)
* Focusrite Saffire Pro10
* Focusrite Saffire Pro26
* Focusrite Saffire Pro14, Pro40
* ECHO AudioFire2, AudioFire4, AudioFire8, AudioFire12
* Mackie Onyx Mixer FireWire expansion
* RME Fireface 400, RME Fireface 800
The FFADO driver is written to provide generic support for all devices it
might be able to handle. This means that most devices based on the BridgeCo
BeBoB, the ECHO FireWorks platform or the TC Electronics DICE platform will
work, at least to a certain extent. For some devices specific functions
have been added to augment the generic framework and provide enhanced
support, usually in the area of device and mixer control.
FFADO includes device-specific functionality for following devices. The
code has been developed based on feedback received from users, and it has
been reported to work by users. Note that FFADO may not support all device
functions.
* Presonus Firebox and Inspire1394
* Presonus FireStudio Tube, FireStudio Project
* M-Audio Ozonic, FireWire Solo
* M-Audio Profire 2626, 610
* M-Audio Audiophile and 410 (latest firmware and startup workaround needed,
see http://sourceforge.net/p/ffado/mailman/message/30807938)
* M-Audio 1814 and ProjectMix (mixer only, audio streaming not supported. and
FireWire 1814 needs startup workaround above)
* Focusrite Saffire Pro24
* Focusrite Saffire Pro24 DSP (audio streaming only, DSP control not available)
* Yamaha GO44 and GO46
Devices that have been reported to (partially) work with the generic support:
* Presonus FirePod / FP10
* Alesis io14
* TC Konnekt 8, Konnekt 24D, Konnekt Live
As a result of a significant reverse-engineering effort a selection of
devices from MOTU are supported. The developers had no support from the
device vendor and this of course limits the extent to which problems can be
solved. You have been warned. Please do not buy devices for which support
is based upon reverse engineering, nor from vendors who are hostile towards
Linux like MOTU. Value the support that some vendors provide and buy their
stuff. Check ffado.org for details. It can't be said enough: currently it
is extremely unwise to buy a MOTU device if you intend to use Linux.
MOTU devices reported to work with FFADO are:
* MOTU Traveler
* MOTU 828mkII, MOTU Ultralite, MOTU 896HD, MOTU 8pre, MOTU 4pre
* Audio only: MOTU Ultralite mk3, MOTU Traveler mk3, MOTU 896mk3, MOTU 828mk3
* Audio only, FireWire interface only: MOTU Ultralite mk3 hybrid
"Audio only" means that FFADO can be used to stream audio to and from the
device, control sample rate and clock source. Control of the mixer and DSP
functions is not presently supported. It is planned but no ETA is available
at this stage.
Devices for which work is in progress. These are not yet usable:
* RME UFX and UCX FireWire devices
Usupported devices:
* Presonus FireStation
* Other TC Konnekt devices
* Other Alesis devices
* Metric Halo devices
We constantly try to persuade vendors to help us extend our device support.
Dependencies
------------
FFADO uses the scons build system, which must be available on the system
when building FFADO. It is not a runtime dependency. Scons 2 is currently
used to build FFADO. Work continues on making FFADO's scons scripts
compatible with both scons 2 and 3. Testing and bug reports when using
scons 3 are welcomed.
To build libffado you need several libraries. For all libraries a
version is provided which is a "known good" version. The first few
libraries it seems it is not necessary that the version must
match. The chances that it works also with an older versions are good:
libxml++2 (>= 2.6.13)
These libraries here should be at least the version listed:
libraw1394 (>= 2.0.7), https://ieee1394.wiki.kernel.org/
libiec61883 (>= 1.1.0), https://ieee1394.wiki.kernel.org/
dbus-1 (>= 1.0), http://dbus.freedesktop.org
dbus-c++ (>= 0), http://sourceforge.net/apps/mediawiki/dbus-cplusplus/
libconfig (>= 0), http://www.hyperrealm.com/libconfig/
Currently only the jackd audio server is supported:
jackd (>= 0.109.12), http://jackaudio.org
While jack1 0.109.12 will work, jack1 >= 0.122.0 or jack2 >= 1.9.9 are
recommended if support for jack's setbufsize functionality is desired.
Optionally, but recommended is that you install qjackctl:
qjackctl (>= 0.2.20.10), http://sourceforge.net/projects/qjackctl
To build the optional ffado device mixer control utility you also require:
Qt >= 4.0, http://qt-project.org/
SIP >= 4.7.0, http://www.riverbankcomputing.co.uk/software/sip/intro
PyQt (note below), http://www.riverbankcomputing.co.uk/software/pyqt/intro
dbus-python >= 0.82.0, http://dbus.freedesktop.org/releases/dbus-python/
The version of PyQt must be chosen to exactly match the version of Qt in use.
For Qt 4.x use PyQt 4.x.
SIP is only required to compile PyQt. If using a binary package of PyQt
SIP should not be needed.
Packages for building on Debian/Ubuntu distributions are installed with:
$ sudo apt-get install build-essential subversion scons libxml++2.6-dev \
libiec61883-dev libdbus-1-dev libdbus-c++-bin \
libdbus-c++-dev libconfig++-dev pyqt5-dev-tools \
python3-dbus.mainloop.pyqt5 pyqt5-sip
How to build
------------
If you want to build the release version you can simply do following:
$ scons
$ scons install [as root or via sudo]
If you want some debug information (because something seems not
to work correctly) you can try to do:
$ scons DEBUG=yes
$ scons install [as root or via sudo]
Cleaning a build is done with:
$ scons -c -Q
More extended instructions can be found here:
http://subversion.ffado.org/wiki/InstallingFfadoFromSource
NOTE: In order to build jackd with ffado support, you have
to install libffado before you build jackd. The backend to use in jackd is
"firewire".
NOTE: the beta versions are distributed with debugging enabled by default.
DISTRIBUTION PACKAGERS NOTE: Please do not enable support for devices
if it is not on by default. If device support for a specific device
is not turned on by default by the developers, it means that it is not
ready yet. Most of the time it is placeholder code for future devices.
Running jackd
-------------
The easiest way to run this is using qjackctl. There are only minor
differences with the other backends, however you should change some
of the default values:
- It is recommended to change the "periods/buffer" field to 3, especially
if you use low period sizes (=< 128)
- It is recommended to raise the RT priority to 70.
In order to get it running from the command line, you need to provide some
arguments to jackd.
Run
$ jackd -d firewire --help
to see the backend options. You can easily figure out how to set them using
the remarks given above (for qjackctl).
For the other aspects of jackd usage, consult the jackd documentation.
Here is a sample session (without realtime support enabled):
$ jackd -d firewire
no message buffer overruns
jackd 0.111.0
Copyright 2001-2005 Paul Davis and others.
jackd comes with ABSOLUTELY NO WARRANTY
This is free software, and you are welcome to redistribute it
under certain conditions; see the file COPYING for details
JACK compiled with System V SHM support.
loading driver ..
3106528665: (ffado.cpp)[ 99] ffado_streaming_init: libffado 1.999.20 built Apr 26 2008 20:26:32
libiec61883 warning: Established connection on channel 0.
You may need to manually set the channel on the receiving node.
libiec61883 warning: Established connection on channel 1.
You may need to manually set the channel on the transmitting node.
(Note: you can safely ignore the libiec61883 warnings, they are normal.)
An important remark is that for good performance, one should always run jack
with the -R flag to enable realtime scheduling for critical threads:
$ jackd -R -d firewire
In most cases this is now the default.
For best results across most hardware it is necessary to use a kernel
configured with the "Low latency desktop" option (CONFIG_PREEMPT) enabled.
Most distributions provide this as an option, often called "low latency".
In general it is no longer necessary to use an RT-patched kernel.
Ffado-mixer look and feel
-------------------------
The look and feel of ffado-mixer can be changed via QT themes. When a dark
mode is required, install a suitable QT theme. Some users have found the
dark theme from UKUI to work well with ffado-mixer (often available in
distributions through the qt5-ukui-platformtheme package).
In case of problems
-------------------
First of all, check whether your problem is a known issue, and whether
it is a FFADO problem. Use your chosen web search engine for this.
Many distributor kernels now include the alternative ALSA audio streaming
drivers for selected FireWire audio interfaces (snd-bebob, snd-dice, etc).
These are developed independently of FFADO. If these kernel modules are
loaded then FFADO's streaming engine cannot be used: using jackd's
"firewire" driver will fail because the kernel drivers have ownership of the
interface. To continue to use FFADO's streaming system, the applicable
snd-* module must be unloaded from the kernel and prevented from loading on
boot. Use "rmmod" to remove the module from the running system, and
blacklist the relevant snd-* module in a file under /lib/modprobe.d/ (or
your distribution's equivalent).
When seeking support from the developers keep in mind that none of the FFADO
developers are paid to work on FFADO or to support FFADO users. Answering
the same question multiple times reduces the amount of time they have to
work on the code. Before contacting the developers please see if your query
or problem has been seen before. The following places are helpful:
* http://www.ffado.org/
* http://subversion.ffado.org/
* your chosen search engine
(the terms "ffado-devel" and "ffado-user" work well)
If you have tried to find a solution to your problem but couldn't or are
confused, don't hesitate to ask for help. The preferred way is by signing
up to the mailing list as described on http://www.ffado.org/?q=contact.
Writing a bug report
--------------------
Note that the more effort you put in your bug report, the more effort we
will put into helping you.
Make sure you have compiled a DEBUG=yes version of
libffado. If not there is no way we can trace the problem.
When reporting a problem, please run jackd with the --verbose option,
and add the -v6 option to the firewire backend:
$ jackd --verbose [...] -d firewire -v6 [...]
( [...] = other options )
This will generate an increadible amount of debug output that should
contain what we need to track down the problem. If you have troubles
saving the output, try redirecting it to a file:
$ jackd --verbose -d firewire -v6 2> ffado-jack.log
this will create a ffado.log file containing the output. Use CTRL-C
to exit jack if necessary.
The distribution contains a tool to gather some information about your
system. When FFADO is installed on the system it can be run directly:
$ ffado-diag > ffado-diag.log
It is also possible to run it from the source tree:
$ cd support/tools
$ python ffado-diag.py > ffado-diag.log
It will check your system for basic problems and gather some information
regarding your hardware configuration. This will allow us to diagnose
your problem faster.
Once the logs have been created you can create a support ticket at
http://subversion.ffado.org/newticket
Be sure to include the following information:
* the log file(s) (zipped/tar.gz'ed and attached)
* the device you're trying to use
* a description of what went wrong and how to reproduce it. You
preferably try to figure out a sequence of steps that can reliably
reproduce the issue on your system. A one-time failure is very difficult
to diagnose and/or fix.
* the distribution and its version
libffado-2.4.5/admin/ 0000755 0001750 0000144 00000000000 14206145612 013751 5 ustar jwoithe users libffado-2.4.5/admin/dbus.py 0000644 0001750 0000144 00000002740 14206145246 015266 0 ustar jwoithe users #!/usr/bin/python
#
# Copyright (C) 2007-2008 Arnold Krille
# Copyright (C) 2007-2008 Pieter Palmers
#
# This file is part of FFADO
# FFADO = Free FireWire (pro-)audio drivers for Linux
#
# FFADO is based upon FreeBoB.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
#
# xml translator
#
def dbusxx_xml2cpp_adaptor_action( target, source, env ):
env.Execute( "dbusxx-xml2cpp %s --adaptor=%s" % ( source[0], target[0] ) )
return 0
def dbusxx_xml2cpp_proxy_action( target, source, env ):
env.Execute( "dbusxx-xml2cpp %s --proxy=%s" % ( source[0], target[0] ) )
return 0
def generate( env, **kw ):
env['BUILDERS']['Xml2Cpp_Adaptor'] = env.Builder(action = dbusxx_xml2cpp_adaptor_action,
suffix = '.h', src_suffix = '.xml')
env['BUILDERS']['Xml2Cpp_Proxy'] = env.Builder(action = dbusxx_xml2cpp_proxy_action,
suffix = '.h', src_suffix = '.xml', single_source=True )
def exists( env ):
return 1
libffado-2.4.5/admin/doxygen.py 0000644 0001750 0000144 00000015431 14206145246 016007 0 ustar jwoithe users #!/usr/bin/python
#
# Copyright (C) 2007-2008 Arnold Krille
#
# This file is part of FFADO
# FFADO = Free FireWire (pro-)audio drivers for Linux
#
# FFADO is based upon FreeBoB.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
#
# Astxx, the Asterisk C++ API and Utility Library.
# Copyright (C) 2005, 2006 Matthew A. Nicholson
# Copyright (C) 2006 Tim Blechmann
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License version 2.1 as published by the Free Software Foundation.
#
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import os
import os.path
import glob
from fnmatch import fnmatch
from functools import reduce
def DoxyfileParse(file_contents):
"""
Parse a Doxygen source file and return a dictionary of all the values.
Values will be strings and lists of strings.
"""
data = {}
import shlex
lex = shlex.shlex(instream = file_contents.decode(), posix = True)
lex.wordchars += "*+./-:"
lex.whitespace = lex.whitespace.replace("\n", "")
lex.escape = ""
lineno = lex.lineno
token = lex.get_token()
key = token # the first token should be a key
last_token = ""
key_token = False
next_key = False
new_data = True
def append_data(data, key, new_data, token):
if new_data or len(data[key]) == 0:
data[key].append(token)
else:
data[key][-1] += token
while token:
if token in ['\n']:
if last_token not in ['\\']:
key_token = True
elif token in ['\\']:
pass
elif key_token:
key = token
key_token = False
else:
if token == "+=":
if not key in data:
data[key] = list()
elif token == "=":
data[key] = list()
else:
append_data( data, key, new_data, token )
new_data = True
last_token = token
token = lex.get_token()
if last_token == '\\' and token != '\n':
new_data = False
append_data( data, key, new_data, '\\' )
# compress lists of len 1 into single strings
to_pop = []
for (k, v) in data.items():
if len(v) == 0:
# data.pop(k) # Shouldn't modify dictionary while looping
to_pop.append(k)
# items in the following list will be kept as lists and not converted to strings
if k in ["INPUT", "FILE_PATTERNS", "EXCLUDE_PATTERNS"]:
continue
if len(v) == 1:
data[k] = v[0]
for k in to_pop:
data.pop(k)
return data
def DoxySourceScan(node, env, path):
"""
Doxygen Doxyfile source scanner. This should scan the Doxygen file and add
any files used to generate docs to the list of source files.
"""
default_file_patterns = [
'*.c', '*.cc', '*.cxx', '*.cpp', '*.c++', '*.java', '*.ii', '*.ixx',
'*.ipp', '*.i++', '*.inl', '*.h', '*.hh ', '*.hxx', '*.hpp', '*.h++',
'*.idl', '*.odl', '*.cs', '*.php', '*.php3', '*.inc', '*.m', '*.mm',
'*.py',
]
default_exclude_patterns = [
'*~',
]
sources = []
data = DoxyfileParse(node.get_contents())
if data.get("RECURSIVE", "NO") == "YES":
recursive = True
else:
recursive = False
file_patterns = data.get("FILE_PATTERNS", default_file_patterns)
exclude_patterns = data.get("EXCLUDE_PATTERNS", default_exclude_patterns)
for node in data.get("INPUT", []):
if os.path.isfile(node):
sources.append(node)
elif os.path.isdir(node):
if recursive:
for root, dirs, files in os.walk(node):
for f in files:
filename = os.path.join(root, f)
pattern_check = reduce(lambda x, y: x or bool(fnmatch(filename, y)), file_patterns, False)
exclude_check = reduce(lambda x, y: x and fnmatch(filename, y), exclude_patterns, True)
if pattern_check and not exclude_check:
sources.append(filename)
else:
for pattern in file_patterns:
sources.extend(glob.glob("/".join([node, pattern])))
sources = map( lambda path: env.File(path), sources )
return sources
def DoxySourceScanCheck(node, env):
"""Check if we should scan this file"""
return os.path.isfile(node.path)
def DoxyEmitter(source, target, env):
"""Doxygen Doxyfile emitter"""
# possible output formats and their default values and output locations
output_formats = {
"HTML": ("YES", "html"),
"LATEX": ("YES", "latex"),
"RTF": ("NO", "rtf"),
"MAN": ("YES", "man"),
"XML": ("NO", "xml"),
}
data = DoxyfileParse(source[0].get_contents())
targets = []
out_dir = data.get("OUTPUT_DIRECTORY", ".")
# add our output locations
for (k, v) in output_formats.items():
if data.get("GENERATE_" + k, v[0]) == "YES":
targets.append(env.Dir( os.path.join(out_dir, data.get(k + "_OUTPUT", v[1]))) )
# don't clobber targets
for node in targets:
env.Precious(node)
# set up cleaning stuff
for node in targets:
env.Clean(node, node)
return (targets, source)
def generate(env):
"""
Add builders and construction variables for the
Doxygen tool. This is currently for Doxygen 1.4.6.
"""
doxyfile_scanner = env.Scanner(
DoxySourceScan,
"DoxySourceScan",
scan_check = DoxySourceScanCheck,
)
import SCons.Builder
doxyfile_builder = SCons.Builder.Builder(
action = "cd ${SOURCE.dir} && ${DOXYGEN} ${SOURCE.file}",
emitter = DoxyEmitter,
target_factory = env.fs.Entry,
single_source = True,
source_scanner = doxyfile_scanner,
)
env.Append(BUILDERS = {
'Doxygen': doxyfile_builder,
})
env.AppendUnique(
DOXYGEN = 'doxygen',
)
def exists(env):
"""
Make sure doxygen exists.
"""
return env.Detect("doxygen")
libffado-2.4.5/admin/pkgconfig.py 0000644 0001750 0000144 00000006661 14206145246 016306 0 ustar jwoithe users #!/usr/bin/python
#
# Copyright (C) 2007-2008 Arnold Krille
#
# This file is part of FFADO
# FFADO = Free FireWire (pro-)audio drivers for Linux
#
# FFADO is based upon FreeBoB.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
#
# Taken from http://www.scons.org/wiki/UsingPkgConfig
# and heavily modified
#
import subprocess
#
# Checks for pkg-config
#
def CheckForPKGConfig( context, version='0.0.0' ):
context.Message( "Checking for pkg-config (at least version %s)... " % version )
ret = context.TryAction( "pkg-config --atleast-pkgconfig-version=%s" %version )[0]
context.Result( ret )
return ret
#
# Checks for the given package with an optional version-requirement
#
# The flags (which can be imported into the environment by env.MergeFlags(...)
# are exported as env['NAME_FLAGS'] where name is built by removing all +,-,.
# and upper-casing.
#
def CheckForPKG( context, name, version="" ):
name2 = name.replace("+","").replace(".","").replace("-","")
if version == "":
context.Message( "Checking for %s... \t" % name )
ret = context.TryAction( "pkg-config --exists '%s'" % name )[0]
else:
context.Message( "Checking for %s (%s or higher)... \t" % (name,version) )
ret = context.TryAction( "pkg-config --atleast-version=%s '%s'" % (version,name) )[0]
if ret:
context.env['%s_FLAGS' % name2.upper()] = context.env.ParseFlags("!pkg-config --cflags --libs %s" % name)
context.Result( ret )
return ret
#
# Checks for the existance of the package and returns the packages flags.
#
# This should allow caching of the flags so that pkg-config is called only once.
#
def GetPKGFlags( context, name, version="" ):
import os
if version == "":
context.Message( "Checking for %s... \t" % name )
ret = context.TryAction( "pkg-config --exists '%s'" % name )[0]
else:
context.Message( "Checking for %s (%s or higher)... \t" % (name,version) )
ret = context.TryAction( "pkg-config --atleast-version=%s '%s'" % (version,name) )[0]
if not ret:
context.Result( ret )
return ret
out = subprocess.Popen(['pkg-config', '--cflags', '--libs', name], stdout=subprocess.PIPE)
ret = out.stdout.read()
context.Result( True )
return ret
#
# Checks for the existance of the package and returns the value of the specified variable.
#
def GetPKGVariable( context, name, variable ):
import os
context.Message( "Checking for variable %s in package %s... \t" % (variable,name) )
ret = context.TryAction( "pkg-config --exists '%s'" % name )[0]
if not ret:
context.Result( ret )
return ret
out = subprocess.Popen(['pkg-config', '--variable=%s' % variable, name], stdout=subprocess.PIPE)
ret = out.stdout.read()
context.Result( True )
return ret
def generate( env, **kw ):
env['PKGCONFIG_TESTS' ] = { 'CheckForPKGConfig' : CheckForPKGConfig, 'CheckForPKG' : CheckForPKG, 'GetPKGFlags' : GetPKGFlags, 'GetPKGVariable' : GetPKGVariable }
def exists( env ):
return 1
libffado-2.4.5/admin/pyuic.py 0000644 0001750 0000144 00000002762 14206145246 015466 0 ustar jwoithe users #!/usr/bin/python
#
# Copyright (C) 2007-2008 Arnold Krille
#
# This file is part of FFADO
# FFADO = Free FireWire (pro-)audio drivers for Linux
#
# FFADO is based upon FreeBoB.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
import imp
def pyuic_action( target, source, env ):
env.Execute( "pyuic " + str( source[0] ) + " > " + str( target[0] ) )
return 0
def pyuic_string( target, source, env ):
return "building '%s' from '%s'" % ( str(target[0]), str( source[0] ) )
def PyQtCheck( context ):
context.Message( "Checking for pyuic (by checking for the python module pyqtconfig) " )
ret = True
try:
imp.find_module( "pyqtconfig" )
except ImportError:
ret = False
context.Result( ret )
return ret
def generate( env, **kw ):
env['BUILDERS']['PyUIC'] = env.Builder( action=pyuic_action, src_suffix=".ui", single_source=True )
env['PYUIC_TESTS'] = { "PyQtCheck" : PyQtCheck }
def exists( env ):
return 1
libffado-2.4.5/admin/pyuic4.py 0000644 0001750 0000144 00000002774 14206145246 015555 0 ustar jwoithe users #!/usr/bin/python
#
# Copyright (C) 2007-2008 Arnold Krille
#
# This file is part of FFADO
# FFADO = Free FireWire (pro-)audio drivers for Linux
#
# FFADO is based upon FreeBoB.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
import imp
def pyuic4_action( target, source, env ):
env.Execute( "pyuic4 " + str( source[0] ) + " > " + str( target[0] ) )
return 0
def pyuic4_string( target, source, env ):
return "building '%s' from '%s'" % ( str(target[0]), str( source[0] ) )
def PyQt4Check( context ):
context.Message( "Checking for pyuic4 (by checking for the python module pyqtconfig) " )
ret = True
try:
imp.find_module( "pyqtconfig" )
except ImportError:
ret = False
context.Result( ret )
return ret
def generate( env, **kw ):
env['BUILDERS']['PyUIC4'] = env.Builder( action=pyuic4_action, src_suffix=".ui", single_source=True )
env['PYUIC4_TESTS'] = { "PyQt4Check" : PyQt4Check }
def exists( env ):
return 1
libffado-2.4.5/admin/pyuic5.py 0000644 0001750 0000144 00000003041 14206145246 015542 0 ustar jwoithe users #!/usr/bin/python
#
# Copyright (C) 2007-2008 Arnold Krille
# Copyright (C) 2017 Jonathan Woithe
#
# This file is part of FFADO
# FFADO = Free FireWire (pro-)audio drivers for Linux
#
# FFADO is based upon FreeBoB.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
import imp
def pyuic5_action( target, source, env ):
env.Execute( "pyuic5 " + str( source[0] ) + " > " + str( target[0] ) )
return 0
def pyuic5_string( target, source, env ):
return "building '%s' from '%s'" % ( str(target[0]), str( source[0] ) )
def PyQt5Check( context ):
context.Message( "Checking for pyuic5 (by checking for the python module pyqtconfig) " )
ret = True
try:
imp.find_module( "pyqtconfig" )
except ImportError:
ret = False
context.Result( ret )
return ret
def generate( env, **kw ):
env['BUILDERS']['PyUIC5'] = env.Builder( action=pyuic5_action, src_suffix=".ui", single_source=True )
env['PYUIC5_TESTS'] = { "PyQt5Check" : PyQt5Check }
def exists( env ):
return 1
libffado-2.4.5/admin/scanreplace.py 0000644 0001750 0000144 00000002700 14206145246 016605 0 ustar jwoithe users #!/usr/bin/python
#
# Copyright (C) 2007-2008 Arnold Krille
#
# This file is part of FFADO
# FFADO = Free FireWire (pro-)audio drivers for Linux
#
# FFADO is based upon FreeBoB.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
#
# Taken from http://www.scons.org/wiki/ReplacementBuilder
#
from string import Template
import os
def replace_action(target, source, env):
open( str(target[0]), 'w' ).write( Template( open( str(source[0]), 'r' ).read() ).safe_substitute( env ) )
os.chmod( str(target[0]), os.stat( str(source[0]) ).st_mode )
return 0
def replace_string(target, source, env):
return "building '%s' from '%s'" % ( str(target[0]), str(source[0]) )
def generate(env, **kw):
action = env.Action( replace_action, replace_string )
env['BUILDERS']['ScanReplace'] = env.Builder( action=action, src_suffix='.in', single_source=True )
def exists(env):
return 1
libffado-2.4.5/admin/config.guess 0000644 0001750 0000144 00000130361 12235024211 016261 0 ustar jwoithe users #! /bin/sh
# Attempt to guess a canonical system name.
# Copyright 1992-2013 Free Software Foundation, Inc.
timestamp='2013-06-10'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see .
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that
# program. This Exception is an additional permission under section 7
# of the GNU General Public License, version 3 ("GPLv3").
#
# Originally written by Per Bothner.
#
# You can get the latest version of this script from:
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
#
# Please send patches with a ChangeLog entry to config-patches@gnu.org.
me=`echo "$0" | sed -e 's,.*/,,'`
usage="\
Usage: $0 [OPTION]
Output the configuration name of the system \`$me' is run on.
Operation modes:
-h, --help print this help, then exit
-t, --time-stamp print date of last modification, then exit
-v, --version print version number, then exit
Report bugs and patches to ."
version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
Copyright 1992-2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
help="
Try \`$me --help' for more information."
# Parse command line
while test $# -gt 0 ; do
case $1 in
--time-stamp | --time* | -t )
echo "$timestamp" ; exit ;;
--version | -v )
echo "$version" ; exit ;;
--help | --h* | -h )
echo "$usage"; exit ;;
-- ) # Stop option processing
shift; break ;;
- ) # Use stdin as input.
break ;;
-* )
echo "$me: invalid option $1$help" >&2
exit 1 ;;
* )
break ;;
esac
done
if test $# != 0; then
echo "$me: too many arguments$help" >&2
exit 1
fi
trap 'exit 1' 1 2 15
# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
# compiler to aid in system detection is discouraged as it requires
# temporary files to be created and, as you can see below, it is a
# headache to deal with in a portable fashion.
# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
# use `HOST_CC' if defined, but it is deprecated.
# Portable tmp directory creation inspired by the Autoconf team.
set_cc_for_build='
trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
: ${TMPDIR=/tmp} ;
{ tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
{ test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
{ tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
{ echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
dummy=$tmp/dummy ;
tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
case $CC_FOR_BUILD,$HOST_CC,$CC in
,,) echo "int x;" > $dummy.c ;
for c in cc gcc c89 c99 ; do
if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
CC_FOR_BUILD="$c"; break ;
fi ;
done ;
if test x"$CC_FOR_BUILD" = x ; then
CC_FOR_BUILD=no_compiler_found ;
fi
;;
,,*) CC_FOR_BUILD=$CC ;;
,*,*) CC_FOR_BUILD=$HOST_CC ;;
esac ; set_cc_for_build= ;'
# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
# (ghazi@noc.rutgers.edu 1994-08-24)
if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
PATH=$PATH:/.attbin ; export PATH
fi
UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
case "${UNAME_SYSTEM}" in
Linux|GNU|GNU/*)
# If the system lacks a compiler, then just pick glibc.
# We could probably try harder.
LIBC=gnu
eval $set_cc_for_build
cat <<-EOF > $dummy.c
#include
#if defined(__UCLIBC__)
LIBC=uclibc
#elif defined(__dietlibc__)
LIBC=dietlibc
#else
LIBC=gnu
#endif
EOF
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
;;
esac
# Note: order is significant - the case branches are not exclusive.
case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
*:NetBSD:*:*)
# NetBSD (nbsd) targets should (where applicable) match one or
# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
# *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
# switched to ELF, *-*-netbsd* would select the old
# object file format. This provides both forward
# compatibility and a consistent mechanism for selecting the
# object file format.
#
# Note: NetBSD doesn't particularly care about the vendor
# portion of the name. We always set it to "unknown".
sysctl="sysctl -n hw.machine_arch"
UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
/usr/sbin/$sysctl 2>/dev/null || echo unknown)`
case "${UNAME_MACHINE_ARCH}" in
armeb) machine=armeb-unknown ;;
arm*) machine=arm-unknown ;;
sh3el) machine=shl-unknown ;;
sh3eb) machine=sh-unknown ;;
sh5el) machine=sh5le-unknown ;;
*) machine=${UNAME_MACHINE_ARCH}-unknown ;;
esac
# The Operating System including object format, if it has switched
# to ELF recently, or will in the future.
case "${UNAME_MACHINE_ARCH}" in
arm*|i386|m68k|ns32k|sh3*|sparc|vax)
eval $set_cc_for_build
if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ELF__
then
# Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
# Return netbsd for either. FIX?
os=netbsd
else
os=netbsdelf
fi
;;
*)
os=netbsd
;;
esac
# The OS release
# Debian GNU/NetBSD machines have a different userland, and
# thus, need a distinct triplet. However, they do not need
# kernel version information, so it can be replaced with a
# suitable tag, in the style of linux-gnu.
case "${UNAME_VERSION}" in
Debian*)
release='-gnu'
;;
*)
release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
;;
esac
# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
# contains redundant information, the shorter form:
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
echo "${machine}-${os}${release}"
exit ;;
*:Bitrig:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
exit ;;
*:OpenBSD:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
exit ;;
*:ekkoBSD:*:*)
echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
exit ;;
*:SolidBSD:*:*)
echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
exit ;;
macppc:MirBSD:*:*)
echo powerpc-unknown-mirbsd${UNAME_RELEASE}
exit ;;
*:MirBSD:*:*)
echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
exit ;;
alpha:OSF1:*:*)
case $UNAME_RELEASE in
*4.0)
UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
;;
*5.*)
UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
;;
esac
# According to Compaq, /usr/sbin/psrinfo has been available on
# OSF/1 and Tru64 systems produced since 1995. I hope that
# covers most systems running today. This code pipes the CPU
# types through head -n 1, so we only detect the type of CPU 0.
ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
case "$ALPHA_CPU_TYPE" in
"EV4 (21064)")
UNAME_MACHINE="alpha" ;;
"EV4.5 (21064)")
UNAME_MACHINE="alpha" ;;
"LCA4 (21066/21068)")
UNAME_MACHINE="alpha" ;;
"EV5 (21164)")
UNAME_MACHINE="alphaev5" ;;
"EV5.6 (21164A)")
UNAME_MACHINE="alphaev56" ;;
"EV5.6 (21164PC)")
UNAME_MACHINE="alphapca56" ;;
"EV5.7 (21164PC)")
UNAME_MACHINE="alphapca57" ;;
"EV6 (21264)")
UNAME_MACHINE="alphaev6" ;;
"EV6.7 (21264A)")
UNAME_MACHINE="alphaev67" ;;
"EV6.8CB (21264C)")
UNAME_MACHINE="alphaev68" ;;
"EV6.8AL (21264B)")
UNAME_MACHINE="alphaev68" ;;
"EV6.8CX (21264D)")
UNAME_MACHINE="alphaev68" ;;
"EV6.9A (21264/EV69A)")
UNAME_MACHINE="alphaev69" ;;
"EV7 (21364)")
UNAME_MACHINE="alphaev7" ;;
"EV7.9 (21364A)")
UNAME_MACHINE="alphaev79" ;;
esac
# A Pn.n version is a patched version.
# A Vn.n version is a released version.
# A Tn.n version is a released field test version.
# A Xn.n version is an unreleased experimental baselevel.
# 1.2 uses "1.2" for uname -r.
echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
exitcode=$?
trap '' 0
exit $exitcode ;;
Alpha\ *:Windows_NT*:*)
# How do we know it's Interix rather than the generic POSIX subsystem?
# Should we change UNAME_MACHINE based on the output of uname instead
# of the specific Alpha model?
echo alpha-pc-interix
exit ;;
21064:Windows_NT:50:3)
echo alpha-dec-winnt3.5
exit ;;
Amiga*:UNIX_System_V:4.0:*)
echo m68k-unknown-sysv4
exit ;;
*:[Aa]miga[Oo][Ss]:*:*)
echo ${UNAME_MACHINE}-unknown-amigaos
exit ;;
*:[Mm]orph[Oo][Ss]:*:*)
echo ${UNAME_MACHINE}-unknown-morphos
exit ;;
*:OS/390:*:*)
echo i370-ibm-openedition
exit ;;
*:z/VM:*:*)
echo s390-ibm-zvmoe
exit ;;
*:OS400:*:*)
echo powerpc-ibm-os400
exit ;;
arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
echo arm-acorn-riscix${UNAME_RELEASE}
exit ;;
arm*:riscos:*:*|arm*:RISCOS:*:*)
echo arm-unknown-riscos
exit ;;
SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
echo hppa1.1-hitachi-hiuxmpp
exit ;;
Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
if test "`(/bin/universe) 2>/dev/null`" = att ; then
echo pyramid-pyramid-sysv3
else
echo pyramid-pyramid-bsd
fi
exit ;;
NILE*:*:*:dcosx)
echo pyramid-pyramid-svr4
exit ;;
DRS?6000:unix:4.0:6*)
echo sparc-icl-nx6
exit ;;
DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
case `/usr/bin/uname -p` in
sparc) echo sparc-icl-nx7; exit ;;
esac ;;
s390x:SunOS:*:*)
echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;;
sun4H:SunOS:5.*:*)
echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;;
sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;;
i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
echo i386-pc-auroraux${UNAME_RELEASE}
exit ;;
i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
eval $set_cc_for_build
SUN_ARCH="i386"
# If there is a compiler, see if it is configured for 64-bit objects.
# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
# This test works for both compilers.
if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
then
SUN_ARCH="x86_64"
fi
fi
echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;;
sun4*:SunOS:6*:*)
# According to config.sub, this is the proper way to canonicalize
# SunOS6. Hard to guess exactly what SunOS6 will be like, but
# it's likely to be more like Solaris than SunOS4.
echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;;
sun4*:SunOS:*:*)
case "`/usr/bin/arch -k`" in
Series*|S4*)
UNAME_RELEASE=`uname -v`
;;
esac
# Japanese Language versions have a version number like `4.1.3-JL'.
echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
exit ;;
sun3*:SunOS:*:*)
echo m68k-sun-sunos${UNAME_RELEASE}
exit ;;
sun*:*:4.2BSD:*)
UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
case "`/bin/arch`" in
sun3)
echo m68k-sun-sunos${UNAME_RELEASE}
;;
sun4)
echo sparc-sun-sunos${UNAME_RELEASE}
;;
esac
exit ;;
aushp:SunOS:*:*)
echo sparc-auspex-sunos${UNAME_RELEASE}
exit ;;
# The situation for MiNT is a little confusing. The machine name
# can be virtually everything (everything which is not
# "atarist" or "atariste" at least should have a processor
# > m68000). The system name ranges from "MiNT" over "FreeMiNT"
# to the lowercase version "mint" (or "freemint"). Finally
# the system name "TOS" denotes a system which is actually not
# MiNT. But MiNT is downward compatible to TOS, so this should
# be no problem.
atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
echo m68k-atari-mint${UNAME_RELEASE}
exit ;;
atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
echo m68k-atari-mint${UNAME_RELEASE}
exit ;;
*falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
echo m68k-atari-mint${UNAME_RELEASE}
exit ;;
milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
echo m68k-milan-mint${UNAME_RELEASE}
exit ;;
hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
echo m68k-hades-mint${UNAME_RELEASE}
exit ;;
*:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
echo m68k-unknown-mint${UNAME_RELEASE}
exit ;;
m68k:machten:*:*)
echo m68k-apple-machten${UNAME_RELEASE}
exit ;;
powerpc:machten:*:*)
echo powerpc-apple-machten${UNAME_RELEASE}
exit ;;
RISC*:Mach:*:*)
echo mips-dec-mach_bsd4.3
exit ;;
RISC*:ULTRIX:*:*)
echo mips-dec-ultrix${UNAME_RELEASE}
exit ;;
VAX*:ULTRIX*:*:*)
echo vax-dec-ultrix${UNAME_RELEASE}
exit ;;
2020:CLIX:*:* | 2430:CLIX:*:*)
echo clipper-intergraph-clix${UNAME_RELEASE}
exit ;;
mips:*:*:UMIPS | mips:*:*:RISCos)
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#ifdef __cplusplus
#include /* for printf() prototype */
int main (int argc, char *argv[]) {
#else
int main (argc, argv) int argc; char *argv[]; {
#endif
#if defined (host_mips) && defined (MIPSEB)
#if defined (SYSTYPE_SYSV)
printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
#endif
#if defined (SYSTYPE_SVR4)
printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
#endif
#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
#endif
#endif
exit (-1);
}
EOF
$CC_FOR_BUILD -o $dummy $dummy.c &&
dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
SYSTEM_NAME=`$dummy $dummyarg` &&
{ echo "$SYSTEM_NAME"; exit; }
echo mips-mips-riscos${UNAME_RELEASE}
exit ;;
Motorola:PowerMAX_OS:*:*)
echo powerpc-motorola-powermax
exit ;;
Motorola:*:4.3:PL8-*)
echo powerpc-harris-powermax
exit ;;
Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
echo powerpc-harris-powermax
exit ;;
Night_Hawk:Power_UNIX:*:*)
echo powerpc-harris-powerunix
exit ;;
m88k:CX/UX:7*:*)
echo m88k-harris-cxux7
exit ;;
m88k:*:4*:R4*)
echo m88k-motorola-sysv4
exit ;;
m88k:*:3*:R3*)
echo m88k-motorola-sysv3
exit ;;
AViiON:dgux:*:*)
# DG/UX returns AViiON for all architectures
UNAME_PROCESSOR=`/usr/bin/uname -p`
if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
then
if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
[ ${TARGET_BINARY_INTERFACE}x = x ]
then
echo m88k-dg-dgux${UNAME_RELEASE}
else
echo m88k-dg-dguxbcs${UNAME_RELEASE}
fi
else
echo i586-dg-dgux${UNAME_RELEASE}
fi
exit ;;
M88*:DolphinOS:*:*) # DolphinOS (SVR3)
echo m88k-dolphin-sysv3
exit ;;
M88*:*:R3*:*)
# Delta 88k system running SVR3
echo m88k-motorola-sysv3
exit ;;
XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
echo m88k-tektronix-sysv3
exit ;;
Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
echo m68k-tektronix-bsd
exit ;;
*:IRIX*:*:*)
echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
exit ;;
????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
i*86:AIX:*:*)
echo i386-ibm-aix
exit ;;
ia64:AIX:*:*)
if [ -x /usr/bin/oslevel ] ; then
IBM_REV=`/usr/bin/oslevel`
else
IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
fi
echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
exit ;;
*:AIX:2:3)
if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#include
main()
{
if (!__power_pc())
exit(1);
puts("powerpc-ibm-aix3.2.5");
exit(0);
}
EOF
if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
then
echo "$SYSTEM_NAME"
else
echo rs6000-ibm-aix3.2.5
fi
elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
echo rs6000-ibm-aix3.2.4
else
echo rs6000-ibm-aix3.2
fi
exit ;;
*:AIX:*:[4567])
IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
IBM_ARCH=rs6000
else
IBM_ARCH=powerpc
fi
if [ -x /usr/bin/oslevel ] ; then
IBM_REV=`/usr/bin/oslevel`
else
IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
fi
echo ${IBM_ARCH}-ibm-aix${IBM_REV}
exit ;;
*:AIX:*:*)
echo rs6000-ibm-aix
exit ;;
ibmrt:4.4BSD:*|romp-ibm:BSD:*)
echo romp-ibm-bsd4.4
exit ;;
ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
exit ;; # report: romp-ibm BSD 4.3
*:BOSX:*:*)
echo rs6000-bull-bosx
exit ;;
DPX/2?00:B.O.S.:*:*)
echo m68k-bull-sysv3
exit ;;
9000/[34]??:4.3bsd:1.*:*)
echo m68k-hp-bsd
exit ;;
hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
echo m68k-hp-bsd4.4
exit ;;
9000/[34678]??:HP-UX:*:*)
HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
case "${UNAME_MACHINE}" in
9000/31? ) HP_ARCH=m68000 ;;
9000/[34]?? ) HP_ARCH=m68k ;;
9000/[678][0-9][0-9])
if [ -x /usr/bin/getconf ]; then
sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
case "${sc_cpu_version}" in
523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
532) # CPU_PA_RISC2_0
case "${sc_kernel_bits}" in
32) HP_ARCH="hppa2.0n" ;;
64) HP_ARCH="hppa2.0w" ;;
'') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
esac ;;
esac
fi
if [ "${HP_ARCH}" = "" ]; then
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#define _HPUX_SOURCE
#include
#include
int main ()
{
#if defined(_SC_KERNEL_BITS)
long bits = sysconf(_SC_KERNEL_BITS);
#endif
long cpu = sysconf (_SC_CPU_VERSION);
switch (cpu)
{
case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
case CPU_PA_RISC2_0:
#if defined(_SC_KERNEL_BITS)
switch (bits)
{
case 64: puts ("hppa2.0w"); break;
case 32: puts ("hppa2.0n"); break;
default: puts ("hppa2.0"); break;
} break;
#else /* !defined(_SC_KERNEL_BITS) */
puts ("hppa2.0"); break;
#endif
default: puts ("hppa1.0"); break;
}
exit (0);
}
EOF
(CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
test -z "$HP_ARCH" && HP_ARCH=hppa
fi ;;
esac
if [ ${HP_ARCH} = "hppa2.0w" ]
then
eval $set_cc_for_build
# hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
# 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
# generating 64-bit code. GNU and HP use different nomenclature:
#
# $ CC_FOR_BUILD=cc ./config.guess
# => hppa2.0w-hp-hpux11.23
# $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
# => hppa64-hp-hpux11.23
if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
grep -q __LP64__
then
HP_ARCH="hppa2.0w"
else
HP_ARCH="hppa64"
fi
fi
echo ${HP_ARCH}-hp-hpux${HPUX_REV}
exit ;;
ia64:HP-UX:*:*)
HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
echo ia64-hp-hpux${HPUX_REV}
exit ;;
3050*:HI-UX:*:*)
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#include
int
main ()
{
long cpu = sysconf (_SC_CPU_VERSION);
/* The order matters, because CPU_IS_HP_MC68K erroneously returns
true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
results, however. */
if (CPU_IS_PA_RISC (cpu))
{
switch (cpu)
{
case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
default: puts ("hppa-hitachi-hiuxwe2"); break;
}
}
else if (CPU_IS_HP_MC68K (cpu))
puts ("m68k-hitachi-hiuxwe2");
else puts ("unknown-hitachi-hiuxwe2");
exit (0);
}
EOF
$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
{ echo "$SYSTEM_NAME"; exit; }
echo unknown-hitachi-hiuxwe2
exit ;;
9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
echo hppa1.1-hp-bsd
exit ;;
9000/8??:4.3bsd:*:*)
echo hppa1.0-hp-bsd
exit ;;
*9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
echo hppa1.0-hp-mpeix
exit ;;
hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
echo hppa1.1-hp-osf
exit ;;
hp8??:OSF1:*:*)
echo hppa1.0-hp-osf
exit ;;
i*86:OSF1:*:*)
if [ -x /usr/sbin/sysversion ] ; then
echo ${UNAME_MACHINE}-unknown-osf1mk
else
echo ${UNAME_MACHINE}-unknown-osf1
fi
exit ;;
parisc*:Lites*:*:*)
echo hppa1.1-hp-lites
exit ;;
C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
echo c1-convex-bsd
exit ;;
C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
if getsysinfo -f scalar_acc
then echo c32-convex-bsd
else echo c2-convex-bsd
fi
exit ;;
C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
echo c34-convex-bsd
exit ;;
C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
echo c38-convex-bsd
exit ;;
C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
echo c4-convex-bsd
exit ;;
CRAY*Y-MP:*:*:*)
echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit ;;
CRAY*[A-Z]90:*:*:*)
echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
-e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
-e 's/\.[^.]*$/.X/'
exit ;;
CRAY*TS:*:*:*)
echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit ;;
CRAY*T3E:*:*:*)
echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit ;;
CRAY*SV1:*:*:*)
echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit ;;
*:UNICOS/mp:*:*)
echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit ;;
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
5000:UNIX_System_V:4.*:*)
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
exit ;;
sparc*:BSD/OS:*:*)
echo sparc-unknown-bsdi${UNAME_RELEASE}
exit ;;
*:BSD/OS:*:*)
echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
exit ;;
*:FreeBSD:*:*)
UNAME_PROCESSOR=`/usr/bin/uname -p`
case ${UNAME_PROCESSOR} in
amd64)
echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
*)
echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
esac
exit ;;
i*:CYGWIN*:*)
echo ${UNAME_MACHINE}-pc-cygwin
exit ;;
*:MINGW64*:*)
echo ${UNAME_MACHINE}-pc-mingw64
exit ;;
*:MINGW*:*)
echo ${UNAME_MACHINE}-pc-mingw32
exit ;;
i*:MSYS*:*)
echo ${UNAME_MACHINE}-pc-msys
exit ;;
i*:windows32*:*)
# uname -m includes "-pc" on this system.
echo ${UNAME_MACHINE}-mingw32
exit ;;
i*:PW*:*)
echo ${UNAME_MACHINE}-pc-pw32
exit ;;
*:Interix*:*)
case ${UNAME_MACHINE} in
x86)
echo i586-pc-interix${UNAME_RELEASE}
exit ;;
authenticamd | genuineintel | EM64T)
echo x86_64-unknown-interix${UNAME_RELEASE}
exit ;;
IA64)
echo ia64-unknown-interix${UNAME_RELEASE}
exit ;;
esac ;;
[345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
echo i${UNAME_MACHINE}-pc-mks
exit ;;
8664:Windows_NT:*)
echo x86_64-pc-mks
exit ;;
i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
# How do we know it's Interix rather than the generic POSIX subsystem?
# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
# UNAME_MACHINE based on the output of uname instead of i386?
echo i586-pc-interix
exit ;;
i*:UWIN*:*)
echo ${UNAME_MACHINE}-pc-uwin
exit ;;
amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
echo x86_64-unknown-cygwin
exit ;;
p*:CYGWIN*:*)
echo powerpcle-unknown-cygwin
exit ;;
prep*:SunOS:5.*:*)
echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;;
*:GNU:*:*)
# the GNU system
echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
exit ;;
*:GNU/*:*:*)
# other systems with GNU libc and userland
echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
exit ;;
i*86:Minix:*:*)
echo ${UNAME_MACHINE}-pc-minix
exit ;;
aarch64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
aarch64_be:Linux:*:*)
UNAME_MACHINE=aarch64_be
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
alpha:Linux:*:*)
case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
EV5) UNAME_MACHINE=alphaev5 ;;
EV56) UNAME_MACHINE=alphaev56 ;;
PCA56) UNAME_MACHINE=alphapca56 ;;
PCA57) UNAME_MACHINE=alphapca56 ;;
EV6) UNAME_MACHINE=alphaev6 ;;
EV67) UNAME_MACHINE=alphaev67 ;;
EV68*) UNAME_MACHINE=alphaev68 ;;
esac
objdump --private-headers /bin/sh | grep -q ld.so.1
if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
arc:Linux:*:* | arceb:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
arm*:Linux:*:*)
eval $set_cc_for_build
if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ARM_EABI__
then
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
else
if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ARM_PCS_VFP
then
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
else
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
fi
fi
exit ;;
avr32*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
cris:Linux:*:*)
echo ${UNAME_MACHINE}-axis-linux-${LIBC}
exit ;;
crisv32:Linux:*:*)
echo ${UNAME_MACHINE}-axis-linux-${LIBC}
exit ;;
frv:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
hexagon:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
i*86:Linux:*:*)
echo ${UNAME_MACHINE}-pc-linux-${LIBC}
exit ;;
ia64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
m32r*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
m68*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
mips:Linux:*:* | mips64:Linux:*:*)
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#undef CPU
#undef ${UNAME_MACHINE}
#undef ${UNAME_MACHINE}el
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
CPU=${UNAME_MACHINE}el
#else
#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
CPU=${UNAME_MACHINE}
#else
CPU=
#endif
#endif
EOF
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
;;
or1k:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
or32:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
padre:Linux:*:*)
echo sparc-unknown-linux-${LIBC}
exit ;;
parisc64:Linux:*:* | hppa64:Linux:*:*)
echo hppa64-unknown-linux-${LIBC}
exit ;;
parisc:Linux:*:* | hppa:Linux:*:*)
# Look for CPU level
case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
*) echo hppa-unknown-linux-${LIBC} ;;
esac
exit ;;
ppc64:Linux:*:*)
echo powerpc64-unknown-linux-${LIBC}
exit ;;
ppc:Linux:*:*)
echo powerpc-unknown-linux-${LIBC}
exit ;;
ppc64le:Linux:*:*)
echo powerpc64le-unknown-linux-${LIBC}
exit ;;
ppcle:Linux:*:*)
echo powerpcle-unknown-linux-${LIBC}
exit ;;
s390:Linux:*:* | s390x:Linux:*:*)
echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
exit ;;
sh64*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
sh*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
sparc:Linux:*:* | sparc64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
tile*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
vax:Linux:*:*)
echo ${UNAME_MACHINE}-dec-linux-${LIBC}
exit ;;
x86_64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
xtensa*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
i*86:DYNIX/ptx:4*:*)
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
# earlier versions are messed up and put the nodename in both
# sysname and nodename.
echo i386-sequent-sysv4
exit ;;
i*86:UNIX_SV:4.2MP:2.*)
# Unixware is an offshoot of SVR4, but it has its own version
# number series starting with 2...
# I am not positive that other SVR4 systems won't match this,
# I just have to hope. -- rms.
# Use sysv4.2uw... so that sysv4* matches it.
echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
exit ;;
i*86:OS/2:*:*)
# If we were able to find `uname', then EMX Unix compatibility
# is probably installed.
echo ${UNAME_MACHINE}-pc-os2-emx
exit ;;
i*86:XTS-300:*:STOP)
echo ${UNAME_MACHINE}-unknown-stop
exit ;;
i*86:atheos:*:*)
echo ${UNAME_MACHINE}-unknown-atheos
exit ;;
i*86:syllable:*:*)
echo ${UNAME_MACHINE}-pc-syllable
exit ;;
i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
echo i386-unknown-lynxos${UNAME_RELEASE}
exit ;;
i*86:*DOS:*:*)
echo ${UNAME_MACHINE}-pc-msdosdjgpp
exit ;;
i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
else
echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
fi
exit ;;
i*86:*:5:[678]*)
# UnixWare 7.x, OpenUNIX and OpenServer 6.
case `/bin/uname -X | grep "^Machine"` in
*486*) UNAME_MACHINE=i486 ;;
*Pentium) UNAME_MACHINE=i586 ;;
*Pent*|*Celeron) UNAME_MACHINE=i686 ;;
esac
echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
exit ;;
i*86:*:3.2:*)
if test -f /usr/options/cb.name; then
UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then
UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
&& UNAME_MACHINE=i586
(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
&& UNAME_MACHINE=i686
(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
&& UNAME_MACHINE=i686
echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
else
echo ${UNAME_MACHINE}-pc-sysv32
fi
exit ;;
pc:*:*:*)
# Left here for compatibility:
# uname -m prints for DJGPP always 'pc', but it prints nothing about
# the processor, so we play safe by assuming i586.
# Note: whatever this is, it MUST be the same as what config.sub
# prints for the "djgpp" host, or else GDB configury will decide that
# this is a cross-build.
echo i586-pc-msdosdjgpp
exit ;;
Intel:Mach:3*:*)
echo i386-pc-mach3
exit ;;
paragon:*:*:*)
echo i860-intel-osf1
exit ;;
i860:*:4.*:*) # i860-SVR4
if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
else # Add other i860-SVR4 vendors below as they are discovered.
echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
fi
exit ;;
mini*:CTIX:SYS*5:*)
# "miniframe"
echo m68010-convergent-sysv
exit ;;
mc68k:UNIX:SYSTEM5:3.51m)
echo m68k-convergent-sysv
exit ;;
M680?0:D-NIX:5.3:*)
echo m68k-diab-dnix
exit ;;
M68*:*:R3V[5678]*:*)
test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
OS_REL=''
test -r /etc/.relid \
&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
&& { echo i486-ncr-sysv4.3${OS_REL}; exit; }
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
&& { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
&& { echo i486-ncr-sysv4; exit; } ;;
NCR*:*:4.2:* | MPRAS*:*:4.2:*)
OS_REL='.3'
test -r /etc/.relid \
&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
&& { echo i486-ncr-sysv4.3${OS_REL}; exit; }
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
&& { echo i586-ncr-sysv4.3${OS_REL}; exit; }
/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
&& { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
echo m68k-unknown-lynxos${UNAME_RELEASE}
exit ;;
mc68030:UNIX_System_V:4.*:*)
echo m68k-atari-sysv4
exit ;;
TSUNAMI:LynxOS:2.*:*)
echo sparc-unknown-lynxos${UNAME_RELEASE}
exit ;;
rs6000:LynxOS:2.*:*)
echo rs6000-unknown-lynxos${UNAME_RELEASE}
exit ;;
PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
echo powerpc-unknown-lynxos${UNAME_RELEASE}
exit ;;
SM[BE]S:UNIX_SV:*:*)
echo mips-dde-sysv${UNAME_RELEASE}
exit ;;
RM*:ReliantUNIX-*:*:*)
echo mips-sni-sysv4
exit ;;
RM*:SINIX-*:*:*)
echo mips-sni-sysv4
exit ;;
*:SINIX-*:*:*)
if uname -p 2>/dev/null >/dev/null ; then
UNAME_MACHINE=`(uname -p) 2>/dev/null`
echo ${UNAME_MACHINE}-sni-sysv4
else
echo ns32k-sni-sysv
fi
exit ;;
PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
# says
echo i586-unisys-sysv4
exit ;;
*:UNIX_System_V:4*:FTX*)
# From Gerald Hewes .
# How about differentiating between stratus architectures? -djm
echo hppa1.1-stratus-sysv4
exit ;;
*:*:*:FTX*)
# From seanf@swdc.stratus.com.
echo i860-stratus-sysv4
exit ;;
i*86:VOS:*:*)
# From Paul.Green@stratus.com.
echo ${UNAME_MACHINE}-stratus-vos
exit ;;
*:VOS:*:*)
# From Paul.Green@stratus.com.
echo hppa1.1-stratus-vos
exit ;;
mc68*:A/UX:*:*)
echo m68k-apple-aux${UNAME_RELEASE}
exit ;;
news*:NEWS-OS:6*:*)
echo mips-sony-newsos6
exit ;;
R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
if [ -d /usr/nec ]; then
echo mips-nec-sysv${UNAME_RELEASE}
else
echo mips-unknown-sysv${UNAME_RELEASE}
fi
exit ;;
BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
echo powerpc-be-beos
exit ;;
BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
echo powerpc-apple-beos
exit ;;
BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
echo i586-pc-beos
exit ;;
BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
echo i586-pc-haiku
exit ;;
x86_64:Haiku:*:*)
echo x86_64-unknown-haiku
exit ;;
SX-4:SUPER-UX:*:*)
echo sx4-nec-superux${UNAME_RELEASE}
exit ;;
SX-5:SUPER-UX:*:*)
echo sx5-nec-superux${UNAME_RELEASE}
exit ;;
SX-6:SUPER-UX:*:*)
echo sx6-nec-superux${UNAME_RELEASE}
exit ;;
SX-7:SUPER-UX:*:*)
echo sx7-nec-superux${UNAME_RELEASE}
exit ;;
SX-8:SUPER-UX:*:*)
echo sx8-nec-superux${UNAME_RELEASE}
exit ;;
SX-8R:SUPER-UX:*:*)
echo sx8r-nec-superux${UNAME_RELEASE}
exit ;;
Power*:Rhapsody:*:*)
echo powerpc-apple-rhapsody${UNAME_RELEASE}
exit ;;
*:Rhapsody:*:*)
echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
exit ;;
*:Darwin:*:*)
UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
eval $set_cc_for_build
if test "$UNAME_PROCESSOR" = unknown ; then
UNAME_PROCESSOR=powerpc
fi
if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
then
case $UNAME_PROCESSOR in
i386) UNAME_PROCESSOR=x86_64 ;;
powerpc) UNAME_PROCESSOR=powerpc64 ;;
esac
fi
fi
echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
exit ;;
*:procnto*:*:* | *:QNX:[0123456789]*:*)
UNAME_PROCESSOR=`uname -p`
if test "$UNAME_PROCESSOR" = "x86"; then
UNAME_PROCESSOR=i386
UNAME_MACHINE=pc
fi
echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
exit ;;
*:QNX:*:4*)
echo i386-pc-qnx
exit ;;
NEO-?:NONSTOP_KERNEL:*:*)
echo neo-tandem-nsk${UNAME_RELEASE}
exit ;;
NSE-*:NONSTOP_KERNEL:*:*)
echo nse-tandem-nsk${UNAME_RELEASE}
exit ;;
NSR-?:NONSTOP_KERNEL:*:*)
echo nsr-tandem-nsk${UNAME_RELEASE}
exit ;;
*:NonStop-UX:*:*)
echo mips-compaq-nonstopux
exit ;;
BS2000:POSIX*:*:*)
echo bs2000-siemens-sysv
exit ;;
DS/*:UNIX_System_V:*:*)
echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
exit ;;
*:Plan9:*:*)
# "uname -m" is not consistent, so use $cputype instead. 386
# is converted to i386 for consistency with other x86
# operating systems.
if test "$cputype" = "386"; then
UNAME_MACHINE=i386
else
UNAME_MACHINE="$cputype"
fi
echo ${UNAME_MACHINE}-unknown-plan9
exit ;;
*:TOPS-10:*:*)
echo pdp10-unknown-tops10
exit ;;
*:TENEX:*:*)
echo pdp10-unknown-tenex
exit ;;
KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
echo pdp10-dec-tops20
exit ;;
XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
echo pdp10-xkl-tops20
exit ;;
*:TOPS-20:*:*)
echo pdp10-unknown-tops20
exit ;;
*:ITS:*:*)
echo pdp10-unknown-its
exit ;;
SEI:*:*:SEIUX)
echo mips-sei-seiux${UNAME_RELEASE}
exit ;;
*:DragonFly:*:*)
echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
exit ;;
*:*VMS:*:*)
UNAME_MACHINE=`(uname -p) 2>/dev/null`
case "${UNAME_MACHINE}" in
A*) echo alpha-dec-vms ; exit ;;
I*) echo ia64-dec-vms ; exit ;;
V*) echo vax-dec-vms ; exit ;;
esac ;;
*:XENIX:*:SysV)
echo i386-pc-xenix
exit ;;
i*86:skyos:*:*)
echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
exit ;;
i*86:rdos:*:*)
echo ${UNAME_MACHINE}-pc-rdos
exit ;;
i*86:AROS:*:*)
echo ${UNAME_MACHINE}-pc-aros
exit ;;
x86_64:VMkernel:*:*)
echo ${UNAME_MACHINE}-unknown-esx
exit ;;
esac
eval $set_cc_for_build
cat >$dummy.c <
# include
#endif
main ()
{
#if defined (sony)
#if defined (MIPSEB)
/* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
I don't know.... */
printf ("mips-sony-bsd\n"); exit (0);
#else
#include
printf ("m68k-sony-newsos%s\n",
#ifdef NEWSOS4
"4"
#else
""
#endif
); exit (0);
#endif
#endif
#if defined (__arm) && defined (__acorn) && defined (__unix)
printf ("arm-acorn-riscix\n"); exit (0);
#endif
#if defined (hp300) && !defined (hpux)
printf ("m68k-hp-bsd\n"); exit (0);
#endif
#if defined (NeXT)
#if !defined (__ARCHITECTURE__)
#define __ARCHITECTURE__ "m68k"
#endif
int version;
version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
if (version < 4)
printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
else
printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
exit (0);
#endif
#if defined (MULTIMAX) || defined (n16)
#if defined (UMAXV)
printf ("ns32k-encore-sysv\n"); exit (0);
#else
#if defined (CMU)
printf ("ns32k-encore-mach\n"); exit (0);
#else
printf ("ns32k-encore-bsd\n"); exit (0);
#endif
#endif
#endif
#if defined (__386BSD__)
printf ("i386-pc-bsd\n"); exit (0);
#endif
#if defined (sequent)
#if defined (i386)
printf ("i386-sequent-dynix\n"); exit (0);
#endif
#if defined (ns32000)
printf ("ns32k-sequent-dynix\n"); exit (0);
#endif
#endif
#if defined (_SEQUENT_)
struct utsname un;
uname(&un);
if (strncmp(un.version, "V2", 2) == 0) {
printf ("i386-sequent-ptx2\n"); exit (0);
}
if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
printf ("i386-sequent-ptx1\n"); exit (0);
}
printf ("i386-sequent-ptx\n"); exit (0);
#endif
#if defined (vax)
# if !defined (ultrix)
# include
# if defined (BSD)
# if BSD == 43
printf ("vax-dec-bsd4.3\n"); exit (0);
# else
# if BSD == 199006
printf ("vax-dec-bsd4.3reno\n"); exit (0);
# else
printf ("vax-dec-bsd\n"); exit (0);
# endif
# endif
# else
printf ("vax-dec-bsd\n"); exit (0);
# endif
# else
printf ("vax-dec-ultrix\n"); exit (0);
# endif
#endif
#if defined (alliant) && defined (i860)
printf ("i860-alliant-bsd\n"); exit (0);
#endif
exit (1);
}
EOF
$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
{ echo "$SYSTEM_NAME"; exit; }
# Apollos put the system type in the environment.
test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
# Convex versions that predate uname can use getsysinfo(1)
if [ -x /usr/convex/getsysinfo ]
then
case `getsysinfo -f cpu_type` in
c1*)
echo c1-convex-bsd
exit ;;
c2*)
if getsysinfo -f scalar_acc
then echo c32-convex-bsd
else echo c2-convex-bsd
fi
exit ;;
c34*)
echo c34-convex-bsd
exit ;;
c38*)
echo c38-convex-bsd
exit ;;
c4*)
echo c4-convex-bsd
exit ;;
esac
fi
cat >&2 < in order to provide the needed
information to handle your system.
config.guess timestamp = $timestamp
uname -m = `(uname -m) 2>/dev/null || echo unknown`
uname -r = `(uname -r) 2>/dev/null || echo unknown`
uname -s = `(uname -s) 2>/dev/null || echo unknown`
uname -v = `(uname -v) 2>/dev/null || echo unknown`
/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
hostinfo = `(hostinfo) 2>/dev/null`
/bin/universe = `(/bin/universe) 2>/dev/null`
/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
/bin/arch = `(/bin/arch) 2>/dev/null`
/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
UNAME_MACHINE = ${UNAME_MACHINE}
UNAME_RELEASE = ${UNAME_RELEASE}
UNAME_SYSTEM = ${UNAME_SYSTEM}
UNAME_VERSION = ${UNAME_VERSION}
EOF
exit 1
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "timestamp='"
# time-stamp-format: "%:y-%02m-%02d"
# time-stamp-end: "'"
# End:
libffado-2.4.5/configuration 0000644 0001750 0000144 00000055653 14206145246 015474 0 ustar jwoithe users device_definitions = (
{
vendorid = 0x00000f;
modelid = 0x00010065;
vendorname = "Mackie";
modelname = "Onyx FireWire";
driver = "BEBOB";
xmit_max_cycles_early_transmit = 4;
},
{ # Added by arnonym from ffado-mixers list
vendorid = 0x00000f;
modelid = 0x00010067;
vendorname = "Mackie";
modelname = "Onyx FireWire";
driver = "BEBOB";
mixer = "MackieOnyx";
xmit_max_cycles_early_transmit = 4;
},
{ # Added by yellius
vendorid = 0x0022E;
modelid = 0x10067;
vendorname = "Tascam";
modelname = "IFFWDM";
driver = "BEBOB";
},
{ # IDs provided by Travis Kepley
vendorid = 0x000ff2;
modelid = 0x000006;
vendorname = "Loud Technologies Inc.";
modelname = "Onyx 1640i (DICE)";
driver = "DICE";
},
{ # IDs provided by Melanie Bernkopf. Mixer entry from Scott Martin.
vendorid = 0x000ff2;
modelid = 0x000007;
vendorname = "Loud Technologies Inc.";
modelname = "Onyx Blackbird";
driver = "DICE";
mixer = "Generic_Dice_EAP";
},
{ # IDs provided by Steven Tonge
vendorid = 0x000ff2;
modelid = 0x001640;
vendorname = "Loud Technologies Inc.";
modelname = "Onyx 1640i (Oxford)";
driver = "OXFORD";
# This transfer delay was tested at 48 kHz, as per
# http://sourceforge.net/p/ffado/mailman/message/26964819/
xmit_transfer_delay = 12800;
},
{ # entries provided by Holger Dehnhardt
vendorid = 0x000ff2;
modelid = 0x081216;
vendorname = "Loud Technologies Inc.";
modelname = "Onyx-i";
driver = "OXFORD";
xmit_transfer_delay = 11776;
},
{ # IDs from Geoff Beasley.
vendorid = 0x001564;
modelid = 0x00000006;
vendorname = "Behringer";
modelname = "X32";
driver = "BEBOB";
xmit_max_cycles_early_transmit = 4;
},
{ # IDs from Tony Rocco.
vendorid = 0x001564;
modelid = 0x00001604;
vendorname = "Behringer";
modelname = "UFX-1604 mixer";
driver = "BEBOB";
xmit_max_cycles_early_transmit = 4;
},
{
vendorid = 0x0003db;
modelid = 0x00010048;
vendorname = "Apogee Electronics";
modelname = "Rosetta 200";
driver = "BEBOB";
xmit_max_cycles_early_transmit = 4;
},
{
vendorid = 0x0007f5;
modelid = 0x00010048;
vendorname = "BridgeCo";
modelname = "RD Audio1";
driver = "BEBOB";
xmit_max_cycles_early_transmit = 4;
},
{
vendorid = 0x0007f5;
modelid = 0x00010049;
vendorname = "BridgeCo";
modelname = "Audio 5";
driver = "BEBOB";
mixer = "BCoAudio5Control";
xmit_max_cycles_early_transmit = 4;
},
{
vendorid = 0x000a92;
modelid = 0x00010000;
vendorname = "PreSonus";
modelname = "FIREBOX";
driver = "BEBOB";
mixer = "Presonus_Firebox";
xmit_max_cycles_early_transmit = 4;
},
{
vendorid = 0x000a92;
modelid = 0x00010001;
vendorname = "PreSonus";
modelname = "Inspire1394";
driver = "BEBOB";
mixer = "Presonus_Inspire1394";
},
{
vendorid = 0x000a92;
modelid = 0x00010066;
vendorname = "PreSonus";
modelname = "FirePOD";
driver = "BEBOB";
mixer = "Presonus_FP10";
xmit_max_cycles_early_transmit = 4;
},
{ # Presonus Firestudio 26x26, Bob Hamil via jaimes on the forums
vendorid = 0x000a92;
modelid = 0x00000008;
vendorname = "Presonus";
modelname = "Firestudio 26x26";
mixer = "Generic_Dice_EAP";
driver = "DICE";
},
{ # Presonus Firestudio Project, from Walt Baldwin
vendorid = 0x000a92;
modelid = 0x0000000b;
vendorname = "Presonus";
modelname = "Firestudio Project";
mixer = "Generic_Dice_EAP";
driver = "DICE";
},
{ # Presonus Firestudio Tube, from Tobi Kraus
vendorid = 0x000a92;
modelid = 0x0000000c;
vendorname = "Presonus";
modelname = "Firestudio Tube";
mixer = "Generic_Dice_EAP";
driver = "DICE";
},
{ # Entry for Firestudio mobile provided by "Pule" via the forums.
vendorid = 0x000a92;
modelid = 0x00000011;
vendorname = "PreSonus";
modelname = "Firestudio Mobile";
mixer = "Generic_Dice_EAP";
driver = "DICE";
},
{ # Entry for StudioLive 2442, from Walt Baldwin
vendorid = 0x00000A92;
modelid = 0x00000012;
vendorname = "PreSonus";
modelname = "STUDIOLIVE_2442";
driver = "DICE";
},
{ # Entry for StudioLive 1602, from Ulrich-Lorenz Schluter
vendorid = 0x00000A92;
modelid = 0x00000013;
vendorname = "PreSonus";
modelname = "STUDIOLIVE_1602";
driver = "DICE";
},
{ # Entry for Studiolive 32.4.2, from Karl Swisher
vendorid = 0x00000a92;
modelid = 0x00000014;
vendorname = "PreSonus";
modelname = "STUDIOLIVE_3242_mk2";
driver = "DICE";
},
{
vendorid = 0x000aac;
modelid = 0x00000003;
vendorname = "TerraTec Electronic GmbH";
modelname = "Phase 88 FW";
driver = "BEBOB";
mixer = "Phase88Control";
xmit_max_cycles_early_transmit = 4;
},
{
vendorid = 0x000aac;
modelid = 0x00000004;
vendorname = "TerraTec Electronic GmbH";
modelname = "Phase X24 FW (model version 4)";
driver = "BEBOB";
mixer = "Phase24Control";
xmit_max_cycles_early_transmit = 4;
},
{
vendorid = 0x000aac;
modelid = 0x00000007;
vendorname = "TerraTec Electronic GmbH";
modelname = "Phase X24 FW (model version 7)";
driver = "BEBOB";
mixer = "Phase24Control";
xmit_max_cycles_early_transmit = 4;
},
{
vendorid = 0x000f1b;
modelid = 0x00010064;
vendorname = "ESI";
modelname = "Quatafire 610";
driver = "BEBOB";
mixer = "QuataFire";
xmit_max_cycles_early_transmit = 4;
},
# Shalok Shalom has a Quantafire 610 which reports a different modelid.
# The reasons for this are unknown.
{
vendorid = 0x000f1b;
modelid = 0x00000210;
vendorname = "ESI";
modelname = "Quatafire 610 variant";
driver = "BEBOB";
mixer = "QuataFire";
xmit_max_cycles_early_transmit = 4;
},
{
vendorid = 0x00130e;
modelid = 0x00000003;
vendorname = "Focusrite";
modelname = "Saffire Pro26IO";
driver = "BEBOB";
mixer = "SaffirePro";
xmit_max_cycles_early_transmit = 4;
},
{
vendorid = 0x00130e;
modelid = 0x00000006;
vendorname = "Focusrite";
modelname = "Saffire Pro10IO";
driver = "BEBOB";
mixer = "SaffirePro";
xmit_max_cycles_early_transmit = 4;
},
{
vendorid = 0x00130e;
modelid = 0x00000000;
vendorname = "Focusrite";
modelname = "Saffire (LE)";
driver = "BEBOB";
mixer = "Saffire";
cmd_interval_time = 10000;
xmit_max_cycles_early_transmit = 4;
},
{
vendorid = 0x0040ab;
modelid = 0x00010049;
vendorname = "EDIROL";
modelname = "FA-66";
driver = "BEBOB";
mixer = "EdirolFa66Control";
xmit_max_cycles_early_transmit = 4;
},
{
vendorid = 0x0040ab;
modelid = 0x00010048;
vendorname = "EDIROL";
modelname = "FA-101";
driver = "BEBOB";
mixer = "EdirolFa101Control";
xmit_max_cycles_early_transmit = 4;
},
{ # Added by Mark Brand (orania)
vendorid = 0x000d6c;
modelid = 0x0000000a;
vendorname = "M-Audio";
modelname = "Ozonic";
driver = "BEBOB";
mixer = "MAudio_BeBoB";
xmit_max_cycles_early_transmit = 4;
},
{
vendorid = 0x000d6c;
modelid = 0x00010062;
vendorname = "M-Audio";
modelname = "FW Solo";
driver = "BEBOB";
mixer = "MAudio_BeBoB";
xmit_max_cycles_early_transmit = 4;
},
{
vendorid = 0x000d6c;
modelid = 0x00010081;
vendorname = "M-Audio";
modelname = "NRV10";
driver = "BEBOB";
# no mixer
xmit_max_cycles_early_transmit = 4;
},
{
vendorid = 0x000d6c;
modelid = 0x00010060;
vendorname = "M-Audio";
modelname = "FW Audiophile";
driver = "BEBOB";
mixer = "MAudio_BeBoB";
xmit_max_cycles_early_transmit = 4;
},
{
vendorid = 0x000d6c;
modelid = 0x00010046;
vendorname = "M-Audio";
modelname = "FW 410";
driver = "BEBOB";
mixer = "MAudio_BeBoB";
xmit_max_cycles_early_transmit = 4;
},
{
// experimental for mixer functionality
vendorid = 0x000d6c;
modelid = 0x00010071;
vendorname = "M-Audio";
modelname = "FW 1814";
driver = "BEBOB";
mixer = "MAudio_BeBoB";
xmit_max_cycles_early_transmit = 4;
},
{
// experimental for mixer functionality
vendorid = 0x000d6c;
modelid = 0x00010091;
vendorname = "M-Audio";
modelname = "ProjectMix I/O";
driver = "BEBOB";
mixer = "MAudio_BeBoB";
xmit_max_cycles_early_transmit = 4;
},
{
vendorid = 0x000d6c;
modelid = 0x000100A1;
vendorname = "M-Audio";
modelname = "ProFire Lightbridge";
driver = "BEBOB";
xmit_max_cycles_early_transmit = 4;
},
{
vendorid = 0x000d6c;
modelid = 0x00000010;
vendorname = "M-Audio";
modelname = "ProFire 2626";
driver = "DICE";
mixer = "Profire2626";
},
{
vendorid = 0x000d6c;
modelid = 0x00000011;
vendorname = "M-Audio";
modelname = "ProFire 610";
driver = "DICE";
mixer = "Profire2626";
},
{
vendorid = 0x000aac;
modelid = 0x00000002;
vendorname = "Acoustic Reality";
modelname = "eAR Master One";
driver = "BEBOB";
xmit_max_cycles_early_transmit = 4;
},
{
vendorid = 0x0000000A;
modelid = 0x00030000;
vendorname = "CME";
modelname = "Matrix K FW";
driver = "BEBOB";
xmit_max_cycles_early_transmit = 4;
},
{
vendorid = 0x1486;
modelid = 0xAF2;
vendorname = "Echo";
modelname = "AudioFire2";
driver = "FIREWORKS";
mixer = "AudioFire";
xmit_max_cycles_early_transmit = 2;
},
{
vendorid = 0x1486;
modelid = 0xAF4;
vendorname = "Echo";
modelname = "AudioFire4";
driver = "FIREWORKS";
mixer = "AudioFire";
xmit_max_cycles_early_transmit = 4;
},
{
vendorid = 0x1486;
modelid = 0xAF8;
vendorname = "Echo";
modelname = "AudioFire8";
driver = "FIREWORKS";
mixer = "AudioFire";
xmit_max_cycles_early_transmit = 2;
},
{
vendorid = 0x1486;
modelid = 0xAF9;
vendorname = "Echo";
modelname = "AudioFire8a";
driver = "FIREWORKS";
mixer = "AudioFire";
xmit_max_cycles_early_transmit = 2;
},
{
vendorid = 0x1486;
modelid = 0xAF12;
vendorname = "Echo";
modelname = "AudioFire12";
driver = "FIREWORKS";
mixer = "AudioFire";
xmit_max_cycles_early_transmit = 2;
},
{
vendorid = 0x1486;
modelid = 0xAF12D;
vendorname = "Echo";
modelname = "AudioFire12HD";
driver = "FIREWORKS";
xmit_max_cycles_early_transmit = 2;
},
{
vendorid = 0x1486;
modelid = 0xF8;
vendorname = "Echo";
modelname = "Fireworks 8";
driver = "FIREWORKS";
xmit_max_cycles_early_transmit = 2;
},
{
vendorid = 0x1486;
modelid = 0xAFD1;
vendorname = "Echo";
modelname = "FW HDMI";
driver = "FIREWORKS";
xmit_max_cycles_early_transmit = 2;
},
{
vendorid = 0xFF2;
modelid = 0x400F;
vendorname = "Mackie";
modelname = "Onyx 400F";
driver = "FIREWORKS";
xmit_max_cycles_early_transmit = 2;
},
{
vendorid = 0xFF2;
modelid = 0x1200F;
vendorname = "Mackie";
modelname = "Onyx 1200F";
driver = "FIREWORKS";
xmit_max_cycles_early_transmit = 2;
},
{
vendorid = 0x1564;
modelid = 0xFC22;
vendorname = "Behringer";
modelname = "FCA202";
driver = "OXFORD";
},
{
vendorid = 0x00001260;
modelid = 0x00001000;
vendorname = "Stanton DJ";
modelname = "SCS.1m";
driver = "GENERICAVC";
xmit_max_cycles_early_transmit = 4;
xmit_sp_dll_bw = 1.0;
recv_sp_dll_bw = 1.0;
},
{ # added by arnonym from ffado-mixers list
vendorid = 0x0001f2;
modelid = 0x00000000;
vendorname = "Motu";
modelname = "All pre-mark3 devices";
driver = "MOTU";
mixer = "Motu";
},
{
vendorid = 0x0001f2;
modelid = 0x00000001;
vendorname = "Motu";
modelname = "All mark3 devices";
driver = "MOTU";
mixer = "Motu_Mark3";
},
{
vendorid = 0x000a35;
# Note: RME detection code compares the modelid field against the
# device's unit version since RME seem to use the configrom modelid
# for other things not necessarily related to device differentiation.
modelid = 0x0001;
vendorname = "RME";
modelname = "FireFace800";
driver = "RME";
mixer = "Rme";
},
{
vendorid = 0x000a35;
# Note: RME detection code compares the modelid field against the
# device's unit version since RME seem to use the configrom modelid
# for other things not necessarily related to device differentiation.
modelid = 0x0002;
vendorname = "RME";
modelname = "FireFace400";
driver = "RME";
mixer = "Rme";
},
{
vendorid = 0x000a35;
# Note: RME detection code compares the modelid field against the
# device's unit version since RME seem to use the configrom modelid
# for other things not necessarily related to device differentiation.
modelid = 0x0003;
vendorname = "RME";
modelname = "FireFace UFX";
driver = "RME";
mixer = "Rme";
},
{
vendorid = 0x000a35;
# Note: RME detection code compares the modelid field against the
# device's unit version since RME seem to use the configrom modelid
# for other things not necessarily related to device differentiation.
# Unit version (0x04) provided by Florian Hanisch.
modelid = 0x0004;
vendorname = "RME";
modelname = "FireFace UCX";
driver = "RME";
mixer = "Rme";
},
{
vendorid = 0x000a35;
# Note: RME detection code compares the modelid field against the
# device's unit version since RME seem to use the configrom modelid
# for other things not necessarily related to device differentiation.
# Unit version (0x05) provided by Florian Hofmann.
modelid = 0x0005;
vendorname = "RME";
modelname = "FireFace 802";
driver = "RME";
mixer = "Rme";
},
{
vendorid = 0x000166;
modelid = 0x0001;
vendorname = "TCAT";
modelname = "DiceII EVM (1)";
driver = "DICE";
},
{
vendorid = 0x000166;
modelid = 0x0002;
vendorname = "TCAT";
modelname = "DiceII EVM (2)";
driver = "DICE";
},
{
vendorid = 0x000166;
modelid = 0x0004;
vendorname = "TCAT";
modelname = "DiceII EVM (4)";
driver = "DICE";
},
{
vendorid = 0x000166;
modelid = 0x00000020;
vendorname = "TC Electronic";
modelname = "Konnekt 24D";
driver = "DICE";
},
{
vendorid = 0x000166;
modelid = 0x00000021;
vendorname = "TC Electronic";
modelname = "Konnekt 8";
driver = "DICE";
},
{ # Details provided by "Juanramon" in a comment post on the website
vendorid = 0x000166;
modelid = 0x00000022;
vendorname = "TC Electronic";
modelname = "Studio Konnekt 48";
driver = "DICE";
},
{
vendorid = 0x000166;
modelid = 0x00000023;
vendorname = "TC Electronic";
modelname = "Konnekt Live";
driver = "DICE";
},
{
vendorid = 0x000166;
modelid = 0x00000024;
vendorname = "TC Electronic";
modelname = "Desktop Konnekt 6";
driver = "DICE";
},
{
vendorid = 0x000166;
modelid = 0x00000027;
vendorname = "TC Electronic";
modelname = "ImpactTwin";
driver = "DICE";
},
{
vendorid = 0x000595;
modelid = 0x00000001;
vendorname = "Alesis";
modelname = "io|14";
driver = "DICE";
},
{
# The MultiMix-16 and MultiMix-12 share the same vendor/model IDs.
# Thanks to Fourer Dominique for the information about the MultiMix-12.
vendorid = 0x000595;
modelid = 0x00000000;
vendorname = "Alesis";
modelname = "MultiMix-12 / MultiMix-16 FireWire";
driver = "DICE";
},
{ # Studiolive 16.4.2, provided by Johan Landman
vendorid = 0x000a92;
modelid = 0x00000010;
vendorname = "PreSonus";
modelname = "STUDIOLIVE_1642";
driver = "DICE";
xmit_transfer_delay = 4;
},
{ # Studiolive 16.0.2, provided by Kim Tore Jensen
vendorid = 0x000a92;
modelid = 0x00000013;
vendorname = "PreSonus";
modelname = "STUDIOLIVE_1602";
driver = "DICE";
},
{
vendorid = 0x00130e;
modelid = 0x00000005;
vendorname = "Focusrite";
modelname = "Saffire PRO 40";
driver = "DICE";
mixer = "Saffire_Dice";
},
{
vendorid = 0x00130e;
modelid = 0x00000007;
vendorname = "Focusrite";
modelname = "Saffire PRO 24";
driver = "DICE";
mixer = "Saffire_Dice";
},
{
vendorid = 0x00130e;
modelid = 0x00000008;
vendorname = "Focusrite";
modelname = "Saffire PRO 24 DSP";
driver = "DICE";
mixer = "Saffire_Dice";
},
{
vendorid = 0x00130e;
modelid = 0x00000009;
vendorname = "Focusrite";
modelname = "Saffire PRO 14";
driver = "DICE";
mixer = "Saffire_Dice";
},
{
vendorid = 0x00130e;
modelid = 0x00000012;
vendorname = "Focusrite";
modelname = "Saffire PRO 26";
driver = "DICE";
mixer = "Saffire_Dice";
},
{
# A new version of the Pro 40 has been released, described in the
# ConfigROM as SAFFIRE_PRO_40_1. Thanks to Mathieu Picot for the info.
vendorid = 0x00130e;
modelid = 0x000000DE;
vendorname = "Focusrite";
modelname = "Saffire PRO 40-1";
driver = "DICE";
mixer = "Saffire_Dice";
},
{
# Casimir Westerholm has a "SAFFIRE_PRO_40_1" interface which somewhat
# unexpectedly uses a different model ID to that which has been seen by
# others. Thanks to Casimir for the information.
vendorid = 0x00130e;
modelid = 0x00000013;
vendorname = "Focusrite";
modelname = "Saffire PRO 40-1";
driver = "DICE";
mixer = "Saffire_Dice";
},
{
vendorid = 0x001C6A;
modelid = 0x00000001;
vendorname = "Weiss Engineering Ltd.";
modelname = "ADC 2";
driver = "DICE";
},
{
vendorid = 0x001C6A;
modelid = 0x00000002;
vendorname = "Weiss Engineering Ltd.";
modelname = "Vesta";
driver = "DICE";
},
{
vendorid = 0x001C6A;
modelid = 0x00000003;
vendorname = "Weiss Engineering Ltd.";
modelname = "Minerva";
driver = "DICE";
},
{
vendorid = 0x001C6A;
modelid = 0x00000004;
vendorname = "Weiss Engineering Ltd.";
modelname = "AFI 1";
driver = "DICE";
},
{
vendorid = 0x001C6A;
modelid = 0x00000005;
vendorname = "Weiss Engineering Ltd.";
modelname = "TAG DAC1";
driver = "DICE";
},
{
vendorid = 0x001C6A;
modelid = 0x00000006;
vendorname = "Weiss Engineering Ltd.";
modelname = "INT 202";
driver = "DICE";
},
{
vendorid = 0x001C6A;
modelid = 0x00000007;
vendorname = "Weiss Engineering Ltd.";
modelname = "DAC 202";
driver = "DICE";
},
{ # Added by david@wwns.com
vendorid = 0x001c2d;
modelid = 0x00000001;
vendorname = "FlexRadio_Systems";
modelname = "Flex-5000";
driver = "DICE";
xmit_max_cycles_early_transmit = 4;
},
{ # Phonic HelixBoard 24 Universal (PHHB24U), provided by Steffen Klein
vendorid = 0x001496;
modelid = 0x000000;
vendorname = "Phonic";
modelname = "HB 24U";
driver = "BEBOB";
xmit_max_cycles_early_transmit = 4;
},
{
vendorid = 0x0000A0DE;
modelid = 0x0010000B;
vendorname = "Yamaha";
modelname = "GO44";
driver = "BEBOB";
mixer = "YamahaGo";
},
{ # Yamaha GO46, provided by Luis Pablo Gasparotto
vendorid = 0x0000A0DE;
modelid = 0x0010000C;
vendorname = "Yamaha";
modelname = "GO46";
driver = "BEBOB";
mixer = "YamahaGo";
xmit_max_cycles_early_transmit = 4;
},
{ # DnR - Axum_FireWire_IO_card_16x16
vendorid = 0x00000F64;
modelid = 0x00000003;
vendorname = "DnR";
modelname = "Axum_FireWire_IO_card_16x16";
driver = "DICE";
},
{ # Lexicon Onix-FW810S, provided by gerradblock
vendorid = 0x00000FD7;
modelid = 0x00000001;
vendorname = "Lexicon";
modelname = "I-ONIX_FW810S";
driver = "DICE";
mixer = "Generic_Dice_EAP";
},
{ # Avid Mbox 2 Pro, information provided by Yves Grenier via the ffado-user
# mailing list.
# Note: as of Oct 2014 FFADO requires that the device be initialised
# under another operating system so routing and clock settings are
# correct. When this is done and the device is transferred to Linux
# without power cycling it, FFADO can stream audio to/from it. The
# initialisation details need to be sorted before FFADO can claim to
# properly support this device.
vendorid = 0x0000A07E;
modelid = 0x000000A9;
vendorname = "Digidesign";
modelname = "Mbox 2 Pro";
driver = "BEBOB";
# A device-specific mixer needs to be written, there being no generic
# bebob mixer modules.
},
{ # Avid Mbox Pro, information provided by Niels Dettenbach.
# Note: this entry is for future reference only. FFADO does NOT have a
# driver for this device: as of March 2013 no Avid/Digidesign interfaces
# are supported or usable with FFADO.
vendorid = 0x0000A07E;
modelid = 0x00000004;
vendorname = "Avid";
modelname = "Mbox 3 Pro";
},
{ # Allen and Heath Zed R16. Information from Brendan Pike.
vendorid = 0x000004C4;
modelid = 0x00000000;
vendorname = "Allen and Heath";
modelname = "Zed R16";
driver = "DICE";
mixer = "Generic_Dice_EAP";
},
{ # Midas Venice F32. Information from Jano Svitok.
vendorid = 0x0010C73F;
modelid = 0x00000001;
vendorname = "Midas";
modelname = "Venice F32";
driver = "DICE";
mixer = "Generic_Dice_EAP";
},
{ # ICON FireXon. Information from Philippe Ploquin.
vendorid = 0x00001A9E;
modelid = 0x00000001;
vendorname = "ICON";
modelname = "FireXon";
driver = "BEBOB";
# A device-specific mixer needs to be written, there being no generic
# bebob mixer modules.
}
);
libffado-2.4.5/deb/ 0000755 0001750 0000144 00000000000 14206145612 013413 5 ustar jwoithe users libffado-2.4.5/deb/SConscript 0000644 0001750 0000144 00000011620 14206145246 015430 0 ustar jwoithe users #
# Copyright (C) 2007-2008 Arnold Krille
# Copyright (C) 2007-2008 Pieter Palmers
#
# This file is part of FFADO
# FFADO = Free FireWire (pro-)audio drivers for Linux
#
# FFADO is based upon FreeBoB.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
# from: http://www.qandr.org/quentin/writings/debscons.html
import os
Import('env') # exported by parent SConstruct
# Here's the core info for the package
DEBNAME = "libffado0"
if env['REVISION']:
DEBVERSION = "%s-%s" % (env['VERSION'], env['REVISION'])
else:
DEBVERSION = env['VERSION']
DEBMAINT = "Pieter Palmers [pieter.palmers@ffado.org]"
DEBARCH = "i386"
DEBDEPENDS = "libraw1394-8 (>= 1.3.0), libiec61883-0 (>= 1.1.0), libavc1394-0 (>= 0.5.3), dbus (>= 1.1.0)" # what are we dependent on?
DEBRECOMMENDS = "qt5-ukui-platformtheme (>= 1.0.0)"
DEBDESC = "FFADO: FireWire audio for Linux (Development build SVN r%s)" % env['REVISION']
DEBFILES = [
# Now we specify the files to be included in the .deb
# Where they should go, and where they should be copied from.
# If you have a lot of files, you may wish to generate this
# list in some other way.
("usr/lib/libffado.so", "#src/libffado.so"),
("usr/lib/pkgconfig/libffado.pc", "#/libffado.pc"),
("usr/include/libffado/ffado.h", "#libffado/ffado.h"),
("usr/bin/ffado-dbus-server", "#support/dbus/ffado-dbus-server"),
]
DEBFILES.append(("usr/share/libffado/ffado_driver_genericavc.txt", "#src/genericavc/ffado_driver_genericavc.txt"))
if env['ENABLE_BEBOB']:
DEBFILES.append(("usr/share/libffado/ffado_driver_bebob.txt", "#src/bebob/ffado_driver_bebob.txt"))
DEBFILES.append(("usr/bin/ffado-bridgeco-downloader", "#support/firmware/ffado-bridgeco-downloader"))
#DEBFILES.append(("usr/share/libffado/fw410.xml", "#src/bebob/maudio/fw410.xml"))
#DEBFILES.append(("usr/share/libffado//fwap.xml","#src/bebob/maudio/fwap.xml"))
#DEBFILES.append(("usr/share/libffado//refdesign.xml","#src/bebob/maudio/refdesign.xml"))
if env['ENABLE_FIREWORKS']:
DEBFILES.append(("usr/share/libffado/ffado_driver_fireworks.txt", "#src/fireworks/ffado_driver_fireworks.txt"))
DEBFILES.append(("usr/bin/ffado-fireworks-downloader", "#support/firmware/ffado-fireworks-downloader"))
if env['ENABLE_MOTU']:
pass
if env['ENABLE_DICE']:
pass
if env['ENABLE_METRIC_HALO']:
pass
if env['ENABLE_RME']:
pass
if env['ENABLE_BOUNCE']:
pass
# This is the debian package we're going to create
debpkg = '#%s_%s_%s.deb' % (DEBNAME, DEBVERSION, DEBARCH)
# and we want it to be built when we build 'debian'
env.Alias("debian", debpkg)
DEBCONTROLFILE = os.path.join(DEBNAME, "DEBIAN/control")
# This copies the necessary files into place into place.
# Fortunately, SCons creates the necessary directories for us.
for f in DEBFILES:
# We put things in a directory named after the package
dest = os.path.join(DEBNAME, f[0])
# The .deb package will depend on this file
env.Depends(debpkg, dest)
# Copy from the the source tree.
env.Command(dest, f[1], Copy('$TARGET','$SOURCE'))
# The control file also depends on each source because we'd like
# to know the total installed size of the package
env.Depends(DEBCONTROLFILE, dest)
# Now to create the control file:
CONTROL_TEMPLATE = """
Package: %s
Priority: extra
Section: misc
Installed-Size: %s
Maintainer: %s
Architecture: %s
Version: %s
Depends: %s
Recommends: %s
Description: %s
"""
env.Depends(debpkg,DEBCONTROLFILE )
# The control file should be updated when the SVN version changes
env.Depends(DEBCONTROLFILE, env.Value(env['REVISION']))
# This function creates the control file from the template and info
# specified above, and works out the final size of the package.
def make_control(target=None, source=None, env=None):
installed_size = 0
for i in DEBFILES:
installed_size += os.stat(str(env.File(i[1])))[6]
control_info = CONTROL_TEMPLATE % (
DEBNAME, installed_size, DEBMAINT, DEBARCH, DEBVERSION,
DEBDEPENDS, DEBRECOMMENDS, DEBDESC)
with open(str(target[0]), 'w') as f:
f.write(control_info)
# We can generate the control file by calling make_control
env.Command(DEBCONTROLFILE, None, make_control)
# And we can generate the .deb file by calling dpkg-deb
env.Command(debpkg, DEBCONTROLFILE,
"dpkg-deb -b %s %s" % ("deb/%s" % DEBNAME, "$TARGET"))
libffado-2.4.5/doc/ 0000755 0001750 0000144 00000000000 14206145612 013426 5 ustar jwoithe users libffado-2.4.5/doc/adding_devices.dox 0000644 0001750 0000144 00000043730 14206145246 017104 0 ustar jwoithe users /**
@page adding_devices Adding support for new devices to libffado
@author Pieter Palmers
@section intro Introduction
Device support is implemented on two levels:
1) Discovery & configuration
2) Streaming layer
Layer 1 is implemented by subclassing the IAvDevice interface, and adding an appropriate
probe function to devicemanager.cpp.
Layer 2 is implemented by subclassing the StreamProcessor class in src/libstreaming/
Basic operation of libffado is:
- Create a DeviceManager that iterates over all nodes connected to the 1394 bus.
For every node present, it tries the probeFunctions (probeBeBoB, probeMotu, ...).
If a probefunction succeeds, the node is considered to be a freeob supported device.
The probefunction should return a pointer to a AvDevice, i.e. a subclass of this
interface. At this point we have access to all supported devices.
- When the streaming layer is started (e.g. by jackd), it will iterate over all IAvDevice's of
the DeviceManager. For every device:
The streaming layer will (most likely) set some config values (at this moment only the
samplerate). Then will then request the number of iso streams the device provides using
getStreamCount(). Most likely this will be 2 streams, one transmit and one receive.
The next step is that for every stream a StreamProcessor is requested using
getStreamProcessorByIndex(i) (i starts at 0). This streamprocessor is responsible for
the translation between iso stream and audio API. A streamprocessor is a class that is
a subclass of StreamProcessor (see the documentation of that class for more info).
- Once the streaming layer fetched all streamprocessors of all devices, it will proceed with
initializing them, and setting up all support stuff (threads, iso handlers, etc...)
- After this initial setup, the streaming layer will ask the IAvDevice to start the streams
on the hardware device, using startStreamByIndex(). When the streaming layer shuts down,
it will use stopStreamByIndex() to stop the device's streams, and free up the (possibly
allocated) bus resources.
\note the jackd backend also supports to specify a specific node. In that case only the
AvDevice for that node is used, instead of iterating over all of them.
\note Starting the hardware streams is part of the IAvDevice because this allows for a
more generic streamprocessor for AMDTP streams. This stream format is used by
BeBoB's, DICE-II devices, mLan devices, etc. Keeping the start/stop system
separate from the streamprocessor allows the re-use of the streamprocessor should
the start/stop mechanism differ.
In order to add support for a device to libffado, two things should be implemented:
- an IAvDevice descendant that takes care of the device discovery & configuration
- a StreamProcessor descendant that takes care of the device specific stream translation
@section discoverybaseclasses Streaming base class hierarchy and operation
@ref iavdevice.h "" is the device interface. It should be more or less
self-explanatory
@section streamingbaseclasses Streaming base class hierarchy and operation
This section explains the implementation details of the streaming part of libffado.
The following figure shows the base class diagram, and the derrived classed that implement
the AMDTP (AM824, IEC61883-6) streaming decoders. It can come in handy when trying to understand the following sections.
@image html class_diagram_1.png "Streaming Class Diagram"
@image latex class_diagram_1.eps "Streaming Class Diagram"
The basic idea is that when the streaming layer is initialized, it creates a DeviceManager
(not shown in the figure) and a StreamProcessorManager.
The DeviceManager is responsible for discovering and configuring the devices, as explained in the introduction.
The StreamProcessorManager will take care of the actual 'streaming'. This incorporates:
- handling the Isochronous traffic (allocating handlers, iterating handles, ...)
- translating the iso streams into the data format requested by the client application
- handling all threading issues (creation/destruction, realtime behaviour, synchronisation, ...)
- ...
It joins the iso side with the Audio API side.
To accomplish this, it consists of two parts:
- a collection of StreamProcessor 's
- an IsoHandlerManager instance
Related classes: Streaming::StreamProcessorManager
@subsection isoside The iso side: 1394 isochronous traffic management
The IsoHandlerManager is responsible for the management of IsoHandlers. This means creating/destroying the handlers when needed, starting & stopping them, etc...
An IsoHandler in its turn will serve an IsoStream. This means that the getPacket or putPacket callback of an IsoStream will be called by the IsoHandler whenever this is nescessary.
\note The IsoHandler and IsoStream are separate classes because in the case of multichannel Isochronous receive, one IsoHandler can serve more than one IsoStream. The distinction lies in the fact that IsoStreams are bound to a channel and an ieee1394 port, while IsoHandlers are only bound to an ieee1394 port. [multichannel receive is however not implemented yet]
The handling of an IsoStream by an IsoHandler can be started by registering the IsoStream with the IsoHandlerManager. The manager figures out if it has to allocate a new handler for this stream, and will do so if needed. It will also keep track of the IsoHandler-IsoStream relations and will clean up any unused IsoHandlers.
To summarize: if we want to handle (receive from/transmit on) a channel of an ieee1394 port, the only thing we have to do is create an IsoStream, setup its parameters and register it with the IsoHandlerManager. If we then start() the IsoHandlerManager and call its Execute() function, the IsoStream callback will be called whenever activity happens.
\note This abstraction is completely device independent, it only provides a mechanism to transmit or receive a certain isochronous stream. It could as well be used for video streams...
Related classes: Streaming::IsoStream, Streaming::IsoHandlerManager, Streaming::IsoHandler
@subsection audioapiside The Audio API side: port management
\note not all stuff described here is implemented yet.
The abstraction presented at the audio side is based upon Ports. A 'Port' is an entity that has the following properties:
- It has an associated buffer to store 'events'. These events can be samples, midi bytes, control data, ... . The buffer can be allocated outside of the Port (external buffer) or can be allocated internally. Currently there are two buffer types available: E_PointerBuffer and E_RingBuffer.
- E_PointerBuffer is a buffer that can be accessed using the getBufferAddress() method, i.e. by directly reading/writing to memory. It is assumed that routines using this method keep it's size in mind (can be obtained by multiplying getEventSize() and getBufferSize()). This buffer can be an external buffer or an internal buffer. It is important that both the reader and the writer use the correct data type.
\note for this type, currently only externally attached buffers are supported.
- E_RingBuffer is a ringbuffer that can be accessed using read/write type of calls.
\note for the ringbuffer type, only internal buffers are supported.
- DataType: The datatype defines the data type of the events in a Port's buffer. This also determines the size of the events and hence (together with the setBufferSize()) the buffer size in bytes.
- PortType: The port type determines the type of events that is flowing through this port. Currently there are three port types: E_Audio, E_Midi, E_Control. In the future there might be more (e.g. E_AC3 or E_Adat).
- SignalType: The signalling type defines how the 'new event' signalling should occur for this port. Currently there are two possibilities:
- E_PacketSignalled: The port contents should be updated every time a packet arrives. This means that the read to/write from operation of the port is to be called for every packet that arrives (i.e. from within the packet handler callback). The most obvious use is for midi ports, as it can be a problem when midi bytes are quantized to period boundaries.
- E_PeriodSignalled: The port contents should be updated every time time one period of packets is ready. This is for audio data, as this allows the code responsible for reading/writing the Port buffers to buffer the sink/source events untill one period has arrived, and then encode/decode the events all at once from/to the Port buffer. This is a big performance boost due to locallity of data (cache) and the possibility of using SIMD instructions, especially for big buffers.
- Direction: A port is either a Playback or a Capture port. Playback ports are filled by the Audio API and packetized into the iso stream, Capture ports are filled by the iso stream and read out by the Audio API.
\note maybe someday we'll allow any access type with any buffer type, but that doesn't seem to be nescessary now.
\note there are some relations between the DataType and the PortType. These relations should be established in the derrivative classes of Port.
\note one of the fishy things about Ports is the order in which you can call Port methods and change parameters. more on that later.
In order to facilitate the management of a collection of Ports, a PortManager class is implemented. This class implements methods like addPort(), deletePort() etc... It also allows to initialize, prepare and reset all ports in it's collection.
The idea is that we present a collection of ports to the Audio API side which from which it can read or to which it can write.
Related classes: Streaming::Port, Streaming::PortManager
@subsection connectingisoandaudio Connecting the iso side with the Audio API side
The connection between the iso side and the Audio API side is done by the StreamProcessor class. This class inherits both from IsoStream and PortManager. It therefore can be registered to the IsoHandlerManager in order to receive/transmit an iso stream. It can also contain a collection of Ports that serve as a destination/source for the events in the iso stream.
The StreamProcessor class is an abstract class, it cannot be instantiated by itself. The classes that implement a StreamProcessor should derrive from either ReceiveStreamProcessor or TransmitStreamProcessor. These classes provide some extra code that differs between directions.
A ReceiveStreamProcessor implements the putPacket callback, which is called every time a packet arrives. It is supposed to buffer the events (or the decoded frames). When one period of frames can be transmitted to the Audio API, it should signal this when its isOnePeriodReady() method is called.
For PeriodSignalled Ports, the actual transfer from the internal buffer(s) to the Port buffers should be done in the transfer() method. This is because it is not nescessarily so that the buffers of the StreamProcessor's Ports are valid. When the transfer() method is called, the buffers are guaranteed to be valid. The jackd backend for example sets the Port buffers to an internal address before calling transfer(). This allows for a near-zero-copy transfer of the audio: the iso stream events are decoded directly into the jackd sample buffer.
For PacketSignalled Ports, the StreamProcessor should decode & write the events when they arrive (in the packet callback).
A TransmitStreamProcessor implements the getPacket method to construct packets. The rules wrt Port buffer access and internal buffering are similar to those of the ReceiveStreamProcessor.
A StreamProcessor can be enabled and disabled. When a StreamProcessor is disabled, it should not read from or write to it's Port buffers. However, it's putPacket or getPacket callback can be called, so especially for TransmitStreamProcessors one should make sure to generate valid packets (if the device needs them). This behaviour is because some devices need some time before they start sending data, and we want to prevent our port buffers (especially playback) from Xrun due to a StreamProcessor that is already consuming while others are not ready yet. The enable state can be tested with the m_disabled variable.
Closely coupled to the enable/disable functionallity is the isRunning() function. This should return true when a StreamProcessor is ready to consume or provide events.
\note Mostly, a TransmitStreamProcessor is always 'runnable', but a ReceiveStreamProcessor only becomes running when it actually starts to receive events.
In order to make the streaming system work, the StreamProcessors should update the value of m_framecounter in the packet callback. For a ReceiveStreamProcessor this denotes the number of received events, for a TransmitStreamProcessor this is the number of events transmitted. Most of the time this value should be incremented by the number of frames processed in the callback. This increment should be done by calling incrementFrameCounter(nb_frames) to do this thread-safe. The framecounter will be decremented by the streaming thread.
A StreamProcessor also has the init(), prepare() and reset() calls, which are still to be documented (see later).
Related classes: Streaming::StreamProcessor, Streaming::ReceiveStreamProcessor, Streaming::TransmitStreamProcessor, Streaming::PortManager
@subsection mappingports Mapping Ports to IsoStreams
The only thing not explained up till now is how the StreamProcessor knows which iso substream to decode to which port. This is done by defining device specific subclasses of the Port class. These classes inherit both from the generic Port class and from a device specific class (e.g. PortInfo). This PortInfo class contains all information the StreamProcessor needs to map the Port onto the IsoStream, or vice versa. Due to the subclassing, these new device-specific ports can be used as if they were a normal Port. An example can be found in \ref amdtpdescription .
@subsection puttingtogether Putting it all together
@note this is outdated
The framework is completed by introducing the StreamProcessorManager. As indicated before, this class implements a 'collection of StreamProcessors' and an IsoHandlerManager.
First of all, the StreamProcessorManager is a collection of StreamProcessors, hence it implements the registerStreamProcessor and unregisterStreamProcessor methods. It maintains the list of StreamProcessors under it's control. When StreamProcessors are (un)registered, they are automatically (un)registered to the IsoHandlerManager too, creating IsoHandlers to handle them. Remember that StreamProcessor is a descendant of IsoStream, and can therefore be registered to an IsoHandlerManager. This results in the fact that the iso stream the StreamProcessor is supposed to handle, will be attached to an IsoHandler.
Furthermore StreamProcessorManager is a child of the Runnable interface, and can therefore be used as the worker class for a Thread. A complicated sentence to say that the StreamProcessorManager will start up a thread that calls its Execute() function, which in its turn calls the IsoHandlerManager Exectute() method (hence iterating the IsoHandlers managed by the IsoHandlerManager). This thread also performs the synchronisation as described in the next paragraph.
The third function of the StreamProcessorManager is the synchronisation between the iso side and the Audio API side. To implement this, the class provides a wait() method that waits on a synchronisation primitive. This primitive is signalled by the thread that iterates the IsoHandlerManager. This thread will signal the primitive when all StreamProcessors indicate that they have one period ready.
\note this condition is not perfect, but it will do for the moment
The Audio API should call wait(), and when it returns, should call transfer() to transfer the internal buffer contents to the Port buffers. It can then proceed to reading out these Port buffers. The near-zero-copy approach would be to call wait(), then change the Port buffer address to the client's audio buffer for that channel, and then call transfer().
Currently this is for PeriodSignalled Ports only. The PacketBuffered Ports require the Audio API to read/write each Port individually using read/write routines. There is no signalling for these ports. The calls to read/write are also non-blocking, meaning that the Audio API will have to contignously poll these Ports for activity. This can be done with a separate thread, possibly using a sleep() call beween Port buffer fill checks.
\note A blocking-read/nonblocking write (and the other way around) version of access to PacketBuffered Ports is planned.
Related classes: Streaming::StreamProcessorManager, Streaming::IsoHandlerManager, Streaming::Port
@subsection callingorder Some notes on when which method is called
It is not very clear when which method is called (init/prepare/reset/...). This is due to the fact that this isn't really 'clean' yet. Therefore it will be documented later. The source code contains some notes on this.
Some preliminary statements for StreamProcessor's:
- init() should call it's parent class' init to initialize the IsoStream
- prepare()
- should call it's parent class' prepare first, this makes m_nb_buffers and m_period available. These are needed to allocate the internal buffer. It should then proceed to allocate it's internal buffer(s).
- should make sure all ports are ready by calling init() and prepare() for the ports. However this can only be done after all Port parameters (buffersize, port type, ...) are set. Once a Port is init()'d, there are some parameters that cannot be changed (see Port documentation)
- when the StreamProcessor is an TransmitStreamProcessor, it might be good to prefill internal buffers.
- reset() is called when an xrun occurs. it should clear (& prefill) all buffers, and should also be passed on to the parent in order to reset all counters, parent classes and ports.
@section refimplementation Reference Implementation
The BeBoB discovery with the AMDTP StreamProcessor can be considered the reference implementation of this model. You can find a description of the AMDTP StreamProcessor in \ref amdtpdescription .
*/
libffado-2.4.5/doc/mainpage.dox 0000644 0001750 0000144 00000002501 14206145246 015724 0 ustar jwoithe users /*
* This is the main page of the FFADO reference manual, built using
* doxygen.
*/
/**
@mainpage FFADO - Free FireWire (pro-)Audio Drivers for Linux
@author Pieter Palmers
@section intro Introduction
FFADO is intended as an intermediate layer between the Linux1394 kernel/userspace layer, and the various audio API's (ALSA, jack, ...) present.
\note this is a SVN version, therefore it is highly volatile. Certain parts of the documentation can be outdated. This documentation is also auto-generated, and it can occur that unused classes and interfaces appear in the documentation. This pollution will be cleaned up as we go along.
@see
@section library Client side library
FFADO presents an interface that can be used to implement backends for various audio
API's. Currently the best support is for the JACK backend. It is also intended to implement configuration applications like mixer controls etc..
The library API's external C interface is defined in:
- @ref ffado.h ""
@section devicesupport Adding support for unsupported devices
Initial support by FreeBoB was for BeBoB devices only, however the FFADO framework
is usable for all FireWire audio devices.
Take a look at the @ref adding_devices page for a detailed description.
*/
libffado-2.4.5/doc/motu_firewire_protocol.txt 0000644 0001750 0000144 00000156073 14206145246 021007 0 ustar jwoithe users Notes on the FireWire protocol used by MOTU audio devices
=========================================================
Author: Jonathan Woithe
Document version: 20100914-1
Audio/MIDI data
---------------
Note: while this section focuses on the Traveler, the same basic data format
is utilised for the 828Mk2, 896HD, Ultralite and possibly other MOTU
interfaces. The differences lie in the number of discrete audio channels
sent and perhaps the order of some channels within a data block.
Audio data is sent via iso packets. With nothing else present on the
FireWire bus Iso channel 0 is used by the PC to send data to the MOTU while
iso channel 1 is used by the MOTU to send data to the PC. The channels
used can be arbitarily chosen by software subject to availability as
indicated by the Isochronous Resource Manager (IRM).
The MOTU appears to utilise some ideas from IEC 61883-6. For example, each
iso packet seems to include a CIP header (the iso packet header has the tag
field set to 0x01 to indicate the presence of the CIP). However, the
standard is not followed completely to the finest detail. Typical CIP
header values from the Traveler for audio data packets at a 44.1 kHz rate
with SPDIF enabled and the optical I/O ports set to ADAT mode are as
follows:
SID = 0x02 dependent on bus topography
DBS = 0x13 expressed in quadlets
FN = 0 as expected from IEC 61883-6
QPC = 0 as expected from IEC 61883-6
SPH = 1 indicating a source packet header is included. IEC 61883-6
expects SPH to be 0 for A/V transport.
Rsv = 0
DBC = yyy Data block count varies from packet to packet
FMT = 0x02 IEC 61883-6 expects this to be 0x10 for A/V data. MOTU
seem to be using 0x02 for their own purposes.
FDF = 0x22 This means the data is 32 bit floating point according to
IEC 61883-6. The data isn't 32 bit floating point, so MOTU
obviously use this field to mean their own thing.
SYT = 0xffff IEC 61883-6 says this field is the time the event is to be
presented to the receiver. Clearly this isn't used by MOTU.
The FDF field is interesting in that when interpreted as per IEC 61883-6, it
doesn't reflect the reality of the audio stream used by the Traveler (see
below). One has to assume that MOTU have redefined this for their own
purposes.
The DBC field is incremented from packet to packet by the number of
data blocks contained in the packet. At 1x rates there are nominally 8
data blocks per packet, so DBC increments by 8 between successive iso data
packets.
The DBS (Data Block Size) varies according to the sampling rate in use. On
the Travler at 1x rates (44.1 kHz, 48 kHz) it is 0x13. At 2x rates it
reduces to 0x10 while at 4x rates it decreases again to 0x09. Similarly the
iso data length differs according to the sampling rate: 0x268 at 1x rates
(giving 8 blocks per iso data packet), 0x408 at 2x rates (giving 16 blocks
per iso data packet) and 0x488 at 4x rates (giving 32 blocks per iso data
packet).
DBS/FDF behaves a little differently with the Ultralite interface. At both
1x and 2x rates DBS is 19 (0x13) while FDF is still 0x22. Based on
behaviour of earlier interfaces this would give a block size of 19*4 = 76
bytes. However, in reality it is only 52 bytes: 4 bytes SPH, 6 bytes
MIDI/control data, 8x3 bytes analog data, 2x3 bytes SPDIF, 2x3 bytes Mix1
and 2x3 bytes padding (probably used as headphone send in transmit stream).
It's not clear how the given DBS/FDF values relate to this block size.
There are still 8 blocks per iso data packet at 1x rates, and 16 at 2x
rates, giving total packet sizes (including the 8 byte CIP) of 424 bytes at
1x rates and 840 at 2x rates.
The Traveler usually becomes the IRM on the FireWire bus it is plugged into;
when functioning as the IRM it also broadcasts "cycle start" packets on a
regular basis as would be expected. These appear to be as per ieee1394-1995.
These broadcast a quadlet in the same form as the Traveler's cycle time
register with a value equal to the cycle time register at the time the
packet was submitted for transmittsion. The format of this register is as
follows:
bits 31-25 = seconds count (0-127)
bits 24-12 = cycle count (0-7999)
bits 11-0 = cycle offset (0-3071)
Each portion of the register wraps to 0 at the end of the range, causing
the next most significant component to be incremented by one. When the
"seconds count" overflows it simply wraps to 0 without incrementing
anything. The cycle offset is incremented by a 24.576 MHz clock.
The cycle count can be thought of as the fractional part of the current
second in units of 125 us.
The data portion of a typical iso packet to/from the Traveler contains a CIP
header and 8, 16 or 32 data blocks (depending on sampling rate) of size DBS
quadlets (DBS*4 bytes). Empty packets are utilised periodically to maintain
the long-term average equal to the sampling interval. For example, at 48
kHz, 3 packets with 8 datablocks are sent, followed by a single empty
packet.
The format of each data block varies according to whether a 1x, 2x or 4x
clock multiplier is in use. At 44.1 kHz or 48 kHz (ie: a 1x clock), each
data block contains the following in this order:
32 bit Source Packet Header (SPH) (+)
48 bits of control/MIDI data (&)
24 bit audio values: headphone L&R / mix1 L&R (*)
24 bit audio values: analog channels 1-8
24 bit audio values: AES-EBU L and R
24 bit audio values: SPDIF L and R
24 bit audio values: ADAT channels 1-8
At 2x clock frequencies (88.2 kHz and 96 kHz) the ADAT channels 5-8 are
dropped from the datablock, leaving the following arrangement:
32 bit Source Packet Header (SPH) (+)
48 bits of control/MIDI data (&)
24 bit audio values: headphone L&R / mix1 L&R (*)
24 bit audio values: analog channels 1-8
24 bit audio values: AES-EBU L and R
24 bit audio values: SPDIF L and R
24 bit audio values: ADAT channels 1-4
At 4x clock frequencies (176.4 k kHz and 192 kHz) all digital I/O is disabled
along with the separate headphone / mix1 bus. The resulting datablock
is formatted as follows.
32 bit Source Packet Header (SPH) (+)
48 bits of control/MIDI, MSB first (&)
24 bit audio values: analog channels 1-8
16 bits of padding (%)
Notes:
(+) The SPH is defined in IEC 61883-6:
Bits 31-25 = reserved
Bits 24-12 = cycle count (0-7999)
Bits 11-0 = cycle offset (0-3071)
(&) These values have been observed to be almost always 0 in packets sent
by the PC except when MIDI is sent, but for packets sent by the MOTU
they are generally non-zero. See below for more details on these
bytes.
(*) Packets from the traveler send mix1 data here; packets from the PC
send data for the headphone channel here.
(%) It appears the Motu pads data in a cycle using values of either 0x0000
or 0xffff. It appears to use a regular pattern, although the pattern
itself appears variable. Two patterns have been observed so far:
* two blocks of 0xffff followed by two blocks of 0x0000.
* a block of 0xffff followed by three blocks of 0xffff.
The PC driver always appears to send pad values of 0x0000.
If the optical ports have been set to TOSLINK rather than ADAT, the data
sent in the iso datablocks is adjusted accordingly - the 8 (or 4) ADAT
channels and 2 coax SPDIF channels are omitted and the 2 optical TOSLINK
channels are sent in their place.
For packets from the PC to the MOTU, the timestamp given in the SPH probably
represents the cycle time at which the data given should be output by the
interface. For packets coming from the MOTU to the PC this timestamp is
most likely the cycle time at which the data was sampled by the interface.
The cycle offset increment used for each successive datablock varies
according to the sampling frequency as one would expect. While the
increment value is "mostly constant" it does vary by +/-1 at times. This
would be to keep the data in sync with the audio sampling frequency in use,
as some audio sampling frequencies - those which are multiples of 44.1 kHz -
are not integral factors of the cycle offset frequency (and even those which
are sometimes deviate from the theoretical increment by 1). The increments
seen in data coming from the Motu are generally a lot more consistent than
those coming from the PC. It is clear from this that the audio clock is not
locked to the firefire cycle clock in any way.
The 48 bits Control/MIDI data appears to play a part in MIDI data
transmission. When the PC is transmitting a MIDI stream to the Motu it does
so byte by byte. A byte of midi data is sent using the first and third bytes
following a data block's SPH, forming a midi subpacket for want of a better
description. The format of the midi subpacket appears to be
0x0100nn
where nn is the MIDI byte being sent. Having more than one MIDI subpacket
in a single transmitted iso data packet has never been observed; it seems
therefore that on this interface the timing of the MIDI subpackets is to
match exactly their transmission onto the wire. Furthermore, sending data
to the MOTU at a rate faster then the hardware midi rate of 3125 bytes per
second (31250 baud with 8 bit data, 1 start bit and 1 stop bit) will cause
MIDI bytes to be dropped or corrupted in interesting ways.
For data coming from the Motu it appears that these 48 Control/MIDI bits are
used for a number of purposes, although some of the details are yet to be
worked out. However, it appears that MIDI data is intermingled with this.
At this stage it seems that when bit 40 is set then bits 24-31 contain a
MIDI byte. The contents of bits 41-47 and 32-39 do not appear to be
affected by having bit 40 set, so at this stage one concludes that their
function (mostly related to Cuemix setting updates) continues even when MIDI
data is sent. Obviously any other function of bits 24-31 is interrupted when
these bits are required for a MIDI byte.
Putting all this together, bit 40 appears to be a "MIDI byte present" bit;
if set, bits 24-31 contain a MIDI byte. All other bits of the Control/MIDI
fields continue to function even when bit 40 is set. If this definition is
adopted it applies equally well to both incoming and outgoing MIDI data.
It should be noted that the Traveler has never been observed to send more
than one MIDI data byte per iso packet. Presumedly therefore the timing of
the bytes delivered by the Traveler is very close to the timing on the MIDI
wire. However, other MOTU devices (the 828Mk2 for example) do transmit more
than one MIDI byte in a single packet. On these devices MIDI messages must
be buffered in the device and sent in a burst once a complete message has
been received.
Audio channel locations in a frame
----------------------------------
Not surprisingly the different MOTU interfaces place channels at different
offsets within a frame. This section attempts to document what we know
about the channel locations for various devices.
828 Mk 1:
Analog 1-8: 10, 13, 16, 19, 22, 25, 28, 31
SPDIF 1-2: 34, 37
ADAT 1-4: 40, 43, 46, 49
ADAT 5-8 (1x rates only): 52, 55, 58, 61
896HD:
Mix L-R (in, not at 4x): 10, 13
Phones L-R (out, not at 4x): 10, 13
Analog 1-8 (1x/2x rate): 16, 19, 22, 25, 28, 31, 34, 37
Analog 1-8 (4x rate): 10, 13, 16, 19, 22, 25, 28, 31
MainOut L-R (out, 1x/2x only): 40, 43
Unknown 1-2 (in, 1x/2x only): 40, 43
ADAT 1-4 (1x/2x only): 46, 49, 52, 55
ADAT 5-8 (1x only): 58, 61, 64, 67
AES/EBU 1-2 (1x with ADAT active): 70, 73
AES/EBU 1-2 (2x with ADAT active): 58, 61
AES/EBU 1-2 (1x/2x with ADAT off): 46, 49
828 Mk 2:
Mix L-R (in): 10, 13
Phones L-R (out): 10, 13
Analog 1-8: 16, 19, 22, 25, 28, 31, 34, 37
Mic 1-2 (in): 40, 43
Main L-R (out): 40, 43
SPDIF 1-2: 46, 49
ADAT 1-4: 52, 55, 58, 61
ADAT 5-8 (1x rates only): 64, 67, 70, 73
Traveler:
Mix L-R (in, 1x/2x rates only): 10, 13
Phones L-R (out, 1x/2x rates only): 10, 13
Analog 1-8 (1x/2x rate): 16, 19, 22, 25, 28, 31, 34, 37
Analog 1-8 (4x rate): 10, 13, 16, 19, 22, 25, 28, 31
AES/EBU 1-2 (1x/2x rate): 40, 43
SPDIF/Toslink 1-2 (1x/2x rate): 46, 49
ADAT 1-4 (1x/2x rate): 52, 55, 58, 61
ADAT 5-8 (1x rate): 64, 67, 70, 73
Ultralite:
Mix L-R (in): 10, 13
Phones L-R (out): 10, 13
Mic 1-2 (in): 16, 19
Analog 1-2 (out): 16, 19
Analog 3-8: 22, 25, 28, 31, 34, 37
SPDIF 1-2 (in): 40, 43
Main L-R (out): 40, 43
Padding (in): 46, 49
SPDIF 1-2 (out): 46, 49
8Pre:
Mix L-R (in): 10, 13
Phones L-R (out): 10, 13
Analog 1-8 (in): 16, 19, 22, 25, 28, 31, 34, 37
Main L-R (out): 16, 19
Padding (out): 22, 25
ADAT 1-8 (in): 40, 43, 46, 49, 52, 55, 58, 61
ADAT 1-8 (out): 22, 25, 28, 31, 34, 37, 40, 43
828 Mk 3:
Mic 1-2 (in, 1x/2x rates): 10, 13
Phones L-R (out, 1x/2x rates): 10, 13
Unknown 1-2 (out, 4x rates): 10, 13
Analog 1-8: 16, 19, 22, 25, 28, 31, 34, 37
Return 1-2 (in): 40, 43
Main L-R (out): 40, 43
SPDIF 1-2 (1x/2x rates): 46, 49
Unknown (out, 4x rates): 46, 49
Reverb 1-2 (in, 1x/2x rates): 52, 55
[ Optical ports follow according to optical mode: first Optical-A
channels, then optical-B channels. Out channels start at 52, in channels
start at 58. At 1x rates 58/61 are "unknown" ahead of the optical
channels, with inputs at 76/79 being unknown at 2x rates. ]
Ultralite Mk 3:
Mix L-R (in): 10, 13
Phones L-R (out): 10, 13
Mic 1-2 (in): 16, 19
Analog 1-2 (out): 16, 19
Analog 3-8: 22, 25, 28, 31, 34, 37
SPDIF 1-2 (in, 1x/2x rates): 40, 43
Padding (out, 1x/2x rates): 40, 43
SPDIF 1-2 (out, 1x/2x rates): 46, 49
Ultralite Mk 3 hybrid:
Mix L-R (in): 10, 13
Phones L-R (out): 10, 13
Mic 1-2 (in): 16, 19
Analog 1-2 (out): 16, 19
Analog 3-8: 22, 25, 28, 31, 34, 37
SPDIF 1-2 (in, 1x/2x rates): 40, 43
Main L-R (out): 40, 43
Reverb 1-2 (in, 1x/2x rates): 46, 49
SPDIF 1-2 (out, 1x/2x rates): 46, 49
Unknown 1-4 (in, 1x/2x rates): 52, 55, 58, 61
Traveler Mk 3:
Mix L-R (in): 10, 13
Phones L-R (out): 10, 13
Analog 1-8: 16, 19, 22, 25, 28, 31, 34, 37
AES/EBU 1-2 (1x/2x rates): 40, 43
SPDIF 1-2 (1x/2x rates): 46, 49
Reverb 1-2 (in, 1x rates): 52, 55
Unknown 1-2 (in, 1x rates): 58, 61
[ Optical port channels follow in a similar was as for the 828 Mk 3.
The precise locations are yet to be confirmed as of 14 Sept 2010. ]
SMPTE timecode
--------------
It appears that the traveler itself has no way to generate SMPTE timecode
internally. The SMTPE console application allows one to generate timecode,
but the timecode stops as soon as this application is exitted.
In addition, changing any of the settings in the SMPTE console does not
appear to change any hardware settings in the MOTU with the exception of the
"clock/address" control - this changes the source in a similar way to that
in the main MOTU setup program. The obvious conclusion here is that SMTPE
generation appears to be a feature implemented in the host software.
Talkback/listenback
-------------------
These features of the Cuemix console appear to be implemented in the host
software. Enabling either of these appears to simply set the mixer
registers to suit talkback/listenback, with the "normal" settings
restored when talkback/listenback is disengaged. The motu itself does not
appear to have any explicit on-board support of these modes.
Bus renaming in Cuemix console
------------------------------
The naming of the 4 mix buses provided by the Cuemix console seems to be
internal to the Cuemix console application. Changing the mix names results
in no traffic being sent to/from the motu.
MIDI in/out
-----------
MIDI data is sent within the first 48 bytes of the data blocks within an
iso data packet. This is described in detail in the "Audio/MIDI data"
section.
Controlling Cuemix in pre-Mark3 models
--------------------------------------
It has been noted that some mixer settings (particularly registers 0x4yyy)
have been found to utilise "write enable" bits which when set allow their
associated part of the control register to be acted upon. There is no
reason to think that the 0x4yyy registers are unique here; it's likely that
other control registers implement a similar idea. It is thought that
whenever bits are seemingly set to 1 by the Cuemix console there is a stong
possibility they form some kind of enable mask. When such values are noted
in the register description it is likely that they must be supplied as noted
if the desired register change is to be successful. In time it is hoped that
the function of these magic settings can be deduced.
Finally, when manually changing Cuemix settings on the Motu's front panel,
the Cuemix console is observed to update its display accordingly. The data
for these updates comes via a byte stream transmitted by the Motu using a
key/value system in the first two bytes of each data block in the iso
stream. Within a given data block, bits 7-1 of the first byte is the key
while the second byte gives the respective value. Recall that bit 0 of the
first byte is a "MIDI byte present" flag, indicating that the third byte in
the data block contains a MIDI data byte - refer to the "Audio/MIDI data"
section for more details.
The following describes all keys observed so far from the Traveler. Note
that the key values reported here are for bits 7-0 of the first byte with
bit 0 (the MIDI present bit) masked to zero.
0x04 = Some kind of timer/counter. Details not yet identified.
0x0c = Mix bus sync key. The mix bus to which the next mix bus
parameter(s) apply to is given by bits 7-5 in the data byte.
0x14 = channel gain value (0x00-0x80)
0x1c = channel pan value (0x00-0x80, 0x40=centre)
0x24 = channel control: 0x01=mute, 0x02=solo, 0x08=paired
0x2c = mix bus gain (0x00-0x80)
0x34 = mix bus destination/mute. Bits 3-0 are as per "output destination"
in register 0x0c20; bit 4 is the mute bit.
0x3c = main out volume (0x00-0x80)
0x44 = phones volume (0x00-0x80)
0x4c = phones assign (values as per "output destination" in register 0x0c20)
0x54 = at 48 kHz remains fixed at 0x00. Purpose unknown.
0x64 = at 48 kHz remains fixed at 0x00. Purpose unknown.
0x6c = +6 dB boost (analog channels 5-8 only). Bits 4-7 = channels 5-8.
0x74 = ref level. Bits 4-7 = channels 5-8. Bit set/clear = +4/-10.
0xfc = Some kind of timer/counter. Details not yet identified.
For many of these keys there are multiple values to communicate; for
example, for key 0x14 (channel gain) there are up to 20 values for each of 4
mix buses, corresponding to the 20 input channels available (analog 1-8,
SPDIF, AES/EDU, ADAT 1-8). In such situations the multiple values for a
given mix bus are transmitted sequentially (each having the same key)
following a mix bus sync key which gives the mix bus to which the values
apply.
In the case of the Traveler the following sequence of keys is used.
Timing/counter events have been omitted from this sequence. N is the number
of channels active.
Mix bus sync key
N channel gain keys
Mix bus sync key
N channel pan keys
Mix bus sync key
N channel control keys
Mix bus sync key
Mix bus gain key
Mix bus destination key
Main out volume key
Phones volume key
Phones destination key
Input 6dB boost key
Input reference level key
The device-wide keys are therefore seen 4 times as often as the per-mixbus
keys.
Curiously enough, the gain trim and pad settings for analog channels 1-4
use a different method to communicate their changed status; for these
settings the Motu writes to a specific address on the PC and in
response the PC reads a register from the Motu. When a channel's gain trim
or pad setting is altered:
* Motu sends 0x20ffffff to address offset 0x100000000 on the PC
* In response the PC reads register 0x0c1c from the Motu to obtain the new
gain trim value and pad setting.
Controlling Cuemix in Mark3 models
----------------------------------
With the introduction of the "Mark3" interface models (Ultralite, Traveler,
828) MOTU completely changed the method used to control the Cuemix features
of the interface. This was partly out of necessity - with the additional
Cuemix features being added to the "Mark3" models MOTU otherwise faced an
unbounded expansion in the number of device registers needed.
Protocol analysis of an Ultralite-mk3 was provided by MG and GQ.
The Mark3 interfaces use a variation of a key-value protocol involving block
writes to register device register 0x10000 (bus address ffc0-ffff-0001-0000
nominally. Either 2 or 3 quadlets are written depending on the message
being sent. For this documentation we will refer to the bytes within a
message as b00 .. b11, with b00 being the first byte sent.
Byte b00 and b01 form a heartbeat word. Precisely how this is constructed
is not currently known, but it seems it might just be a monotomically
increasing number probably used by the device to detect missing data or
something.
Byte b02 seems to be some kind of class identifier. Currently identified
classes are:
0x66: Faders (including bus master), pan, input trim
0x69: Mute/Solo, Routing selection
Specific message formats are described below.
Trim: 3 quadlet message
b00-b01 - heartbeat
b02 - 0x66
b03 - channel select (0x00-0x09)
b04 - 0x02 (select trim control)
b05-b06 - unknown, TBA
b07-b10 - data (big endian float, 0.0 - 24.0)
b11 - 0x00
Reverb send: TBA
Channel faders: 3 quadlet message
b00-b01 - heartbeat
b02 - 0x66
b03 - bus select (0x00-0x09)
b04 - 0x03 (select fader control)
b05 - channel select (0x02-0x09)
b06 - 0x02
b07-b10 - data (big endian float, 0.0 - 1.0)
b11 - 0x00
Pan: 3 quadlet message
b00-b01 - heartbeat
b02 - 0x66
b03 - bus select (0x00-0x09)
b04 - 0x02 (select pan control)
b05 - channel select (0x02-0x09)
b06 - 0x02
b07-b10 - data (big endian float, -1.0 - 1.0)
b11 - 0x00
Bus master fader: 3 quadlet message
b00-b01 - heartbeat
b02 - 0x66
b03 - bus select (0x00-0x09)
b04-b05 - 0x02-0x00 (select bus master control)
b06 - 0x02
b07-b10 - data (big endian float, 0.0 - 1.0)
b11 - 0x00
Bus routing: 2 quadlet message
b00-b01 - heartbeat
b02 - 0x69
b03 - output select (0x00-0x06, 0xff=disabled)
b04 - bus select (0x00-0x07)
b05-b07 - 0x00-0x00-0x02
Mute: 2 quadlet message
b00-b01 - heartbeat
b02 - 0x69
b03 - state (0x00=disable, 0x01=enable)
b04 - bus select (0x00-0x07)
b05 - 0x00 (select mute control)
b06 - channel select (0x01=bus master, 0x02-0x0b)
b07 - 0x02
Channel solo: 2 quadlet message
b00-b01 - heartbeat
b02 - 0x69
b03 - state (0x00=disable, 0x01=enable)
b04 - bus select (0x00-0x07)
b05 - 0x01 (select solo control)
b06 - channel select (0x01=bus master, 0x02-0x0b)
b07 - 0x02
Controlling sample rate
-----------------------
Sample rate is mainly controlled by the clock control register (0x0b14)
although other registers do play a part. It seems that the front panel
sample rate control is locked out by any write to the clock control
register; once locked it is only unlockable by power cycling the MOTU or by
unplugging it from the computer.
Device identification
---------------------
The ieee1394 vendor ID field currently seems to be set to 0x000001f2 to
signify MOTU.
The ieee1394 model ID is a little more interesting. Originally it was
thought that 0x00101800 represented the 828MkII while 0x00104800 was the
Traveler. However, following an update to Traveler firmware 1.07 the model
ID field changed to 0x00107800. From this it appears that the model ID
field probably does not identify the MOTU model but rather communicates the
firmware version along with other information. It appears that bits 19-12
of the model ID are a binary-coded decimal representation of the minor
firmware version number while at least bits 23-20 (and possibly 27-20) give
the major firmware version number. Further datapoints will be needed to
verify these details, particularly the span of the major version number.
The meaning of bits 11-0 are currently unknown; they seem to equal 0x800
in all 828MkIIs and Travelers.
The ieee1394 GUID (globally unique ID) is preserved for a given unit
across firmware updates, but is unique to each particular unit. Therefore
it cannot be used to unambiguously differentiate between different MOTU
interfaces. However, the unit directory version entry does appear to be set
for particular models across firmware upgrades (0x00000003 for 828MkII,
0x00000009 for Traveler). Therefore the best bet at this stage appears to be
a probe for a vendor ID of 0x000001f2 with one of the above version values
in the unit directory of the config ROM. Unit directory versions for MOTU
hardware are as follows:
0x00000001 = The original 828
0x00000003 = 828 Mk 2
0x00000005 = 896HD
0x00000009 = Traveler
0x0000000d = Ultralite
0x0000000f = 8pre
0x00000015 = 828 Mk 3
0x00000019 = Ultralite Mk 3
0x0000001b = Traveler Mk 3
0x00000030 = Ultralite Mk 3 hybrid
Alternatively one could probe for registers known to exist on only one of
the interfaces. The trim gain / 20 dB pad status register (0x0c1c) for
example can be used to differentiate a Traveler from an 828Mk2 since these
features are only present on the Traveler. At this stage however the unit
version number is probably sufficient and far less complicated in the long
run.
Firmware updates
----------------
A firmware update is initiated by powering the unit up in "update" mode by
turning on while the "cursor" button is held. After verifying "update"
mode, registers 0x010000, 0x010004, 0x010008 and 0x01000c are read; with
firmware 1.04 loaded the values returned were 0x23ba58f, 0x86e5aa30,
0xe7fb2202 and 0x4b85130d. These match exactly the first 16 data bytes of
firmware 1.07 as downloaded to the device, so it's thought that these first
4 quadlets contain some kind of magic number signature designed to confirm
that the device really is a MOTU, or (somewhat less likely) to perhaps
confirm that the MOTU is in update mode.
Next 0x4d4f5455 ("MOTU") is written to register 0x0c00; the new firmware is
then loaded by writing to sequential registers 0x010000 - 0x019ffc and
0x01c000 - 0x02fffc. At the end of writing, 0x00 is written to register
0x0c00.
Verification is by way of reading back the firmware registers from the
device.
The process of confirming that the device is in update mode is not yet fully
understood. In terms of the startup sequence it appears that the only
difference between normal and update modes is that register 0x0400 is set to
0x410df42 in normal mode and 0x410f3a8 when in update mode.
The Travimage.bin firmware file provided by MOTU seems to comprise some kind
of header in bytes 0x00 - 0x17, with the actual firmware data starting at
byte 0x18. The firmware is stored in network byte order (ie: big endian)
quadlets - precisely the same format used to send them to the MOTU device.
The file also appears to include bytes 0x01a000 - 0x01bfff even though the
traveler updater doesn't appear to send this range to the MOTU device.
The firmware file for 1.07 seems to contain 0x020000 bytes of firmware data;
given that the firmware updater writes up to register 0x02fffc the updater
must infer data values of 0xff once the file ends.
Register map
------------
MOTU registers currently known. The base address is 0xfffff0000000.
0x0b00 - Iso streaming control
0x0b04 - Device initialisation/discovery?
0x0b08 - Device initialisation/discovery?
0x0b10 - Optical port control?
0x0b14 - clock control register
0x0b1c - 896HD register possibly related to programmable meters
0x0b24 - 896HD programmable meter register (always probed during discovery/init)
0x0b28 - copy of model_id unit directory
0x0b2c - something related to selections in mixer application
0x0c00 - firmware programming control
0x0c04 - routing / port configuration
0x0c08 - input level (for analog channels 5-8 only)
0x0c0c - "Main out" volume control
0x0c10 - Phones volume control
0x0c14 - boost controls (for analog channels 5-8 only)
0x0c18 - something related to selections in mixer application
0x0c1c - gain trim / 20 dB pad controls (for analog channels 1-4 only)
0x0c20 - mix1 routing control
0x0c24 - mix2 routing control
0x0c28 - mix3 routing control
0x0c2c - mix4 routing control
0x0c60 - ASCII name of current clock source (characters 0-3)
0x0c64 - ASCII name of current clock source (characters 4-7)
0x0c68 - ASCII name of current clock source (characters 8-11)
0x0c6c - ASCII name of current clock source (characters 12-15)
0x0c70 - gain trim / phase invert (Ultralite only, analog channels 1-4)
0x0c74 - gain trim / phase invert (Ultralite only, analog channels 5-8)
0x0c78 - gain trim / phase invert (Ultralite only, SPDIF 1 and 2)
0x4000 - mix1 gain/pan/solo/mute, analog channel 1
0x4004 - mix1 gain/pan/solo/mute, analog channel 2
0x4008 - mix1 gain/pan/solo/mute, analog channel 3
0x400c - mix1 gain/pan/solo/mute, analog channel 4
0x4010 - mix1 gain/pan/solo/mute, analog channel 5
0x4014 - mix1 gain/pan/solo/mute, analog channel 6
0x4018 - mix1 gain/pan/solo/mute, analog channel 7
0x401c - mix1 gain/pan/solo/mute, analog channel 8
0x4020 - mix1 gain/pan/solo/mute, AES-EBU 1/L
0x4024 - mix1 gain/pan/solo/mute, AES-EBU 2/R
0x4028 - mix1 gain/pan/solo/mute, SPDIF 1/L
0x402c - mix1 gain/pan/solo/mute, SPDIF 2/R
0x4030 - mix1 gain/pan/solo/mute, ADAT channel 1
0x4034 - mix1 gain/pan/solo/mute, ADAT channel 2
0x4038 - mix1 gain/pan/solo/mute, ADAT channel 3
0x403c - mix1 gain/pan/solo/mute, ADAT channel 4
0x4040 - mix1 gain/pan/solo/mute, ADAT channel 5
0x4044 - mix1 gain/pan/solo/mute, ADAT channel 6
0x4048 - mix1 gain/pan/solo/mute, ADAT channel 7
0x404c - mix1 gain/pan/solo/mute, ADAT channel 8
0x4100
: - mix2 gain/pan/solo/mute, order as for mix1
0x414c
0x4200
: - mix3 gain/pan/solo/mute, order as for mix1
0x424c
0x4300
: - mix4 gain/pan/solo/mute, order as for mix1
0x434c
0x010000
: - firmware, block 1
0x019ffc
0x01c000
: - firmware, block 2
0x02fffc
Register details
----------------
0x0b00 - Iso streaming control
This register is primarily for the control of iso streaming. It has been
observed to be set to one of two values: 0x80810000 or 0xc0c10000. The
latter value appears to activate iso streaming while the former turns it
off. On readback bits 31 and 23 are zero no matter whether the previously
written value was 0x80810000 or 0xc0c10000. This suggests that these two
bits are effectively "write enable" for iso receive/send configuration on
the Motu, with bits 30/22 being "iso receive/send enable" (again as viewed
by the Motu).
Experiments indicate that bits 29-24 give the iso channel number the Motu
should expect data on (ie: the PC->Motu iso channel number) while bits 21-16
specify the iso channel the Motu should send its data on (ie: the Motu->PC
iso channel number). This makes sense since there are 64 iso channels
available on the FireWire bus requiring 6 bits to specify. If it is then
assumed that bits 15-0 are reserved we have the following layout for
this register.
bit 31 = enable configuration change of PC->Motu iso streaming
bit 30 = PC->Motu iso streaming enable
bits 29-24 = PC->Motu iso channel
bit 23 = enable configuration change of Motu->PC iso streaming
bit 22 = Motu->PC iso streaming enable
bits 21-16 = Motu->PC iso channel
bits 15-0 = reserved, always 0
0x0b04 - Device initialisation/discovery?
This register seems to come into play only during device
discovery/initialisation. The driver writes 0xffc20001 to this register
which is accepted by the MOTU. The purpose of this is not known.
0x0b08 - Device initialisation/discovery?
This is another register which shows up only during device
discovery/initialisation. A value of 0x00 is written to this register which
is accepted by the MOTU. The purpose of this is not currently understood.
0x0b10 - Optical port control?
It is not yet clear what this register does. It plays some part in
setting the mode of the optical ports (see also register c04).
Bit 7 is set to 1 by Cuemix console whenever the optical input port is set
to "off" or "TOSLink" and is 0 if set to "ADAT".
Bit 6 is set to 1 by Cuemix console whenever the optical output port is set
to "off" or "TOSLink" and is 0 if set to "ADAT".
Bit 1 seems to be set most if not all of the time in values written by
the Cuemix console.
Originally it was thought that bit 7 might control the availability of
the 8 ADAT inputs while bit 6 controlled the ADAT outputs. However,
subsequent tests seemed to indicate that this was not the case - setting
these bits in isolation did not affect the hardware cuemix display in
any way.
When this register is read back its value appears to be 0x00001800 no matter
what the optical inputs are set up as.
0x0b14 - clock control register
This register is used in conjunction with others (like 0x0c0-0x0c6) to
control the sample clock. Not all bits have been identified yet. Any write
to this register seems to lock out the front panel sample rate control until
the MOTU is turned off or the MOTU is unplugged from the computer.
The details of the clock control register are summarised below.
bits 31-29: unknown at present. Seem to always be set to 0.
bit 28: unknown at present. For 896HD this seems to be set to 1 whenever
the sample rate, sample rate conversion or clock mode is changed. For other
interfaces it appears to always be set to 0.
bit 27: in 2x or 4x clock mode, this bit indicates whether word clock out
should follow the system clock (bit 27 set to 1) or should be forced to
the base rate (bit 27 set to 0).
bits 26: purpose unknown at present. Bit 26 appears to be set in every
write to this register for the Traveler while for the Ultralite it is
always 0. Behaviour on other interfaces are unknown at present.
On the Traveler, if bit 26 is set then bits 25-24 seem to control device
muting in some way.
Based on other systems we currently take bit 26 to be an "enable" bit
for bits 25-24 on the Traveler. For other interfaces we take it to
always be zero.
bits 25-24: related to device muting, although behaviour differs between
devices and is dependent in some ways on bit 26. Bits 26-24 are toggled
at various staged of rate changes. On the Traveler if bit 26 is set
then the device is muted if both bits 25 and 24 are off. Having either
bit set seems enough to unmute the device, but other systems seem to set
both on. On the Ultralite the device is muted if both bits are off
irrespective of the setting of bit 26. The nature of the behaviour on
other interfaces is yet to be determined.
Based on other systems we'll assume bits 25-24 together control device
muting: both off means device muted, both on means device unmuted, and
other combinations (which seem to still unmute the device in practice)
are unknown.
bits 23-6: unknown at present. All bits appear to always be set to zero.
bit 9-8: Sample rate conversion setting (896HD only, always 0 on other
interfaces):
0 = off
1 = AES/EBU in
2 = AES/EBU out slave
3 = AES/EBU out 2x
bits 7-6: unknown at present. Always observered to be 0.
bit 5: 4x rate multiplier selector
Enables the 4x clock multiplier (giving access to 176000 Hz and 192000 Hz
rates)
bit 4: 2x rate multiplier selector
Enables the 2x clock multiplier (giving access to 88200 Hz and 96000 Hz
rates)
bit 3: Base rate selector:
0 = 44100 Hz
1 = 48000 Hz
bits 2-0: clock source:
0 = internal (and SMTPE if in the Audio console)
1 = ADAT optical
2 = (coaxial) SPDIF or (optical) TOSLink
3 = SMTPE (set only by SMTPE console)
4 = Word clock in
5 = ADAT 9 pin
6 = [ reserved? ]
7 = AES-EBU
Note: when changing the rate multipliers additional work needs to be done
involving bits 11-8 of register 0x0c04 (routing/port configuration
register), bits 6 and 7 of 0x0b10 (optical control register) and other as
yet unidentified bits of 0x0b14. While 0x0b10 and 0x0c04 are always
written, they only seem to change value only when moving to a 4x multiplier.
to ensure the ADAT/SPDIF optical port is disabled at 4x sample rates.
The rest of the details associated with these other registers are yet to be
deduced. Note for instance that the 0x0b10 changes only appear to affect
ADAT controls - verified by observing that the same changes to 0x0b10 are
made when the optical ports are turned off in the Audio console program.
When the clock source is changed via this register, the textual name of the
source is always sent immediately afterward to 0x0c60-0x06c. This is used
to report the current clock as selected by the PC on the LCD via the setup
menu. See the description of these registers for more details.
SMTPE is interesting: its distinct value (3) is configured only if one
requests SMTPE as the clock source under the SMTPE console. Selecting SMTPE
as the source in the Audio console appears to use the "internal" setting for
bits 0-3.
0x0b1c - 896HD register associated with programmable meters
The role of this register is currently unknown. Whenever the programmable
meters are configured via register 0x0b24, 0x0400 is written to this register
after the write to register 0x0b24.
0x0b24 - 896HD programmable meter register
Register 0x0b24 doesn't exist in the MOTU Traveler/828Mk2 hardware, but a
read request is always sent to it twice during device
discovery/initialisation. In response these interfaces return "type_error"
with data equal to 0x40000. The precise purpose of this is not known but it
could be part of the device probing sequence.
Register 0xb24 does however exist on the 896HD and appears to control the
programmable meters:
bits 31-14: Unknown at present. Always observed to be set to 0.
bits 13-11: Peak hold time:
000 = off
001 = 2 sec
010 = 4 sec
011 = 10 sec
100 = 1 minute
101 = 5 minutes
110 = 8 minutes
111 = infinite
bits 10-8: Clip hold time:
000 = off
001 = 2 sec
010 = 4 sec
011 = 10 sec
100 = 1 minute
101 = 5 minutes
110 = 8 minutes
111 = infinite
bits 7-3: Unknown at present. Always observed to be set to 0.
bit 2: AES/EBU meter source:
0 = AES/EBU out
1 = AES/EBU in
bits 1-0: Programmable meter source:
0 = Analog out
1 = ADAT in
2 = ADAT out
0x0b28 - copy of model_id unit directory
This register appears to be a copy of the model_id unit directory, normally
found in config ROM register 0x0434. The presence and contents of this
register have only been verified on the 828MkII - the driver reads this
register when a 828MkII is connected but the Traveler initialisation
sequence does not appear to read it.
0x0b2c - something related to selections in mixer application
This register has something to do with destination of the selected mix bus
in the mixer application. When a mix bus is selected, 0xbXX is written to
this register where XX is the output destination of the selected mix bus.
The interpretation of XX is the same as for the 0x0c20 register - see below.
The point of this is not currently known.
If "Cuemix input includes computer output" is selected in cuemix console:
0xc01 is written to register 0x0b2c
0x001 is written to register 0x0c18
When "Cuemix input includes computer output" is turned off in cuemix console:
0xc00 is written to register 0x0b2c
0x000 is written to register 0x0c18
When Cuemix console is started, 0xb00 is written to register 0x0b2c after
the rest of the startup sequence is complete; some time later a value
of 0x0b02 is written. This sequence is possibly related to the mix
inherently selected when cuemix is started; as noted above, when a mix
is selected it does cause 0xb00 to be written to.
Register 0x0b2c appears to be read-only.
0x0c00 - firmware programming control
It appears that when the MOTU is in "update" mode this register is used
to enable writing to the device's firmware area (registers 0x010000 -
0x019ffc and 0x01c000 - 0x02fffc). Writing 0x4d4f5455 ("MOTU") seems
to enable writes to the firmware while writing 0x00 is written when the
firmware update is complete.
0x0c04 - routing / port configuration
This register appears to have something to do with routing and port
configuration. On some devices (the Ultralite for example) this register
must be initialised to something sensible before the device will accept
streaming enable commands via the streaming control register.
Bits 7-0 control the source for the phones output. The numbers used are
the same as for the output destination of the mix routing control (0x0c20
etc) - see below for details.
Bits 9-8 specify the mode of the optical input port:
00 = off, 01 = ADAT, 10 = TOSLink (numbers given are in binary)
The "TOSLink" option is not available on the 896HD. Register 0xb10 also
plays a role in setting the optical input port mode.
Bits 11-10 specify the mode of the optical output port in the same way
as for the optical input port. Again, register 0b10 seems to play a role
in setting the optical output port mode.
Bit 24 enables the setting of the phones source. Bit 25 probably allows the
optical modes to be set.
Bits 31-26, 23-12 are unknown at present. They seem to always be zero.
0x0c08 - input level (for analog channels 5-8 only)
This sets the input level for analog channels 5 to 8. The default is
+4 dBU, but this register can be used to select -10 dBU if desired.
Only bits 4-7 appear to be significant in this register when setting input
level; all other bits are set to zero.
bit 4: analog channel 5 input level
bit 5: analog channel 6 input level
bit 6: analog channel 7 input level
bit 7: analog channel 8 input level
It seems likely that bits 0-3 are reserved for analog channels 1-4
respectively.
When a channel's bit is set (the default condition) an input level of +4 dBU
is assumed. If the bit is zero it selects an input level of -10 dBU for
the respective channel.
A write to this register sets the input level for all channels.
The MOTU mixer application ties analog channels 5/6 and 7/8 together
(presumedly as a stereo pair) and activates the input level for the pair
whenever one channel is selected (even when the channels are not "paired").
However, it has been verified that the input level of channels can be
individually controlled though this register.
0x0c14 - boost controls (for analog channels 5-8 only)
Bits 4-7 of this register controls the activation of an additional 6dB of
gain for analog channels 5-8. All other bits are set to zero.
bit 4: analog channel 5 boost
bit 5: analog channel 6 boost
bit 6: analog channel 7 boost
bit 7: analog channel 8 boost
Once again, bits 0-3 are probably reserved for analog channels 1-4 if they
were ever to acquire this functionality.
When a bit is zero (the default condition) the additional 6 dB boost is not
active. When set to 1, the boost becomes active for the respective channel.
The boost status of all 4 channels is always updated by a write to this
register.
0x0c18 - something related to selections in mixer application
If "Cuemix input includes computer output" is selected:
0xc01 is written to register 0x0b2c
0x001 is written to register 0x0c18
When "Cuemix input includes computer output" is turned off:
0xc00 is written to register 0x0b2c
0x000 is written to register 0x0c18
0x0c0c - "Main out" volume control
Bits 7-0 of this register control the device's "main out" volume (0x80 = 0 dB,
0x00 = -inf). Bits 31-8 appear unused at present.
0x0c10 - phones volume control
Bits 7-0 of this register control the device's phones volume (0x80 = 0 dB,
0x00 = -inf). Bits 31-8 appear unused at present.
0x0c1c - gain trim / 20 dB pad controls (for analog channels 1-4 only)
This register controls the trim gain and 20 dB pad available on analog
channels 1-4. Byte 0 (the least significant byte) controls analog channel
1. Bytes 1-3 are for analog channels 2-4 respectively.
Bit 7 in each byte appears to always be set to 1. The effect of setting
bit 7 to 0 is currently unknown. On write, bit 7 may be a write-enable
control.
Bit 6 of a byte controls the 20 dB pad for the channel. When bit 6 is set
(ie: equal to 1) the pad is engaged. When bit 6 is zero the pad is switched
out.
Bits 0-5 set the gain trim value; 0 sets a gain of 0dB (the default) while
a value of 0x35 (53) sets the maximum gain of 53 dB. The trim gain acts
in steps of 1 dB.
It seems the gain trim and pad settings of all channels can be set with a
single write to this register. However, if a channel's byte is written as
zero its settings remain unchanged.
0x0c20, 0x0c24, 0x0c28, 0x0c2c - mix1, mix2, mix3 and mix4 routing controls
These registers control routing for the mix buses. The format used by the
four mix buses is the same, so only 0x0c20 (mix1 routing control) is
explicitly discussed.
bits 31-26: function currently unknown. All bits seem to be set to 0.
bit 25: enable setting of mute status and destination.
bit 24: enable setting of fader.
bits 23-16: function currently unknown. All bits seem to be set to 0.
bits 15-13: purpose unknown. Seems to be set to 0.
bit 12: mute control. 0=unmute, 1=mute.
bits 11-8: output destination (see below).
bits 7-0: mix output fader. 0x80 = 0 dB, 0x00 = -inf
The output destination is defined as follows:
0x0 = disabled
0x1 = headphone output
0x2 = analog 1-2
0x3 = analog 3-4
0x4 = analog 5-6
0x5 = analog 7-8
0x6 = AES-EBU (Main-out on 896HD)
0x7 = SPDIF (AES-EBU on 896HD)
0x8 = ADAT 1-2
0x9 = ADAT 3-4
0xa = ADAT 5-6
0xb = ADAT 7-8
Note that it is not possible to set the mute and destination status
separately - they are both set when bit 25 is set.
0x0c60, 0x0c64, 0x0c68, 0x0c6c - ASCII name of current clock source
These registers appear to hold the ASCII name of the current clock source.
If the source name is less than 16 characters it is padded with spaces
(0x20). The most significant byte of each register holds the leftmost
character of the group of 4 characters held by a that register. For
example, if a register needs to hold the string "ABCD", the most significant
byte will be 65 ("A").
Currently defined strings are as follows.
"Internal " - internal clock source
"SMPTE " - SMPTE syncing
"AES-EBU " - use clock from AES-EBU
"SPDIF " - clock from (coaxial) SPDIF
"TOSLink " - clock from (optical) TOSLink
"Word Clock In " - use the word clock input
"ADAT 9-pin " - use the 9-pin ADAT interface for the clock
"ADAT Optical " - sync from ADAT optical interface
When a computer is connected to the MOTU the only way to set the clock
source is from the computer - the front panel controls for this are
disabled. The string sent via these registers is used to display the name
of the clock source as selected by the computer. If the clock source is
changed (via register 0x0b14) but nothing is downloaded using these
registers, the "current clock source" display on the LCD via the setup menu
will be blank.
One would have thought the Motu would be smart enough to provide the display
string by itself given that it seems to manage to set the string fine by
itself when there's no PC connected and the front panel is used to change
the clock source.
0x0c70 - gain trim / phase invert (Ultralite only, analog channels 1-4)
On the Ultralite, gain trim is controlled using a different register than
with the other MOTU devices. This register controls gain trim and phase
inversion for analog channels 1-4. Byte 0 (the least significant byte)
controls analog channel 1. Bytes 1-3 are for analog channels 2-4
respectively.
Bit 7 in each byte appears to always be set to 1 when changing the
corresponding channel's setting. It therefore seems that bit 7 is a
write-enable bit for the channel's setting.
Bit 6 of a byte controls the phase inversion setting. When set (ie: equal
to 1) phase inversion is active. When bit 6 is zero phase inversion is not
enagaged.
Bits 0-5 set the gain trim value; 0 sets a gain of 0dB (the default). The
maximum gain available is determined by the type of channel. For analog
channels 1-2 (the mic inputs), the maximum effective setting is 0x18 (24).
For analog channels 3-8 the maximum is 0x12 (18) while for SPDIF channels
the maximum is 0x0c (12). The value written is in dB - thus each gain trim
control operates in steps of 1 dB.
Setting a channel's byte to zero causes its settings to remain unchanged.
This allows any combination of the 4 channels to be changed without
interference to those not being changed.
0x0c74 - gain trim / phase invert (Ultralite only, analog channels 5-8)
This register operates as described for 0x0c70 except it controls analog
channes 5 to 8. The least significant byte corresponds to analog channel 5.
0x0c78 - gain trim / phase invert (Ultralite only, SPDIF 1 and 2)
This register operates as described for 0x0c70 except it controls SPDIF 1
and SPDIF 2. The least significant byte corresponds to SPDIF 1. Bytes 2
and 3 are currently unused and should always be set to zero when writing to
this register.
0x4y00-0x4y4c (y=0-3) - gain/pan/solo/mute registers
These registers control the fader, pan, mute and solo settings for a given
input channel in each of the 4 mix buses. y=0 is mix1, y=1 is mix2, y=2 is
mix3 and y=3 is mix4.
Bit 31: enable setting of pan
Bit 30: enable setting of gain
Bit 29: enable setting of bit 21
Bit 28: enable setting of bit 20
Bit 27: enable setting of pairing
Bit 26: enable setting of bit 18
Bit 25: enable setting of solo
Bit 24: enable setting of mute
Bit 23: seems to be unsettable; set to zero
Bit 22: seems to be unsettable; set to zero
Bit 21: can be set to 1 but no effect apparent
Bit 20: can be set to 1 but no effect apparent
Bit 19: activate pairing
Bit 18: can be set to 1 but no effect apparent
Bit 17: channel solo. 0=solo off, 1=solo on.
Bit 16: channel mute. 0=unmuted, 1=muted.
Bits 15-8: pan. 0x40=0 (centre), 0x80=+64 (right), 0x00=-64 (left)
Bits 7-0: gain. 0x00 = -inf, 0x80 = 0 dB.
When reading these registers in normal operation, bits 31-27 and bits 23-18
seem to be all zero while bits 26-24 are all 1. The Cuemix console however
appears to set bits 31-30 and zero bits 29-18. In other words, a typical
read-back value might be 0x0700406a while to actually set the mixer to this
one would need to use a value of 0xc300406a. It seems likely that at least
some of the bits have different meanings when read and written; for instance
there doesn't seem to be much point in bits 24-26 being set on readback
given the above definitions, but they are.
If channel pairing is to be activated it must be set in both channels which
form a stereo pair. However, paired channels are still controlled
individually by the mixer registers - for example, if channels 1 and 2 are
paired it is still possible to raise channel 1's volume in mix1 by writing
only to register 0x4000. In other words, the device does not enforce linked
controls when channels are paired. The "paired" flag is really just a hint
to the mixer at the end of the day.
Gain and pan value-dB mappings for the Traveler
===============================================
The following gain map runs from 0x00 (-inf) to 0x80 (0 dB). The dB values
were taken directly off the Cuemix console application.
Gain steps (dB): -inf, -84, -72, -65, -60, -56, -53, -50, -48, -46, -44,
-43, -41, -39.7, -38.4, -37.2, -36.1, -35.1, -34.1, -33.1, -32.2, -31.4,
-30.6, -29.8, -29.1, -28.4, -27.7, -27.0, -26.4, -25.8, -25.2, -24.6,
-24.1, -23.5, -23.0, -22.5, -22.0, -21.5, -21.1, -20.6, -20.2, -19.8,
-19.4, -19.0, -18.6, -18.2, -17.8, -17.4, -17.0, -16.7, -16.3, -16.0,
-15.6, -15.3, -15.0, -14.7, -14.4, -14.1, -13.8, -13.5, -13.2, -12.9,
-12.6, -12.3, -12.0, -11.8, -11.5, -11.2, -11.0, -10.7, -10.5, -10.2,
-10.0, -9.8, -9.6, -9.3, -9.1, -8.8, -8.6, -8.4, -8.2, -7.9, -7.7, -7.5,
-7.3, -7.1, -6.9, -6.7, -6.5, -6.3, -6.1, -5.9, -5.7, -5.5, -5.4, -5.2,
-5.0, -4.8, -4.6, -4.5, -4.3, -4.1, -3.9, -3.7, -3.6, -3.4, -3.3, -3.1,
-3.0, -2.8, -2,6, -2.5, -2.3, -2.2, -2.0, -1.9, -1.7, -1.6, -1.4, -1.3,
-1.1, -1.0, -0.8, -0.7, -0.6, -0.4, -0.3, -0.1, 0.0
Pan: (approximate findings)
full pan on: +3 dB gain
0: 0 dB
20/64 pan off: -3 dB
40/64 pan off: -6 dB
55/64 pan off: -15 dB
59/64 pan off: -24 dB
full pan off: -inf gain
Pan dB map. This table runs from value 0 (pan full left) to 0x80 (pan
full right). The gain values are for a left channel signal.
2.505, 2.505, 2.505, 2.499, 2.499, 2.492, 2.486, 2.479, 2.473, 2.460,
2.453, 2.440, 2.427, 2.414, 2.400, 2.387, 2.367, 2.347, 2.331, 2.308,
2.288, 2.267, 2.241, 2.220, 2.194, 2.166, 2.139, 2.105, 2.078, 2.044,
2.016, 1.982, 1.940, 1.905, 1.870, 1.828, 1.786, 1.743, 1.700, 1.657,
1.607, 1.563, 1.512, 1.461, 1.409, 1.358, 1.298, 1.245, 1.185, 1.124,
1.063, 1.001, 0.931, 0.868, 0.797, 0.725, 0.653, 0.580, 0.507, 0.424,
0.341, 0.265, 0.257, 0.087, 0.000,
-0.087, -0.176, -0.274, -0.373, -0.473, -0.584, -0.687, -0.801, -0.916,
-1.033, -1.151, -1.271, -1.403, -1.526, -1.662, -1.800, -1.940, -2.083,
-2.239, -2.386, -2.548, -2.713, -2.881, -3.058, -3.240, -3.437, -3.614,
-3.814, -4.018, -4.228, -4.457, -4.678, -4.920, -5.168, -5.489, -5.688,
-5.969, -6.259, -6.568, -6.889, -7.222, -7.568, -7.928, -8.327, -8.722,
-9.160, -9.621, -10.108, -10.624, -11.205, -11.810, -12.460, -13.182,
-13.971, -14.886, -15.855, -16.976, -18.264, -19.819, -21.715, -24.143,
-27.526, -33.143, -inf
dB factors for values of 0, 1 and 2 are all 2.505 dB while those for pan
values of 3 and 4 are both 0.499. This is because the voltage variation
across each of these groups of values was below the resolution of the meter
used to measure the voltages (0.001 Vrms). One can probably safely assume
that the actual variation across these groups is approximately linear, so
"corrected" dB values for the first 5 pan values can probably be taken to be
2.508, 2.505, 2.504, 2.501, 2.499
The pan map was measured by injecting a 0.992 Vrms sine wave at 308 Hz into
analog1 input channel of the Motu. Channel 1's -20 dB pad was switched in
to avoid overloading the preamp and a gain trim of +11 dB was used. This
combination resulted in a signal of 0.999 Vrms being emitted from analog1
output with the analog1's fader set to 0 dB.
The output RMS voltage was then measured for each setting of the pan
control. Resolution of these measurements was 0.001 Vrms. The dB gain
value was calculated relative to the centre pan position using
dB = 20log10(V/ref)
where ref was the voltage measured with the pan control set to the centre
(ie: a pan value of 0x40).
A frequency of approximately 300 Hz was chosen since this was firmly within
the flat response region of the multimeter used for measuring the voltage.
If the frequency drifted slightly the frequency response of the meter would
therefore not artificially change the voltage measurement.
The input signal was generated using a precision audio signal generator.
The amplitude is tightly regulated and did not change for the duration of
these tests.
The meter used was not able to measure voltages below 0.004 Vrms. This was
a limitation of the meter - it was not an additive offset which affected
voltage measurements.
Putting all this together it is expected that the dB values for the pan map
are accurate to at least 1 decimal place.
libffado-2.4.5/doc/rme_notes/ 0000755 0001750 0000144 00000000000 14206145612 015421 5 ustar jwoithe users libffado-2.4.5/doc/rme_notes/rme_config_register_map.txt 0000644 0001750 0000144 00000111655 14206145246 023047 0 ustar jwoithe users RME Fireface-400 / Fireface-800 register map
============================================
Version: 0.26
Author: Jonathan Woithe
Date: 11 April 2013
Definitions
-----------
CBA = Command Buffer Address
FF800 = Fireface-800
FF400 = Fireface-400
Multi-byte values sent to/from the Fireface in async packets are generally
little endian - that is, the device interprets quadlets in asynchronous
packets as little endian even though the bus definition is big-endian. If
writing a driver for use on a little endian machine, this means that a lack
of byte swapping (to account for the bus endianness standard) will cause bit
0 on the host to be bit 0 on the device.
By default, FFADO however adheres to the bus standards and byteswaps on
little endian machines. Under this regime, bit 0 on the host will in fact
be read by the device as the least significant bit in the most significant
byte.
In order to retain consistency with device documentation, the FFADO RME
driver currently sends async packet data in the little endian format which
the RME device expects. Although this is technically wrong (in so far as
the FireWire standard is concerned), at this stage it is considered that
introducing an endianness difference between the FFADO driver and the
documentation is likely to result in maintenance issues down the track.
The bit maps in this document regarding the configuration registers are
written from the device's point of view. That is, the values quoted should
be sent to the device in little endian format unless otherwise stated.
Curiously enough, preliminary investigations suggest that audio data appears
to be sent on the bus in big endian format (although this is to be
confirmed).
The FF800 includes a number of instrument options for input 1 which are
described using several different terms interchangeably:
- "Drive" (also referred to as "fuzz") activates 25 dB extra gain
- "Speaker emulation" (also referred to as "filter") removes LF noise and
some HF
- "Limiter" activates a soft-limiter with a threshold of -10 dBFS. This
can only be switched off if the Front input is used for channel 1.
Device address space location
-----------------------------
While some register addresses are common between the two interfaces, the
absolute addresses of the settings and control differ. These are defined
relative to the device "command buffer" address:
FF800: command buffer address (CBA) = 0xfc88f000
FF400: command buffer address (CBA) = 0x80100500
The location of the configuration (settings) registers relative to the
command buffer is consistent across devices:
conf reg 1 address = command buffer address + 5*4
For a FF800 this equates to 0xfc88f014.
Controlling sample rate (DDS)
-----------------------------
Sample rate is controlled by writing the desired sample rate in Hz to the
sample rate control register located at offset 0 from the command buffer
address (0xfc88f000 on a FF800). The hardware DDS allows a wide range of
frequencies to be requested (possibly anything from 30 kHz up to 210 kHz).
The more common rates are of course 32k, 44.1k, 48k, the pull-up/down rates
(44.056k, 44.144k, 45.937k, 46.080k, 47.952k, 48.048k) and the corresponding
2x and 4x rates.
Software connecting to the Fireface device is restricted to the normal rates
of 32k, 44.1k, 48k and the related 2x and 4x rates.
If the device is in master clock mode and the user has not made an explicit
DDS setting, the hardware DDS will be determined by the sampling rate
requested by the application opening the device. If a DDS frequency has
been requested by the user the actual rate used by the device will be that
DDS frequency regardless of what the application has asked for. In this
case a device open will only succeed if the software has requested a speed
whose multiplier matches the DDS configuration.
If the device is locked to an external clock, a device open will succeed
only if the multiplier of the requested sampling rate matches that of the
external rate.
The device status registers allow the PC to determine the sampling rate when
an external clock is in use. However, there is no way to read the sampling
rate when in master clock mode. It is therefore necessary to cache this in
the driver so it can be provided when requested.
In terms of multipliers the RME treats sample rates greater than 112000 Hz
as 4x rates, with rates greater than 56000 Hz as 2x rates. Rates less than
30000 Hz and greater than 210000 Hz are invalid.
Configuration registers 1, 2 and 3
----------------------------------
Most RME device configuration is done using configuration registers 1, 2
and 3. For the ff800 these are:
config1 = configuration register 1 (FF800: 0xfc88f014, FF400: 0x80100514)
config2 = configuration register 2 (FF800: 0xfc88f018, FF400: 0x80100518)
config3 = configuration register 3 (FF800: 0xfc88f01c, FF400: 0x8010051c)
In essence the configuration registers start at CBA+5*4 for both interfaces.
When making a configuration change these registers are always written in a
block of 12 bytes starting at 0xfc88f014 with a block write operation.
Configuration register 1 (FF800: 0xfc88f014, FF400: 0x80100514):
bits 31-18: unknown, set to 0
bits 17-16: Phones level:
00 = +4 dBu
01 = -10 dBV
10 = hi-gain
bits 15-13: unknown, set to 0
bits 12-10: Output level control (part 1 of 2: FPGA LED drive):
001 = hi-gain
010 = +4dBU
100 = -10dBV
bit 9: FF800: Instr option: Drive (part 1 of 2: FPGA LED drive) (active = 1)
FF400: Channel 3 "instrument" switch
bit 8: FF800: Phantom power, mic 10 (active = 1)
FF400: Channel 3 "pad" switch
bit 7: Phantom power, mic 8 (active = 1)
bit 6: unknown, set to 0
bits 5-3: Input level control (part 1 of 2: FPGA LED drive):
001 = lo-gain
010 = +4dBU
100 = -10dbV
bit 2: FF800: Instrument option: speaker emulation (aka "filter") (part 1
of 2: FPGA LED drive) (active = 1)
FF400: Channel 4 "instrument" switch
bit 1: FF800: Phantom power, mic 9 (active = 1)
FF400: Channel 4 "pad" switch
bit 0: Phantom power, mic 7 (active = 1)
Configuration register 2 (FF800: 0xfc88f018, FF400: 0x80100518):
bits 31-12: unknown, set to 0
bit 11: Input #1 front switch (active = 1)
bit 10: unknown, set to 0
bit 9: Instrument option: Drive (part 2 of 2: CPLD function) (active = 0)
bit 8: Input #8 rear switch (active = 1)
bit 7: Input #8 front switch (active = 1)
bit 6: Input #7 rear switch (active = 1)
bit 5: Input #7 front switch (active = 1)
bits 4-3: Output level control (part 2 of 2: CPLD function):
00 = undefined
01 = -10dBV
10 = hi-gain
11 = +4dBU
bit 2: Input #1 rear switch (active = 1)
bits 1-0: Input level control (part 2 of 2: CPLD function):
00 = lo-gain
01 = undefined
10 = +4dBU
11 = -10dbV
Configuration register 3 (FF800: 0xfc88f01c, FF400: 0x8010051c):
bit 31: "Drop and stop": always set to 1
bit 30: Unit option: TMS (active = 1)
bits 29-27: set to 0
bit 26: set to 1 for FF400, 0 for FF800
bits 25-17: set to 0
bit 16: P12DB_AN0 (normally set to 0)
bit 15: set to 0
bit 14: Toggle TCO (normally set to 0)
bit 13: Word clock single speed: 0 = off, 1 = on
bits 12-10: Sync reference source:
000 = ADAT1
001 = ADAT2
011 = SPDIF
100 = Word clock
101 = TCO
bit 9: SPDIF input source: 0 = coax, 1 = ADAT2 port
bit 8: SPDIF output option: ADAT2
bit 7: SPDIF output option: non-audio
bit 6: SPDIF output option: emphasis
bit 5: SPDIF output option: professional
bit 4: QS control (set to 1)
bit 3: DS control (set to 1)
bit 2: Freq1 control (set to 1)
bit 1: Freq0 control (set to 1)
bit 0: Clock mode: 0 = Master, 1 = Autosync
On the FF400, writing to these registers with valid values for the first
time after power up has the side effect of extingishing the "Host" LED.
Device status registers
-----------------------
There are up to 4 read-only device status registers available, starting at
address 0x801c0000. There seems to be a slight difference in the mapping of
status register 0 depending on the size of the read. If only 2 registers
(quadlets) are read the "general" layout is assumed. If on the other hand 4
registers are used (used when determining the status of the device's
streaming system) the layout of register 0 is slightly different.
Status register 0:
bits 9-0: on a 2-quadlet read these bits are all zero
bits 9-0: on a 4-quadlet read when in autosync mode, these bits contain
SR/250, where SR is the sample rate to be passed to the
streaming subsystem when starting streaming.
bit 10: ADAT1 lock achieved
bit 11: ADAT2 lock achieved
bit 12: Device is synced to ADAT1
bit 13: Device is synced to ADAT2
bits 17-14: SPDIF frequency:
0000 = undefined 0101 = 88.2k
0001 = 32k 0110 = 96k
0010 = 44.1k 0111 = 128k
0011 = 48k 1000 = 176.4k
0100 = 64k 1001 = 192k
bit 18: Device is synced to SPDIF
bit 19: Over detected
bit 20: SPDIF lock achieved
bit 21: undefined (read as zero)
bits 24-22: Primary sync source:
000 = ADAT1 100 = Word clock
001 = ADAT2 101 = TCO
011 = SPDIF
bits 28-25: autosync (external) frequency (defined as for SPDIF frequency)
bit 29: Device is synced to word clock
bit 30: Word clock lock achieved
bit 31: undefined (read as zero)
Status register 1:
bit 0: master clock mode active
bits 21-1: undefined
bit 22: Device is synced to TCO
bit 23: TCO lock achieved
bits 31-24: undefined
Status register 2:
bits 31-0: (FF800 only) FireWire iso channel used for data from FF800 to PC
Status register 3:
bits 31-0: unused
Interfacing to device flash
---------------------------
To preserve the device's settings across power cycles the settings are
stored in a flash memory on the device. This is read during driver
initialisation to ensure the driver's status agrees with that of the device.
There are several classes of things stored in flash: operational settings,
volumes (ie: the mixer status) and configuration/firmware. Device settings
start at address 0x3000f0000 on the FF800 and 0x00060000 on the FF400; mixer
data starts at 0x3000e0000 on the FF800 and 0x00070000 on the
FF400.
Reading blocks from the flash (flash command 0x2)
For the FF800 the entire buffer is read directly from flash as a single
block if the block is less than a sector (256 bytes, 64 quadlets). Polling
for "device not busy" should commence after a wait of 5 ms. For anything
larger, writes are split into sector-sized sub-blocks.
For the FF400, the buffer is read in 32-quadlet sub-blocks. A partial block
is read at the end if the total buffer size is not a multiple of
32-quadlets. To read a sub-block, the address is placed in register
0x80100288 and the sub-block size (in bytes) in 0x8010028c. A 0x02 is
then written to CBA+(8*4) to initiate the read. Polling for "device not
busy" should commence after a wait of 2 ms. Once not busy the data is
available for reading from 0x80100290.
Writing blocks to the flash (flash command 1)
For the FF800, the buffer is written to flash in 256-byte (64 quadlet)
sectors. Polling for "device not busy" should commence after a wait of 5
ms. A write request for a length less than a sector will be honoured by the
device (this is done when writing device settings).
For the FF400, the buffer is written in 32-quadlet (128-byte) sub-blocks via
a bounce buffer. If the final sub-block is not 32-quadlets the write is
only as big as the sub-block (that is, no padding takes place). The
sub-block data to be written is sent to the block starting at 0x80100290.
The 2-quadlet register at 0x80100288 is set with the flash address to write
the block to and the size (in bytes) of the data block. Finally, a 0x1 is
written to CBA+(8*4) to initiate the write. Polling for "device not busy"
should commence after a wait of 2 ms.
Getting other data from flash
There are a few other commands issued to the flash memory system for
obtaining data about the connected interface:
* Device revision
On the FF800 this is read directly from register 0x200000100.
On the FF400, 0xf is written to CBA+(8*4). Poll for "not busy" after a
wait of 2ms. Once not busy the revision is read from register
0x80100290.
Erasing the flash
The flash is divided into sections and it is possible to erase each section
separately. Therefore one only has to erase section of interest when
changing something.
On the FF400, erasure is controlled by writing a special magic number to
the the flash control register (CBA+8*4):
Erase volume: write 0xe
Erase settings: write 0xd
Erase configuration (firmware): write 0xc
On the FF800, erasing is controlled by writing 0 to the applicable register:
Erase volume: register is 0x3fffffff4
Erase settings: register is 0x3fffffff0
Erase firmware: register is 0x3fffffff8
Erase configuration: register is 0x3fffffffc
It's not clear what the distinction between "configuration" and "firmware"
is. The FF400 appears to only support "configuration" but treats this as
"firmware". The FF800 supports both as distinct options.
After issuing the erase command one should wait for 500 ms before polling
the device for the "not busy" status.
Waiting for flash
When interacting with the device's flash memory one must wait for the
completion of an operation before attempting another. The location of the
"device busy" flag differs between the FF400 and FF800.
On the FF800 is part of the quadlet register at 0x801c0004 (part of the
read-only status register block beginning at 0x801c0000). The device is
ready to accept another command when bit 30 is set.
On the FF400 the wait state is found by reading a quadlet from CBA+8*4.
If this quadlet is zero the FF400 is ready to accept another command.
Most device flash operations have a minimum time to complete. There's no
point in polling the device busy flag until at least this much time has
elapsed.
Device settings format
----------------------
The device settings are stored in flash as an array of 59 32-bit unsigned
integers. These are:
0 - Device ID (FF400=0x77e1f4ea)
1 - Device revision (FF400=0x004af3d8)
2 - ASIO latency (FF400=0x00000001)
3 - Samples per frame (FF400 default is 0x30)
4 SPDIF input mode (1=coax, 0=optical)
5 SPDIF output emphasis active
6 SPDIF output is "professional" (ie: AES/EBU)
7 Clock mode (0=master, 1=autosync)
8 SPDIF output is non-audio (eg: AC3 passthrough)
9 Sync reference
10 SPDIF output mode (0=coax only, 1=coax+optical)
11 - Check input
12 - Status (FF400 idle=0x77e691d0)
13 - Register[4] (FF400 = 0x004adbc8,0x001377c0,0x000301ee,0x00000001)
17 - Iso receive channel (FF400=0x7ffde000)
18 - Iso transmit channel (FF400=0x77f43664)
19 - Timecode (FF400 example: 0x004b35c8)
20 - Device type (FF400=0x00000001)
21 - Number of devices (FF400=0x77f43664)
22 TMS (FF400=0x00000000)
23 - Speed (FF400=0x00000000)
24 - Channels available (high) (FF400=0x0012f2e4)
25 - Channels available (low) (FF400=0x00000000)
26 Limit bandwidth setting (0=all channels on, 1=no adat2, 2=analog+spdif
only, 3=analog only)
27 - Bandwidth allocated (FF400=0x00000000)
28 Stop on dropout (FF400=0x00000000)
29 Input level (0=lo-gain, 2=+4dBU, 1=-10dBV)
30 Output level (2=hi-gain, 1=+4dBU, 0=-10dBV)
31 Mic level [0] - FF400: Phoneslevel-1
FF800: Channel 7 front/rear select (0=rear, 1=front,
2=front+rear)
32 Mic level [1] - FF400: unused
FF800: Channel 8 front/rear select (0=rear, 1=front,
2=front+rear)
33 Mic phantom power [4]
37 Instrument - FF400: unused
FF800: Channel 1 front/rear selector (0=rear, 1=front,
2=front+rear)
38 Filter (aka speaker emulation)
39 Fuzz (aka drive)
40 - Sync align
41 - Device index (FF400=0x77e24d0d)
42 - Advanced dialog (FF400=0x000201f8) [but might be related to TCO control)
43 Sample rate (eg: 0x0000ac44) [set to 0x00000000 unless DDS enabled]
44 - Interleaved (FF400=0x00000000)
45 - Sn (FF400=0x77e14925)
46 Word clock single speed (1=single speed)
47 - Number of channels (FF400=0x000000f0)
48 - Dropped samples
49 p12db_an[0] - Disable limiter, settable only if channel 1 front jack active
50 - p12db_an[1-9]
"-" = elements not used (under MacOSX at least)
Total size: 59 quadlets
The default state of these quadlets is 0xffffffff, which is taken to
indicate that the respective setting has not been written to flash. This in
turn causes the driver to assume its own default value. While these
settings can be changed in real time by writing to the relevant control
registers, these are not persistent across device power cycles. To make
them persistent it is necessary to store them into the flash.
Flash mixer settings layout
---------------------------
Mixer (volume) data starts at 0x3000e0000 on the FF800 and 0x00070000 on the
FF400. There are several control groups in the mixer:
0xe0000 (FF800): "mixer shadow", FF800 only
0xe2000 (FF800) / 0x70000 (FF400), 0x0800 bytes: 16-bit volume array
0xe2800 (FF800) / 0x70800 (FF400), 0x0800 bytes: 16-bit pan array
0xe3000 (FF800) / 0x71000 (FF400), 0x0040 bytes: 16-bit "vol3" array +
"enable MIDI control" + "submix" + zero padding to 64 quadlets
All group allocations are written in their entirety (that is, 0x0800 bytes),
with zero padding on the end as needed. Each write is grouped in sectors,
with each sector being 256 bytes (64 quadlets).
It is not known why the "mixer shadow" is stored in the case of the FF800.
It comprises a copy of the 32-bit matrix mixer settings (see "Fireface-800
mixer controls" below), and the information is essentially a duplicate of
what's in the "volume" and "pan" arrays. In any case, what's done is done.
The "mixer shadow" values are written in 64-quadlet (256-byte) blocks, one
per hardware output channel. The FF800 has 28 hardware input channels (I)
and 28 software playback channels (P). Each output has a 64-quadlet block
formatted as follows:
Faders for physical inputs 1..I, zero pad to 32-quadlet boundary
Faders for software playbacks 1..P, zero pad to 32-quadlet boundary
There are 28 hardware input/output channels on the FF800 and 18 for the
FF400.
The "volume" and "pan" arrays are arranged in blocks of N (32 for FF800, 18
for FF400) 16-bit elements. Each block contains the volume/pan value for
each of N possible physical inputs or playbacks when sent to one of the N/2
physical stereo output pairs. Elements are ordered in the standard Fireface
channel index order. The arrangement of the blocks are as follows:
Inputs 1..N to output pair 1+2
Playbacks 1..N to output pair 1+2
Inputs 1..N to output pair 3+4
Playbacks 1..N to output pair 3+4
:
Inputs 1..N to output pair N/2-1 and N/2
Playbacks 1..N to output pair N/2-1 and N/2
In the case of the FF800, N (32) is greater than the number of physical
inputs and mono outputs available (28). Array elements corresponding to
non-existent inputs, outputs or playbacks are filled with zeros.
The "vol3" array represents the hardware output volume settings. The 16-bit
volume data for each of the hardware output channels is included in the
standard Fireface channel index order. The array has room for 30 outputs
while the FF400/FF800 has only 18/28 outputs; elements corresponding to
outputs not physically present are set to zero. In addition, a boolean
indicating whether MIDI control is enabled is stored in zero-based array
index 30 while a submix index is stored in array index 31 (array elements
are considered 16-bit here). The meaning of the submix index isn't known;
it's thought that the GUI mixer applications in other systems use this as a
convenient place to store the submix index that the user was last editting
(assuming they were editting in submix mode).
All 16-bit values are written in little endian byte order.
The "volume" and "vol3" values are unsigned 16-bit values:
0x0000 = -inf (minimum)
0x0255 = -6 dB
0x0323 = 0 dB
0x03ff = 6 dB (maximum)
When panned hard left or right, the value F written to the flash as a
channel's volume given a fader value of V (0..0x10000) appears to be:
F = (1023.0/3) * ln( V*(exp(3)-1)/65536 + 1)
F is rounded to the nearest integer value.
The "pan" values are unsigned 16-bit values. 0x0000 is hard left, 0x0080 is
centre and 0x0100 is hard right. Therefore if the pan value is represented
as a floating point number Pf from 0.0 (hard left) to 1.0 (hard right), the
pan value Pv written to flash will be
Pv = 0x0100 * Pf
In the hardware, each channel of a stereo pair is controlled independently
the mixer registers. It is therefore necessary to convert bidirectionally
between fader value pairs and the volume/pan pair as used in the flash. Let
V0 and V1 be the fader value (0..0x10000) for each of the two channels. The
volume (V) and pan (P) values can be calculated as follows.
V = V0 + V1
Pf = V1 / (V0 + V1)
P = 0x0100 * Pf
V is then transformed into the equivalent flash value F according to
the expression given previously:
F = (1023.0/3) * ln( V*(exp(3)-1)/65536 + 1)
When starting with the volume/pan pair, V is first calculated from F by
rearranging the above equation. Pf is then calculated:
Pf = P / 0x100
This allows V0 and V1 to be found:
V0 = V * (1 - Pf)
V1 = V * Pf
Careful attention to round-off is required to ensure that flash and fader
values remain unchanged through fader-flash-fader and flash-fader-flash
round trips.
User interfaces under other operating systems include a "pan law" control
which sets the gain when panned to centre. This setting is not sent to the
device at any time; the default in the mixer software is -6 dB. Other
options are -4.5 dB, -3 dB and 0 dB. Changing these affects the values sent
to the individual mixer registers (and hense the "mixer shadow"), but not
the values stored in the "volume" and "pan" flash arrays. In the case of
the FF400, the power on state obtained from flash is therefore independent
of the pan law control (the FF800 stores the mixer shadow data and could
make use of it if it wanted to). Experimentation shows that when powering
up, the FF400 assumes a pan law of -6 dB when mapping from the volume/pan
flash arrays to individual mixer element registers. Tests are still to be
done on the FF800 to see if it uses the "mixer shadow" values instead of the
volume/pan arrays.
TCO (TimeCode Option)
---------------------
The TCO is an optional card for the FF800 which adds video timecode
generation and clock locking capabilities to the FF800. It is controlled by
writing a block of 4 quadlets to register 0x810f0020 while its status can be
retrieved by reading a block of 4 quadlets from register 0x801f0000.
The configuration space is as follows.
Quadlet 0 (written to register 0x810f0020):
bit 31: MTC active if set to 1
bits 30-0: reserved (equal zero)
Quadlet 1 (written to register 0x810f0024):
bits 31-12: reserved (equal to zero)
bits 11-10: LTC format (00=24fps, 01=25fps, 10=29.97fps, 11=30fps)
bit 9: dropframe active
bit 8: set timecode request
bit 7: reserved (set to 0)
bit 6: PAL format video input
bit 5: NTSC format video input
bit 4-3: reserved (set to 0)
bits 2-1: word clock input rate (00=1x, 01=2x, 10=4x)
bit 0: reserved (set to 0)
Quadlet 2 (written to register 0x810f0028):
bit 31: set sampling frequency from application
bits 30-29: input select (00=wordclock, 01=video, 10=LTC)
bit 28: input termination active
bit 27: Base frequency (0=44.1 kHz, 1=48 kHz)
bit 26: Pull up flag
bit 25: Pull down flag
bit 24: Pull up/down amount (0=0.1%, 1=4.0%)
bit 23: reserved (set to 0)
bit 22: Flywheel select
bit 21: Jam sync select
bits 20-19: dropframes select (unused, set to 0)
bits 18-17: word clock conversion (00=1:1, 01=44.1->48, 10=48->44.1)
bit 16: set TC run
bits 15-0: reserved, set to 0.
Quadlet 3:
bits 31-0: reserved, set to 0
The 4 quadlets returned by a TCO status query are mapped as follows.
Quadlet 0:
bit 31: set to 1
bits 30-24: LTC, hours field in BCD(*)
bit 23: set to 1
bits 22-16: LTC, minutes field in BCD
bit 15: set to 1
bits 14-8: LTC, seconds field in BCD
bit 7: set to 1
bits 6-0: LTC, frames field in BCD
Quadlet 1:
bit 31: set to 1
bits 30-24: reserved (equal to zero)
bit 23: set to 1
bits 22-16: reserved (equal to zero)
bit 15: set to 1
bits 14-12: reserved (equal to zero)
bits 11-10: LTC format (00=24fps, 01=25fps, 10=29.97fps, 11=30fps)
bit 9: dropframe active
bit 8: reserved (read as zeros)
bit 7: set to 1
bit 6: PAL format video input
bit 5: NTSC format video input
bit 4: Word clock input valid (0=invalid, 1=valid)
bit 3: LTC input valid (0=invalid, 1=valid)
bits 2-1: reserved (read as zeros)
bit 0: TCO lock flag (0=no lock, 1=locked)
Quadlet 2
bit 31: set to 1
bits 30-24: reserved (equal to zero)
bit 23: set to 1
bits 22-16: reserved (equal to zero)
bit 15: set to 1
bits 14-8: upper 7 bits of PLL phase
bit 7: set to 1
bits 6-0: the lower 7 bits of the PLL phase
Quadlet 3:
bit 31: set to 1
bits 30-16: reserved
bit 15: set to 1
bits 14-0: set to 0
Notes:
(*) BCD is Binary Coded Decimal. The high nibble (which is only 3 bits in
these cases) contains the "tens" digit while the lower nibble contains
the "units" digit.
The calculation of the PLL phase from quadlet 2 (q2) is as follows:
phase = (q2 & 0x7f) + ((q2 & 0x7f00) >> 1)
which then allows the incoming frequency to be calculated using
freq = (25000000 * 16) / phase
To detect the presence of a TCO in a FF800, read the 4 TCO status quadlets.
If a TCO is present:
- bits 31, 23, 15 and 7 in quadlets 0, 1 and 2 will be 1, AND
- bits 31 and 15 in quadlet 3 will be 1, AND
- bits 14 to 0 in quadlet 3 will be 0
Streaming control registers
---------------------------
There appears to be a number of registers involved in the setup of device
streaming.
Device (streaming) initialisation register (FF800: 0x20000001c, FF400: CBA)
This register comprises the 3 quadlets starting at address 0x20000001c on
the FF800 and the 5 quadlets starting at the CBA on the FF400. The first
quadlet contains the sample rate in Hz. The second quadlet is mapped as
follows:
bits 31-11 = number of audio channels
bits 10-0 = iso tx channel (PC to interface)
In all local tests with a FF800 the value of this quadlet was always equal
to 0x0000e000 (28 channels, PC transmits on iso channel 0).
The third quadlet is mapped as follows.
bits 10-0 = number of audio channels
bit 11 = speed flag; set to 1 if FireWire bus is at 800 Mbps
In local tests with a FF800 the value of this register was always 0x0000001c
(28 channels, 400 Mbps FireWire bus).
The forth and fifth quadlets (used only by the FF400) are zero.
After this register is configured, 4 quadlets are read starting from
0x801c0000. When read, these are the device status registers.
Device (streaming) start register (FF800: 0x200000028, FF400: CBA+0x0c):
The start of streaming differs between the FF400 and FF800 in more than just
the address of the relevant register. On the FF800 this register is mapped
as follows:
bits 10-0 = number of audio channels
bit 11 = bus speed flag; set to 1 if FireWire bus is at 800 Mbps
On a FF400 the register is as follows:
bits 4-0 = number of audio channels
bits 9-5 = iso tx channel (PC to interface)
During initial testing with a FF800 the value of this register was always
0x0000001c (28 audio channels, PC tx on iso channel 0).
Channel mute setup register (write to 0x801c0000):
After writing to the streaming start register, 0x70 bytes (28 quadlets) are
written starting at 0x801c0000. Each quadlet represents one channel on the
Fireface800. A value of 1 mutes the respective channel - indeed on closing
down streaming each quadlet is set to 1. During startup some values are set
to zero - the ones set to zero may be determined by the channels which have
active software data sources although this is yet to be confirmed with more
testing. Irrespective of the setting of these registers it appears that
data for all channels is always sent to/from the Fireface-800.
Note that when register 0x801c0000 is read it functions as the device status
register. It is read during streaming setup, but obviously it bears no
relationship to the channel mute status.
Streaming end register (FF800: 0x200000034, FF400: CBA+0x4):
On the FF800, streaming is stopped by writing 3 zeroed quadlets to
consecutive registers starting at address 0x200000034. For the FF400 one
writes 3 zeroed quadlets to consecutive registers from CBA+0x4, followed
by a 0x00000001 to CBA+0x10 (making a 4-quadlet write in total).
Iso data
--------
Audio/midi data is sent and received on isochronous channels previously
configured by the driver. On a dedicated bus with nothing else present, the
stream to the fireface is sent on iso channel 0 while data from the fireface
is sent on iso channel 1.
No CIP header is included in the iso data packet. Fireface data follows
immediately after the standard 2-quadlet FireWire iso packet header.
Each iso packet contains a number of samples across all 28 device channels
(18 channels in the case of the ff400). For 1x rates, 7 samples per channel
seem to be sent. Thus the size of the data portion of a 1x iso packet is
28*4*7 = 784, with a total packet size being 784 + 8 = 792.
The data is sent with one audio channel per quadlet. The audio data is a 24
bit integer stored in the most-significant 3 bytes of a quadlet. The LSB
(low byte) of certain channels in the stream sent by the Fireface is used to
send synchronising information:
Low byte of channel 6 = current frame
Low byte of channel 7 = phase
Low byte of channel 1 = rx sample counter, low byte
Low byte of channel 4 = rx sample counter, high byte
Low byte of channel 0 = tx buffer size, low byte
Low byte of channel 5 = tx buffer size, high byte
Low byte of channel 2 & 3 = unknown (midi?)
The low byte data from channels 0-7 is repeated in channels 8-15 and 16-23
respectively, with channels 24-27 containing the low byte data from channels
0-3. This repetition holds for the low bytes of channels 2-3 in all data
seen so far, it might not necessarily be the case in general - it depends
what the low byte data from channels 2 and 3 are used for.
The rx sample counter appears to be used to detect missed samples. The
current frame and phase from a received packet is used in conjunction with
the stored values of these from the previous frame to track the phase of
the audio clock.
A "frame" consists of a fixed number of samples across all channels of the
device. At 1x rates this appears to be 7, but it might not be fixed. Even
though this is the same as the number of samples per channel per packet, a
given packet can experience a change in the "current frame" part way
through. In other words, the "current frame" is not necessarily constant
for all samples in a packet.
With the number of samples per channel contained in each iso packet it is
not necessary for the RME to send audio data in every iso cycle. When it is
deemed that a cycle can be skipped the RME simply doesn't send any packet at
all in that cycle. This contrasts with other devices which tend to send
empty "placeholder" packets when the need arises. This means that a cycle
without a packet from the RME is not necessarily an error condition. To
detect dropped packets one must instead rely on the rx sample counter
embedded in the audio data stream.
Input preamp / output amp gain control
--------------------------------------
On the Fireface-400 the gain of the mic/instrument preamps and output
amplifiers can be set. Mic channel gain is in steps of 1 dB from 10 dB up to
65 dB, with 0dB also available. Instrument input gain ranges from 0 dB to
18 dB in 0.5 dB steps. Output gains range from +6 dB down to -53 dB (a 58
dB range) in steps of 1 dB, with compete "mute" also available.
The gains are set using the register at 0x801c0180.
bits 31-24: unknown (set to 0)
bits 23-16: channel being set (see below)
bits 15-8: unknown (set to 0)
bits 7-0: the gain value
For mic channels the gain value is the dB value. For instrument channels, a
value of 2G is written for a gain value of G (thereby allowing a stepsize of
0.5 dB). For output gain, 0 = +6 dB, 0x3b = -53 dB, 0x3f = mute.
The definition of the "channel being set" is as follows.
0 = mic input 1 gain
1 = mic input 2 gain
2 = instrument input 3 gain
3 = instrument input 4 gain
4-9 = analog outputs 1-6 level
10-11 = phones output level
12-13 = SPDIF output level
14-21 = ADAT outputs 1-8 level
Firefice-400 mixer controls
---------------------------
The Fireface-400 matrix mixer is controlled using a block of registers
starting at 0x80080000. An 18x18 matrix mixer is implemented allowing any
hardware input to be sent to any device output. Pan control is effected by
manipulating the "left/right" controls within an output pair.
For each input channel block the order of channels is Analog 1-8, SPDIF 1-2,
ADAT 1-8.
0x80080000 - 0x80080044: input channel sends to Analog 1 output.
0x80080048 - 0x8008008c: playback channel sends to Analog 1 output.
0x80080090 - 0x800800d4: input channel sends to Analog 2 output.
0x800800d8 - 0x8008011c: playback channel sends to Analog 2 output.
:
0x80080990 - 0x800809d4: input channel sends to ADAT 8 output.
0x800809d8 - 0x80080a1c: playback channel sends to ADAT 8 output.
0x80080f80: matrix mixer analog 1 output fader
0x80080f84: matrix mixer analog 2 output fader
:
0x80080fc4: matrix mixer ADAT 8 output fader
Each fader control ranges from 0x00000000 (-inf) through 0x00008000 (0.0 dB)
up to a maximum of 0x00010000 (+6.0 dB). -52.7 dB appears to correspond to
a value of 0x0000004c, -46.6 dB is 0x00000099. From this we can see that if
v is the value being written, the dB gain applied can be found using
dB = 20.log10(v/32768)
Alternatively, to set the gain to G dB, one calculates the value to send to
the device (v) using
v = 32768 * exp10(G/20)
When setting the output fader controls, the associated output amplifier
gain control (see previous section) are generally kept in sync. That is, if
register 0x80080f80 (analog 1 output fader) is set to 0 dB, so is the analog
output 1 level via register 0x801c0180.
Fireface-800 mixer controls
---------------------------
The matrix mixer on the Fireface-800 is controlled using a block of
registers starting at 0x80080000. A 28x28 matrix mixer is implemented
allowing any device input to be sent to any device output. The pan controls
are synthesised by manipulating the "left/right" controls.
In each sub-block, the order of channels is in fireface numeric order. That
is, Analog 1-10, SPDIF, ADAT1 1-8, ADAT2 1-8.
0x80080000 - 0x8008006c: input channel sends to Analog 1 output.
0x80080080 - 0x800800ec: playback channel sends to Analog 1 output.
0x80080100 - 0x8008016c: input channel sends to Analog 2 output.
0x80080180 - 0x800801ec: playback channel sends to Analog 2 output.
:
0x80081b00 - 0x80081b6c: input channel sends to ADAT2-8 output.
0x80081b80 - 0x80081bec: playback channel sends to ADAT2-8 output.
0x80081f80: matrix mixer analog 1 output fader
0x80081f84: matrix mixer analog 2 output fader
:
0x80081fec: maxtrix mixer ADAT2-8 output fader
Each fader control ranges from 0x00000000 (-inf) through 0x00008000 (0.0 dB)
and up to a maximum setting of 0x00010000 (+6.0 dB). As for the
Fireface-400, if v is the value being written, the dB gain applied can be
found using
dB = 20.log(v/32768)
Mute is synthesised by setting the respective send value to -inf (0).
Conversely, solo is synthesised by muting all sends to the selected bus
except the send being soloed.
Note that a different scale is used when writing mixer settings into flash.
Refer to the "Flash mixer settings layout" section for further details.
Metering values
---------------
The Fireface-800 appears to provide hardware support for metering. The RME
mixer application periodically sends block read requests for register
0x80100000 with a size of 0x3f8. What is returned is a set of two
datablocks with data in little-endian (least significant bit/word first)
format. The first block contains arrays of 64-bit floating point numbers
representing channel amplitude with decay, presumedly useful for metering
display. Arrays are:
28-element array for input channel amplitude with decay
28-element array for playback amplitudes with decay (educated guess)
28-element array for output amplitudes with decay
The second data block contains signed 32 bit integers representing the input
amplitudes without decay. Valid range is 0 - 0x7ffffff. Again there are 3
arrays:
28-element array for input channel ampltude
28-element array for playback amplitudes (educated guess)
28-element array for output amplitudes
At the end of this second block are two zero quadlets. Their purpose is
unknown at this stage.
In each 28-element array the channel data appears in standard fireface
order.
Host LED
--------
The "host" LED of the FF800 is controlled by a dedicated register at
0x200000324. Note that this register address goes beyond the 32-bit
boundary.
On the FF400 the host LED is controlled internally. On power up it is
turned on. Once the host PC programs the configuration registers with
valid values the host LED will automatically turn off.
libffado-2.4.5/doc/rme_notes/rme_protocol_notes.txt 0000644 0001750 0000144 00000032416 14206145246 022107 0 ustar jwoithe users RME Fireface800 protocol notes
==============================
Author: Jonathan Woithe
Date: 24 March 2008
Introduction
------------
This document contains random notes made while observing the protocol used
by the RME Fireface 800 interface. This document is not necessarily all
that coherent but fully documents what is seen on the bus when various
actions are carried out. For a distilled version of our current knowledge
of the protocol please refer to rme_config_register_map.txt.
The information contained here was observed from a Fireface 800 device:
RME vendor ID: 0x000a35
GUID: 0x0093e1daf1
Node capabilities: 0x0083c0
Unit spec ID: 0x0a35
Sw version number: 0x0001
Model ID: 0x101800
Setting device configuration options in general
-----------------------------------------------
It seems that generally device configuration is effected by writing 0x0c
bytes to register 0xfc88f014. However, the existing drivers do much
more than just this. For example, when setting DDS inactive (which doesn't
appear significantly different to setting it active):
Read 0x10 @ 0x801c0000: 01c000b1 a0001001 ffffffff ffffffff
Read @ 0xfffff0000410: 0x93e1daf1
Read 0x10 @ 0x801c0000: 01c000b0 a0001001 ffffffff ffffffff
Read @ 0xfffff0000410: 0x93e1daf1
Read 0x10 @ 0x801c0000: 01c000b0 a0001001 ffffffff ffffffff
Read @ 0xfffff0000410: 0x93e1daf1
Read @ 0xfffff000040c: 0xa3500
Write 0xfc88f000: 0000ac44
Read 0x10 @ 0x801c0000: 01c000b1 80001001 ffffffff ffffffff
Read @ 0xfffff0000410: 0x93e1daf1
Read 0x10 @ 0x801c0000: 01c000b1 80001001 ffffffff ffffffff
Read @ 0xfffff0000410: 0x93e1daf1
Read 0x10 @ 0x801c0000: 01c000b0 80001001 ffffffff ffffffff
Read @ 0xfffff0000410: 0x93e1daf1
Read 0x10 @ 0x801c0000: 01c000b0 80001001 ffffffff ffffffff
Read @ 0xfffff0000410: 0x93e1daf1
Read 0x10 @ 0x801c0000: 01c000b1 80001001 ffffffff ffffffff
Read @ 0xfffff0000410: 0x93e1daf1
When setting to 48k:
Read 0x10 @ 0x801c0000: 01c000b0 a0001001 ffffffff ffffffff
Read @ 0xfffff0000410: 0x93e1daf1
Read 0x10 @ 0x801c0000: 01c000b0 a0001001 ffffffff ffffffff
Read @ 0xfffff0000410: 0x93e1daf1
Read 0x10 @ 0x801c0000: 01c000b0 a0001001 ffffffff ffffffff
Read @ 0xfffff0000410: 0x93e1daf1
Read 0x10 @ 0x801c0000: 01c000b0 a0001001 ffffffff ffffffff
Read @ 0xfffff0000410: 0x93e1daf1
Read 0x10 @ 0x801c0000: 01c000b1 a0001001 ffffffff ffffffff
Read @ 0xfffff0000410: 0x93e1daf1
Read @ 0xfffff000040c: 0xa3500
Write 0xfc88f000: 0000bb80
Read 0x10 @ 0x801c0000: 01c000c0 a0001007 ffffffff ffffffff
Read @ 0xfffff0000410: 0x93e1daf1
Read 0x10 @ 0x801c0000: 01c000c0 a0001007 ffffffff ffffffff
Read @ 0xfffff0000410: 0x93e1daf1
Read 0x10 @ 0x801c0000: 01c000c0 a0001007 ffffffff ffffffff
Read @ 0xfffff0000410: 0x93e1daf1
Read 0x10 @ 0x801c0000: 01c000bf a0001007 ffffffff ffffffff
Read @ 0xfffff0000410: 0x93e1daf1
Read 0x10 @ 0x801c0000: 01c000c0 80001007 ffffffff ffffffff
Read @ 0xfffff0000410: 0x93e1daf1
Read 0x10 @ 0x801c0000: 01c000c0 a0001007 ffffffff ffffffff
Read @ 0xfffff0000410: 0x93e1daf1
When using the "course" control, the frequency seems to be set by:
Read quadlet @ 0xfffff000040c: 0xa3500
Write @ 0xfc88f000
Each write to 0xfc88f000 seems to be preceeded by a read of 0xfffff000040c,
resulting in a value of 0xa3500. Before and after this is a variable number
of repeats of the sequence
block read of 0x10 bytes (4 quadlets) at 0x801c0000
quadlet read at 0xfffff0000410
These reads seem to be some kind of status check on the device. However,
there doesn't seem to be any consistent pattern as to when the write is
performed relative to changes in these registers, nor does the process
terminate in response to a particular setting of these registers. It seems
that most if not all parameter settings are done with this pattern of reads
above and below the actual write which (presumedly) activates the respective
change.
Looking for patterns, consider the settings of quadlets 0 and 1 in the last block
from 0x801c0000 before the respective set operation finishes:
32k: 01c00080 80001003
44.056: 01c000b1 a0001001
44.144: 01c000b0 80001001
44.1: 01c000b1 80001001
45.937: 01c000b8 a0001001
46.080: 01c000b8 80001007
47.952: 01c000c0 a0001007
48: 01c000c0 a0001007
48.048: 01c000c0 a0001007
mult 2x-1x:
t=866835 01c0017f 8000100f
876846 01c00180 8000100f
377579 01c00180 8000100f
t=512691 write
t=868285 01c000c0 80001007
878299 01c000c0 80001007
379027 01c000c0 80001007
mult 2x-4x:
t=278863 01c00180 a000100f
769567 01c00180 a000100f
779580 01c00180 a000100f
280315 01c00180 a000100f
t=536803 write
t=771004 01c002ff a0001017
781034 01c00300 a0001017
281784 01c00300 a0001017
mult 4x-1x:
t=784082 01c00300 a0001017
794099 01c00300 a0001017
294837 01c00300 a0001017
t=753719 write
t=785530 01c000c0 a0001007
795553 01c000c0 a0001007
296297 01c000c0 a0001007
786993 01c000c0 a0001007
797001 01c000c0 a0001007
mult 4x-2x:
01c00300 80001017
01c00300 80001017
write
01c00180 8000100f
01c00180 a000100f
01c00180 a000100f
01c00180 a000100f
DDS active:
01c000b1 a0001001
01c000b1 a0001001
01c000b0 a0001001
write
01c000b0 a0001001
01c000b0 80001001
01c000b1 a0001001
01c000b0 80001001
01c000b1 80001001
01c000b1 80001001
DDS inactive:
01c000b1 a0001001
01c000b0 a0001001
01c000b0 a0001001
write
01c000b1 80001001
01c000b1 80001001
01c000b0 80001001
01c000b0 80001001
01c000b1 80001001
Before and after settings:
x - 32k: - 01c00080 80001003
32-44.1: 01c00080 80001003 - 01c000b1 80001001
44.1-48: 01c000b0 a0001001 - 01c000c0 a0001007
48-96: 01c000c0 a0001007 - 01c00180 8000100f
48-192: 01c000c0 a0001007 - 01c00300 80001017
96-192: 01c00180 a000100f - 01c00300 a0001017
96-48: 01c00180 8000100f - 01c000c0 80001007
192-48: 01c00300 a0001017 - 01c000c0 a0001007
192-96: 01c00300 80001017 - 01c00180 a000100f
(jitter in bit 0 of 1st quadlet, and possibly bit 29 of 2nd quadlet)
For now there's little we can do - we'll ignore these additional reads (or
maybe just do a few token ones of our own) and see how far we get. It seems
that some clock rate information is included in here, but not the complete
picture. Perhaps the base rate is available here, but little else. In fact
there doesn't appear to be anywhere which conveys the device's rate back to
the PC; the PC seemingly sets the rate to its desired rate and then
effectively caches the sample rate.
Buffer sizes
------------
All settings: 0xfc88f014 = 00000810 0000035e c400101f
It seems that device configuration is not affected by this setting.
Obviously *some* setting is sent to the device whenever the buffer size is
changed though.
Clock mode
----------
Master: 0xfc88f014 = 00000810 0000035e c400101f
Autosync: 0xfc88f014 = 00000810 0000035e c400101e
DDS (Frequency setting)
-----------------------
32k: 0xfc88f000 = 00007d00 (32000)
44.056: 0xfc88f000 = 0000ac18 (44056)
44.144: 0xfc88f000 = 0000ac70 (44144)
44.1k: 0xfc88f000 = 0000ac44 (44100)
45.937: 0xfc88f000 = 0000b371 (45937)
46.080: 0xfc88f000 = 0000b400 (46080)
47.952: 0xfc88f000 = 0000bb50 (47952)
48k: 0xfc88f000 = 0000bb80 (48000)
48.048: 0xfc88f000 = 0000bbb0 (48048)
Multiplier (base freq of 48k):
1-2: 0xfc88f000 = 00017700 (96000)
2-1: 0xfc88f000 = 0000bb80 (48000)
2-4: 0xfc88f000 = 0002ee00 (192000)
1-4: 0xfc88f000 = 0002ee00 (192000)
4-2: 0xfc88f000 = 00017700 (96000)
4-1: 0xfc88f000 = 0000bb80 (48000)
Set DDS active: 0xfc88f000 = 0000ac44
Set DDS inactive: 0xfc88f000 = 0000ac44
To set the RME Fireface800 frequency, write the actual frequency to register
0xfc88f000.
Setting DDS active doesn't appear to make any changes to the actual
hardware.
Input level
-----------
+4dBU: 0xfc88f014 = 00000810 0000035e c400101f
-10dBV: 0xfc88f014 = 00000820 0000035f c400101f
lo-gain: 0xfc88f014 = 00000808 0000035c c400101f
Inputs
------
#1 set front: 0xfc88f014 = 00000810 00000b5a c400101f
#1 set front+rear: 0xfc88f014 = 00000810 00000b5e c400101f
#1 set rear: 0xfc88f014 = 00000810 0000035e c400101f
#7 set front: 0xfc88f014 = 00010810 0000033e c400101f
#7 set front+rear: 0xfc88f014 = 00020810 0000037e c400101f
#7 set rear: 0xfc88f014 = 00000810 0000035e c400101f
#8 set front: 0xfc88f014 = 00000810 000002de c400101f
#8 set front+rear: 0xfc88f014 = 00000810 000003de c400101f
#8 set rear: 0xfc88f014 = 00000810 0000035e c400101f
Instrument options
------------------
none-drive: 0xfc88f014 = 00000a10 0000015e c400101f
none-lim: 0xfc88f014 = 00000810 0000035e c400101f
none-sp_emu: 0xfc88f014 = 00000814 0000035e c400101f
*-none: 0xfc88f014 = 00000810 0000035e c400101f
"Lim" would appear to be a software setting since the hardware setting
for "lim" seems to be the same as for "none".
Output level
------------
+4dBU: 0xfc88f014 = 00000810 0000035e c400101f
-10dBV: 0xfc88f014 = 00001010 0000034e c400101f
hi-gain: 0xfc88f014 = 00000410 00000356 c400101f
Phantom
-------
mic 7 on: 0xfc88f014 = 00000811 0000035e c400101f
mic 8 on: 0xfc88f014 = 00000890 0000035e c400101f
mic 9 on: 0xfc88f014 = 00000812 0000035e c400101f
mic 10 on: 0xfc88f014 = 00000910 0000035e c400101f
SPDIF in
--------
coax: 0xfc88f014 = 00000810 0000035e c400101f
ADAT2: 0xfc88f014 = 00000810 0000035e c400121f
SPDIF out
---------
ADAT2: 0xfc88f014 = 00000810 0000035e c400111f
emphasis: 0xfc88f014 = 00000810 0000035e c400105f
non-audio: 0xfc88f014 = 00000810 0000035e c400109f
professional: 0xfc88f014 = 00000810 0000035e c400103f
Sync reference source
---------------------
ADAT1: 0xfc88f014 = 00000810 0000035e c400001f
ADAT2: 0xfc88f014 = 00000810 0000035e c400041f
SPDIF: 0xfc88f014 = 00000810 0000035e c4000c1f
TCO: 0xfc88f014 = 00000810 0000035e c400141f
Wordclock: 0xfc88f014 = 00000810 0000035e c400101f
Unit options
------------
Start with all options on. Turn each of separately:
-checkinput: 0xfc88f014 = 00000810 0000035e c400101f
-interleaved: 0xfc88f014 = 00000810 0000035e c400101f
-syncalign: 0xfc88f014 = 00000810 0000035e c400101f
-tms: 0xfc88f014 = 00000810 0000035e 8400101f
This tends to indicate that TMS is the only "unit option" which affects
the hardware. All the others would appear to be software features.
Word clock
----------
Single speed on: 0xfc88f014 = 00000810 0000035e c400301f
Single speed off: 0xfc88f014 = 00000810 0000035e c400101f
Streaming start
---------------
Frequency was 44100 Hz.
Playback:
Read from 0xfffff000040c: 0xa3500
Read from 0xfffff000040c: 0xa3500
Write 0x0c bytes to 0x20000001c: 0000ac44 0000e000 0000001c
Read 0x10 bytes from 0x801c0000: 81c000b0 80001001 00000001 00000001
Write quadlet to 0x200000028: 0x1c000000
Write 0x70 bytes to 0x801c0000:
00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001
00000000 00000000 00000001 00000001 00000001 00000001 00000001 00000001
00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001
00000001 00000001 00000001 00000001
Recording:
Reads from 0x801c0000 and 0xfffff0000410 as for parameter setting.
0x801c0000 = 81c000b0 80001001 00000001 00000001
0xfffff0000410 = 0x93e1daf1
Read from 0xfffff000040c: 0xa3500
Read quadlet from 0x801c0000: 81c000b1
Read from 0xfffff000040c: 0xa3500
Read quadlet from 0x801c0000: 81c000b1
Read from 0xfffff000040c: 0xa3500
Read from 0xfffff000040c: 0xa3500
Write 0x0c bytes to 0x20000001c: 0000ac44 0000e000 0000001c
Read 0x10 bytes from 0x801c0000: 81c000b0 a0001001 00000001 00000001
Write quadlet to 0x200000028: 0x1c000000
Read 0x10 bytes from 0x801c0000: 81c000b0 80001001 00000001 00000001
Read from 0xfffff0000410: 0x93e1daf1
...
Streaming end
-------------
Frequency was 44100 Hz.
Playback:
Write 0x0c bytes to 0x200000034: 00000000 00000000 00000000
Write 0x70 bytes to 0x801c0000:
00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001
00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001
00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001
00000001 00000001 00000001 00000001
Read quadlet from 0xfffff000040c: 0xa3500
Recording:
Reads from:
0x801c0000 = 81c000b1 80001001 00000001 00000001
0xfffff0000410 = 0x93e1daf1
Write 0x0c bytes to 0x200000034: 00000000 00000000 00000000
More reads from 0x801c0000 and 0xfffff0000410
Streaming data format
---------------------
The PC functions as the IRM and thus provides the cycle timer. The packets
do not contain an SPH. It is not clear how device synchronisation is done.
Channels are sent in Fireface numeric order: Analog 1-10, spdif, ADAT1 1-8,
ADAT2 1-8 (a total of 28 channels).
Each sample is 32 bits, seemingly ordered least significant byte first.
By default iso channel 0 is for PC->Fireface800 data and channel 1 carries
Fireface800->PC audio data.
In an example capture, packets carrying 6 frames were observed, reportedly
at 44.1 kHz. Packets of varying lengths were observed (0x230, 0x2a0 from
the PC, a constant 0x310 from the Fireface800). It is not known how the
device maintains the correct flow of packets for the various odd-ball
frequencies it supports. It appears that in certain iso cycles an iso
packet is simply not sent in order to resync, but how either side knows when
to do this is a mystery at present.
The quadlets in a packet normally used by a CIP header seem to correspond to
analog1+2.
libffado-2.4.5/doc/streaming.xmi 0000644 0001750 0000144 00005472305 14206145246 016161 0 ustar jwoithe users
umbrello uml modeller http://uml.sf.net
1.5.6
UnicodeUTF8
libffado-2.4.5/doc/SConscript 0000644 0001750 0000144 00000000656 13246707102 015450 0 ustar jwoithe users #! /usr/bin/env python
Import( 'env' )
env = env.Clone()
# At this point BUILD_DOC is either 'all' or 'user'
doxygen_dir_list = [env["top_srcdir"] + "/libffado"]
if env["BUILD_DOC"] == 'all':
doxygen_dir_list += [env["top_srcdir"] + "/src",
env["top_srcdir"] + "/doc"]
env["DOXYGEN_INPUT"] = " ".join(doxygen_dir_list)
env.ScanReplace( "reference.doxygen.in" )
env.Doxygen( "reference.doxygen" )
libffado-2.4.5/doc/reference.doxygen.in 0000644 0001750 0000144 00000173777 13246707102 017417 0 ustar jwoithe users # Doxyfile 1.6.1
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project
#
# All text after a hash (#) is considered a comment and will be ignored
# The format is:
# TAG = value [value, ...]
# For lists items can also be appended using:
# TAG += value [value, ...]
# Values that contain spaces should be placed between quotes (" ")
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
# This tag specifies the encoding used for all characters in the config file
# that follow. The default is UTF-8 which is also the encoding used for all
# text before the first occurrence of this tag. Doxygen uses libiconv (or the
# iconv built into libc) for the transcoding. See
# http://www.gnu.org/software/libiconv for the list of possible encodings.
DOXYFILE_ENCODING = UTF-8
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
# by quotes) that should identify the project.
PROJECT_NAME = LIBFFADO
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
# This could be handy for archiving the generated documentation or
# if some version control system is used.
PROJECT_NUMBER = $VERSION
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
# If a relative path is entered, it will be relative to the location
# where doxygen was started. If left blank the current directory will be used.
OUTPUT_DIRECTORY = reference
# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
# 4096 sub-directories (in 2 levels) under the output directory of each output
# format and will distribute the generated files over these directories.
# Enabling this option can be useful when feeding doxygen a huge amount of
# source files, where putting all generated files in the same directory would
# otherwise cause performance problems for the file system.
CREATE_SUBDIRS = NO
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language.
# The default language is English, other supported languages are:
# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
OUTPUT_LANGUAGE = English
# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
# include brief member descriptions after the members that are listed in
# the file and class documentation (similar to JavaDoc).
# Set to NO to disable this.
BRIEF_MEMBER_DESC = YES
# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
# the brief description of a member or function before the detailed description.
# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
# brief descriptions will be completely suppressed.
REPEAT_BRIEF = YES
# This tag implements a quasi-intelligent brief description abbreviator
# that is used to form the text in various listings. Each string
# in this list, if found as the leading text of the brief description, will be
# stripped from the text and the result after processing the whole list, is
# used as the annotated text. Otherwise, the brief description is used as-is.
# If left blank, the following values are used ("$name" is automatically
# replaced with the name of the entity): "The $name class" "The $name widget"
# "The $name file" "is" "provides" "specifies" "contains"
# "represents" "a" "an" "the"
ABBREVIATE_BRIEF =
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
# Doxygen will generate a detailed section even if there is only a brief
# description.
ALWAYS_DETAILED_SEC = NO
# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
# inherited members of a class in the documentation of that class as if those
# members were ordinary class members. Constructors, destructors and assignment
# operators of the base classes will not be shown.
INLINE_INHERITED_MEMB = NO
# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
# path before files name in the file list and in the header files. If set
# to NO the shortest path that makes the file name unique will be used.
FULL_PATH_NAMES = NO
# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
# can be used to strip a user-defined part of the path. Stripping is
# only done if one of the specified strings matches the left-hand part of
# the path. The tag can be used to show relative paths in the file list.
# If left blank the directory from which doxygen is run is used as the
# path to strip.
STRIP_FROM_PATH =
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
# the path mentioned in the documentation of a class, which tells
# the reader which header file to include in order to use a class.
# If left blank only the name of the header file containing the class
# definition is used. Otherwise one should specify the include paths that
# are normally passed to the compiler using the -I flag.
STRIP_FROM_INC_PATH =
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
# (but less readable) file names. This can be useful is your file systems
# doesn't support long names like on DOS, Mac, or CD-ROM.
SHORT_NAMES = NO
# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
# will interpret the first line (until the first dot) of a JavaDoc-style
# comment as the brief description. If set to NO, the JavaDoc
# comments will behave just like regular Qt-style comments
# (thus requiring an explicit @brief command for a brief description.)
JAVADOC_AUTOBRIEF = NO
# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
# interpret the first line (until the first dot) of a Qt-style
# comment as the brief description. If set to NO, the comments
# will behave just like regular Qt-style comments (thus requiring
# an explicit \brief command for a brief description.)
QT_AUTOBRIEF = NO
# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
# treat a multi-line C++ special comment block (i.e. a block of //! or ///
# comments) as a brief description. This used to be the default behaviour.
# The new default is to treat a multi-line C++ comment block as a detailed
# description. Set this tag to YES if you prefer the old behaviour instead.
MULTILINE_CPP_IS_BRIEF = NO
# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
# member inherits the documentation from any documented member that it
# re-implements.
INHERIT_DOCS = YES
# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
# a new page for each member. If set to NO, the documentation of a member will
# be part of the file/class/namespace that contains it.
SEPARATE_MEMBER_PAGES = NO
# The TAB_SIZE tag can be used to set the number of spaces in a tab.
# Doxygen uses this value to replace tabs by spaces in code fragments.
TAB_SIZE = 4
# This tag can be used to specify a number of aliases that acts
# as commands in the documentation. An alias has the form "name=value".
# For example adding "sideeffect=\par Side Effects:\n" will allow you to
# put the command \sideeffect (or @sideeffect) in the documentation, which
# will result in a user-defined paragraph with heading "Side Effects:".
# You can put \n's in the value part of an alias to insert newlines.
ALIASES =
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
# sources only. Doxygen will then generate output that is more tailored for C.
# For instance, some of the names that are used will be different. The list
# of all members will be omitted, etc.
OPTIMIZE_OUTPUT_FOR_C = NO
# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
# sources only. Doxygen will then generate output that is more tailored for
# Java. For instance, namespaces will be presented as packages, qualified
# scopes will look different, etc.
OPTIMIZE_OUTPUT_JAVA = NO
# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
# sources only. Doxygen will then generate output that is more tailored for
# Fortran.
OPTIMIZE_FOR_FORTRAN = NO
# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
# sources. Doxygen will then generate output that is tailored for
# VHDL.
OPTIMIZE_OUTPUT_VHDL = NO
# Doxygen selects the parser to use depending on the extension of the files it parses.
# With this tag you can assign which parser to use for a given extension.
# Doxygen has a built-in mapping, but you can override or extend it using this tag.
# The format is ext=language, where ext is a file extension, and language is one of
# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
EXTENSION_MAPPING =
# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
# to include (a tag file for) the STL sources as input, then you should
# set this tag to YES in order to let doxygen match functions declarations and
# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
# func(std::string) {}). This also make the inheritance and collaboration
# diagrams that involve STL classes more complete and accurate.
BUILTIN_STL_SUPPORT = YES
# If you use Microsoft's C++/CLI language, you should set this option to YES to
# enable parsing support.
CPP_CLI_SUPPORT = NO
# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
# Doxygen will parse them like normal C++ but will assume all classes use public
# instead of private inheritance when no explicit protection keyword is present.
SIP_SUPPORT = NO
# For Microsoft's IDL there are propget and propput attributes to indicate getter
# and setter methods for a property. Setting this option to YES (the default)
# will make doxygen to replace the get and set methods by a property in the
# documentation. This will only work if the methods are indeed getting or
# setting a simple type. If this is not the case, or you want to show the
# methods anyway, you should set this option to NO.
IDL_PROPERTY_SUPPORT = YES
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
# tag is set to YES, then doxygen will reuse the documentation of the first
# member in the group (if any) for the other members of the group. By default
# all members of a group must be documented explicitly.
DISTRIBUTE_GROUP_DOC = YES
# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
# the same type (for instance a group of public functions) to be put as a
# subgroup of that type (e.g. under the Public Functions section). Set it to
# NO to prevent subgrouping. Alternatively, this can be done per class using
# the \nosubgrouping command.
SUBGROUPING = YES
# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
# is documented as struct, union, or enum with the name of the typedef. So
# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
# with name TypeT. When disabled the typedef will appear as a member of a file,
# namespace, or class. And the struct will be named TypeS. This can typically
# be useful for C code in case the coding convention dictates that all compound
# types are typedef'ed and only the typedef is referenced, never the tag name.
TYPEDEF_HIDES_STRUCT = NO
# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
# determine which symbols to keep in memory and which to flush to disk.
# When the cache is full, less often used symbols will be written to disk.
# For small to medium size projects (<1000 input files) the default value is
# probably good enough. For larger projects a too small cache size can cause
# doxygen to be busy swapping symbols to and from disk most of the time
# causing a significant performance penality.
# If the system has enough physical memory increasing the cache will improve the
# performance by keeping more symbols in memory. Note that the value works on
# a logarithmic scale so increasing the size by one will rougly double the
# memory usage. The cache size is given by this formula:
# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
# corresponding to a cache size of 2^16 = 65536 symbols
SYMBOL_CACHE_SIZE = 0
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
# documentation are documented, even if no documentation was available.
# Private class members and static file members will be hidden unless
# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
EXTRACT_ALL = YES
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
# will be included in the documentation.
EXTRACT_PRIVATE = YES
# If the EXTRACT_STATIC tag is set to YES all static members of a file
# will be included in the documentation.
EXTRACT_STATIC = YES
# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
# defined locally in source files will be included in the documentation.
# If set to NO only classes defined in header files are included.
EXTRACT_LOCAL_CLASSES = YES
# This flag is only useful for Objective-C code. When set to YES local
# methods, which are defined in the implementation section but not in
# the interface are included in the documentation.
# If set to NO (the default) only methods in the interface are included.
EXTRACT_LOCAL_METHODS = NO
# If this flag is set to YES, the members of anonymous namespaces will be
# extracted and appear in the documentation as a namespace called
# 'anonymous_namespace{file}', where file will be replaced with the base
# name of the file that contains the anonymous namespace. By default
# anonymous namespace are hidden.
EXTRACT_ANON_NSPACES = NO
# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
# undocumented members of documented classes, files or namespaces.
# If set to NO (the default) these members will be included in the
# various overviews, but no documentation section is generated.
# This option has no effect if EXTRACT_ALL is enabled.
HIDE_UNDOC_MEMBERS = NO
# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy.
# If set to NO (the default) these classes will be included in the various
# overviews. This option has no effect if EXTRACT_ALL is enabled.
HIDE_UNDOC_CLASSES = NO
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
# friend (class|struct|union) declarations.
# If set to NO (the default) these declarations will be included in the
# documentation.
HIDE_FRIEND_COMPOUNDS = NO
# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
# documentation blocks found inside the body of a function.
# If set to NO (the default) these blocks will be appended to the
# function's detailed documentation block.
HIDE_IN_BODY_DOCS = NO
# The INTERNAL_DOCS tag determines if documentation
# that is typed after a \internal command is included. If the tag is set
# to NO (the default) then the documentation will be excluded.
# Set it to YES to include the internal documentation.
INTERNAL_DOCS = YES
# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
# file names in lower-case letters. If set to YES upper-case letters are also
# allowed. This is useful if you have classes or files whose names only differ
# in case and if your file system supports case sensitive file names. Windows
# and Mac users are advised to set this option to NO.
CASE_SENSE_NAMES = YES
# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
# will show members with their full class and namespace scopes in the
# documentation. If set to YES the scope will be hidden.
HIDE_SCOPE_NAMES = NO
# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
# will put a list of the files that are included by a file in the documentation
# of that file.
SHOW_INCLUDE_FILES = YES
# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
# is inserted in the documentation for inline members.
INLINE_INFO = YES
# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
# will sort the (detailed) documentation of file and class members
# alphabetically by member name. If set to NO the members will appear in
# declaration order.
SORT_MEMBER_DOCS = YES
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
# brief documentation of file, namespace and class members alphabetically
# by member name. If set to NO (the default) the members will appear in
# declaration order.
SORT_BRIEF_DOCS = NO
# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
SORT_MEMBERS_CTORS_1ST = NO
# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
# hierarchy of group names into alphabetical order. If set to NO (the default)
# the group names will appear in their defined order.
SORT_GROUP_NAMES = NO
# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
# sorted by fully-qualified names, including namespaces. If set to
# NO (the default), the class list will be sorted only by class name,
# not including the namespace part.
# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
# Note: This option applies only to the class list, not to the
# alphabetical list.
SORT_BY_SCOPE_NAME = NO
# The GENERATE_TODOLIST tag can be used to enable (YES) or
# disable (NO) the todo list. This list is created by putting \todo
# commands in the documentation.
GENERATE_TODOLIST = YES
# The GENERATE_TESTLIST tag can be used to enable (YES) or
# disable (NO) the test list. This list is created by putting \test
# commands in the documentation.
GENERATE_TESTLIST = YES
# The GENERATE_BUGLIST tag can be used to enable (YES) or
# disable (NO) the bug list. This list is created by putting \bug
# commands in the documentation.
GENERATE_BUGLIST = YES
# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
# disable (NO) the deprecated list. This list is created by putting
# \deprecated commands in the documentation.
GENERATE_DEPRECATEDLIST= YES
# The ENABLED_SECTIONS tag can be used to enable conditional
# documentation sections, marked by \if sectionname ... \endif.
ENABLED_SECTIONS =
# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
# the initial value of a variable or define consists of for it to appear in
# the documentation. If the initializer consists of more lines than specified
# here it will be hidden. Use a value of 0 to hide initializers completely.
# The appearance of the initializer of individual variables and defines in the
# documentation can be controlled using \showinitializer or \hideinitializer
# command in the documentation regardless of this setting.
MAX_INITIALIZER_LINES = 30
# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
# at the bottom of the documentation of classes and structs. If set to YES the
# list will mention the files that were used to generate the documentation.
SHOW_USED_FILES = YES
# If the sources in your project are distributed over multiple directories
# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
# in the documentation. The default is NO.
SHOW_DIRECTORIES = NO
# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
# This will remove the Files entry from the Quick Index and from the
# Folder Tree View (if specified). The default is YES.
SHOW_FILES = YES
# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
# Namespaces page.
# This will remove the Namespaces entry from the Quick Index
# and from the Folder Tree View (if specified). The default is YES.
SHOW_NAMESPACES = YES
# The FILE_VERSION_FILTER tag can be used to specify a program or script that
# doxygen should invoke to get the current version for each file (typically from
# the version control system). Doxygen will invoke the program by executing (via
# popen()) the command , where is the value of
# the FILE_VERSION_FILTER tag, and is the name of an input file
# provided by doxygen. Whatever the program writes to standard output
# is used as the file version. See the manual for examples.
FILE_VERSION_FILTER =
# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
# doxygen. The layout file controls the global structure of the generated output files
# in an output format independent way. The create the layout file that represents
# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
# file name after the option, if omitted DoxygenLayout.xml will be used as the name
# of the layout file.
LAYOUT_FILE =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
# The QUIET tag can be used to turn on/off the messages that are generated
# by doxygen. Possible values are YES and NO. If left blank NO is used.
QUIET = YES
# The WARNINGS tag can be used to turn on/off the warning messages that are
# generated by doxygen. Possible values are YES and NO. If left blank
# NO is used.
WARNINGS = YES
# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
# automatically be disabled.
WARN_IF_UNDOCUMENTED = YES
# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
# potential errors in the documentation, such as not documenting some
# parameters in a documented function, or documenting parameters that
# don't exist or using markup commands wrongly.
WARN_IF_DOC_ERROR = YES
# This WARN_NO_PARAMDOC option can be abled to get warnings for
# functions that are documented, but have no documentation for their parameters
# or return value. If set to NO (the default) doxygen will only warn about
# wrong or incomplete parameter documentation, but not about the absence of
# documentation.
WARN_NO_PARAMDOC = NO
# The WARN_FORMAT tag determines the format of the warning messages that
# doxygen can produce. The string should contain the $file, $line, and $text
# tags, which will be replaced by the file and line number from which the
# warning originated and the warning text. Optionally the format may contain
# $version, which will be replaced by the version of the file (if it could
# be obtained via FILE_VERSION_FILTER)
WARN_FORMAT = "$file:$line: $text"
# The WARN_LOGFILE tag can be used to specify a file to which warning
# and error messages should be written. If left blank the output is written
# to stderr.
WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
# The INPUT tag can be used to specify the files and/or directories that contain
# documented source files. You may enter file names like "myfile.cpp" or
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
INPUT = $DOXYGEN_INPUT
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
# also the default input encoding. Doxygen uses libiconv (or the iconv built
# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
# the list of possible encodings.
INPUT_ENCODING = UTF-8
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
# and *.h) to filter out the source-files in the directories. If left
# blank the following patterns are tested:
# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
FILE_PATTERNS = *.cpp \
*.h \
*.dox
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
# should be searched for input files as well. Possible values are YES and NO.
# If left blank NO is used.
RECURSIVE = YES
# The EXCLUDE tag can be used to specify files and/or directories that should
# excluded from the INPUT source files. This way you can easily exclude a
# subdirectory from a directory tree whose root is specified with the INPUT tag.
EXCLUDE =
# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
# directories that are symbolic links (a Unix filesystem feature) are excluded
# from the input.
EXCLUDE_SYMLINKS = NO
# If the value of the INPUT tag contains directories, you can use the
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
# certain files from those directories. Note that the wildcards are matched
# against the file with absolute path, so to exclude all test directories
# for example use the pattern */test/*
EXCLUDE_PATTERNS = *.svn* \
*reference*
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the
# output. The symbol name can be a fully qualified name, a word, or if the
# wildcard * is used, a substring. Examples: ANamespace, AClass,
# AClass::ANamespace, ANamespace::*Test
EXCLUDE_SYMBOLS =
# The EXAMPLE_PATH tag can be used to specify one or more files or
# directories that contain example code fragments that are included (see
# the \include command).
EXAMPLE_PATH =
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
# and *.h) to filter out the source-files in the directories. If left
# blank all files are included.
EXAMPLE_PATTERNS =
# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
# searched for input files to be used with the \include or \dontinclude
# commands irrespective of the value of the RECURSIVE tag.
# Possible values are YES and NO. If left blank NO is used.
EXAMPLE_RECURSIVE = NO
# The IMAGE_PATH tag can be used to specify one or more files or
# directories that contain image that are included in the documentation (see
# the \image command).
IMAGE_PATH = .
# The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program
# by executing (via popen()) the command , where
# is the value of the INPUT_FILTER tag, and is the name of an
# input file. Doxygen will then use the output that the filter program writes
# to standard output.
# If FILTER_PATTERNS is specified, this tag will be
# ignored.
INPUT_FILTER =
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
# basis.
# Doxygen will compare the file name with each pattern and apply the
# filter if there is a match.
# The filters are a list of the form:
# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
# is applied to all files.
FILTER_PATTERNS =
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
# INPUT_FILTER) will be used to filter the input files when producing source
# files to browse (i.e. when SOURCE_BROWSER is set to YES).
FILTER_SOURCE_FILES = NO
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
# If the SOURCE_BROWSER tag is set to YES then a list of source files will
# be generated. Documented entities will be cross-referenced with these sources.
# Note: To get rid of all source code in the generated output, make sure also
# VERBATIM_HEADERS is set to NO.
SOURCE_BROWSER = NO
# Setting the INLINE_SOURCES tag to YES will include the body
# of functions and classes directly in the documentation.
INLINE_SOURCES = NO
# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
# doxygen to hide any special comment blocks from generated source code
# fragments. Normal C and C++ comments will always remain visible.
STRIP_CODE_COMMENTS = YES
# If the REFERENCED_BY_RELATION tag is set to YES
# then for each documented function all documented
# functions referencing it will be listed.
REFERENCED_BY_RELATION = YES
# If the REFERENCES_RELATION tag is set to YES
# then for each documented function all documented entities
# called/used by that function will be listed.
REFERENCES_RELATION = YES
# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
# link to the source code.
# Otherwise they will link to the documentation.
REFERENCES_LINK_SOURCE = YES
# If the USE_HTAGS tag is set to YES then the references to source code
# will point to the HTML generated by the htags(1) tool instead of doxygen
# built-in source browser. The htags tool is part of GNU's global source
# tagging system (see http://www.gnu.org/software/global/global.html). You
# will need version 4.8.6 or higher.
USE_HTAGS = NO
# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
# will generate a verbatim copy of the header file for each class for
# which an include is specified. Set to NO to disable this.
VERBATIM_HEADERS = YES
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
# of all compounds will be generated. Enable this if the project
# contains a lot of classes, structs, unions or interfaces.
ALPHABETICAL_INDEX = YES
# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
# in which this list will be split (can be a number in the range [1..20])
COLS_IN_ALPHA_INDEX = 3
# In case all classes in a project start with a common prefix, all
# classes will be put under the same header in the alphabetical index.
# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
# should be ignored while generating the index headers.
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
# generate HTML output.
GENERATE_HTML = YES
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `html' will be used as the default path.
HTML_OUTPUT = html
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
# doxygen will generate files with .html extension.
HTML_FILE_EXTENSION = .html
# The HTML_HEADER tag can be used to specify a personal HTML header for
# each generated HTML page. If it is left blank doxygen will generate a
# standard header.
HTML_HEADER =
# The HTML_FOOTER tag can be used to specify a personal HTML footer for
# each generated HTML page. If it is left blank doxygen will generate a
# standard footer.
HTML_FOOTER =
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
# style sheet that is used by each HTML page. It can be used to
# fine-tune the look of the HTML output. If the tag is left blank doxygen
# will generate a default style sheet. Note that doxygen will try to copy
# the style sheet file to the HTML output directory, so don't put your own
# stylesheet in the HTML output directory as well, or it will be erased!
HTML_STYLESHEET =
# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
# files or namespaces will be aligned in HTML using tables. If set to
# NO a bullet list will be used.
HTML_ALIGN_MEMBERS = YES
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
# documentation will contain sections that can be hidden and shown after the
# page has loaded. For this to work a browser that supports
# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
HTML_DYNAMIC_SECTIONS = YES
# If the GENERATE_DOCSET tag is set to YES, additional index files
# will be generated that can be used as input for Apple's Xcode 3
# integrated development environment, introduced with OSX 10.5 (Leopard).
# To create a documentation set, doxygen will generate a Makefile in the
# HTML output directory. Running make will produce the docset in that
# directory and running "make install" will install the docset in
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
# it at startup.
# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
GENERATE_DOCSET = NO
# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
# feed. A documentation feed provides an umbrella under which multiple
# documentation sets from a single provider (such as a company or product suite)
# can be grouped.
DOCSET_FEEDNAME = "Doxygen generated docs"
# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
# should uniquely identify the documentation set bundle. This should be a
# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
# will append .docset to the name.
DOCSET_BUNDLE_ID = org.doxygen.Project
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
# will be generated that can be used as input for tools like the
# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
# of the generated HTML documentation.
GENERATE_HTMLHELP = NO
# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
# be used to specify the file name of the resulting .chm file. You
# can add a path in front of the file if the result should not be
# written to the html output directory.
CHM_FILE =
# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
# be used to specify the location (absolute path including file name) of
# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
# the HTML help compiler on the generated index.hhp.
HHC_LOCATION =
# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
# controls if a separate .chi index file is generated (YES) or that
# it should be included in the master .chm file (NO).
GENERATE_CHI = NO
# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
# is used to encode HtmlHelp index (hhk), content (hhc) and project file
# content.
CHM_INDEX_ENCODING =
# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
# controls whether a binary table of contents is generated (YES) or a
# normal table of contents (NO) in the .chm file.
BINARY_TOC = NO
# The TOC_EXPAND flag can be set to YES to add extra items for group members
# to the contents of the HTML help documentation and to the tree view.
TOC_EXPAND = NO
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
# are set, an additional index file will be generated that can be used as input for
# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
# HTML documentation.
GENERATE_QHP = YES
# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
# be used to specify the file name of the resulting .qch file.
# The path specified is relative to the HTML output folder.
QCH_FILE =
# The QHP_NAMESPACE tag specifies the namespace to use when generating
# Qt Help Project output. For more information please see
# http://doc.trolltech.com/qthelpproject.html#namespace
QHP_NAMESPACE = LIBFFADO
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
# Qt Help Project output. For more information please see
# http://doc.trolltech.com/qthelpproject.html#virtual-folders
QHP_VIRTUAL_FOLDER = reference
# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
# For more information please see
# http://doc.trolltech.com/qthelpproject.html#custom-filters
QHP_CUST_FILTER_NAME =
# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
# Qt Help Project / Custom Filters.
QHP_CUST_FILTER_ATTRS =
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
# filter section matches.
# Qt Help Project / Filter Attributes.
QHP_SECT_FILTER_ATTRS =
# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
# be used to specify the location of Qt's qhelpgenerator.
# If non-empty doxygen will try to run qhelpgenerator on the generated
# .qhp file.
QHG_LOCATION =
# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
# top of each HTML page. The value NO (the default) enables the index and
# the value YES disables it.
DISABLE_INDEX = NO
# This tag can be used to set the number of enum values (range [1..20])
# that doxygen will group on one line in the generated HTML documentation.
ENUM_VALUES_PER_LINE = 4
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
# structure should be generated to display hierarchical information.
# If the tag value is set to YES, a side panel will be generated
# containing a tree-like index structure (just like the one that
# is generated for HTML Help). For this to work a browser that supports
# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
# Windows users are probably better off using the HTML help feature.
GENERATE_TREEVIEW = NO
# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
# and Class Hierarchy pages using a tree view instead of an ordered list.
USE_INLINE_TREES = YES
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
# used to set the initial width (in pixels) of the frame in which the tree
# is shown.
TREEVIEW_WIDTH = 250
# Use this tag to change the font size of Latex formulas included
# as images in the HTML documentation. The default is 10. Note that
# when you change the font size after a successful doxygen run you need
# to manually remove any form_*.png images from the HTML output directory
# to force them to be regenerated.
FORMULA_FONTSIZE = 10
# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript
# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP)
# there is already a search function so this one should typically
# be disabled.
SEARCHENGINE = NO
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
# generate Latex output.
GENERATE_LATEX = NO
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `latex' will be used as the default path.
LATEX_OUTPUT = latex
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
# invoked. If left blank `latex' will be used as the default command name.
LATEX_CMD_NAME = latex
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
# generate index for LaTeX. If left blank `makeindex' will be used as the
# default command name.
MAKEINDEX_CMD_NAME = makeindex
# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
# LaTeX documents. This may be useful for small projects and may help to
# save some trees in general.
COMPACT_LATEX = NO
# The PAPER_TYPE tag can be used to set the paper type that is used
# by the printer. Possible values are: a4, a4wide, letter, legal and
# executive. If left blank a4wide will be used.
PAPER_TYPE = a4
# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
# packages that should be included in the LaTeX output.
EXTRA_PACKAGES =
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
# the generated latex document. The header should contain everything until
# the first chapter. If it is left blank doxygen will generate a
# standard header. Notice: only use this tag if you know what you are doing!
LATEX_HEADER =
# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
# is prepared for conversion to pdf (using ps2pdf). The pdf file will
# contain links (just like the HTML output) instead of page references
# This makes the output suitable for online browsing using a pdf viewer.
PDF_HYPERLINKS = YES
# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
# plain latex in the generated Makefile. Set this option to YES to get a
# higher quality PDF documentation.
USE_PDFLATEX = YES
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
# command to the generated LaTeX files. This will instruct LaTeX to keep
# running if errors occur, instead of asking the user for help.
# This option is also used when generating formulas in HTML.
LATEX_BATCHMODE = NO
# If LATEX_HIDE_INDICES is set to YES then doxygen will not
# include the index chapters (such as File Index, Compound Index, etc.)
# in the output.
LATEX_HIDE_INDICES = NO
# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER.
LATEX_SOURCE_CODE = NO
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
# The RTF output is optimized for Word 97 and may not look very pretty with
# other RTF readers or editors.
GENERATE_RTF = NO
# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `rtf' will be used as the default path.
RTF_OUTPUT = rtf
# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
# RTF documents. This may be useful for small projects and may help to
# save some trees in general.
COMPACT_RTF = NO
# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
# will contain hyperlink fields. The RTF file will
# contain links (just like the HTML output) instead of page references.
# This makes the output suitable for online browsing using WORD or other
# programs which support those fields.
# Note: wordpad (write) and others do not support links.
RTF_HYPERLINKS = NO
# Load stylesheet definitions from file. Syntax is similar to doxygen's
# config file, i.e. a series of assignments. You only have to provide
# replacements, missing definitions are set to their default value.
RTF_STYLESHEET_FILE =
# Set optional variables used in the generation of an rtf document.
# Syntax is similar to doxygen's config file.
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
# generate man pages
GENERATE_MAN = NO
# The MAN_OUTPUT tag is used to specify where the man pages will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `man' will be used as the default path.
MAN_OUTPUT = man
# The MAN_EXTENSION tag determines the extension that is added to
# the generated man pages (default is the subroutine's section .3)
MAN_EXTENSION = .3
# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
# then it will generate one additional man file for each entity
# documented in the real man page(s). These additional files
# only source the real man page, but without them the man command
# would be unable to find the correct page. The default is NO.
MAN_LINKS = NO
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
# If the GENERATE_XML tag is set to YES Doxygen will
# generate an XML file that captures the structure of
# the code including all documentation.
GENERATE_XML = NO
# The XML_OUTPUT tag is used to specify where the XML pages will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `xml' will be used as the default path.
XML_OUTPUT = xml
# The XML_SCHEMA tag can be used to specify an XML schema,
# which can be used by a validating XML parser to check the
# syntax of the XML files.
XML_SCHEMA =
# The XML_DTD tag can be used to specify an XML DTD,
# which can be used by a validating XML parser to check the
# syntax of the XML files.
XML_DTD =
# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
# dump the program listings (including syntax highlighting
# and cross-referencing information) to the XML output. Note that
# enabling this will significantly increase the size of the XML output.
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
# generate an AutoGen Definitions (see autogen.sf.net) file
# that captures the structure of the code including all
# documentation. Note that this feature is still experimental
# and incomplete at the moment.
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# configuration options related to the Perl module output
#---------------------------------------------------------------------------
# If the GENERATE_PERLMOD tag is set to YES Doxygen will
# generate a Perl module file that captures the structure of
# the code including all documentation. Note that this
# feature is still experimental and incomplete at the
# moment.
GENERATE_PERLMOD = NO
# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
# the necessary Makefile rules, Perl scripts and LaTeX code to be able
# to generate PDF and DVI output from the Perl module output.
PERLMOD_LATEX = NO
# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
# nicely formatted so it can be parsed by a human reader.
# This is useful
# if you want to understand what is going on.
# On the other hand, if this
# tag is set to NO the size of the Perl module output will be much smaller
# and Perl will parse it just the same.
PERLMOD_PRETTY = YES
# The names of the make variables in the generated doxyrules.make file
# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
# This is useful so different doxyrules.make files included by the same
# Makefile don't overwrite each other's variables.
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
# evaluate all C-preprocessor directives found in the sources and include
# files.
ENABLE_PREPROCESSING = YES
# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
# names in the source code. If set to NO (the default) only conditional
# compilation will be performed. Macro expansion can be done in a controlled
# way by setting EXPAND_ONLY_PREDEF to YES.
MACRO_EXPANSION = NO
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
# then the macro expansion is limited to the macros specified with the
# PREDEFINED and EXPAND_AS_DEFINED tags.
EXPAND_ONLY_PREDEF = NO
# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
# in the INCLUDE_PATH (see below) will be search if a #include is found.
SEARCH_INCLUDES = YES
# The INCLUDE_PATH tag can be used to specify one or more directories that
# contain include files that are not input files but should be processed by
# the preprocessor.
INCLUDE_PATH = $top_srcdir/src
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
# patterns (like *.h and *.hpp) to filter out the header-files in the
# directories. If left blank, the patterns specified with FILE_PATTERNS will
# be used.
INCLUDE_FILE_PATTERNS =
# The PREDEFINED tag can be used to specify one or more macro names that
# are defined before the preprocessor is started (similar to the -D option of
# gcc). The argument of the tag is a list of macros of the form: name
# or name=definition (no spaces). If the definition and the = are
# omitted =1 is assumed. To prevent a macro definition from being
# undefined via #undef or recursively expanded use the := operator
# instead of the = operator.
PREDEFINED =
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.
# The macro definition that is found in the sources will be used.
# Use the PREDEFINED tag if you want to use a different macro definition.
EXPAND_AS_DEFINED =
# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
# doxygen's preprocessor will remove all function-like macros that are alone
# on a line, have an all uppercase name, and do not end with a semicolon. Such
# function macros are typically used for boiler-plate code, and will confuse
# the parser if not removed.
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration::additions related to external references
#---------------------------------------------------------------------------
# The TAGFILES option can be used to specify one or more tagfiles.
# Optionally an initial location of the external documentation
# can be added for each tagfile. The format of a tag file without
# this location is as follows:
#
# TAGFILES = file1 file2 ...
# Adding location for the tag files is done as follows:
#
# TAGFILES = file1=loc1 "file2 = loc2" ...
# where "loc1" and "loc2" can be relative or absolute paths or
# URLs. If a location is present for each tag, the installdox tool
# does not have to be run to correct the links.
# Note that each tag file must have a unique name
# (where the name does NOT include the path)
# If a tag file is not located in the directory in which doxygen
# is run, you must also specify the path to the tagfile here.
TAGFILES =
# When a file name is specified after GENERATE_TAGFILE, doxygen will create
# a tag file that is based on the input files it reads.
GENERATE_TAGFILE =
# If the ALLEXTERNALS tag is set to YES all external classes will be listed
# in the class index. If set to NO only the inherited external classes
# will be listed.
ALLEXTERNALS = NO
# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
# in the modules index. If set to NO, only the current project's groups will
# be listed.
EXTERNAL_GROUPS = YES
# The PERL_PATH should be the absolute path and name of the perl script
# interpreter (i.e. the result of `which perl').
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
# or super classes. Setting the tag to NO turns the diagrams off. Note that
# this option is superseded by the HAVE_DOT option below. This is only a
# fallback. It is recommended to install and use dot, since it yields more
# powerful graphs.
CLASS_DIAGRAMS = YES
# You can define message sequence charts within doxygen comments using the \msc
# command. Doxygen will then run the mscgen tool (see
# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
# documentation. The MSCGEN_PATH tag allows you to specify the directory where
# the mscgen tool resides. If left empty the tool is assumed to be found in the
# default search path.
MSCGEN_PATH =
# If set to YES, the inheritance and collaboration graphs will hide
# inheritance and usage relations if the target is undocumented
# or is not a class.
HIDE_UNDOC_RELATIONS = NO
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
# available from the path. This tool is part of Graphviz, a graph visualization
# toolkit from AT&T and Lucent Bell Labs. The other options in this section
# have no effect if this option is set to NO (the default)
HAVE_DOT = YES
# By default doxygen will write a font called FreeSans.ttf to the output
# directory and reference it in all dot files that doxygen generates. This
# font does not include all possible unicode characters however, so when you need
# these (or just want a differently looking font) you can specify the font name
# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
# which can be done by putting it in a standard location or by setting the
# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
# containing the font.
DOT_FONTNAME = FreeSans
# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
# The default size is 10pt.
DOT_FONTSIZE = 10
# By default doxygen will tell dot to use the output directory to look for the
# FreeSans.ttf font (which doxygen will put there itself). If you specify a
# different font using DOT_FONTNAME you can set the path where dot
# can find it using this tag.
DOT_FONTPATH =
# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for each documented class showing the direct and
# indirect inheritance relations. Setting this tag to YES will force the
# the CLASS_DIAGRAMS tag to NO.
CLASS_GRAPH = YES
# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for each documented class showing the direct and
# indirect implementation dependencies (inheritance, containment, and
# class references variables) of the class with other documented classes.
COLLABORATION_GRAPH = NO
# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for groups, showing the direct groups dependencies
GROUP_GRAPHS = YES
# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
# collaboration diagrams in a style similar to the OMG's Unified Modeling
# Language.
UML_LOOK = YES
# If set to YES, the inheritance and collaboration graphs will show the
# relations between templates and their instances.
TEMPLATE_RELATIONS = YES
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
# tags are set to YES then doxygen will generate a graph for each documented
# file showing the direct and indirect include dependencies of the file with
# other documented files.
INCLUDE_GRAPH = NO
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
# documented header file showing the documented files that directly or
# indirectly include this file.
INCLUDED_BY_GRAPH = NO
# If the CALL_GRAPH and HAVE_DOT options are set to YES then
# doxygen will generate a call dependency graph for every global function
# or class method. Note that enabling this option will significantly increase
# the time of a run. So in most cases it will be better to enable call graphs
# for selected functions only using the \callgraph command.
CALL_GRAPH = NO
# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
# doxygen will generate a caller dependency graph for every global function
# or class method. Note that enabling this option will significantly increase
# the time of a run. So in most cases it will be better to enable caller
# graphs for selected functions only using the \callergraph command.
CALLER_GRAPH = NO
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
# will graphical hierarchy of all classes instead of a textual one.
GRAPHICAL_HIERARCHY = YES
# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
# then doxygen will show the dependencies a directory has on other directories
# in a graphical way. The dependency relations are determined by the #include
# relations between the files in the directories.
DIRECTORY_GRAPH = NO
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
# generated by dot. Possible values are png, jpg, or gif
# If left blank png will be used.
DOT_IMAGE_FORMAT = png
# The tag DOT_PATH can be used to specify the path where the dot tool can be
# found. If left blank, it is assumed the dot tool can be found in the path.
DOT_PATH =
# The DOTFILE_DIRS tag can be used to specify one or more directories that
# contain dot files that are included in the documentation (see the
# \dotfile command).
DOTFILE_DIRS =
# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
# nodes that will be shown in the graph. If the number of nodes in a graph
# becomes larger than this value, doxygen will truncate the graph, which is
# visualized by representing a node as a red box. Note that doxygen if the
# number of direct children of the root node in a graph is already larger than
# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
DOT_GRAPH_MAX_NODES = 50
# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
# graphs generated by dot. A depth value of 3 means that only nodes reachable
# from the root by following a path via at most 3 edges will be shown. Nodes
# that lay further from the root node will be omitted. Note that setting this
# option to 1 or 2 may greatly reduce the computation time needed for large
# code bases. Also note that the size of a graph can be further restricted by
# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
MAX_DOT_GRAPH_DEPTH = 0
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
# background. This is disabled by default, because dot on Windows does not
# seem to support this out of the box. Warning: Depending on the platform used,
# enabling this option may lead to badly anti-aliased labels on the edges of
# a graph (i.e. they become hard to read).
DOT_TRANSPARENT = YES
# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This
# makes dot run faster, but since only newer versions of dot (>1.8.10)
# support this, this feature is disabled by default.
DOT_MULTI_TARGETS = YES
# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
# generate a legend page explaining the meaning of the various boxes and
# arrows in the dot generated graphs.
GENERATE_LEGEND = YES
# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
# remove the intermediate dot files that are used to generate
# the various graphs.
DOT_CLEANUP = YES
libffado-2.4.5/doc/motu_firewire_protocol-mk3.txt 0000644 0001750 0000144 00000051453 11375520625 021475 0 ustar jwoithe users Protocol details for MOTU "mark 3" devices, obtained in the first instance
using an 828 Mk 3.
Version: 20100517-1
Author: Jonathan Woithe
Audio data streaming packets
----------------------------
It appears the streaming packets in the "mark 3" devices use a very similar
protocol to the earlier interfaces. Each iso packet begins with a 64-bit
CIP header. Following this are N data blocks, where N varies according to
the sample rate selected (8 for 1x, 16 for 2x, 32 for 4x). Each data block
comprises a 32-bit SPH field (consisting of a standard SPH timestamp), 48
bits of control/MIDI data and then the audio data itself. The audio data is
sent as packed big-endian signed integer data, as for the earlier
interfaces.
At 1x rates, the maximum packet size sent to the MOTU is 0x328 (808) bytes:
8 bytes CIP header
8 data blocks
Each data block contains:
4 bytes SPH timestamp
6 bytes control/MIDI data
90 bytes of audio data (30 channels)
The audio data is ordered as follows: phones, analog 1-8, main out, SPDIF,
ADAT1 1-8, ADAT2 1-8.
At 1x rates the MOTU sends 0x388 (904) bytes per packet, providing space
for 34 audio channels (order to be investigated): mic/guitar 1-2, analog
1-8, return 1-2, reverb 1-2, SPDIF, Unknown 1-2, ADAT1 1-8, ADAT2 1-8.
At 2x rates, packets sent to the MOTU have a maximum size of 0x4c8 (1224)
bytes while those sent by the MOTU are 0x0588 (1416) bytes. 16 blocks are
send in each packet. 22 channels sent to the MOTU (order to be confirmed):
phones, analog 1-8, main out, SPDIF, ADAT1 1-4, ADAT2 1-4. There is space
for 26 channels sent from the MOTU (order to be investigated): analog 1-8,
mic/guitar 1-2, SPDIF, return 1-2, reverb 1-2?, ADAT1 1-4, ADAT2 1-4,
unknown 1-2.
At 4x rates 0x0508 (1288) bytes are sent to the MOTU and 0x0688 (1672) are
sent from the MOTU. For sending to the MOTU there are 32 blocks with room
for 10 audio channels: unknown 1-2, analog 1-8. The MOTU sends 14 audio
channels (order to be investigated): analog 1-8, mic/guitar 1-2, return 1-2,
unknown 1-2.
The following matrix represents the current best guess as to the layout of
the audio channels in the iso data. Offset refers to the number of bytes
from the start of the data block. "?" signifies that the channel assignment
is yet to be confirmed and/or is positioned as a result of educated
guesswork.
Offset 1x Rates 2x Rates 4x Rates
Playback Capture Playback Capture Playback Capture
-------------------------------------------------------------------------
10 Phones-L Mic-1? Phones-L Mic-1? Unknown-1 Mic-1?
13 Phones-R Mic-2? Phones-R Mic-2? Unknown-2 Mic-2?
16 Analog 1 Analog 1 Analog 1 Analog 1 Analog 1 Analog 1
19 Analog 2 Analog 2 Analog 2 Analog 2 Analog 2 Analog 2
22 Analog 3 Analog 3 Analog 3 Analog 3 Analog 3 Analog 3
25 Analog 4 Analog 4 Analog 4 Analog 4 Analog 4 Analog 4
28 Analog 5 Analog 5 Analog 5 Analog 5 Analog 5 Analog 5
31 Analog 6 Analog 6 Analog 6 Analog 6 Analog 6 Analog 6
34 Analog 7 Analog 7 Analog 7 Analog 7 Analog 7 Analog 7
37 Analog 8 Analog 8 Analog 8 Analog 8 Analog 8 Analog 8
40 MainOut-L Return-1? MainOut-L Return-1? Return-1?
43 MainOut-R Return-2? MainOut-R Return-2? Return-2?
46 SPDIF-1 SPDIF-1? SPDIF-1? SPDIF-1? Unknown-1
49 SPDIF-2 SPDIF-2? SPDIF-2? SPDIF-2? Unknown-2
52 ADAT1-1 Reverb-1? ADAT1-1? Reverb-1?
55 ADAT1-2 Reverb-2? ADAT1-2? Reverb-2?
58 ADAT1-3 Unknown-1? ADAT1-3? ADAT1-1?
61 ADAT1-4 Unknown-2? ADAT1-4? ADAT1-2?
64 ADAT1-5 ADAT1-1? ADAT2-1? ADAT1-3?
67 ADAT1-6 ADAT1-2? ADAT2-2? ADAT1-4?
70 ADAT1-7 ADAT1-3? ADAT2-3? ADAT2-1?
73 ADAT1-8 ADAT1-4? ADAT2-4? ADAT2-2?
76 ADAT2-1 ADAT1-5? ADAT2-3?
79 ADAT2-2 ADAT1-6? ADAT2-4?
82 ADAT2-3 ADAT1-7? Unknown-1?
85 ADAT2-4 ADAT1-8? Unknown-2?
88 ADAT2-5 ADAT2-1?
91 ADAT2-6 ADAT2-2?
94 ADAT2-7 ADAT2-3?
97 ADAT2-8 ADAT2-4?
100 ADAT2-5?
103 ADAT2-6?
106 ADAT2-7?
109 ADAT2-8?
------------------------------------------------------------------------
#ch 30 34 22 26 10 14
When an optical port is configured in Toslink mode, the two Toslink channels
take the place of that port's 8 ADAT channels in the data stream. That is,
ADAT-x 1-8 are removed and in their place Toslink-A 1-2 are added. So in
the case of 1x playback, the Toslink channels appear at offset 52, with
ADAT-B's channels commencing at offset 58 (the total packet size in this
case being 0x02c8 bytes).
Unlike previous MOTU generations, the Toslink outputs in the Mark 3 devices
are present as channels in their own right - they do not mirror the SPDIF
channel.
Device control
--------------
Optical port modes
The modes of the two optical ports can be controlled independently. The
primary mechanism for this is via a quadlet write to register
0xfffff0000c94.
Bit 22: optical port B output mode (0=ADAT, 1=Toslink)
Bit 20: optical port B input mode (0=ADAT, 1=Toslink)
Bit 18: optical port A output mode (0=ADAT, 1=Toslink)
Bit 16: optical port A input mode (0=ADAT, 1=Toslink)
Bit 9: optical port B output enabled (0=disabled, 1=enabled)
Bit 8: optical port A output enabled (0=disabled, 1=enabled)
Bit 1: optical port B input enabled (0=disabled, 1=enabled)
Bit 0: optical port A input enabled (0=disabled, 1=enabled)
Other areas of the driver also appear to refresh the device status with
writes to other registers at the time the optical mode is updated:
0xfffff0000c04
0xfffff0000c60 - 0xfffff0000c6c (ASCII name of clock source)
0xfffff0000c94
0xfffff0000b14
0xfffff0000b38
0xfffff0000b3c
0xfffff0000b04
0xfffff0000b08
0xfffff0000b38
0xfffff0000b3c
0xfffff0000b1c
It is not known whether these additional writes are necessary.
Clock source control and sample rate
The clock source is set with a quadlet write to bits 0, 1, 3 and 4 of
register 0xfffff0000b14. Values for bits 4-3-1-0:
0-0-0-0 = internal
0-0-1-0 = SMTPE
0-0-0-1 = Word clock
1-0-0-0 = SPDIF
1-1-0-0 = ADAT port A / Toslink-A (depending on current optical port mode)
1-1-0-1 = ADAT port B / Toslink-B (depending on current optical port mode)
The sample rate is selected using bits 10-8 of register 0xfffff0000b14:
0x0 = 44.1 kHz
0x1 = 48 kHz
0x2 = 88.2 kHz
0x3 = 96 kHz
0x4 = 176.4 kHz
0x5 = 192 kHz
Bits 25 and 24 of register 0xfffff0000b14 are used in connection with
streaming control (see separate section). All other bits not mentioned
are set to zero.
Writes to other registers (as for ADAT modes) accompany the setting of
register 0xfffff0000b14.
MainOut/Phones assign
Register 0xfffff0000c04 controls the MainOut assign via bits 7-4:
0x0 = MainOut
0x1 = Ana 1-2
0x2 = Ana 3-4
0x3 = Ana 5-6
0x4 = Ana 7-8
0x5 = SPDIF
0x6 = Phones
0x7 = ADAT-A 1-2 (or Toslink if ADAT-A optical out mode is Toslink)
0x8 = ADAT-A 3-4
0x9 = ADAT-A 5-6
0xa = ADAT-A 7-8
0xb = ADAT-B 1-2 (or Toslink if ADAT-B optical out mode is Toslink)
0xc = ADAT-B 3-4
0xd = ADAT-B 5-6
0xe = ADAT-B 7-8
Bits 3-0 of register 0xfffff0000c04 control the Phones assign. The meaning
of the bit combinations is as per the MainOut assign case.
Bits 11-8 of register 0xfffff0000c04 control the "Return" assign. Again,
the meaning of the bit combinations is as per the MainOut assign case.
All other bits in register 0xfffff0000c04 appear to be zero at present.
Streaming control
Bits 31 to 16 of register 0xfffff0000b00 control the streaming channels
in the same way as for earlier MOTU devices.
To start streaming:
- a value of 0x00000002 is written to register 0xfffff0000b10.
- bit 24 of register 0xfffff0000b14 is set to 1 (other bits are set to
their current values)
- a bunch of other registers are written to which, given experience with
earlier MOTU interfaces, are not strictly required
- register 0xfffff0000c04 is polled. A result of 0x00000111 requires
another poll. Polling stops when the value is 0x00000303.
- register 0xfffff0000b14 is read.
- bits 24 and 25 in register 0xfffff0000b14 are set (other bits remain
unchanged)
- another bunch of (possibly inconsequential) registers is written to.
- register 0xfffff0000b14 is read again.
- writes to the same collection of registers again.
To stop streaming:
- bit 25 of register 0xfffff0000b14 is cleared (other bits remain
unchanged; this includes leaving bit 24 set to 1)
- register 0xfffff0000b00 is used to stop streaming in the same way as for
earlier MOTU interfaces
- write to other registers of potentially little value
- register 0xfffff0000b14 has bit 24 cleared (all other bits remain
unchanged, so bits 25 and 24 are both zero)
- immediately, register 0xfffff0000b14 has bit 24 set (all other bits
remain unchanged).
- other registers are read again.
It appears based on this that the streaming control of the Mark3 MOTU
devices is the same as for previous generations.
CuemixFX control
----------------
Control of the CuemixFX system is via writes starting at register
0xffff00010000. Either 1, 2 or 3 quadlets are written depending on what is
being done. Each packet includes a serial number which is incremented after
sending each control packet. The same serial number counter is used
regardless of the type of control packet being sent.
CuemixFX heartbeats
-------------------
The MOTU periodically sends a heartbeat packet back to the PC. This is sent
to address 0x000300000000 and consists of a single quadlet length write
block request of the following form:
00 aa 00 00
"aa" is the serial number ranging from 0x00 to 0xff.
It appears that heartbeat packets are sometimes sent to the MOTU. These take
the form of single-quadlet writes to the CuemixFX address. The quadlet
takes the following form:
02 aa 00 00
"aa" is the serial number of the packet ranging from 0x00 to 0xff.
It's not yet certain what purpose these packets serve and whether they are
in fact necessary. It is also not yet known whether the MOTU or the PC
initiates the process (that is, which one sends a packet with a given serial
number first).
Pedal events
------------
When a pedal event occurs the MOTU sends a quadlet write request to address
0x000300000000 on the PC. The format of the quadlet is as follows.
bb 00 00 c2
"bb" is 0 for a "pedal up" event and 1 for a "pedal down" event. The pedal
is "down" when the pedal switch is closed.
CuemixFX variable controls
--------------------------
The control of continuously variable controls (for example, faders, pan
controls) is by way of 3-quadlet writes to the CuemixFX register. The
format of these writes is as follows:
02 aa 66 bb - cc dd ee v1 - v2 v3 v4 00
where:
aa = packet serial number as previously described
bb = the bus/channel number (0x00 = mix bus 1, mic 1)
cc-dd-ee = the key of the control being changed
v1-v4 = the value being written. v1 is the most-significant byte. The
value appears to be a 32-bit float. That is, v1..v4 is a big
endian 32-bit float.
Keys presently identified are as follows.
00-01-02 = Bus reverb send (0-0x3f800000)
00-0c-01 = Input reverb send (0 ("-inf") to 0x3f800000 ("0 dB")). bb is
the zero-based input channel index for this key.
01-01-02 = Bus reverb return (0-0x3f800000)
02-00-01 = Input trim control (mic inputs: 0 ("+0 dB") - 0x42540000 ("+53
dB"); line inputs: 0xc2c00000 ("-96") - 0x41b00000 ("+22")).
For this key, bb is the zero-based channel index.
02-00-02 = Bus master fader
02-mm-02 = Channel pan. mm is the standard channel index. Values range
from 0xbf800000 (L) to 0x3f800000 (R).
03-mm-02 = Channel fader. mm is the channel index starting at 0x02 for
the first channel (on the 828-mk3 this is mic 1). Values range
from 0 (-inf) to 0x3f800000 (0 dB).
05-mm-02 = Channel balance (active only for stereo paired channels).
Values are from 0xbf800000 ("-1") to 0x3f800000 ("1").
06-mm-02 = Channel width (active only for MS-paired channels). Values are
from 0 ("0") to 0x3f800000 ("1").
07-00-00 = Focus select. v4 = 0x01 for channel select, 0x03 for bus
select. For channel select one is focusing the actual input,
not the channel in the current bus. Therefore the bus select
byte (bb) is always zero for this key. v1 = 0x00 (mic 1 or 2),
0x01 (ana 1 or 2) and so forth for channel pairs. Bus focus
focuses the output assigned to the bus, not the bus itself. v1
in this case is 0x00 for Main, 0x01 for Analog 1-2 and so
forth. Again the bus select byte is always zero.
v2 and v3 are always zero.
Channel EQ controls:
02-yy-01 = Input EQ frequency. Value range 0x41a00001 (20 Hz) to
0x469c4004 (20 kHz)
03-yy-01 = Input EQ gain. Value range 0xc1a00000 (-20 dB) to 0x41a00000
(+20 dB)
04-yy-01 = Input EQ Q. Value range 0x3c23d70a (0.01) to 0x40400000 (3.00)
02-yy-03 = Output EQ frequency. Value range 0x41a00001 (20 Hz) to
0x469c4004 (20 kHz)
03-yy-03 = Output EQ gain. Value range 0xc1a00000 (-20 dB) to 0x41a00000
(+20 dB)
04-yy-03 = Output EQ Q. Value range 0x3c23d70a (0.01) to 0x40400000 (3.00)
The EQ number ("yy" in this table) is as follows:
02 = EQ F
03 = EQ A
04 = EQ C
05 = EQ D
06 = EQ E
07 = EQ B
80 = EQ G
Input channel dynamics controls:
01-0a-01 = compressor threshold. Value range 0xc2400000 (-48 dB) to
0x00000000 (0 dB).
02-0a-01 = compressor ratio. Value range 0x3f800000 (1.0:1) to
0x41200000 (10.0:1).
03-0a-01 = compressor attack. Value range 0x41200000 (10 ms) to
0x42c80000 (100 ms)
04-0a-01 = compressor release. Value range 0x41200000 (10 ms) to
0x44fa0000 (2 s)
05-0a-01 = compressor trim. Value range 0xc0c00000 (-6 dB) to
0x00000000 (0 dB)
02-0b-01 = leveler makeup gain. Value range 0x00000000 to 0x42c80000.
03-0b-01 = leveler gain reduction. Value range 0x00000000 to 0x42c80000.
Output channel dynamics controls:
01-09-03 = compressor threshold. Value range 0xc2400000 (-48 dB) to
0x00000000 (0 dB).
02-09-03 = compressor ratio. Value range 0x3f800000 (1.0:1) to
0x41200000 (10.0:1).
03-09-03 = compressor attack. Value range 0x41200000 (10 ms) to
0x42c80000 (100 ms)
04-09-03 = compressor release. Value range 0x41200000 (10 ms) to
0x44fa0000 (2 s)
05-09-03 = compressor trim. Value range 0xc0c00000 (-6 dB) to
0x00000000 (0 dB)
02-0a-03 = leveler makeup gain. Value range 0x00000000 to 0x42c80000.
03-0a-03 = leveler gain reduction. Value range 0x00000000 to 0x42c80000.
Channel index values (mm in the above tables) are as follows on the 828 Mk3.
0x02 = mic 1
0x03 = mic 2
0x04 - 0x0b = analog 1-8
0x0c - 0x0d = SPDIF 1 and 2
0x0e - 0x15 = ADAT A 1-8
0x16 - 0x1c = ADAT B 1-8
If a channel pair is flagged as a stereo pair then only the first control
register is written to.
Reverb parameters:
02-00-04 = predelay. 0x00000000 (0 ms) to 0x42c80000 (100 ms).
03-00-04 = shelf filter frequency. 0x447a0000 (1 kHz) to 0x469c4000 (20
kHz).
04-00-04 = shelf filter cut. 0xc2200000 (-40 dB) to 0x00000000 (0 dB).
05-00-04 = reverb time. 0x42c80000 (100 ms) to 0x476a6000 (60 sec).
06-00-04 = reverb design: low time. 0x00000000 (0%) to 0x42c80000 (100%).
07-00-04 = reverb design: mid time. 0x00000000 (0%) to 0x42c80000 (100%).
08-00-04 = reverb design: high time. 0x00000000 (0%) to 0x42c80000
(100%).
09-00-04 = reverb design: crossover low. 0x42c80000 (100 Hz) to
0x469c4004 (20 kHz).
0a-00-04 = reverb design: crossover high. 0x447a0000 (1 kHz) to
0x469c4004 (20 kHz).
0b-00-04 = reverb design: width. 0xbf800000 (-100%) to 0x3f800000
(+100%).
0d-00-04 = early reflections size. 0x42480000 (50%) to 0x43c64000 (400%).
0e-00-04 = early reflections level. 0x00000000 (-inf) to 0x3f800000 (0
dB).
CuemixFX switches
-----------------
Switches and discrete controls in CuemixFX are controlled through a
2-quadlet write to the CuemixFX register. The format of this is
02 aa 69 v1 - bb k1 k2 k3
where:
aa = packet serial number
bb = bus/channel index (0x00 = mix bus 1 or mic 1, depending on the control)
v1 = the value of the switch / discrete control
k1-k2-k3 = the key of the control being set
Depending on the control, the channel number being set is communicated
either as part of the key (for controls which operate on a per-mixbus basis)
or in the "bb" field of the packet (for controls which operate on a
per-input/output basis.
The keys appear to be rather structured. The value of k3 appears to
indicate what kind of object the key applies to:
00 = global resource (eg: talkback)
01 = input channel (corresponding to a physical device input)
02 = a channel in a bus mix
03 = output channel (corresponding to a physical device output)
04 = global configuration
Keys presently identified:
00-00-01 = Input channel phase. Value is 0x00 (normal), 0x01 (invert)
bb is the input channel index (0 is mic 1). When two adjacent
channels are paired the phase of each can still be independently
controlled. FIXME: also under the 00-cc-01 entry.
00-00-02 = bus output assignment. Values are:
0xff = disabled
0x00 = main L-R
0x01-0x04 = Analog 1-2 though 7-8
0x05 = SPDIF 1-2
0x06 = Phones L-R
0x07-0x0a = ADAT A 1-2 through 7-8
0x0b-0x0e = ADAT B 1-2 through 7-8
00-03-00 = talkback channel select. The value is the 0-based channel index
of the talkback channel.
00-cc-01 = input channel EQ/dynamics switches. Value is 0x00 (off) or 0x01
(on). cc values identified to date:
00 = phase (0x00 normal, 0x01 invert)
02 = EQ F enable
03 = EQ A enable
04 = EQ C enable
05 = EQ D enable
06 = EQ E enable
07 = EQ B enable
08 = EQ G enable
0a = Compressor enable
0b = Leveler enable
FIXME: work out some way to identify the EQs.
00-cc-03 = output channel EQ/dynamics switches. Value is 0x00 (off) or
0x01 (on). cc values identified to date:
01 = EQ F enable
02 = EQ A enable
03 = EQ C enable
04 = EQ D enable
05 = EQ E enable
06 = EQ B enable
07 = EQ G enable
09 = Compressor enable
0a = Leveler enable
00-04-00 = talkback listen channel select. The value is the 0-based
channel index of the talkback listen channel.
00-mm-02 = mix channel mute. mm is the channel index as for other keys.
Value is 0x00 (off) or 0x01 (on).
00-01-02 = bus mute. Values are 0x00 (off), 0x01 (on).
00-0c-03 = output channel monitor enable (0x00=off, 0x01=on)
01-00-01 = input channel mono/stereo mode. Value is 0x00 (mono), 0x01
(stereo). bb (bus select byte) is always zero for this key
since this acts globally on the input.
01-00-04 = Reverb split point. Value is 0x00 for "mixes", 0x01 for
"outputs".
01-mm-02 = mix channel solo. mm is as for the mute control. Value is
0x00 (off) or 0x01 (on).
01-0a-03 = output channel leveler mode (0x00=compress, 0x01=limit)
01-0c-03 = output channel talkback talk (0x00=off, 0x01=on)
02-0c-03 = output channel talkback listen (0x00=off, 0x01=on)
03-00-01 = input channel swap L and R. Value is 0x00 (no swap), 0x01
(swap). bb is the input channel index.
04-00-01 = input channel stereo mode. Value is 0x00 for normal stereo,
0x01 for MS. Relevant only if input channel is in stereo mode
(and thus part of a stereo pair).
06-00-01 = input channel Vlimit on (mic channels only). Values are 0x00
(off), 0x01 (on).
06-0a-01 = input channel compressor mode (0x00=peak, 0x01=RMS)
06-0b-01 = input channel leveler mode (0x00=compress, 0x01=limit)
06-09-03 = output channel compressor mode (0x00=peak, 0x01=RMS)
07-00-01 = input channel Vlimit lookahead (mic channels only). Values are
0x00 (off), 0x01 (on).
08-00-01 = input channel soft clip (mic channels only). Values are 0x00
(off), 0x01 (on).
0c-00-04 = Reverb early reflections model. Value is 0x00-0x04 for "Room
A" through to "Room E". bb is zero.
libffado-2.4.5/doc/amdtpstreamprocessor.dox 0000644 0001750 0000144 00000000256 10604255365 020433 0 ustar jwoithe users /**
@page amdtpdescription The AMDTP StreamProcessor
@author Pieter Palmers
@section intro Introduction
( still to be written )
*/
libffado-2.4.5/doc/class_diagram_1.eps 0000644 0001750 0000144 00001500423 10441126147 017154 0 ustar jwoithe users %!PS-Adobe-1.0 EPSF-3.0
%%BoundingBox: 36 207 872 820
%%Creator: Qt 3.3.6
%%CreationDate: Mon Jun 5 17:23:50 2006
%%Orientation: Portrait
%%Pages: 1
%%DocumentFonts: NimbusSansL-Bold NimbusSansL-Regu
%%EndComments
%%BeginProlog
% Prolog copyright 1994-2005 Trolltech. You may copy this prolog in any way
% that is directly related to this document. For other use of this prolog,
% see your licensing agreement for Qt.
/d/def load def/D{bind d}bind d/d2{dup dup}D/B{0 d2}D/W{255 d2}D/ED{exch d}D
/D0{0 ED}D/LT{lineto}D/MT{moveto}D/S{stroke}D/F{setfont}D/SW{setlinewidth}D
/CP{closepath}D/RL{rlineto}D/NP{newpath}D/CM{currentmatrix}D/SM{setmatrix}D
/TR{translate}D/SD{setdash}D/SC{aload pop setrgbcolor}D/CR{currentfile read
pop}D/i{index}D/bs{bitshift}D/scs{setcolorspace}D/DB{dict dup begin}D/DE{end
d}D/ie{ifelse}D/sp{astore pop}D/BSt 0 d/LWi 1 d/PSt 1 d/Cx 0 d/Cy 0 d/WFi
false d/OMo false d/BCol[1 1 1]d/PCol[0 0 0]d/BkCol[1 1 1]d/BDArr[0.94 0.88
0.63 0.50 0.37 0.12 0.06]d/defM matrix d/nS 0 d/GPS{PSt 1 ge PSt 5 le and{{
LArr PSt 1 sub 2 mul get}{LArr PSt 2 mul 1 sub get}ie}{[]}ie}D/QS{PSt 0 ne{
gsave LWi SW true GPS 0 SD S OMo PSt 1 ne and{BkCol SC false GPS dup 0 get
SD S}if grestore}if}D/r28{{CR dup 32 gt{exit}if pop}loop 3{CR}repeat 0 4{7
bs exch dup 128 gt{84 sub}if 42 sub 127 and add}repeat}D/rA 0 d/rL 0 d/rB{rL
0 eq{/rA r28 d/rL 28 d}if dup rL gt{rA exch rL sub rL exch/rA 0 d/rL 0 d rB
exch bs add}{dup rA 16#fffffff 3 -1 roll bs not and exch dup rL exch sub/rL
ED neg rA exch bs/rA ED}ie}D/uc{/rL 0 d 0{dup 2 i length ge{exit}if 1 rB 1
eq{3 rB dup 3 ge{1 add dup rB 1 i 5 ge{1 i 6 ge{1 i 7 ge{1 i 8 ge{128 add}if
64 add}if 32 add}if 16 add}if 3 add exch pop}if 3 add exch 10 rB 1 add{dup 3
i lt{dup}{2 i}ie 4 i 3 i 3 i sub 2 i getinterval 5 i 4 i 3 -1 roll
putinterval dup 4 -1 roll add 3 1 roll 4 -1 roll exch sub dup 0 eq{exit}if 3
1 roll}loop pop pop}{3 rB 1 add{2 copy 8 rB put 1 add}repeat}ie}loop pop}D
/sl D0/QCIgray D0/QCIcolor D0/QCIindex D0/QCI{/colorimage where{pop false 3
colorimage}{exec/QCIcolor ED/QCIgray QCIcolor length 3 idiv string d 0 1
QCIcolor length 3 idiv 1 sub{/QCIindex ED/x QCIindex 3 mul d QCIgray
QCIindex QCIcolor x get 0.30 mul QCIcolor x 1 add get 0.59 mul QCIcolor x 2
add get 0.11 mul add add cvi put}for QCIgray image}ie}D/di{gsave TR 1 i 1 eq
{false eq{pop true 3 1 roll 4 i 4 i false 4 i 4 i imagemask BkCol SC
imagemask}{pop false 3 1 roll imagemask}ie}{dup false ne{/languagelevel
where{pop languagelevel 3 ge}{false}ie}{false}ie{/ma ED 8 eq{/dc[0 1]d
/DeviceGray}{/dc[0 1 0 1 0 1]d/DeviceRGB}ie scs/im ED/mt ED/h ED/w ED/id 7
DB/ImageType 1 d/Width w d/Height h d/ImageMatrix mt d/DataSource im d
/BitsPerComponent 8 d/Decode dc d DE/md 7 DB/ImageType 1 d/Width w d/Height
h d/ImageMatrix mt d/DataSource ma d/BitsPerComponent 1 d/Decode[0 1]d DE 4
DB/ImageType 3 d/DataDict id d/MaskDict md d/InterleaveType 3 d end image}{
pop 8 4 1 roll 8 eq{image}{QCI}ie}ie}ie grestore}d/BF{gsave BSt 1 eq{BCol SC
WFi{fill}{eofill}ie}if BSt 2 ge BSt 8 le and{BDArr BSt 2 sub get/sc ED BCol{
1. exch sub sc mul 1. exch sub}forall 3 array astore SC WFi{fill}{eofill}ie}
if BSt 9 ge BSt 14 le and{WFi{clip}{eoclip}ie defM SM pathbbox 3 i 3 i TR 4
2 roll 3 2 roll exch sub/h ED sub/w ED OMo{NP 0 0 MT 0 h RL w 0 RL 0 h neg
RL CP BkCol SC fill}if BCol SC 0.3 SW NP BSt 9 eq BSt 11 eq or{0 4 h{dup 0
exch MT w exch LT}for}if BSt 10 eq BSt 11 eq or{0 4 w{dup 0 MT h LT}for}if
BSt 12 eq BSt 14 eq or{w h gt{0 6 w h add{dup 0 MT h sub h LT}for}{0 6 w h
add{dup 0 exch MT w sub w exch LT}for}ie}if BSt 13 eq BSt 14 eq or{w h gt{0
6 w h add{dup h MT h sub 0 LT}for}{0 6 w h add{dup w exch MT w sub 0 exch LT
}for}ie}if S}if BSt 24 eq{}if grestore}D/mat matrix d/ang1 D0/ang2 D0/w D0/h
D0/x D0/y D0/ARC{/ang2 ED/ang1 ED/h ED/w ED/y ED/x ED mat CM pop x w 2 div
add y h 2 div add TR 1 h w div neg scale ang2 0 ge{0 0 w 2 div ang1 ang1
ang2 add arc}{0 0 w 2 div ang1 ang1 ang2 add arcn}ie mat SM}D/C D0/P{NP MT
0.5 0.5 rmoveto 0 -1 RL -1 0 RL 0 1 RL CP fill}D/M{/Cy ED/Cx ED}D/L{NP Cx Cy
MT/Cy ED/Cx ED Cx Cy LT QS}D/DL{NP MT LT QS}D/HL{1 i DL}D/VL{2 i exch DL}D/R
{/h ED/w ED/y ED/x ED NP x y MT 0 h RL w 0 RL 0 h neg RL CP BF QS}D/ACR{/h
ED/w ED/y ED/x ED x y MT 0 h RL w 0 RL 0 h neg RL CP}D/xr D0/yr D0/rx D0/ry
D0/rx2 D0/ry2 D0/RR{/yr ED/xr ED/h ED/w ED/y ED/x ED xr 0 le yr 0 le or{x y
w h R}{xr 100 ge yr 100 ge or{x y w h E}{/rx xr w mul 200 div d/ry yr h mul
200 div d/rx2 rx 2 mul d/ry2 ry 2 mul d NP x rx add y MT x y rx2 ry2 180 -90
x y h add ry2 sub rx2 ry2 270 -90 x w add rx2 sub y h add ry2 sub rx2 ry2 0
-90 x w add rx2 sub y rx2 ry2 90 -90 ARC ARC ARC ARC CP BF QS}ie}ie}D/E{/h
ED/w ED/y ED/x ED mat CM pop x w 2 div add y h 2 div add TR 1 h w div scale
NP 0 0 w 2 div 0 360 arc mat SM BF QS}D/A{16 div exch 16 div exch NP ARC QS}
D/PIE{/ang2 ED/ang1 ED/h ED/w ED/y ED/x ED NP x w 2 div add y h 2 div add MT
x y w h ang1 16 div ang2 16 div ARC CP BF QS}D/CH{16 div exch 16 div exch NP
ARC CP BF QS}D/BZ{curveto QS}D/CRGB{255 div 3 1 roll 255 div 3 1 roll 255
div 3 1 roll}D/BC{CRGB BkCol sp}D/BR{CRGB BCol sp/BSt ED}D/WB{1 W BR}D/NB{0
B BR}D/PE{setlinejoin setlinecap CRGB PCol sp/LWi ED/PSt ED LWi 0 eq{0.25
/LWi ED}if PCol SC}D/P1{1 0 5 2 roll 0 0 PE}D/ST{defM SM concat}D/MF{true
exch true exch{exch pop exch pop dup 0 get dup findfont dup/FontName get 3
-1 roll eq{exit}if}forall exch dup 1 get/fxscale ED 2 get/fslant ED exch
/fencoding ED[fxscale 0 fslant 1 0 0]makefont fencoding false eq{}{dup
maxlength dict begin{1 i/FID ne{def}{pop pop}ifelse}forall/Encoding
fencoding d currentdict end}ie definefont pop}D/MFEmb{findfont dup length
dict begin{1 i/FID ne{d}{pop pop}ifelse}forall/Encoding ED currentdict end
definefont pop}D/DF{findfont/fs 3 -1 roll d[fs 0 0 fs -1 mul 0 0]makefont d}
D/ty 0 d/Y{/ty ED}D/Tl{gsave SW NP 1 i exch MT 1 i 0 RL S grestore}D/XYT{ty
MT/xyshow where{pop pop xyshow}{exch pop 1 i dup length 2 div exch
stringwidth pop 3 -1 roll exch sub exch div exch 0 exch ashow}ie}D/AT{ty MT
1 i dup length 2 div exch stringwidth pop 3 -1 roll exch sub exch div exch 0
exch ashow}D/QI{/C save d pageinit/Cx 0 d/Cy 0 d/OMo false d}D/QP{C restore
showpage}D/SPD{/setpagedevice where{1 DB 3 1 roll d end setpagedevice}{pop
pop}ie}D/SV{BSt LWi PSt Cx Cy WFi OMo BCol PCol BkCol/nS nS 1 add d gsave}D
/RS{nS 0 gt{grestore/BkCol ED/PCol ED/BCol ED/OMo ED/WFi ED/Cy ED/Cx ED/PSt
ED/LWi ED/BSt ED/nS nS 1 sub d}if}D/CLSTART{/clipTmp matrix CM d defM SM NP}
D/CLEND{clip NP clipTmp SM}D/CLO{grestore gsave defM SM}D
/LArr[ [] [] [ 13.333 4.000 ] [ 4.000 13.333 ] [ 4.000 4.000 ] [ 4.000 4.000 ] [ 6.667 4.000 4.000 4.000 ] [ 4.000 6.667 4.000 4.000 ] [ 6.667 4.000 4.000 4.000 4.000 ] [ 4.000 6.667 4.000 4.000 4.000 4.000 ] ] d
/pageinit {
36 24 translate
% 184*280mm (portrait)
0 794.25 translate 0.75 -0.75 scale/defM matrix CM d } d
%%EndProlog
%%BeginSetup
% Fonts and encodings used
/NimbusSansL-ReguList [
[ /NimbusSansL-Regu 1.0 0.0 ]
[ /NimbusSansL 1.0 0.0 ]
[ /Helvetica 0.988 0.000 ]
] d
% Font resource
%!PS-AdobeFont-1.0: NimbusSansL-Regu 1.06
%%Title: NimbusSansL-Regu
%%CreationDate: Sat Sep 4 15:58:56 2004
%%Creator: frob
%%DocumentSuppliedResources: font NimbusSansL-Regu
% Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyri
% Generated by FontForge 20040824 (http://fontforge.sf.net/)
%%EndComments
FontDirectory/NimbusSansL-Regu known{/NimbusSansL-Regu findfont dup/UniqueID known{dup
/UniqueID get 4095404 eq exch/FontType get 1 eq and}{pop false}ifelse
{save true}{false}ifelse}{false}ifelse
11 dict begin
/FontType 1 def
/FontMatrix [0.001 0 0 0.001 0 0 ]readonly def
/FontName /NimbusSansL-Regu def
/FontBBox {-174 -285 1022 1196 }readonly def
/UniqueID 4095404 def
/PaintType 0 def
/FontInfo 10 dict dup begin
/version (1.06) readonly def
/Notice (Copyright \050URW\051++,Copyright 1999 by \050URW\051++ Design & Development; Cyrillic glyphs added by Valek Filippov \050C\051 2001-2004) readonly def
/FullName (Nimbus Sans L Regular) readonly def
/FamilyName (Nimbus Sans L) readonly def
/Weight (Regular) readonly def
/FSType 0 def
/ItalicAngle 0 def
/isFixedPitch false def
/UnderlinePosition -151 def
/UnderlineThickness 50 def
end readonly def
/Encoding StandardEncoding def
currentdict end
currentfile eexec
743f8413f3636ca85a9ffefb50b4bb27302a5955dc23e0f3397300c8fca519e5
6c902cb3b617f2a7538b6dc265a7cf20d53eb36e373340044ed3c3212b846132
e1960981d2006ccde888fd9671cdd7ed1352864a4b63c0967db2112fa1c98585
65c8fbd0ddd08b57b7fceb3d24b86e4b8f343e1d177e9f46bdf43b991761555a
2bd0087d171a8d4e0704d7976ec07f0120f5004a55851e3d7f1b101ccddc3f8f
02070217787e5d3d718929d6e6b9f17d30a17eb6ace1f85be11ba385884d9d00
1bf3ff9cce9ea1f0b0ab744dd526509fcdf64158c62aa1cb3291ff7366804024
16786710a83edd39fb5680e8afb4754d6141d843d8a0fcbc57c15daf7ac9d506
b9b8c2ff41b6fbdd8545d760da8a23868b017b34eb16a584d2d421063572d2c5
2e7abdfecf267f260ba26ba2c91f02f6919737b1fbf601d8139cad84b23eed0c
6f704c14677829d72acb3468e9b4833622726ad6ec0cad8f7395586491972c60
6576dc156cc7719b66525e3c5bdaf621fe1dafb2f9f64e3b8bfb11332c8e26a5
bf836a2ef8166dccde5136f14dca3e9e1d1c6ad39240b64fe8d8ba2f4a524aca
eb0b854af443bd6cfef9e95d27b6881a66ff7feb8b9f06ebd84fd14be7409379
ed65ad5e1e045fcc55b554c1c6e9f573b6a1827309a2229634a8f0c84249616d
d08cd17e467fc66a69ba0fa1f736d80d949adeea1f86bf7ebbaa577df96d267d
901d56d61159edff1868138d8414da43e2b9243b20deb8edc7153581d9a4ba84
03cea0cabb0888f56e1942b1a58c57052b6496f97d1e92084374bb60f94fd697
af2a4c05f01411a8edecc569f44a5b5def29e344a28cd438b41c06deda5eb531
96f03961dac7871fe1e915cdc99e5226e610eab9625c25cf6d859b5d0bc21359
dfe416af33c2de4b119d5a57d911ed47d4383342ffed04c461fca1bdd96b3723
b17e0150fcbe0c45033d663e067aa0cc3902d2397dadc77352b4740acab53b8b
1d27d2e97c5f500ea19191812af6c6a845e095c12ff2d4d73431e18446168fab
5fc2b561bc282dc05711ac9d96a1f006f33eff91584f7d57a6a2b41568116bad
128f111b3af6e5d1e965a6e2c97e9f8934cffdc6d017c10ad915f35d79ea94ea
67ea9e7fa67f6980c92157576df80f37896283c0a768c5591cfcbd40150ff1be
848921a1d91877aee63426c9a6fc7139b9f5cc77bc9edb6cc3dd75ef6bb95707
7cae7ebd8f64573a081ca828955cbf51d3c9a4b0f43ee1ed059eca8577850f64
a98501bf933ef80df9a5a269a00126e3b279a17394de3948f26feb527f630e20
bff6dd07c2a513d205c6a122ce1168ac9efb96cd227bb77614f6cd851ce93123
ee0ce5d9561a94df1d6e82a6cade76cbe9e7542bbcbe83688a6b2facfe692d56
f2ec8efe2cfcddb2ad31de40d19541e61783246c91ade32e75314429133442c7
81a90c58d2fc738867e362b488587a12b7343c74f5a70ca624d56547ba9c0b4a
d7755efff3f454ba7cbba779cb3d52261c8e1be78d6a14d211b153d82350b38d
5a2aeacc05d5ac56ec358ab0025e70045fb3c9588f605c950e57e6ded3f69292
780324da0d28bef378e5528c4bb9a1074e1ea3f9170b2d766a73f3e51fcee031
cf974331f2a54c9d44c22cf37fcb015d8ee8a11252bc119ecbf218c6bcce816c
33e97e4aafae256337be81803542a4870a2afd7543612eadd87d6abadcdd1fb1
6f48981953dfafc04ff72434c7f63f3ec5e3350009a9af65ccd9180268832e54
31ce448d52594e6540fee70442fb6bfc8f19d44bd76af7cf78b081ec54c86257
32f98f48d473bbc564f3d1bb2c2d177adb04193d02841f0611825d53a04ff283
9382d8ab0e7fb100ddab56e3f9a2b89179ca4fa267bfbefce5bea4ee0edfebf5
5127f31a67b740a7821d1aa851f370c5ecb8e6c39841ef22b6a9d9de1486dd21
13624aadf66af256723bf850d09b9053376a446172923f986abdf3374f07715c
c5671228224d5df6b308d90908616d5c73c9b95f5eefc2b31165556b3b7f0ba3
ca4d50a719e65bc02eb4698488db79f63fd703f6cf638f0a7c74e25118a43468
06ae05e5d22b1def20759382bd1fcb38a87ae5fefede6a0bed5ac7902cf4b8e0
308a8540f9348355182934eecb3001898379cd38ff86cc181a748fd10dc8100e
ea23eb64f01354fd6e649b1364d13cbee3ec817dd6bb20dd5b2d08df0dbfae4e
13d3a393eb9d1cb73d5658f7118e5255c760f6fdf672d24a6c0cafb741c387fe
4dd6d3dc95ba927d609f4d257148095f0186d98ae263c17192a6bc3f1698107a
510baefe6ca7606a46e39cbe846d98849c94ee556f5714d512882dca4186639e
9378443ec0ec35cbf7c1938f7d256a653a0754e365b060b491aa51431fd36bb8
0a4f93fe933eef1cf29ba7263ea0b3fd1a784823ba62cfde6dd8aa9ee68ec056
8476076a4af1d7b4c1757e9903f53089152a9af0f2f39b46de7a6d5f3882b587
f7bf0daca257ee71089813b180b19acf4c51c35518ab547e31779c2adf0a3e4c
69328d4b8e013734f9072d79628987d1d2746d77d3342edc6c78e0ad52d2adc8
ff5e375de0684738079808e3012cd24f755b5e0dd651cfa4009872f985b795af
1d37fc1dad0e7171d0261b3c94fda70d0ec5f1d6f0d0ea2bd36a4f106c11c14b
56ca7c5a90ff6f6d7e854848992de617de552dfe8bec2d3fea6689e215ed3c43
5346e37607c1d5c0fefaf641e3bb9e1d6691528bcfa844d1a19d4a80ffbe50a4
c1d37d1bc0c5a5684182bb7a03120137c592c93ca6551999ecd883e1fad354b0
75d9f5a0e2fd2f5871d00e307df675a3885d0e9decb59753f29cf0f54e9a4261
2ff3833c860a74fd04b340d1bb216e0864e540ec9eb2f2443075958b8d3dabec
c5fc0a507dfbea0d26ad21dfac24096ae1a9ec1e7098a753e5ba46ce12480320
163f8de943e60d875796b4a897bc8b840f39a0d5bdeb2f42879f6f8b049c86a3
86387a8301a86997d7a8332fc848f7127f497732357e2eb74b051a0e2d647350
5b3e457d96538f1cd4046fa1f3dfc27f6017d8b983a84edb92793376c67f4cfc
598741426d0552d1438444f8cfc83ba80a1e4e2a873c75f8bb2333cec60d5dbb
f14d158eb6d1fcb95fc553c27cbef47e6ed0fba29cc68a64b5b6d99aeae08352
74efcc0dbd27a1a18d4f0a4829d6d1cbe876f7f79e71323175361ae8e8970f9e
dacc93d211b4738f13b96217aa1af066257f6c2f595da272ace492e5763968c0
eef844dd8dc6ef550f47ee2366f4d4285b5621dfc3c9888cbc2cadc5e6989a9f
f297c4b0227e56e665a7138b32ac85fb78210b6c431043820bd416a55e7d8f4a
91a842e889371755f2bf94b9c0f187e11e999344dfbcfb5888b879e9adfca294
8696f5702dc73362055335453c72086a29961dc8a7bea74cbb9db0ec7aa9bc2b
1d9ed6d09d9050ffb47d07022e9fef701dea45e17cbb7d6b2e0914cfe921253a
08afde725b7163804607aafdc0c3b5505fbbb9098dbc4655d75113b34e1cbcf7
8a7703a6c66801b55de92c936782eaebee313f925397b81cce16946aaa44fecd
e499d17ebb392e760314a35a26b29bf11cd620a9fab1feeaa8fb7e57574f65ef
3ddc6cffebc6af3d887c975a68c0108a030b7074fd392a2ee4d9735c72ad3c5d
cc278d820afdf8499ea43ed69c48c0a291a779e9f19baae56d978ab35d32a9c1
996445dc89cd2e85f06c59222ebf56e65df8e68feb85bc17f12135e2f0395245
fe864741f1d078eb4695191d8bd8ed8bb021873b77bb81d95673b916006a43a7
a25d4e71b9ec641c026d767125b906d123550c7f0db77555deae1342d2d1c1e6
e71e62fe37c9fefe74f79fc5c57983b9cccffb99882ce6064a98e41c2d53f2a0
6438bfc08d1ed2afbd5abf37e539882e1bb36a93f2af3fd56a69dd2edbfcd31a
c7a65804cb397e8ae3cecd62300b75e69d6e6522c79dd119340d4a0bcf5d2153
04a8934372e5f11c22d4a0e2309b8e8cc620991c197896813f12a170774d19d7
39b4dbafd5a2d89ade785ad8ad978f7afc787b984bcc00b933b76de6c2c4ff93
8ba58db35e16cc7895a64597b1b004d931a0957e72c96ffc5de8efa7d5110d77
4c227cd8689c04ddce2322c7acff5c7d39e62ac75a20837191e12c6208f892ee
737c4b7a9b999b338943c0c9a2f934e4c24a4481598cd344e0e9ae4583c93d95
489f12bf0550cd449c95025fa6c59bae268962b0078fa1fac6b58c449148ecdb
6ab6e65d1174fc75af7d3e205ae51b3a96d4cc3169eaa5e02a3169f7a0393059
475cba0e35df4cf8edc7276895329b21d9c3af7819e9be50a36564dcef530750
48083259c6c642d7d99dda2049c654139ed8662a139fe1c80d3de43bef2628c3
38d1510012bc17b89ae25d8d381508d81c02c1fdae9a0947ec24b1a87177d631
386fad62c51073a9f723d9d1d5d3dcbae0eb3d2295b0337bbd8e4bf27ad0b07b
9fad81ed86f6aa04e6497fab0f341006453f96ab1dfbfef5db17caad07b320fc
bf9f2d4d859fd43ec7d9c5be237e8700c76108f95f5dae5762f45597ca585563
d6bb979d7ed3cb7753fe947846b73357a19b7cf0521153399e9c600a94d851be
6ad10c12d85706324794aaf43bb0a979d4f173b776cae5a4755393d3b545b64e
deb22d7f4e033cb259658b2c64327e94e1e223f112981c9f3dac9626931684a4
48b4e8c7b946d58fc041f1a58805ca689ae366a49451a257bfb519e1f4daadc7
c06c7df549cf3fb1168458d378f136110de61967c726888e69c38185068145a4
11e04fec34d20cd91bc45eabd103220728fc7deb9bc811b82bd534656f062c4a
ccce035844b59c02b9b8959b6e2ce80d0c735723c2f77a3da3e9a0d4ebd89de6
72735cd768dc00d7c49d400d20cb1efd273b655bcd03b9a040390701d4b7c1bc
ad9e4539b41d9ecb852b0881670768774c843dcd9eec2072717afcbb262a70ed
2b36ab5c8ebe038be36774383b92aec6249e8bdd5337e4cf71783fd879c8fdce
2c62808aa9377d1b1c60d282698f76983ef18d013346f88772e43b06339467ad
bce48329422863e8118b15c550cd3c0bfdb8018c0f87a0a579ce23d625a62d70
e053efdf3c6c1be5b4d1301a623e2c2e46b8a62a379e4ebbf11cf671082eff23
2a8bebed16a079e8540b38c18c959952fef19cc2b3d314d69f9897029e74b51b
8cf85d43bc42fc2173db77d9ea70370a468c31c89a745c2e1c96e1861e9d9336
c3a3a4e7d94a0913749b0158178f31d123c5cd8422540056599b138b1709076c
950395a677d6a1656846bf988da23117f5a468b87909c26fad871f3d7d95cd9a
9de992e5400df7ad77308e731683e85a86f20271e3144a68d06291bd9b134f46
b9f641b26f495da5d227721d3b09b9475eeffef7c2dd807dd9119f0cf2d8f1a6
b0ebed030f65aac99ead62c3d8c4c59a223e199a6263a61e67ef7e55c41598af
e5b124dffe5ffa3604c5aac39bac71e2235897db370c0352026ba5460a596fb6
965a6b5a10a0312fb9ca5797d4fa732c4e9f6ccb8af1014202bd76e04ecc5506
cf970bb71f72a600259e5cdff9ce8e190a92b5979a35a22df7b49eb583a39423
9446ef4f270e275f49f5606bc408038193a566ec0ea60c1a46e1df2b88481711
659491ba8aeb831ed0a273d715d12bcce2040b652c74e6cb2b40a87fc07366a5
efe6f0fff3613aa8b2659c9586bbb6eaf65f4b27b5aeb9dbfc0b608337d4cfcf
56366559e930330861864e9b03bb4c559c9309fb4152bdc97a90cfa5e9aa649d
d8a090dd24070419921499c61fa56f574929649b6a80d84683ee4783f131d149
b12f23e18d5e012e592da0dc18c24b7a2141f58db72fe1de536161cfb9425996
9ef7276fada54845a46c23070fe9badbd79123db19e25ffde0b1ef08112e332b
b3f1aed16220d289cb0c59e4c65b3dab135b6708ca4a5b5aff292e412499a369
df98d830773398ea7de81fcde779d6fe1edaab9145ebeae8d45685c326d41a08
35c5b211fc7e93f5334dcfbdacaa6a6cdf4ce532fac62cb80e3fb646fedf675b
ee9422fa2021a08633ffc893a317473f8b6dba84405075bcdd06f2c0bee7bb6b
c2bf7d341a7bd77e4d5c7ed964dde13acb197fbe10e6c1648e18dd4b5260d61a
5e219c9a08612f7ec8b50ccba576a6a29a6d848afd04d754b18a745576fa8edc
ab6b2caa4935bfbe5c659c41e047da36e4ddc9bf04cf5ffe8512cc2830c4f6a6
8132c8b3056960ea102494867054b3e7d016305784d835dce4a636dcc49757c2
395709cb7afd06f23456aa2fc739b87ace0f766a5c21a8e48c9c8b77b7161905
9c34c956dd58525d6eba9987e0d9da375e4d74633bd06eb1c813155e40cc3e16
2e43914799aca218295b9d9222b603d56d67cb985d769ca9488baafa37b70050
4bb4ae2f4ecde32aafd1e8d6da43ed5cfccbd28cdbd7df57501358f85892e412
adf9c207fdcf922659125efced634f2bd6d64e95e5516dbbe8e6ee1ed9c4251d
39624540c29fe0a0fa72451f8bcfde9081010c6a3fc4569d80df21fec34e1629
88b0e09cc4a801c1c6e4c10f1c9e32e829e5c75b86f7153ce19052fa3a593b97
b0f73e11e42b9a33adaab0def989fd8fa7557e1acaa866c70b6ad9e4fea68890
d94df460d5ab99fcf3551ffad27711fdbd1b4bba756a2307edfa68efa2c96328
50b05eb06e4d02f8f3a9d731c41ca6d55c02f8d0712b054619f31686b159261b
85c6b9a42cb6419b24dc9e2891f3c125acc5a651a60542c1fd753ef549e611c8
d458e0fa31d8e4f12b3299a024d8fb19d898da955b0febdfecfa335d1fbf243b
518023c28016819c93fd5de0d584baa55e6ba184f591081d7c4cf3a7a2ae458c
295fd4fdf34754324a31961eebcbf36c9931d62e0a01acf83c5c28987eaa4422
2c71d8fe4450e802328e4c217de9d20c8091b685670bf9b88bb37f9976e272c1
f291bd1094f2bac577ab5cd77ece0066dd8dbbbbf866226afe1bb13e4e93092b
c412dcae799e4f533f08c609bfefd826d1fc5721ddb7dd8ee23406e229ffa72c
4db12301e70997cb9970f411e8c3f3ef06d3fdc55c2a80f5042f1b9e48e4a700
c0a484586974c897e3aa0685484b09049e01a3f1d46b8bba57c7f2a66aa30c5e
a0d45604e53eb934142699ae88bbcc3d5eb1564e34a35b5de4e1d8cf120ef7f6
212cac2dd6f3f9a7752b608f0ff548567bed2b85be9b097955fed21e8460000e
b7ab68e3b48cca79ac3ae78b79c541e51ff58de85da19d8c92442f2f6865efc8
a050684f849d1123e244748bf5e5ea0d2be2825bfafebbf6e484c2231996abf5
847752466f58e65946a2f52bff40603bb05da95b03d5af03f4014a408dc556e0
f879a6c1aea5d34c5a9399f1784afed929bcc3244214172b0306178b9a6b9cab
78ac619cb08750e62b5e847bc73d8558003aa2e3fa9ba2837d33fc3c7de9cbe6
00dbfdd5ab61d0b8c481e50e8b62865e7728fcdf99d820a7fd0f738f0be6f641
746fc74f8632a75d676a6bd5957989d40d2877332f25c5cc5a61f328bf92e94c
0ebf439b2e6921c3b465c1a8277d0c3050db075ba5844b512d2da571a7d656a7
6e2bef22762904bd9a1c95825cb4b5ecb9237e1227a0777fbab880ee8dcff8b0
bc1e0a2127de9455e546ef259aecf2826ea6c6b7562550f965a5c7a922f2813b
e6538a3a423bebc7a3fd0f38a43a2e03418fe1640af682ce600ebadb8c65e730
80695e1adcaee1b0f80c8c64ed3435a9b9203e38931c1a89b0a3ade28990a2cd
0fb13d5e57a77389b26c32c1e2f1a228a2c18fd87e8f933f86f4d6852d93f21d
8ede9e1f6175cee6ee86882289564161b3aa8916fb6dda5000faef6f915c1ab2
0a13a2b89aece0cf33ce493c72ba30375a408f099a4425306f14a3f9a45a9327
107f6cfed4d4f7ec60f3af29288fdd29d976b27995dcfd1093b4b4e83eab4882
896be8a8fe39eba6ed88f2e8ceea897efe14dd3c8756cd688569615995d8adb5
ccdb30f9c25ed1a4e4232b9504708973ee5aa944afffd2a1c3cf0912acc3db8d
9380adfa309d44921dfd32eb75b8ee4daca997bce1618fb8fa7cc3c3b8511829
e251ffaacab3ef9cc1e97d7ca96b9c6dbe2404324f527993b9645e6d653487d9
b21ddbaae1cfcfe43a3c7953b8d969b2681647f99668bd415ce748f11460cb4e
a16645b1997852024b1e7712d2a9716cc675badb16714ca4616eef27f92a4fdc
f6c2abc231ecdfc762215c46b438bab7574a52da5031ee4a849b9754f9669c4f
e9f7c001c6f32aa388d73c00f6f0fdc7f93c359337c75b05755006cfee89071d
b7dab43a91457125239dbd06cebb7acc3383a89efb8bc9d9bfc5f9232228f229
8ed28bdbd430f2e1301a90e6421b44c201a79caf0340f399d95c2546d514b100
ea16242c2cc6bfcb457463b5bc5f89b0bd3353f5008f48f26c04f9ca7779f501
400c8cdae6618707fc8656ef9de576ef8da67e650eb7b1d96ae111ffa488f8f4
5b30cb96ae35a6ba0b59619a45079205ea3b586955e8c545b301b5801f7525c0
f1210550193785e67fa3b14f828cd6e2a39dcd8f955e5a7c1569199bf387b45c
3797058c9ca8d86f74cfe9e43cc2675254f0dfe9c41c462d9b8fbb2b5a4b3f03
c950598d243fa22077898d3ae323e145f4d1e816ef971ab103780de2d801dc4e
30fffc449253111facdab4f3001a3d0e7b61a419cd530b4b2035d56f8ffa0966
0c9ec64724b35f5529fff9ccfa1185a2f0ea576723dce36120017e0bf2e23050
82f7b537df8db02711eed2f8efdc085e78c46a07fa5ad65e2b3772f3357f715a
46b375f2553e5029ccce04c62ef20cc800419b3004bc3162856786c5e0c465c1
903e026f887868d6303a1d589dc73eb64597216f23b53b789fcfe3baf05ed7cb
df6d7ccac332ce905574b89bfc76d18d16abffb166443aee6e9c8e2dd3c3dbe6
d7db420fbf9e4e8d3ead3836a2691bfad08120b512ae464ce9da2025082719ed
908925bf284326d4c4a3b7e78466b2ecce191ab1ddf66e94d6ed4f53f574f4d9
7784bcd075eaa4c002b57a0804cc34d1f749fa558efa7a85f5d0078ad6850533
7865c7fa67681eb18750ce5cd2716d70229c6dd001c38124f033ca1c910f8f10
7e0c138cf6e68737bab55f28d9fb17c5fa830e473c5fa59d2b1c6846ac271b9b
5575cdec3e22ca1a68ea6cc4fd5fc025ad218d67532ee83fb6732ff6529fc9ff
bcfaf958cc125adfafd97b5ee4b04e0b479aa4cbcfddbfe9546ec31e3d83385a
d0a85ecc23f1ae8de7ce95ae36c2d6ba7da12602456d3a911b5115f7affb6dfe
8015011fc680eef6a623243e2cf4cb9c39e511c3125870ebc6131b4f32c6bb7f
74a4ed9f594d745f64adf5d4c9ead5bd6fe180816565730b8620a4d71bacaf1c
7c532668ee560c192f3cfa2d0bfdbc644303acc2450c7e20e75c2cc659a2ead9
65241320660da8239c0f6058873097b470f157509520cbd06c85108f7943df89
183f2cbcd7e16591d4472ad6654cf991f753cf7b95ac1fda5c2b425f32c8c372
675d77a34f8749608248e964fca69a8029c05895682b2d5dee6110b3bda64117
431391eb571ae75bf5aa45dcc38eb82cf68a50a7528ba315b2f4110beb7d2be3
832dd59f069ecdcbbb8785d054358287fa6efc25b6973c075ea14b305c0c2875
b0f50f1d881ddf1e772c045b69fd30f5268395f055285d48d2eae810aeedb224
42cceb8402d9aecd45bfdf588d63bbb4a69e329ad2f81df2148ee4f74707d086
0d66e528b593e649a4bceda32fbd1fcf50b0333d16a6663b15c7743af91c0c16
53dcd3c6f5b82419f53269a7493af9f83295bd8472731c777b35bd1874e91c0c
944594271694e79430612f9732c9ab96a1fc160e40f07f64c88009591281285d
c3d400fac3e6ef8a887e2e48d37cf51c92e506ce8fd58f898aa98f4a439930d1
68d60fd3591da6c4a51cea92c485fa5745789f5557975b885d72841a08be2dc7
7fc39e73eae0e4c162e5c5f9dc869ff15a61481687a44f655e2dc84d6e67e51f
5ad392006f951fc4064d8b66417a099cca78c953a0501a50b90dfb9396a8a395
fe2cd399ce5e770be1e002560d8f3b912d34199d932231166377104f6c24241b
1644c4d249ae268d3c2393b0145ca01a9237453caacdf129b2bb843a335030b0
17a9169eb840e4f2af1f02604a4e1ab46d4a6ce4cd13d914251d465a083ebd52
bb0b2bd8605f0e3da61516938aa132866925f99df3a7eccd0851d8f4ead5de97
09be2b86c947ad2bf3258a67b5154a3170d141b5b8734a3d9f61753c9830092b
f5e0582c2db209479f091f0986cc9b26294f3e6df5706ee8d071c2bc6468706d
e31b2a4ae292fdc6eca90bd63dd79a1b796131ea6fc90c2dc7cefcb07aa56ada
cfd3f8328afb7387999beced0868747f2110ac5858c10e8060c58a433b052902
29a96d44b87648c7a4ee7a3fd16219ceaa2accaa63361939e5f599c7f7117b38
6cf3c882dc53a69478766cc2daf7b5d21f6cfd57c05e11eff746fa53fd4a97d6
07c21ba356037d1e0742659fd32e5d060621572bf17f31b2701321f8de946270
5e7f900c2aadd7e456a84bbabe59f8b626077a7a56a59579dc8a8d1f58d8266e
0bd08eadbb9ebe4b1f6f486d08303950eff9736b4b0c2a7084d65622995a7f38
2bdb76c72962ee4f64774dd9278fe8cb356b5b756baae77d7670d83e94fdc7eb
db4e9ddb33d0f380ade780551c1c745582cbcfdfe64255537bd2f47472592808
c260c04f66ce245004f9240a05ad37839f59ed573a530fead7854d9147598585
731baa2e8a3c77197d448994d1ec57e3f08b7cd08d8b8d9ff27600503370de02
e22523c39edaf5cd7f0e2abc45bbd3af7ed6dad10529e0cf141550d6e4a8c0f9
05cdf8a75153ec4a3fbd9eeb97a33c2a80756a54ce5f50aead8210f7ac185dd2
52a0415db3b914721b4685e974dcda85fb667ea1b24ff6c382ada5075fc9186f
4bd4709c13f70d0dbaa8593925a8488879c26149f64f2403e84932780779776a
12b74becda5d99221c57f0763168079a22ba4f3c6571363d8672ded8ab7c17b9
df095741d4a50dbef9135fa3e075e354057603ee04853c9811b3b3488b70d8bb
6def81b0780adac61a3a8e149efb58a698e609a8817294fcf2bc0fb79a51a74d
d7eba2535176375348789be20c7ead87d29a2812ba83ef4d42314f1bb1c3a4ac
a41c167aff72dfee7d9f86df2b4df1a4cc5c2d2433d5de5f8d382b4802daa345
9b5f90ad23d801bf0767c2771db146d3d081b9ee3c1de927e536bd7398ff5417
467ebb5fa1628343afdd5df49d2b0fb1583b05df76cdb22e1f984c220c76e23c
d621ec44967047edf637600d8a8bbdef1aa3a419aa552939f9bb68261dc40089
7b7d2c0dc1eed23f2d09233cf15ad6e4201e25800685f9123bfd7bf069701ca6
8734b4c18a9a7997e2e16e350396b74e3620dab0ea81d84cbba9dbdbffc999e3
95ecde58eb46dd271efe69c67b6e0be603c5dac6d452f04dd76b892e9e0da0d7
b8df8f75f09e33606e4375b05428e02eec2487b22267c638ccf14a0f0153b2eb
d56a34b8fa2ff46ecd2cfc7f92802dfd57c0bf673a5db8e6475585dda1c060b0
b877e3c58b1c541e8201360161d045a3927cce49cc6a339894a9acdeff26a459
f4a2593310245b0d46d42862fbb696a3e67e276661f25b9c3f36a6b68c2495cf
91fbfd4aceaf39249f47283b9825ae4acdf0fc74b262bad2d3df54a22d72073b
0dfe7351627757709f06ecc05374b491a0f78459504ecb9470d4d841a9760628
5b8b836611a801490f591ee616dd21e8d5a96d604d2c8de2c7c501cf19fa7b17
2937f6cdbec94a649587dcd69d8d9497fbad78abd811b693f5aebb6b834e41b5
44678a9b463b4a198320c8811d0269195f952b7b717e00afd518f20655fcac89
e9d1375930ee2faa04fba739dcc7cbdb8e5c2a6ee01b8c9e5da99dc5618a16e0
2c87e5c0b7554a026698aab6e8c1116b6943e00696c6fdeacdc7f266295b0a2e
c9c568a5ff0e205f3c3709750b94c8dd871a8af789e1da1a7850dd4fdc0c0e2f
1a2fe67632740499a6c2178038c828737633d1beb6be9fd9de57cc35175db7d9
6f4dca7e88924638717bd1ef5a41f24f8d89bb7d5b85b8c2da2948176a4b31e6
44de434283570dbc57f42ac69ab281b5af48f89e59c11001c1f822e67211a56d
ee454b2a7cfd79dd4ab7b1692efcc011c9262d553d7cb13158e8946fdc1ba4a8
58345549249b5fbbf13ac9163ab000d66e36ae53c8bb1fd69c3c24fcadc9f8c0
b531a0149b69bdd3854d6ebbfb1fa225ea697d02450e6bd7168664ed07c1ffe9
8c5582ad994029df4bdaf4fa2f411725486cbc599cd71974214461fb072f3ae1
2cf68fb73885671ba1a0891eb6608d70ae170c427d588b38230b1b07e7298adf
498101a83536b60f85adea9dcc4d4e9bb45a402bb06d99cac86e0795efc71b5a
6c6ef7f500181fa185cec705e9d67ae89ca85b720f1560ae779c873359dd0c9e
aae6aacf5237ce041b9af54300b6e76a69528cd4014548b26af9b171fc44a225
d45e78f38aacb5bf27f2f528db29a05cb1d9ec09e266a7335fe0ee18b59569e3
b505c43af13cb17e52820eaa45670162ea896c806fa7d46a774eca6367220e02
bddb7234f0fee5f97f9060b88ebc99e7e0b8bcb02210d375b4bbe694f4f4ff47
779a5523f06bb1fd21f497d993db96414ba5025709c448a58a6e7e51f1657268
f248d54f40616650b24c7ed4f9b7abb95f57b5d221ae2a5e2d143d9415537b44
df3bb102887628a9a8a5208ebece0fb2e37430951c7b25c14e70bf9df94e28a5
6d7164819cc810f3b2b069ca8d80059115fe2b036feb3c2d0b1b30784bc31de5
251ad937a323d419b5fe9f17baaa3a1c71b5ec2519e31db52069f6dbcfca4eb3
e5bb458a081b733d470b6ffcce993f35735256cd053edc8cd07af0d0edbf29c1
e6d25485bbb66f6a16c66cb4f0b7766d448b39bddaa4271dd99eefcb15ce9cd1
0410221c47777be26ca0a1b8421ed159fbe958c56aa99d8a62bc84a3ce896050
0e2dd7356c3166017fa2f3528521c1815333fd3f47ca5cb812450b22db266526
1772325820e9563209040d73c71ae8c8203622c72902c139a99e8bbbc3172112
5cdb573b5a60a8a8eae3608f08034b047882176a93892b3360a35ca57756b911
d617d0bc4cbcdfca43f1a879449112feab7901f20db006189948c45e108aea48
91e6adf40b9d1f66e6bdd025878ac558fd6c217f55e668b8ca147bb7886b2c43
c86c29deb4405e285f62582dfb8ebbbd87f7c7f9b64b028913dda664bed4d6b1
c1ce535452f7f2a0d02a459cbb548505b9d3f253c0b613b0750c3146ca29c674
b96e2fe4d7ff9839f27e414034ff69f7ae6f453dbe57c3cac978937e5855aba8
cfadc0adb175c4e5a961dfe73b570ee8a7b6c825ad721f50da8f21539e3499e1
680b1fc414654bb6dc7b31b778794e876a7a1660d3996277c97eb092e8b98b60
f4311a006376538f012e60b89dccca7c924059a3aa5d1db5a92c75ef733a0244
04a81b3d0cbf27510248ec325bfb498f9283ee5ca0820273858ffe571636ed2b
5a9da76badcf59fbb3ed03123f33c94e419b9794ce014a73dadafa590fe51683
7efef9b902428b88c0a68337c9816cbc340925f08444174fe582f6989b89d790
5696d5f83ccbf61b2e8fe34ae010cb902aef07de3b598f620bdf85bd44ca1b3c
8b2e16adadf24378421f10e78478060dccafef7130b0801968bf8e6892e3d324
a307c440566d8413d148981059cf05778bdc9d68eb1aa86598c9f1612c518a75
342ed87cd90005573602a4c96f84d2d1a2e436bdf133c02c1b48ce90a5dacc1c
5e06ad6eac3945549c4ebcc1aca9b309b619b2336b99077020341d0c81bb11d4
67f5c97ba80341fc0fb542068b883da5d2cd5fb780f5bfb22590e1da5e0f51c6
9a1186c962d26847b0cc2d563c101c9e640becd754a6bad70d13e48a8eac8880
7bbf38ae23ee7ef5da88d45a5ccfdd69cd16d06fcd3a7788700b671b8d1ed1eb
49e224fd029618d40f2b2d2084c28715c78668d8257fdaea09462e9c20ca3e8c
2718fdd6948a6ef90bfafcd136544797d3db9ae51bdad43a2bafa4423177abaa
0463a1d97fbc1e64b469a2276ea82cb696c3d1ec32ec56219c335876db2f6e82
348b86e6d1928d8d8c6bdc7d7e89d5287ce0300a32c24d7d72ef354dd638e084
450aba0e4ee992477bdae8844f700a89d03e2de885b01dd0c1940d42e5a6d164
47e31449b132f93e91ae8dea7ab5b3c31cbae9775e4be242017eaeaeba211a8f
c70541d4e7f4ca10dfc38ed322e6da56e0a03ec0de291a88a2bcd96fc01f52a9
3ba9bc1206fb82b98bb86d1c77d807f7b852b1f5778a69b362a8e8e9c5c2c6b9
3c78f4a702bf5fde5fa3f1313f058aadebb6ad2f9772c7c7cbd08b1685d08cec
fc12fb52f3567b674f6eda30949a9cd163f7190184fc1a3b27f0f1a69e39512f
d56175716e33c8316d5fab45050fc413a50373e17669b9290e245291f9f07b95
2269e7e91d5859dd0feae55aae5f597cac9c32228cba5632c5c642a1a62be4b0
83ff3f30b6c05f92394167e350dccf45d61ab9b031d565801fbb6bcf66c40f22
f2334343e4c39f7755723fbd4d21a3529130bc0c5f89ed583497aab0d303a116
fcd47db62e7e8c0d68a4b89535ff060e6f41cac899eba85724d841f99c93f427
0762772fa6356f8361822d759e292bcb9532323c4d302eec337f9750b87a0e33
297ceca56447db08ca3430629a9d33e64b5e2579f6812d9491a77d5f75f96212
937441aa375265af6ed847d0b1517789d5f2718b7f3fa44ef854a2aacffe7f84
8d35b89366f1ec0cf30f1dd54025e90c1739b4e243b11a0b5cfa8905aa11781a
072b9b711f0f1595221e655a868ffcae766d56b395c444bafb13276ed6874820
c52986ee61aebb2558ef18e9408bd34d8a5c4c2a06919da7ca733b4b3cc8c9de
eb3e969d64e265d75026ba35b2a0f95cd0373fe56dfb02a73836f46378c72f1a
fb9d7ae59677eaeaf55306c39e2801d757b83e2090337d4373cbd76038bcb61b
a26b0d8a8e5cb05c04daaae6c8813e7d2f45f5fd8dd10f696d66169bdc648aaa
ecf3b1df3b5f1ad84f69db46e661703d3ab89e25b11366e74ac7a5a1b1570ac4
0a16a35865b057f75e9f036b6970fd366bf90a65181129faffa940fcdd33fbdc
72daa6bdd852810d07ba9a666a041c4b9e299da11501eda0181d35eee2aaa601
d14bc542428f8b958f6225f7c24968b44d1b489defbf6dc7611eae15b659abd3
7502cc94422f5f6c8c364366e4dd0992f9fff62a1f71eebd59b715dd5462ba30
de7bdf74b0dd2cbff670fa0168c456a59f738087e7e1bb02b02588c996b6f84a
4884476411f40a55717c052f0667884ea0bf767bc5a3aa29b84853b55ddb99ec
072a55ee751bb0a2171e9cf983f661f02595865c49e1c5fb11eeeddde9dfcdc8
f446fb7704232ecacf0797b892fa6ef37e3a10494e4d00cac3b4b86ce3055cbf
3d15ff20cc36b4125cd8ff980a995af2effd9ffb15359a7c58fcc6be2318193f
8011dc5c2ec4e2496f8761c0638a317ae01a43b9194eb0ebc0cea4fe57d34def
6a21829457936409e025e6bcfddc80f39f89fd00ae4a6387e3a1c063954cd09d
3a46f9c791a5a48c343e411caaccdc03aec37e05c8c9a59f83c8d9b1b979261b
0535190ca822c5b35e8f011040e17c581a8540120014a439b5c6e36aa774dbe2
d44dd341b231ed818044cf3c72c12d2798b873cb5568f00cff1b0adaaf731862
19df2975eea040870a12f564e181e6fbb3f3142ada7893ac78d382fc8ba93a73
49ce7be6e9aa47d19036be9062bc15cf2bced0eebf2fd40a7a9a873527501dbe
50de2b82bd26c06ab0d2b7c34b7ce9c5d8408e54ad98f11a063ac14429124355
f28140dbcdcd485ad0652ac46c367b5768f7a35349aa7916a064b3e64c66b855
1d6aa656bd513e5be907edb988fa281a6f5065f6498f97b02faffe2ba1ddcc98
43c84025675a7c67c17b12af3cee45979ba37136ca837adc6f26f1579f2dda53
90a3c6aa78e26622ad5ad8d0cda7257a9e542af625a84cc550a214a0604b57fd
481a135057a0d7811ecc10e8470a926a227d942d53db45828557e83b04e9f241
ff9f80f6884a7bceb7e2bd803d18e89604ad2bd3d24fe72f76a523b0411d53bc
4fdd03a068212facb573c4d458756b928afa5f5892602ca12104b5a5f0d69375
7c3a5b86e2a64c3eab2397e68e3439ac3f1d56d3ab69bac91088934959c8ac06
a62524c3113cef9a5103112ea4120f8f3a3193e5358442ba3d5444191fd9ecca
a0468c5bd8ffb970a18bc62103812991073f2f634fd58dc7c27c19f8e67c8c70
5c9086ed8e8e569d3d3dc4e423bad045a29d57886da6a151c7a1c2eaf3309b15
1babfcf5d305945d5ffa185dad36f41274fb0bff9df2d36d44a92158905498b9
156db251f56540c8daa475bcb973c654bb3511e39ef715161e7c7dbccc179452
cf95ec4d59f98cb8d15a41c9f56b1236bd6c33369974c38a6bb16e4c5d7d9e36
e55f44252b5c8af5d625d0b24aa85adf6c0fef93d21ba17927c9333d72f90d9b
366555eb891710cdb2bd662749fdff89184bd4bb397ce3745fe4aef6cfeb0aef
b2caa5d4d0a616747b4738635b04e6945c691171313e06be14e6d46958b6da24
4230557e472ea07fddc5325a572de292a1a58f3322aeded33a028700c8710e6f
42517d6ab674aeff330451ab071dbb05bce00db964dfa4a83b38577e80bafb5d
9e130ee02ded4fef2b67ce1f9235244b3a8a3fc6492795968610765b2a327f23
e4fd4e0d8f017813ee984aa43aff3862063c0bd738d6f450aa53b513a2c8ed47
25d13e03e3a78373390eb74759f435679cb6229f126d10b8d0b31c60e4edd914
4793aa810ff29bf4aab4421079581d760c23b9b3b19fcf274eae1db62380e8b0
dd097773cfd3b557b91999349a912fa1e4e300c06312cf347e1e4a14ba5730a4
fe0405e11575d19276b93b81bec00455b635a1c09c4c31ceb2abd660d2b550cb
5667e18c302420495b2cc2aee615d428a4babffdc941e514426d69f09f0f6a5d
b36b34e0a6f25531307fa0cb54d17c7937c75ccc591e6f19f5d35d5dbf0edbfd
d7ce198236054882d0d43c02144a602fae78b968d6a59038819c34a4aff9a54e
bb9f10b41c38f62e86b9feb16b3c7f9df8a9f963b6dfa5d89183442aa199326b
02bcb0ccdd132c55952bf88088b9b3fade6dc067a5bdfb454a94e77faec1d944
2400959a62cacf5c0458fd5fa3b2abe4a82989ce9b2128b04a403e7e7cd03e8d
6e4c094ad6e230546b5c8e29f71c9ef548ba45d029af92c83441b426a3406e64
b139d5ec75e90d93be1ff2a2b9f2baa26bdc69966a789fa2f37d752513b76237
c43c172ffd93e4559f60f796b65464879cfe791cf2d142ddeabe6deed472b2c2
b85b60a32f57034f376bea19a233de40647b0947a60a5787c961fe2354a7d564
f578f5110239045b472eb3ac2dc595a4ce7c4ca5f2d8bc92d60d85b04382edc7
02d3d57b09ef8ff2697b987a16e2266e71af802ac9e3f1a9a662b91f949d2501
42beb6197cd91d9b4f4ee2faba5360b9827e6ec7d46a4305a8673b923c7a0a89
3bc413ae15ee6cdd9a9fa5b18ec88ab0d1403280c462a720b428369488872613
3b0393316a6eb6a7d011a7f2285d7d7431553e7c431afcf6226a5d6a6a72c8e3
ff10f72df4cab8d51adcc5a1050ccba8847d8ebf12f369a37afbcd81c77bf5c1
73b5d2e0fa6a1a20e7754d4713d50f3fa8594f6137148cca7ae72912b3932923
53533423ab0907f250ef64f55ef84348d61d2268e2ab9c0f48855d71309eed5f
55380631885db8ced90c23ed7363ac26fbc02e2ea89469aa899f616089503be2
7796e51be6945ecfca740211388c7164c2923d59479bcbeb1cd3c43df916fa58
c3441f617f4f3568097b60e1b563cc9598440505b03c100f7d03533b36077a29
6c85f64916d55ccdf8f1517f6f06d9ab7ed8f4780b722dad14c38a42f435d113
29ec83d68fa94928834bee3a0c700ed78e8c6ca5829087af79f1a56fd146174c
f99ebe2efc019ff4f97fbd12d7276afdecb790793ca119b2f0be07b57b804e48
9e6bee084cde5cadfd82c6585e084b871bdd38e288c97e89ed30f60a5f3844a5
3c23a041489a8fe9856aa93affcfa638dfe9a595ed91541b400f6cd66869ced0
d79fe1fe13233f9fae365f503d92dbd82089da23baaf1696fee4bdc1b326be1c
9c281a188360af4eb0437b6e09f56f4bd51b540df8d76b121308ccde1c1f8645
da03eeb6c5f3968cb1bdc2ea12ec3f6f49b5c077448a2c15c0d273fe1188ca7f
55e18d5abcc6b79dcdcbc7c5bb06a75ac6a15c2deef7a50e0a5c483bb9239b58
93f29b343d8be7242d8a0f8278c6ecb538b1bf021b2a29e33a7d3348467464d6
62a7d1bef1ea36e50eb9c1c548c563f832f0388b0bd6d579327de8c6acfab8d4
0b9af08e997456ab4946fbf091435e77b49f96c4c723889974850d054dbd9ed9
1b812fc7242710fd68714b36c107c776f9c8395a832d490b23d1bb0a2a83a08c
95adb3064af2c0cf02dcdb2c86df8e3066292564f7c91c26db87dcbf1263bec0
3e3f7f11ae31569a1b32d93164a3f11c58148aa6951d13c0df0c072a3c8f557d
965aecd9d7f02db7db34ee37a0dc6ee944c5ee7644a170a89a2279bf7ef0a240
11564c8f30027e950abfa8b7ddf58d3a47fbff9429fd2d82740ad335199e8c89
f5c6baa1b6e60524dc967b19ed8dd3fa8a20eba26493d2c862496ae3456fb692
333e15418156eeec0038692d29411b4410bd96ac794b79c9b57c4e88e458f354
8d325ec2d8c0fd7d52ca2b448242d6361e955ec109b18bd1d5a72bd912ab3118
3610dbac45e78ba254e6b1145834bac13c4f841939609b3a3d29f08c9fc0d5ee
4d3417ffdaf36a14135e3ee4a3cee956d6482f66d24db97ff27348b1cde9043f
bf4840d5ab338db31fe77b820d4ead2b08968ec4ca490ad70312495eefeec624
b79a81aeaa9a6705885b7b85fd56a44965485529fb1ba8357eac75058816aaef
f5f63c12749009b0a3374474f1d4be7277a637b4ca300fda3dc7d08d86670eb6
85d84ac3db999e8c45169fe1b9d6b3db0f8017d950a70713ae1bd2e6367314da
577f2f14349160eea931f49feada5637fab98708a84fee1498f7bef607c948a9
26fbbba55e2910010a91e0e39e9fe09943483671b2ae0e2041c5f4189e8257a8
793f40268d547fa3b451c7f61559a38d6f4ac60b657decce905f188569c93c3b
66d3059e74ceada455e8f15e3608febd0a9b6a992c16d26fcaf9869188c131d6
8baac78817673a2efe78c504017f0efb00d18ff44d2b065a82c5fe8a188f2b8c
a045a10d6ddf1979f4d70978b9e8e14fb3f69840c5a257d08497024ec67bbfd4
08277c1bfb461f2ee5a636320e828d62b6d8be423809f1f27b13382227a754c1
e32fd3b7a375cdefd3e573f27f3f5e950c7158c2ab94bde13b2f94fe71236ac1
c26b720435763aa895506bb9024e7ffc0598477b46825e828ea8b9449ce081e1
1e1775d9ec93656f402ebd8a07160deb415db6d3e2780ebbfb7d332db4b7d822
ae83234a02a9904e2492e7aabe744bc9fd75b73edc0e30f2e76dcb772219e8d0
0cfa8ad303e284abb2bad49eeb3ed0553ece8c816e0a9650eab8079908d909ad
63f58f8034eb40bee8b5c55d9f5882914819d830f4a611c158ba3c558b6192b8
f895da07b12ed98245826b1b2f83c663a774aebc4e1107fd50a10cb6448783d0
e0663dc967dde0219c84f16a907bbdb861661d96f2378ac8464f8523a85df10f
a23ae8c9f9526132ce41ec5c2f4501e1401d23e2b28a43b6e1905ed5352aed40
34ee1be5baa9968c6312b115c00d2361123b8530374860133820ffde5bbcc5eb
37967bb806bc3648e421fcc9481f49574c2c1c1ffd17c0a126683efb7343ea55
cd36c440cc518007ab96283acded7ca1636b1bca3b3aa29b47982a66c064a019
3ca40df6be1ad73c7e31e979fe162935b14d7a77d1241dddbce9d16946482481
c337c2b2b772a11c43e3f1761ae17220ee54acc998ba96961425a18051a0c0c2
c0971174290aeeae2081ff1c50000fcc967d0622c27aabf8ea7ecbe0e33d1b15
51ad17404b75f017be0d051bb73dea2b8b4805e68e995280873e7d824528486f
878bfac43de3b735936881781b805f2d6dc2ae6e2e34c602d0f73a09ceaa50b8
3f38898a76ac6c0a91d0c699defe6b49b8bb4058d05999afde1450ba5a54aaba
34c52e1af58a09b085a9b4504d71561a746ef950f486c618a19edbde27ae6e05
b5d77bb722f2d661e82a8f70ee19487fc2b6844308370aec3a28d40d3e8a3cb3
1352845e46396b4d2419ee29afae5272a44e168cbad73cb98ba270c2adb01c92
6f1f6cd0aad9d6ebabf7becce4385fa933a3ee7d2cffaf04355858f3312b4495
b80298d7bad56002c296953f4fe18bf6b29ff4a47525cd0948d2e40e50b4f800
6d3b37a0eacb2b89207936c6997e133dc99e70ab32f46e0eb7e7f0ade22d9f16
42bcbdd59d0b67151099003cd6dbaf9807c23208ed4c057dee0ddfba037c927f
dca7f009d90b08f4c5051fe7c43f9d1cf3e4c152d6e261876517087f5705a09e
605533360756ff45515c55b25d904967e28b74e534b51f1f18d106959ebbd9b8
73cf97fbce379ba50198afe82b93db1bb3a23f3afe2d546dc2dd482f8c14a76a
c74c34163d2cad590d476987ea13507d53990f5d6fa12849a84d7ef6ac645778
2128432c5d39f018998f22addbb1608094717b2fd01149cbf8c567d95f02852f
5c29a69713f1c358d83420f4b02bd741b134a8f705afb31298ae6d61a679f074
695c2e6a262b20b6f4eed444fd1f37687b723eb420d1cb15ff02a498309b05e8
24304bf567585faf611e9284c1034e25512325c75bc97e70cfba0d4f199e079d
12a4fbe964c36ab2a6ae975f4fe68c7ff61272f810afe817f053f9c6a4f184ed
d1f0c48dce07ade610c82ac25f8320976247f43ea18af7ac9f19903025a47047
23a9a49a54d9f092d4a453410cf492313678126a21a25e04e0822fb662566d51
428c5d5ca1f39bcd7452270c753bf87752ca08b622ddf38d6eca2f8ae3733d74
bdff39b6df9c4f87b0ef573affa92c40bcdc702ec1c2854d20c03b948e2be718
701388946b4c23d1c294bd1d1541e27eeb978c7dd9ad05567abe1bd66fca113c
d657ea7a28baadbd447b77b23f863a512ebf5b256053cd8cefecac63dc5d4fc3
1b8b27120420fbfc6a0398156ad44e80768c70824d82e49ca20fd5720d4a78ed
e55730c58ff778b14592d0127509679591a4253403e374e1767e17455260d34f
09a665db912e33344f4ac8d256948349baa549a87b47a8b31553fb68e29579be
99ebcc1b00e1b26a7917e4ca0251c48865d499be8910ca78af6b19bc7b39b33b
22732edcbc6539d3668d1bdf2d2514b0d6b96c076599beda71b3df88a55e3de7
fbe52957064c6366059ed4bf0a19f3d1eaf9bc01034391fbe9127a3a47280407
d4a8dd12bef7c2e9b3615953ac83253f8e73a769fdff3d8fed8c2881c5fffaca
395ee0e45f05b2612654089fb0809d10025ea8b1e1c2ae015d1886c575f4b5bf
13d9ab616717f7579db4d69a32259567da9a00125160635ff8c7296b53d0afc3
27873b8378d23ab487cfd0b2f3940b0c8ccbd696f1d6e18f1fcc7bac5f8730fe
26b0a9651ccf8bef00f426a3d16b634ff1edb34084e78ea788bea2af4b4d0eff
011dcf5a74f5d7e7ef33c12ea6254541a361ffc3c5646e377e6f0c9f377654d1
82bda0efe797dda4b30ba53a413b5e99445b5169d2ac2b3b5ea4a82ef8ecb71d
99b147fdd00196ae756558d3aeffd564ac13dce2b6f20266f113a3fe09b925e0
45d831020da5dbf3c3b7663dda400fb846fabb670fea83b72a9ebc06d1830262
fbd400cf2f807912cd559f6577c71b25de621b2e2171a209cdbc121d057b3ded
46e40e710f113f70a98faf17a0be4f1c0430221cc55f1d3c96d5800af92db0a3
9f715557b4bfd0f34342f1710dfe1973dc8f7b8c17aec77f74ee6eb7e2dc93aa
9184058a02c614022f3040564007da4a9a106e656267acb415fb59aed881c57b
bdc40c5a2c1c62d77871f9069bd98aa30ec894ad85be686bc146f0d62bf20fa4
4f1974aba413d66696df61dd6bbf5b9e4e059c19ee4d07bdb322fb35157e7753
6ddfa988581fac036dd4c95b6b6ef41010e06bd692e7f48cb336b5c31bdf55d6
fec2e9d803a9fa6a29c1ddd75b81bfaa37e0d08ca796f9abd4ea004498a8fad2
d9ba1b570d16ff33706df51b3f92e0c45e5071ed11be711ea163b418d2758bfc
06f4b8b321fa423de5288092423383b6769839755d8d821cd7fc200c90738ba5
08f3155242723822970ea15a61ca0f136655f1acba7c5b29fbeef72d15b1735f
7d589a2762762b7f603115831bb763e2417f26098720cbb71dba177bf1dd9c29
0bfcd4466fc67fded3b4feab1d2edc400e44e57cbeb0ca28a1e598ec4ff04fd9
d3115bf34e5df668d92643c6000b2dbcb40296b701d1b39d419147ecef29d69b
d30ba4dc70f4215478a5cc2690d0d8680f8a41ce3120889be93be7a27b656a84
b8f7fb3d13c02d26b27664670aee0715bc7a036ddf8606cb6d09f452781f913c
aaa2cc92376f9fc121b14e0285e271e2e437dcada997d6eede8a781d7e3253cc
3df77277d765f35b061dce4142bcb0920899e16bdfb7b20cfdf34a5f717b8183
4a23f54e812bccfdcfb6ea6c706c5b89a3e7a3de499ab5982da214b157a57e26
94283f0af62704f47a9672c367ef5088892053b90c9c3e06f57f72990d2d386c
bf4b8b144f75a989869eb84a014855dc8d32fcb816eca42216be542eadfc9f7b
10731bfbb5a0232c1aeba22912d6b2a265de09b0e5c3c54a56e7ba60b901bc2a
25db0d3ed80d538398b1957912b70bc12339a063c5d408c561d2815fb0c3ccd4
d9d8494bf21f16dbd8eae919d0d5a7e29486402abb863832373e5d5c3d529bd2
7e030f711acd73e5b189e67a745fd82ed2f30e6d923151272174c7f574af99df
6cf3677e288242b42eae2d540d749f30f734fab2505b2a4f434f520faf765b6a
640e9625bcb3cb6c9bae6be91f9bad4d89090c1ba3ecaaf038af30d60e362f53
90cf0e0a4118e5aa3d95bb4ca5d0042d2f941fe1313a1df1f54c23f6202da485
1f5c469a490a7748516262fea539a4556b9f492543fef4825a21d030f9425917
0c75deca266d36e5b5e4689c1ceca2c3d32301adbcfaa958feb04ef9b7df6566
396fce961249583a2872c32d87f5710864f41ed7e6071e1935aefce1d106a060
57a5950a8078677867da3e96bd4ebbb12e042b0054d46926d2d9d3f633246d4f
b82ae28952a327d41bb91710b46d47a508e9dced351e04c8181a579d373539e8
ac515ad65154bcc6e807818cfc91cf49f511ff5bee76279538ecb71a866ed2bd
3054cdb2631fad0244e7a83ae34b97d3208899e1302febae8b78abbbf50e4441
7b6e21db768f02b185e85a09808ec5f36eaa14acdb6fc83d45b9d3e6d06171b5
3413fb84d6c48bdf1b9a5662cf9a799127bd3c7221c310d6b49f0446fa00bd2f
0a59d3c7e20321d64f797edc00c4917bdf2519d07122dc52c88a4c131005842d
6e10bd85898ae491e2aae74d8d6093bb70a793a2ad6375bf534ff450e4a02e42
38d9d05f1736803faf4be792f51e17583fd568201acf54de28fb8fa61f2cdf8f
301719437d7132af74ebcb5836db5f5a757a516695cc2f5da0fe3585dc735411
af8473ee7eb7c60423fc27fd630cb662bccbd95493e1bb594d3a339b1435e29f
cf213fbd40b74a9fbfdb53f79ea913d0d344d4f0e9657be2f239b8de200b0c9e
5ac9dfa7381c5f099b39a70ad697c8545446a291abd3209e9834184d8283f0e0
59f44edea64a7c4d6b8f90cf4f43a855888cc30b8dac588b9cd05f8907419559
873efcddfad999a718d66bb6bc6e67b7655b5af313c62452fab1a5aacab225d7
be2bcdd9cdb691e02aaec2888d5409f3a862e92a436e8f7d6b6fa4121e1ed7ff
d273b7377f454654e3314e83b7bf40956b5dcfb79cdeea054b096f9f68b3ee1f
1c7e458a884f750694b386b689fc29c5d73789f9c95c9035ca73bbf4d1d14c41
43e73790e24c7e777e76f039c4eae177e624526eeffe49387c9dada932485e7c
9797aa708d299457b161ef395f2ee27ebad1baab063d4b549c45e40ee6ee8d27
c140e7ab478b97669425ee97da6415aa7561e35be22de4a08156af9c33d3f197
e424f112648c6b9bbdf8425d5bcf8cbc4b00c8d0628c11833f70fe24a5ad3efb
0e11e043cb64cd121dc40b4fa1aa5f14020880b119c7a7f776b1eb5bc0290f7e
15cd96973f8d37c19e16ef79c028431a4d7a64a1fa90bbd4470ebc7ebd8205e9
0814734aed822909ebf42c531bc5e7a7454c6dd74b9aedfd56df18c5c8992ba4
164b91cb5df1e683aac3fbeee4d697ea94060d6c4195bb88f749bfd2b9c7258b
cd0555cdf3f689c0e44e8010f5d4d89ad9368f2bd0e173da613b84361b89ff01
e4631cf56f439aa47487adedcc3b304edbce976a1cb8fb2a8663457abd4734ad
d05ed3388721e47728dd8416d7729767893e7a05a90f3efda2956a2a355ed21a
c7bfb4a60b958be58aa4fa41d3865c014f757fd2d921e986406f70d2c3c67e6d
0a2a388a3fea667b291a12fe53c28fd12031b3ee94eaf7cb34c7627a5cb22bb3
86849133edae65d10eea68de84c907602252743475563ab82caa4f621e4c257f
009acacfac7bba155e04da90bf9140f7bbfa9fbcdfd6f8ffd00709eace830515
f7daa7d44d031da7f19a9fc9e7f1c9a5bea669c647df1257a182e3a0924d265a
b8a16663e87cd9b5516ed60b16c90f11cccfb86c39d1a97487729a5cf38a2952
096cc96b1a90b06e1b6665c98e302b3e09ee66a18a31161b290131a02b9e23f8
ba546a75ca5160eb51500a1272923629ac0832371c5b4bc18baf27a0ff257929
402427f3d866044c53941f650405c2b052f80733058ed16575b2dd37b49f2c69
a13ff0299fe2ace1f7381373c7aa90e92a1d0be8e778ce62df117170fb4e6101
de75cbed28ab762e3fe99c9b19d28b9d9237620ce25ae7d266ea2e3b04505237
085ee203294cc8748309d75ac0a6b1e339b4678c5ded1776f72469fc09cf1141
254f0e7c8060e33905da896047b8650550a980441eafc4fdc62c83fe3f687649
c969e7ba634f02b882916ba00bdf928a68567c67b45a23ed1d5669b77482db84
8885aac2e705c53951fdbe021debd247eaa53be12a2282b18418bbd82e77cf65
f7f669b887415443bb0de7c2c81a6ca7d4d6e6bdc44a8ace61ba10506edfd9dd
68f1e2a157dbf342492135b8f265c1555fbc8803326a872683c972fae527ffd3
c31967321d40007876ad044a200af29a7d3d2a396666255c0033821a73aa84cd
a3c2cfbbafbc6ad96c122f0ed2c620b16fa064b4c6aca4982299456506762f5c
cf7044c4f835420ce798b6fe57de13a1011d4877ccf263ca7249d772bc6d43aa
8e629adf9c9f0a7e22ec0a5c1b8d440c7b6ddeaa000fc9eecf03f5823ffa353d
9be462ecfa670c32b2441933f267794f6e6729b05b56bca54624398aa15fe9e9
6bf2f9662613e96aa16750b0841be0a61ae5524ff355ea169aa84b1eeeec328f
d719b6911ea4e986f26f551c4dcfa860a67268264c32cddb5abf65166a7a8277
8b84f970fbad04244b66c176617041fed9c361bda35a8e92220d86c17453e8a1
01cce26443daffded60bd71bfd3ed390e503cfe21b5613e9ce6c0264cdaf0f97
14d50ac91b8028cd4eb8612fa0e2c33926ae819ccccc7e98ea09143fcd46c0f4
112b2c4971296dc687823fe16ba9b073aab209b35c251f95edfe61480c74d16c
0b41af4a3d8b2b9a368fe626344bd4f78e15bbe5023faf010a7b5c7329e2bff1
6d754fdafee49ba6094d004da8e6ecc7e40ea03c8571822337b9b4434a0e2385
00805ba45b92370503ae8d1f1202ad6982e6bd53646b606e02e4b7cd852f18e0
a4ba249f11318c276e21bdc7abc65beeb52097c390d074b2aec4036297867a0d
d4d78d5f3339cb73261b62599c11aad84bff22e72fa5e94f49640967f3f8c784
311137d8a9fc565b04fe31899e00c5a17610852fef8bfca5946f1ab0f246fc49
cec0d0942a1377a2d2a86a70a06f56878260794789675d9785896380b0e21357
8912097b7942bccde588f8adb01b74adda432a6de2152aa27effad80cbc9e784
bf1fb45f87c16391af7e313f7a3a7d18e6632e2d1662d4fa267639fdc2dffcc0
97b58c21fa441c30e7e761e6948c8420feeef0517702da4ed5d18d8fca170167
de3b43204875d415005864cce9c9b1458317e25c2f08fac9fd77ef6f948d25e5
82b63eb901769f977e5b8e6566b0983ca82d8fe8c848bcfe5a72831645d55ee5
be73dacc9a53538f4cceafeea9660be479224aa2eebd5b02f5e02e96e983a53d
42476aebf2445483d9506551866fc4d2b8cd74ea91bb729e39d54ec5adf74791
d5421ed6b4daf3b1cbe75422e171ff9b36d4374795443e6a7e91b8a10b3497b3
8400d185d8aa49e3efad234ea7c8b7d89b9997ab65a0eff6509ae017c714458f
a7dd613979ab9b0cb9a2c238dcfc0c1e712e8252fbf25b86d34b25d46d660f44
cca88301e1e36783b7769b1c066310fa53867af66c530d13c1be83dd7766cd94
bd44eeb31969c55840ccbdc092eeb565d5185e6443b6bea99dd348f69561363a
ee236107bfa18dad03d97eb46c8daa8b5b3eb562ee8e4fb2c1e9c6fc2c8e02db
355bf2a64afdba149cbebcd5e90a7db74aa2d1e6508c6c0f94f36825677dc47c
211617b68bc7317d8201bad70c42a0d0873cb6455320ee9c6f8b02ac551ef710
eba95eeb75affcb2278d3975799c47c8255c29d4af316ee8ea33c989fd3735ce
799621f5719558dbdc88df5bd185830fc1f33648341f09bb60e01d4cdb5b4cd2
b0de1ff83f5bd52948778c9a4905a8e50a6bd5a253756458ed1f14ea811a3935
2c7de923add54c6b2cd6e66ed529def9398f35ed92a37ec65de1d6722f8d4678
b4454038b3afa2953d46519d849fd0a4688202602cc93f39b25da6fa30aa6f42
da8fc945a65dc61872a86d044d2217b320f2aa7565a21d9486f51c3965068a19
698a812e25389e19507a6b3d83f438e97fd69c9403a3a8984547b6bc596e4708
49ae707a9419f3ffc5d933ea28e0964936e750f85599fd5ffff67bbd964df4fa
d76fae9113c9ab3e6a54efaa5bc634b65b079e38d9b85e843d44b5f0047abc62
bd0f73ee69479f2a2d7f6294461cb06bb451189ee1da1efe332b62c29d07616c
015a88223e54a6f500547441698578b7ed239f77fa31331d0826ee01f2d43b02
180d765fbd63e047eb9d0b8864c64a65ff34ea591dd51c72e9e826a479c46a20
2427762456a52c9967ed189956ebff36a3d6112fcc7361ce12606510f3085a44
69f4baa82a7920d7a9bdaae1eba737ab93b3018e853f3e57f8c4f309b0721a5a
c29ea0ee72611bba18e72fbca63775d0934e8430c5e712a2e9ef9f6979f3d4f7
6739cc3bd517fdebbb6bb161fcf530e6df92fec6712260e44df9980403735d12
9172c854c1e6f566d8087bacbc53442bd7cce75e9bebd647daa4312ee0303adc
730153bc8fa8cdf7b9691fa92f9af0e761a8e3839f4aa6af841444c8a71e60d5
4e49873837761d4ce756344bac71e07ec4e6c902ae0652841174a84e162fd3cf
ae4d2d9ef2410bd9d7b3864e5a1a3dacff44827c0dcb18f1f8191c0d2e9ccb43
968543a00a3a7778cd4a2983534f1c330311fc6effee6bf08098614b2c749c7d
5bd3bd5b4d9f0b80c8bbeea4bf6eea7acc5c53aca9f98d0a8bf8a4ea82519485
69bd9a05dbcaf09b6b797a22c5c091a2805d8a6ec682f13af4482ed44dde0755
93865a4219b0b9f91078ae9e7137e3b5ef88f2a5dc4a75e9e1f4334855f643a1
8ec3e07b7f21fc98940285a71ee0ce24f8928394b3f6a98c97807ede6276fbec
9b117f97150b4946a9b9cc12e07ce9b4591c05cf9f16a37f4ef20d84a891c06b
3b262980685e3de9fd1b95b76ba24296aa8da6efe017d0ece6970ff0fb36ead9
c42cae069f4ffdc0f86040f41060067cb1a54fc49444a0ea88b2cc0bd6cf7c12
30077d8c3808ac833b7ff94bcd1a688788cef57aa1a1725342d2cfbd4426d25c
6f78e4a0b573431035aa4b4889417eb9a8bd09b347314533bb93fae7aa8d7ab7
450022ebf19f523f64a7c2301890837dfcf76de273fa38c7abad9b61c0a51e41
0454e26dab4857b61a2a66294c5a310589e0c4f46113538e5aef5ac63cf3dc4e
5a39f8bd076140ce69da014c6effc6096a8103df4f8ab7c79f48445a714bda9f
951dd228d92733b8ed0679c0aae9fe311642ef05c85e36eed82b290ad42a744a
116aaf5fc061b925daa0dd9eace2dea166f9231230db0b6550bf2ae04ff56f0e
64592a5894a38293d1b6ab1d22dc17b197abf03958430220f65cb34eef181e1a
9176b873aa3bdc9b0ff1f559a6f0bf461a8352023ff96c23ff66936b8eabca1a
e2ac83631850b0cacd5480ba4d829c078a2c585579cd829d87c7c75b84c2d038
6eb13aca0027818c16c6c37d76a23bafef22a0d482b2531b2c9c7ce01f81125a
e432c75580602893e44379a3b10874eea65e3bf11cb65820d07b02e01957abc7
499fa68044f6e6253a26b5b0037e0476cd3d613bff97e0bb27f6afe61703af0f
364cba34e8d1458eb9795eb598caf17cc5b9750511fd8276d38af6ad2d3f79d4
0557d80b3fee0ab3b8acac48dea00bed9919fbbe70475305a78894ad8a0b49c4
d7c39085d3d23d45ea060830217bb8d696554c7ac653552270f5764b0de9e1a5
d6b8790dade3a1404d72ae2adf9ecf0d12afa16841fe85388a30d5e167dade3c
435e51a5845c1a3936d3ed5f8ac42de00dea7943bafb3e2e326f134eab25aadd
0ca58944764d5f18494da29551e1d5ccca942d97ee0945b202683a6840c94967
ced045a1531b118cf733ff61dbaa1907253ac34c10386a6696e910387cd2e1e5
e14a9cbe65ac08bdcd2b5c5a56edd1804e3d0c62b05d4c98958750674fbc90f3
e4d31b4f8fffd25057fb4b24bdf61fe3b21c62c6deae9325d17860aafa4eb7a4
80bb53aa12f6de24b74721fd75b760616270b8b506636fe7bb8fd1d9c1e380a1
618459752756068580ce40dc0cec504d177b07241b40190779f17ff00026edaa
77297c85b33db24404cad277319545a3eb6c4e3ad46fb2742f31dcedfe14e598
21d5eb0d46aa9f0aa1ef513d36b68e1bbb28cb5a09205f25c38eca57e30eb73e
944f672a4242867073c14b6a25aa4132d20f26a82b22c57d31a5c7e42e3ab111
7ea8b9812aed48d3502bf8e5fbb883399ec466b150bc4cfaa8435df44b65a8d4
332671bd4483ab137a576edc7291d04de335eac619820d218548eb712050c6ea
63935263b362a7c63d5917610788894b0b26be0fbf1d7ec8558f1f990315f782
b7f85af441b583885dc950872511f6960ebdd6ebefe49943532bd61b204cec0f
d7e53a747f1737732effc499c8d22a53ece6adc8296ae0fa0696c132a9e6b5b2
802c322173df78a1cb04aad791b4c58e404a487db9ef8a602a0fb1a805b765b8
fdb7b2bb12e275cddd0ea01281f9f30063ecccc65650133f0fabdf18f86327b3
0fc7da830336ae217d1ffc93b49016f92c572caf28ac76b9d1671f4a04716707
26d52ec1f7ede3d6eb0de8e38aaecd2bfaaa14f2a43abbcd9013145c9957b28a
8910cfec259a312cb1341f08c07b7a00c04e541f51c7d50866503c36a8d64890
8c4552203fed5471ba6ba607f0f87c5a44d1c4d01b1a586cf09680a3c13f0a79
aa3221440e3560fa0f27557c8493a4d4016f997e54d69739756c015887829a77
24bcfa8a600f0893f60b4c3be2cce6b883fb79b2a41b0a68177acea880f9138e
2a85bc25b329b85d771c1abbe96725ddc4db7627b188eae3b4a0d80dcbcf630e
b58adddf2b74b6aeb9167068c7dba39b7f3ed0b64cc819143288319fd5e64e8f
30971d488c1f5714dd404966c6ef768d4ce4d3818f55eea7edd6a7e2e5380964
088c3651dd8d0777a2a4f2115fc831c8467a8ea66ae3c011a16e884ad6dbbf57
093cff116da7ee488aa5f9d9fe9d556bed75f3b4dffc89c9f4d74250daf42dab
ef7bb6210ee5717e7cf40da390777fc7a27c25cbfe38b828fa57e33c868579cf
ecb5a7ec1de01632d31a4db9e05f618155439898db2cfc9333b5854b81d88ace
a3b725c18419a7c39a557e7ecd35143bbee16f2d3a199140d3caf3304d70ae71
62f50095f92da84365df278f020561170e77090285966aa407aa3cbd2e721671
f7ded3ef5ab6256580354df02b2d4a10283bbf048d6c4d2605fc504b68040c28
0e2f01f7103aabfe0a23cb23657467740bdb0cc2fa057c05a753d4982b3b1c92
74af97d871557583f32072ff735d306214c2a8683153affc5e026955ac9af942
2e4e8b737aa16c90d7de773b7b7fc1b90715064d89cb8178a03730b4fa53abea
409a357ec9da2b97ac3e19254dd13f518cbcf2de1b89b7a7bcfc806adab01dc2
e0859e580c6fe93de9f6463b4279cfdb726acdeac1e45b85d6a95bd7521a9693
2918d859221107e9b08220534d8f1eaf449e763cc0a191830b21bb88a996efef
b766f0c74b382378c5e3f19750f6abfecd05679f95a7255049469da6c15fac1f
c0f5d65c12c0a1fe4eedeaac2fccc52eac03882ce862cf56bfb20ce22b8f2950
e4148fa74eeb948c26d2d95cca7e9808adc7cec98884ce8ec6e420d0f72cad58
44b1f6e855ae4b82830f53c1c57586295a29027c3f0b6240e0c54f30688f2f1f
4b02cf3f5b6b194dd361067f4fdf42b5d81c56de03e86cdbfa7ad2f1d4ed3cd4
72de437f00b8828436404b0fe40d94780a515e536931fe347c2779a4ccf2f150
996e0ec66b1680a18bb3adcfc2cc1d4a8b252d3b8b44b3a45b40907ad045da79
893863da8b616cf609d99da8d42015f4b2f2b7e12b43ca271110450ccca981d8
09e31613cff15f95ffbb0b51daf9c3c481057110c466349d4c66fbd2ac1cf2a7
3005633522481446f41a64555a51474bde32a18f4736a5929a73539db46c9bae
637dedf27873087a17006efcfd8dd8ebb421353fc4d36b2f8d25400ab3e6d26a
07e0a753159596b434c8843591079279b21ec273e9840895e6538a61fae48e91
917022acb0f763bb4cdfcbe64d7b2f90758aae0db6132eb05256b17689b8c6b4
d35c42166a8441156271b8ae76d9e48da3c37f5967073d04cbf466fc3be33b16
0fb62300e46e0fd83ef441f0e1ab5ae6805ae0d2999f6e8d5af8fd2bfa4f2eae
43967ec0a0ee483e0a24b5603af622a35fb7487759dca20b6d1fa484ecaa9814
5b2bd50028be987a1f041ebdd8f9221ba2af034d5062abf12fe2ba282d291cca
06998c7dac0a62eaa0dc60aa96e20015adac42ccdda81a35bbdd94155fdb1422
c05c1db27fb2803bf38a34d23fb57366ec68d2817c075a5cc1d8a520df26eef7
07c2f5167862a9479c6a354e5277da6975f48053fb33dc53cb1ee27f00b9e894
82c1a3997523a4bf8dc41a40d0672f46eec9204e9fd7ddea1655f1f4197d4aef
a1243de6bad6099569063a416a06b4786e98f0955a90abd92fac2aa40d676e15
70b97f8e57cc4575aafa94e9e4a75720313d6ae28346da371bfd0f3f2be0eedc
e54fbd36bc8912d0842c6f95e1cdd0ad3127ead290179d5b6e3e286615688650
d39ab2ea5f841599a43228245c2eaf708ed34fd8abe85051c5afd73a2ce49fc8
26ffddc2870fddd4ecd16b80b623459ffb7ff6bd4a54dc580ec5c72489fba538
bf4a16c7905db847156c2ae0d2bbad9a76952779cb93cb79f85f90d62a85b19a
8d6a129639b83593e69368c81809f2e202fed076ac28f8b08bf5a8eb844cdbd1
a3623e9ec972d57e250d967f36f87187f0dce7e4cd7a9dee87da7c8f34369e25
55b4c7739bbccc1f95b700b9b1cbc49305a7ce0fa51d5ced8e16a25ca6af7bfc
25c5779b123dc3df22bc09e1ef5dff33920ec244ff63763f347dda257e8279da
e9a8c3262c398790bb9a98e8b6af899fd88aa6bcfa15a8c351abc3723e0fa14f
ebde847234caf045cf09f6cf2448892afae0290588af1655f6b539ec34cb7f74
a2555a44c90da8b8d559b007f3656ab15d94f6b66030416698c229bafd197127
8b416829c524d8de9c61bb0f56b727e49fddf6ec501ba10a01760a0301201e8b
43adfe7b6af8f07f78b81f39cb107c282b3d46a3e13e987ac291a80f226d58a0
7ad73cd3387b60a2d18194717b2f13115f317ebeb9bae5de358b0148b91c3f79
6cb8a9263b8ad5f2d8cb731b51c2c1289bcdda103d10c14a80c28d67c36fd6f1
8ba0ba8bc8cf90d7faf54dbfb00a9caa26cbcbd5d920584e32d05707ed0c948e
3a034c49508ea2f573650564ce7829dfc8740abfa785e837631a0f1f3f3f0339
b1fbe18fa629d1e03bd87818197790d407ff82163863012f63539405cfe56d68
d4d56049b05e5dbb12fb644068ee836efa7018e84399dc2f59a425de0b8b50c0
33b74a80816a63a475fcfc5de321ef24c46f2f15f29fd39beb1ea26b47d91716
86090162a17cbe3f8c70ce55b36649485d383bfe13cdbdf3deebc4b2835e0894
7c03d909d5edba98029272eea5a06537bd1053ff212efdada586e199b7fadb54
2a52f1d323c353d3ccfc3ca74058585ce62bb4b6a259c0a1fe73ad7ae1bdd0d1
54f98fc48347aadc834b6b60e45fe917fd261b2542de6b1ead767ff8f93c1ceb
63b03e2c622e47fd83b572d28e7b0457b4313ff94c3a53a33d8d0a625b901792
6d3587066e16d8f96525862387df924b9829f268cf72877bc4d67411f714e620
80b702ff95174cb05fc547d21ab72ac15b2c9e2d44d161025444a2c95595a27c
d6b3f2ac70409f24080771f86cab8ca530b50f56f45eaccd7124859b25ce6a5a
75b09299e6f5436de708f09b554f95d7fd1c1aa70f711557d745e1bd1de31f98
3c578d8130a7e308acb1d336ced62626c6387acd0772c1446ad16501b463a701
b74439b2be4904d09725c2a579d80d800d1a3501c34052d84298f32dab3af886
5d888fc487dc97e9a1e4efa8587c7a1cecf3790d5368af5c149ffec8cbf25e3c
fe2b9aba68e5322d1fe93803bc36bb5643946fe3fb95d9408f348cd50a8efeff
d8aa82d5f87c653c3d3aba4ac4346a2c87feb1f69a33e6fc46f13da2acb19fb0
220a1be53ab2d7aea2d7869ca086b4f567cf3a9c1db6d0ece28ef6a64c41dcce
25ced3dbc8e6c8c4e85cd4d504a83696e97bdf91dca64bb24dfe02cb8bccd7ed
146794dddf3689ad2e5d621ccd5e63b16cb17b07e0a2f12f928bf820fb1d58af
ef10472416aaaf28627b244c629d2ec01bca5f57d7f1137e8e2cd27f962277c6
c3465b80f301498aa2d437aa0a4bc82ed3fbf7163cc1adc71ebd7c706c6894d3
ff3ef20e1934bc16d871e968abbedb8fdc9fc0058b3476652a54f5047798cd71
23817b4d05f33b508e11d97932e00553337cd811daf3393adcc7210a4049e35a
e5be9cdf38c46a792248bd89ee16ca15eb54e811d53418d0688fbb42e71d17ca
3aa517521d25e30fcda4bcec8b9d902bfffaec452f8abf92e5559fda4250a316
125c4284da74350e2424bac49e731098e2d8e3e6c88386af04a79d6e249617c4
a051d017160006b473058ffb31dbcc3ea3a0640be57cb1deb1d1196f3dc8fc53
4c4cf65ec1bafcf2245f1b7fb16c9cf2a640b1cda3d8e4a2045e8717f4257c2c
b4fcdc2d3c47df4181cf4d2fcd9b10dacf72513f9721807a5fc27e763d1f7d41
64b23bb0c3c3f85691b45b2943de5732908036b38797ff52e54f6aa6fc564fc5
0d2ed23b619387ba50c6ac354397948cc7d64b98f51d126d57c0cdfb7e969b34
edd281bce38647f716db19db3b2b5ab8032ff9f51ccac7481031e732d756d1d6
db86e98db4b9edd23fa55fce0e116cd04d9de723933f6bfc4032ad96b9fed037
e9bacc961d4c796aa124dc07429d79d315f6332991c846ab578904f810210372
fb4d65fee2ce91577d7b1476878ac029289d0cae57ea705fcd547ba402abd8aa
7c58abccf083b97800931d69bcd2175b520160c85351d4cb10f1ce33018efc79
0c579dd4af19a0276bc7e0a3c78d64411a904a23bb41e99403c53ac41ac307de
f2dd1316d0ecea25d8d715a4998a7d5b3ac534f4a27b5882ae2bb4ba1d80096c
e9fc3f7f38efc6a2f58cc8f2b9a8609210f9865eb95314732d1f50c80dfc554f
a4086c45b58ebcfb2c9385fb063eb251839c6288fc8d56c95877fd9c91ce7374
a17eaeed5adf47fd2bf528844963f340e585aa1b93ae53b9854e58f6d29bd0b5
b03b50418b421bb9aeb616fe9b0f85cac4472b05f330a85811bb708070eda6d3
5236c7cad540ed69dfa505287171b5902966df134cf67f057a0a71c11311e621
492d9c123011a02b5ca334cc099ab2d1505f20672b49cc658ca3dc6e71c512ae
3c28d2fc3b74ca08033ad49b41defa2186787b65ec8fb65d38bf162ca5aafe83
05e621ad8824fff83b71b0d527828e83d9910a5f38381dd8c81ac40b3fb7c328
ef1a9b7e590fb4c08ea1785e20e912931ebf275b136404598a0942bd42179d07
e30a1f02e6c9b401e1f28d94a07eb96d6883efb9dac725414df68bada14bf6da
7f8cc19ef0d62d44d79909277d3bfa79e0f8c761d9346324bba7c28ec4e4c2f8
076f97cb237638a878944a643886305ce08525d1610101b878cc82f1d3b12150
c688c8bba1600308b9be2138c942c2956aa18a12a6dca015f484974d93221f19
25a10000dbb3b693a4d7f37e3b22a44ea5c017f623ef0c63c73be423ffaf8c04
2609e85e63d7ca48ae577bfbfb23294f7fbb14b8f27a0256a761100cfa05c23a
c96940e58ac1c5146994e7495ee6ac18a5f45f669fe20dfc3e0bae39fd65b307
501d013c2b7598946df96f559bb735eedbd6360b58f689c6f6fe83ff8b4022bb
ff9d11bd4f83f0fcf2511ba5450e0c4f21848d98937a684f011857204642bc09
58e09ef4358e2c044b885e2af256a3ab08621c063a18ae86ed3083ff2d40478f
2495cd69d81773ae9356efdcad814015a1199e58359109c503ef36a047547924
ae3625ee5cc50d758e22ae6244565c0210e0ba1d4c44722eca04358009c0cafe
60b3aa98909464b9b19b8a06a1be7b8ccf1b1ac73f7b590ab09ed6ff05850d45
dd57e8422b8351a399305b79ef433db94ad7095beede3c6ed9bbfd24f94a014e
748fa6fa8e5cbb0f5d7e21f12421c362fc11e3e88bda60345470494adce32791
aa1b3d6e75eb973e91dcb77dddd54b84816cf347ecb7b6a5d6a9fd68ee054385
7b655d81dc3983c096de6f4b11032375e01fc4dbb9ede396d2f16d4abc7855e5
316bbecae2a8dfd576f65094bf5ada5583d629b516e8a7b8fae6f4316a337737
08108a0e31a7e3a81e12944a21069ed4ade16f5eb48943508d0dcff83dd38586
8c01d6f50b59462d350ed9bddfefbc98b7f6a4dd2d93b6cbf910a75a490a071f
7b26de878f843d41310b7287aae45951244a9694ce0a34a71dcafdb1403a8ee7
a7547f3134a7224e0e7149d8bd8e71c789af20c532a1982b89d0a9c759b0e0ec
bf0abd6f7cb0497c67c5e1d17550e0590df5577721adbdcfc98c293de0f1291e
5221fea0dd26b8a9f9b1d56172671d750f6c55749c72525696a3163bdd4802fc
e3631d455a4b2faf7753a334cfcde15cee0ef73bed1ac1fcedf27a0add8f4e39
911d9599911ec00ca76d10bf03c6a66611421381627351fc0e264d5c887b6f00
6b89e660f297adef02b62ac44bd47a2da2405456770b1d0f5d1792a5b3bada33
db938941cc971b115ff6d99e3e7b36f60fcbf589a60c26e6cabb9be2859f5c03
17d53eebf9cef86abac569a05d2ae8067236ef0131f1386583db921507cadb20
7a79be1106b86a4ab60ae4d6d077d5ccab100b0b36d602a6a9221e355704d38d
b2fe6e9eb6a935417de5ff9acde0546e7c6ee7c289b8c9c957186c23bfe3b16a
de56256fda6b3825fb96f507dfc91138382504d82aee2b8c02f7e438a5796c6a
9847c64dfd4c8846300462122529cd680a8a6806d56664ad701f406a8fe89e32
39a91e63ef3566dd9aed53e73c2c7f2b76fff54244ba883628ab2f585927bb6a
f5fb1d7aea714e46654d2ee5e0dc2647a524369100d1b282fb5c02b3303cce0c
c357f8aa28ba3b8d38be055bae445a53d8aedc865920b946f577af73d48701ff
8d3b9410ce4b2186e9305622cc8c28a7f2a8ddb5f80d53cae258b9cd5402397f
5801390a17af769a0bae673ab3599f4f1cdc9535c2f8296d44f51c48b09e80e7
fdea899ca9b531911eaec01624c2712f9697e0a84b274eb096eb1976bc63fb02
d1eb0769f7b9656d441665f170775b7259aaec8639acba81a9090443cd932980
4bf32f5dafc6c975c19c8f91271c63d02cacd721f9f9deb41bc118133b6a5933
3a27d72d4b05ddaad0ebe1c8b77d57f915205bc8594e79b03f6a11d26f988317
32b8c3173788199507256b7dca8e97071ab0027d856902062946c6a61ba00267
d4aba1b5d94202eb87438f3117db8c5cac01beac648954b70961f3d97dfae29e
07a6e7f92529f5cd27bf6a52b8f95acbe63b17adcfe6a116d191a136417394d5
5b2ff629906e5341ce1ab08bc179daed42cc51c55a48384fcc7eb0f332cbd7c6
ebbf256e802f881c34a979547d358b7957538b989ab8d31612321724546637b8
c2352a4f829174b334a1083663efa23397367b5ef19cfd687396ab2597ec5568
42e080060806b2da0dce653665f6adda76cb50a35ded6d728eb30a4d715e66b0
398b585444f93dcda676ac9529b7a35b23626c350c5322b05af82a8795a14da5
5ff5d4f983c31daec0d239e43581ae769754092766872b0fc738fada648b1de3
397bbea58e33a57e9708e27e1867ec9c01d3ecadfe4000222785fbdc7127c135
9196e798d04ba21a7a9becddca4153228135c9d425a0f1948fe587c76ea67dda
f981da2fa8ce9f9d1c5d4e84262ee369afcd01b2f914c25dc1666700c095cf1f
1fe1974887f2e83d782b9103afd324ef6551f6e371624f997399a87668b69f94
b3654a8f14380aad61c17ca015cd130e015b5f145c13fe8610861f3fc847db79
a19c47f13cd0d0247e8da3de7ed87ef6e1f398c3d3d064e304fd138e4cbf91f7
4435b63bf930e6c7b0cf8d88452f3b1ab83110b8491104e647056f8e285da2cf
db32d97c68c20ea73cd7f320b92220a121cf9a1f449aacd71bb45ae852aa3b51
6862e2e4447480bc6dcd91a52fc3ddac7828945087c09deaab71de29f8cdbdd9
0642bb374a1b330ee346f7cdbf238268d3b4bf12dddf124f3fe888f8a8dc292c
6d515c9db4ab6c44fb27f8b556329e5dd1c06d08b4efa5597d66394fa1515dea
1b95e436c79bf66e4ae3b0cc143e9dfbd4b99e13e9501481c37f790e0684787b
5ee755e81387c7383bde3cca9af972cf2e2ef54abceb93fef59510caf921b75e
e38fb41db1f43e0e13dee1645377dba647631bb6b1b7a76275dd998f703217cb
7b3b9ca18747186e5a686699c79bb19c6c9147d4ccd98e0002e58379a40335a3
faa087c88bee826f018ba10b24cb4770fd3d75119fc6a4727d24feebbe7713f3
d9dfeda28612f9507deab1a42ba139630ff92b3a789642d33c8bd16750677b02
5376e8e8be7afb0270995c8ed7264c68aab84275ef976c57189f36d15f4ea224
3e65552306aa3013303f55f4a95a08f956caed4f674b0578a9b13db367dc9528
df5b07eab3acb4e1bf4d76c0b8846ccc54c7fe76440e3481f7d2154bc6fd8e48
eb8dba7b0f2b1ccbff81fdf38c894389ea75c406490940aa33b15f052a40a1ee
cd933da01cf7e352a1b23df78443896e13f9fff8c6f2dc9ebc5bfa70ecef508f
d15b90dce2234a5bcd067c723868027029f1eee5f77e28b178edebfaaa64bec3
9d9f8d8a6ed7a3b17b053796dd1e24e02c3332fa53dd4ed3187e5b9a59b17a55
972e309c5c8cf3d3e0beb964b998cef016106a7e220072c578a96a5bbd8574e5
d6b7d121fe6326474ba3765f810dc24b84a8d9f5a183f0858626d178f4223979
1aa41de563a9a0dc7c744354e2c06d2e0eb9e6a0f926172bd97e5ca848c640d4
db5383ff00b89557173f6484a56de7bb41cecf5c243332f1e8cb3f4a8eb83f5a
ebdf240b83fbd156cb99e7fd4b88469f2eef2acc0e502cf9afaaf38cdcc9fb11
913d686b5a140824a1b3b785d6f4bf01cf7a0d48289cad89825c9140403ecd78
da0e77930ef448b4e4e0e1acc6e15068a1191772a77f84463e529636a14d2674
33baef4e5802e4a7a94fde5d84c663e92fbdf6a22883f3b117197080abcc1d0b
b83ab2d5efe76a68b4667df820b2ff888443a9a9b11cbabf38a89262a156e21b
0bf87a17c442e00f49c47f0c2331f93e149e6268376e0d439cf285e303fc711c
86b10c055da5b76702ee975c8d228f00a2def442967ff378716a4aca93128dea
b86624c2cb578db5dc6a2a36e5081745aff0c58b02e28dd43984d024251e8bd2
81a5afaafbd44b3a1ce9d9d1d0321408f7a5e69a7e2857394fa3425d63ef1f2d
32a5faed206400dd0084cdda7b0398065449a6422752d14147acce0ef2558213
81eb33634e686fb8675e11c8a3ad17e4598e9a40af3e00d872b60902fa1636b1
1cf156b5befa857c859401f2adb7023cc85c61ef681c83ad1f9d79938cf9ca17
867c19dc3b2bbc075194d3eaa1012225d13fcc4e97d9d35ca35cfd1e32beb026
4863e179266da048433384adf9fb1532b02a9d2feb8a31020d79aea4c4de81b3
7b94ea2a183cbbd4fd8ce3141c148fcf95f3568e8562bd8e540fadc94cd2b0e9
fdb9a55f78ecd6d1d5ff76644c5830aa2fc81a6c3ee93c0fc6921ee258fe082e
70bd4a777ba9f3c2d34637b15ab48eab20481c2385c0a99d32a435cf67b6a8e7
277ecc3382c94b9ae9b4f98ad4b2a09e4e5c5c3715ff2e5f92d107f92b304061
733bacb1e3d6a11bbce09f22ce7f502053639925607c6bb0a30e4dd609685167
3f57970633cf8ecd61ab78b7cd4754ee5dff472420e9fab2fd6d32d75be0d8fd
804ca5dc7aa266f074c0a9f2a3f4ef6d63b586cbf89b1dd9015a03df898c9b67
01841ff851d2a80dde2c5d08f3ca382b5181bd9125f922d7b5610c0dde495731
ad691eaa5b94b2dc2d4c8f94eec56df201da4ed6f614f64670b9cc8fe4a20874
ef924586e7379c018f18ed7ff2ef9a21a46c7aae2ecae6e0cc0597930adcd284
48d58cd5850e29bcabaa45b09257997e6c2523f9864f8762f628e5d0907720dd
6abf59e955563fa3aa75ea833d05c63df978434b9393120410ceb491f1b28ebd
a2b90c9051bd21f98f0a4926edc97322202ee67011847c39cf2ba36ead49bc32
e8d29f5964384c2ff7af9022c67c3cc34468d13f7c5a431f2ac8baf8b9b21499
9eb31b25531f11405e86ec6417dfc5ff50524721e0e8d6707047534c8d71b5e8
8baac897c00c2e876f4b100122d8239540d9d935769715008f16746d0c5e3abc
05890b2c6c685ddf9ea0f6f8db37ec323c7b929031d0bc2c626765e7d0ec25a2
3c8f09b3229c9b2c0daf01998e70298d526e53766dfdce2294832ac2b342144b
f6cadf3fa76f38065e523e19dfc68c9880a6c377a5cd622f9bb3fc8f70716d02
72aed23d3200d9bf6baa7b59e14ece77e6fef2a9ba8a00f9b1055b0d2b930f6c
040336d7897b5785614121894068a009e3446bb420b3cf559a1179c234cc7def
0e2e8d343bae2c54944258f3d4c5d60030bf5f32b734aad83826c1ebaac4f31c
3a94e10bc636cc129f1ae9e3601be09ebfaa026cea55cc794f0789eed7a44fc6
7a8484d1a711877dab3c39e95f6ee340ca2274edc0a98d887eb43e46df78c77f
8d211308089019aca40737febb733ee0c930f1524b451ca19e70a13fd93d0832
1e76b716b66d6263eada70c66d961efbe6d16f23c3e9bff9e4ea4d5055d14bc6
f9852c50a6213c164829e7be909ca53bc9e74a08564668427ee856b5215697a2
44ee99b6e6b589d53116ca579b78545912d82c946c0d19be4e43012956a383c6
b228f6c06db63f381fca429fd64d6559be72c468279cca028a201c8938e17816
5da563d721efbc7c405b4d43cda13edc5ad6bcfe101d1ae6402949d5db39b0b1
e7b2b990fdde603cc27e1a3fddb43a14bfe15edca96f846d5637cd138ec5f2c6
0ab26cda4e672c027a51925d653c8eea8ce831821c61a5d86d0fb40c0ca781b6
d3886059c0d229061f646141852309262a87371c312ce6ea074ac8680a378128
151c103e2efe29edc2e56bde223b218ad8921248ef248f5d3002619747b8293a
b0577ac3a7af257161b3ce213545a212ef624b797234253ba9595871fbdff751
bb94875086feda06e108f4b75bcd33c9ce25aec2fd0feb25616cc06c0f009ad6
0db28f042827802936195f265b0a5ff856f2a6bfb0111f7156bf6c644ea62306
ad18c747b14897aff1bbbf03b185cca423de9b40e6d9a659f890e884920fe610
99af84183263c425a35c08bb89342a06acb9077bb60182cce402dcf0e9f9b741
fca75ed18da859797cf4ca22d3084959863bdfdf1050d71927fc7eb90f5d1b5b
bd789ace4532a1cc6f5339d89ca1e1d723565a5b77afdb8920d86f06fec36bc4
d9f2bcc93378ca534855700b730da8d2d7c3e5102f764f7ccf8d5bd1e4f1fe83
e20f8737a302454badb7b443881ded5289f233b1cc3aa278b7c04cf3fa105317
346fe2fd6a28fd7a9c2a3f9b2184fac167444619e0c8103c51462227f9723031
b1d7144b7eb6eb030425187843304528356954e1c9866c1bef4335fc03831bf0
24fcb6d74dfb720634a511a14094b104c42c440d2097a25331ded75d1f53b8b3
2277c76ad5a46e49beea6cbac48da6f93ffdc9a9d258dcb09f69286f8c2909dc
831d5ceb5f601606954ccced0dec3f8b83175aff529cb6a9b746af49562d41ce
90938e504e89fdae6527b76f5ace47abd46e7c6c9f7f4e1a6697bb1733eb91f4
a4d81e560f40e9b3f64fc447d2f9323e180b3cd19a252a038ecadd7e13b36106
2c3fc7e2e73791d8bdb2ffc4a682384c24938e5c5b4da3badafe15d55dfce92a
e4b63ec38c6bfeaa2685db1fb961d30e0c29754b68a173cad5379f5c6fd36bbb
67ad46c1c2a41a2c924b4bc1e8e106ff142fa1190f5c791aafb4bf5b57fc5964
dd7b5b358cb26526d242fc09a0aef5495896614f012f51922359e3adccbace1c
c4301ef251bfc70aa99b321b2e1ba5cd8a6b03dc6640c7f431666f79520aa237
cc3e3852313b70cd011136714df55226ece520933b33a4da5a0545341b37291d
ab601ce16a334c7100a90a78f5e5252507a777f2535c79caf9dfacced4e432b0
b8fe99b11f20a201164081fdd3bd9fd7a3a51cec0878bb9ef14dc1accbbb667b
998b4262227cbfe26f3470028c53d1a7a2b9509f01904ee9252e7989d76acb57
6d28f745a2531fd139c77bbe528c1d15e9c69c10ca1868ee113e7e8a0dfda3d1
6b0c18995959de3609f17ea52e508c3343e97e9d28f0e48225330a880038ce21
b28e58d6f0704102377570a5947dc88a4b471ce4e7b429494deca60230efc1a5
71776f9f94fa8368a2431c8941c413ed05a24b67d160a8339cc320978c5bbcad
95e66d9aed2097f4531408368dd8fa095b64f946181d3a3e31b357327703094d
76f459813f6fa638e0e3313b32be0ef5331d33b9a0cd51b3fbfce41245a25051
abb02b47b86f851c7e275f02b7928be9185ebe0c175a88da801ca603eecefb6b
ece52dd3a852d42daf409667a1e860293d7507c43988ca805af268cee35dfe50
6fb6f11b2f82c7a0b65b08c89f88a6af23c30e54fa77282a6d04074199167190
832ba371039cab123624096f71448d135b32248d51e19a1c45d198968f321ef3
9e31d3d6db300e95fa046f7b342210529b9b5248abda8498af92dae7cd857a74
d891e6c0d8e3da47cbdead6362a0948a44f3f4f8fae3d4b5251589952e523403
24a7aae1e9fc400bef4996ebd5367f928c5108979f9ee7358015d8968f3b7d29
06340458f0ce45df8cb0f75ebb22ce42489faa940b25322568740abf60e6c1a5
154fe199e6caf85ff28e0f224b879f7e7c79810411bc416d433f0491945385b9
c66317cff74e4dc86850ec8fe4df648c8c966ab019c6eee14da2f1d3f6e17c3c
fe29877d6b78b94b9193b16db571f1391154b0e9c4924d270097d2b1469aea0e
a1ee24b86d537f30125e8fbbb7dd12d900d3dd0a782404b78e7fabbeb8e3e0f4
68bbd761edf1b535ab6eea5a4ccec0cdd435f240cb73ba8c573fc43e4c2eea05
0de743c81d8827e4c7679c2d226c6dd1a54783935bbb9e09e160c995658c2355
d47f81441d09a56347595f3561da1363ca6ce17fae41ece4ba44a404e9bd4c15
a6433b85ae3cc3f8d5f882522a13fc8946ef39593f86a23aa7cc4d2e602bd91c
aca09d0c77137faad9cc4c979b2ef9317e5b15d36bcd7bd796619f703c1c3eae
10c33cad719426f8010b71cafa2014d0d3edbae2521fe5c9f3ff8a1a116f0fa1
b22db7a96362eed739d9a85b7137dc436a7896ac96ebd5367f81538304cc6125
dfd34841edd732a37629727b30ad642024b38985a3f24516313f6578ee3f94b2
0ebbea90a9283ac7a86235578619f5c2c389b313e505530ebe99f4421e16a743
319e89cf90c515f1b58febee3cbc35359b3233b70d18e3efd5c71487f13556dc
11bb56524bfea67c5beae297cb371f5733000c3336ea4d7572a4ae68af19a698
2882af80e0765809bb0e7d157711459e8d7bd46b7e60ea5c47c751504445e201
f55d8cafc81b17213f472c594aa27204d99ade879b4f70b760a62b9f60042e28
9162a89491faf0f020eb737b1a35b9e567216e3d9d6f0a8713bfd310fd42f139
9a2884d4066b5481268cb6973d9a1e9e224054723d57a61a61a232b413de23f1
b8d593b53291a7d22e39d6c02669cdd826fc54e303c078b700c1b57884a422df
55c5349109a2e08453d4e32e3d4389521e225b5d52e414064a17133a2d24e4fe
79d725b27462b75d8b791b5f4bf1ee16bf4060cf43ff3fb25170635877ac6d70
2e99c3dc2cabd20d9b7d83b55f1bdc29916c033fda2980eb401294e7eafeedfa
1956d4bcd56da72e34d08d33110f36c70d6d926ec6516854fdc0a69b14e92b1a
f8d15979f05dfb0df9696edf794672dc1f88605b92726c5a7d0976ed3c7d2feb
9e5e945e6adb53398132d6ad9884d37b3c953830e6e34d38e0c8cf7e31107c76
fca4dd6964aa16797fe5c9103e47f6ce96372f7f07a2351f2467a104e22837a8
a61e4f00705db3bf7c02c57ad4d134e3e98adb90b9dcae5a3b550be702c76e7e
c038dc81bcbeba4bd15f6210f4477f8d48c9b8c514db37ae5a49719921455f7a
6852e005eb38d12c25393905a3245382226d35d0f516e71e9024e10062b9397e
74b8d308e03f524c88f6a02ebb12174b99394e2d4c5cd60e481a8827eed8ad03
07e2c86b8b9c1c611aad156f3d450bfa4aa7f3aad490314e00a31d3d7343289b
df9ccbc247639fb65966dae091013f98ecee14aca603a845ee421f121e888b62
604964b50312d9e9d000be3a80ffc762fab0c1384eb645bd3306eb7d23a1860d
a2ae2bcc3790e0657d7fac24be39b0e80ed61fc575258663dd329821731f8072
90e48ba6018fb404029c62334a0dd6ac7584a3e615a28ff6da044fe1034d7075
34b4dd87db425df6368f9422bcf1218f590335aba12177120b23ca6c5020d195
7127dffa1c43d09832f8271e7d1edb9b509a53ecbaddf7b53aa60d493734f454
e780899ed1fd947abc7b248da0b1d605a05f87ec65f81856055c76afcc4a0493
a7bfc00864957faa4c85f7fc37f9171d5ee991a21aaf8a770de305f2b8f1c0f3
5d67d753d813cf6c8aaa259c7c47af138a7c8c128ed2f8e05cab01184cf572af
766802297d52ba01a129caa00fbbc78ff203748b53b984aedff3d235e475068c
65b3112f4da78255ac54403acfae6e3f957487bf73bd92ff0bff34e676ac0739
766a2065696f916ff08cadf7143267a964b58c5ddd7fb94126d93e32519ef6a2
5c1f1e428b865ecc839ae48229fe45dceb20e69b0802cc86f6fab7a44850acf9
cf8f4a30c2c05a4ed12c8e20de190195409684946eb9e7153851b0bac8efaa97
e1c00f6af7edb41d75afd001fdc242cef66fbfaf33bbd9567b1b1f32a1cb8b94
fcc45d6aa4f9ba7e4052f960e608eba306d920b374665455a09148aa88ae4fed
025c11b29d7080a4f313c854f9c74081d26b9f2871c055e519b35ca343421f53
c441a093436457f11129f086329ceda5baf54270f8c2a959c6bd6106484db762
e54748f2b46c3b1697f6e8d10dd2c0c7afb84c5c900aa9f5e8da195e0057152e
d0e324d000851b611c3bb5e997171fe794a99c75cd1182e8e71832b9c63d1c76
9a0280983401eaee0c56574422ea42c96420f14dfd06c5a4fdb6fba65e5db069
484b60b74fb575685d64dc710f3e72e198b34dc8f085b3d8168a6b97c39535c9
d54d88369a749288e210723a2135348238ed3bac3b57bd84d0c1bdfdf60f0e3a
6501ffe02a8ba9d977cf5126e2b2bfd97ee0aa5b2a9a3585be5efa02b146637b
589ba3ad0f00cdf0e38a51ffe5072236b61f328c13748243f71002fdbf45ff75
9288c24549a06378da377e305d24732d307b3887da5712d183704f5815419db6
d4c816afc5471b7b2d1fd0bae85ba2bbfabd2b183a73ed51f8d15902ed5931ff
8f114e160a00b4d4a7a98fa7181d2a378d544355b8f2c50012a3cb392cf91932
46452a2989ac1c6d7b92ffac25a1d588dde929386575163884ad6aa297814ac4
124113e2de246a527268cb037c117418d03fa5a590b5392000aca533e210457b
5fb7a77546096f2054151c06a529cff0f522660298d2c35836c83ff948d4da1c
a60d9e35307f21821a10d7d5b9b14f6c7c361b7a9c55df6eb9455bf50dd7e2b6
23eec65ba0addf036e9b05d1fafb1948e6ba56545f054367288b38622c73d325
2e77a0b299648f1c8daf20cc132cd8c18a1fd145fb2e85734f4277b17c863824
0918cbfd09f59a7ec8f31dc686d7284dc26abe7973e3f8d313a44955462f94fc
36edbb27c654f937cbbbb472b9c7a52aae6c603de81f6471f9fa539a87bae5f8
da795556374dddb7943c29e550a6eba583978d2fdedbd964883f58390205e2ac
9cf0a0144d0bfb7cc599a40ed87cacfc9668a7c396a6042dd7bd929facbcecd6
1720839d5bc4fa1f767df4313fd8daa6858c4d6afa52c9a3d15c3e2a4ad75f53
5381078894e229679cb143ae88693511bad7c96e9bb36585d9b30fc6d1d6c919
92f8ccc5c9225f7d2f5f700d118d4e5636068f82166337cf3dbdd332d9c11b3a
8108f9557e47b3f1d5c314f0352c8de817c7f3616841c6b5d7658bd620f8af56
b97d2ef07f914ae94ebbd7b346898ba97bc5360b7ec4c6482c9d1b3d108a908f
9a1f33888fefa5f1dca307a0f9b98b674b649ac62ee353b453b20c227d848e90
f7fb4fc81b7a57da40a7d237c124ac2d70e599ba77d8a7942c3688c3c224304c
85500cf826d8ab9dcdc616ba9fe189000d69b51de4e9635fb38d20941839cca6
040370baac271223394eb9e8a660af026fed08ca604b33920455c91de5fb37b8
6c09ac71891e7bf5eaf674043e9c8bfd3049a854f83530b1bcc20c56cd3c1bd4
b5a545824f243f8b07029055a845b108b17a2c94a879c1a84001e811f95cad43
a2acb5aa60fdba1cf4b2e27582a097f5cf5800525551621ca35b88f0a9837dc6
e230fe9885e669d19809912ed7fe90c089bd527715e094301f4a56cdb05abaef
b016bf7f4ff537d3465c51a7cc2ca45becad72361f0863dccacea3c19b2902ff
d5338014993618bd3239f77f8c36e58de4ab318c628f1c08403e8c9b49723bc1
697da2a348fd3cc60c2064dbaa81060b361526e461621da4e3ef0e462b34502b
5789d3f268fd0e5ea48b46601b68905374ff1427aea175154e359829095ce4c0
f56ee3cd5112d34533937d3c900a969d600671163a1e664020f4274d586a9820
155f378d4372dd1ddc35733e1e62249d1e2dabeb851eedbfa4097ea1041f977f
3ec3b7331ffb0df977486262efa6c4ad394f833ca5fa1d45d304065bc6b0059f
6ef08d9c6ee28c9b7d64988f48974d8e06026014c66de1b87ef750ec81dacfc3
d199334cbb15401a031f7098c9a46798971edb155c582b7179743e99987807c7
7cdf82f30b379c2730fb2709647f49c5d53e5f94520413bff4fade93c95ca83d
6c9d4664ad48e7852b41fffa5219ff5d9d3c6d008615029056c6df2aae34ec1c
0e84f3ccd8cf2cdc3bea3ad6bcd8a9900e9f7b3e611f7aebbd5a8d82af421533
12bd2ce27c2d4682ad2a8b24f9daa5554c6dadb9201c14be079c75de5de12d59
d1d6c8810ecaa77b86920386ffc33146b60ce81c891c364f43f3bcaa1a6c37d3
b10a19732163d2affd021a92d8547d4027b98c78ceec9e061103d0359dac08de
cded1811a65a96c0bcfc37490a3389746186af73bcdb78eab06cada8935b41e2
803156731d58b88aa6ff98e050b1077120d98c2bab68a427b53216d1a5dae18b
9ab16371877da92313b9093853fc0210b2d6a2016889a2c0e8c63bb6b84a6831
1f420ac4f2ddac8b5add156f770c545d02b160155a4ca3eb5866e5237503e7cf
15fa37fb8de25bc54b4ec3fe925e6b0e47e4d0a68efc1c8ae8b8fb33f8721203
58e0d56037b329b426aa446c9dd2ac4e2ffda1c675faa108530db7af740f1622
794e3e0f660d70b6cb19c331719b43e8a016ba6e273f124f68808b31241ca15c
7168dc5b84894dc19dbd5f3d13799b8d656fcee75820cf35e8fd5af13d43a97e
283d83ce25c2e26d11bdeb52114f70ea433ae98b230e670f9f4a275cb9f935a1
d7027bf49025d52b39c4b65ac231ff1f404089c8c0c0293091d09699a858a5ec
8d576d670465df3e3b251db8bd90310e4e2ac669697a3881f14106edfab96c1c
6ddf5fdaca335433d2f38af3035cefef7ad7709db72604575c1ca12d9d9f01b0
6c55f569b789da8f7c9efea428be00cd88f44b9e83efdc2518beee404530724a
1842b29444f8256f2aaace6c835198fd325bf1d9debd8083dbd7f499928836f0
03877e47ab2431a7192ad8254780094893e53f86aa5e972aae21ecef13929915
6c7a8df0a054dbd0d6a4fe0e531d95f94eba5cccfbc7ad1cb93ec427e270f20c
bb7736f065baa1526a22809e3c7ffca94799a6a50782b29ed79e002d1e156b78
e29886e1507f3b931fea35a39b1297829a308665638cc397d7273522f0795136
a26a3a411fc7b9f2ca91da0e9b358ea44c645d11f594b5434980c8816066bb29
a80608816e99435ab354b7f43b1649079dffd13588d68dbb7dd8fcfae02bc8d7
b282dda4d2e8330816f6b90a7285ae31da63f198aeac6d511d9ec40308dd0486
cf71263f0f24dc2e6b02af9989d2b7f7d9ab4e0b684d2ce93c56139a5d87171f
81eaf3f3231116dcbcd96d124d1f8f0eb3a2cb3141d09ca910323c263199d5d5
8cd93f99e70bfabf1f2825f1b6ad88e6c9cd9d7a549dc87cf537a4a31b3c3cf2
fc89e4b24753f6045258dbd923fe8ea43a6f1b88bdeffafbcc4a25bc565e549e
72800f84cc08be806553c98d4484f15a6d53b1096aac16d40ace382b112a0c92
542ce314dacaf77e5a4a99006d51a9a632843460b47c40fcffbcc34a5de5a9ec
b391402e546a3cb1eeef5f2655fc4e90a3d781ff083b9433a02aa3aa0f5338a2
c31fd6e88745cc5c51ade9ab68656001a0f419513e66174da10c646e57843798
d342f2fcc5c854e1eeee0462602ce94ed06d3fb0ba1e0654d8b81288bed947d4
c03fd2e46f7c05a6bfea39c05e58cb5b5088e0cc60ff4b7ee949ec6d73761d14
20204fd63603adc72fc050b730d6e41406d39c65fa14a4d2e110fa229133a2d5
97436ba7d5efde246068c4b35c6adbe1ef92b746ecef16b4b9467cfaff1352d8
880df0d3aa5c33f2acd838253c08de4513b474fc0b57b53cacdfc78f9fe50239
46e17f2d0268f9170402e299e43831f86913bc35689441f77e37f8d0f99bfd9f
8de209dc202f773a0f4f3f1b018234f2c2d09207ec319cd1ac6f1ba1d12a7576
eae64932de419586ffa40dc8e214d21077d740666d9e32fb92c9d90b17746336
67f10db9631a65d6a6ea22a99626b6e6346f2ce46a8c8ba4b6a0da3056a2330e
1895d9b0f673030983c2fbbcd38f6188b31d1b734ef71f65859287ff3c618d46
671fa429d884e1548ac10003e8c33731dddb442279e3f3e013c7f6cae71670ce
9befc73b3481239c8b32704dc2dc9b8303afb64517f4e1f4293a3bc64c0018ce
60e47b9002fe25a5d09f1822738a72876bcbeea8c12c0091bc6a5d5dde7c07ab
c16452bbf4997252f96fd86d45f7277d36c4e71ea96209270170055d786dfd68
14d53c65cb781ae34862ebd0e4211a988dec6e34da1dcfa1d5838c37e1bf1809
d0c5d31827970adff8344d2393153bb227bf8ca11840c0003cd578cf49943e72
790dd3f37b850b08352a3fb795e6350e60984455bfa2c27bf08d8e48f39ebedd
8c356f73cfda897634f07040194c9f761e50ee1a02deb8eba12a58b2cc67c154
28005181319ed63d1ba44d5ea0f40d9803855b45ea1b8a92d2a3d6ba521b949d
58a71a1210eb71536cfa11d10ef98016e30dc7fec6782aee867f926c56803213
a61c9cdea26b55167f1fe2e386418ceef667321b6f79641f7a5b6e80dd7d771d
44d6a17480d13cfcde8a7e646dafb52f94030e1924541203ab6d3dd1e10b3eb8
3b419ec5f39598e5a4bf2db5a27319627a03cf256c6620f7649dcaa0cf57d3a8
11a6828d3876e27e9442ffa76bf3a40104f294885b52cf3a3af93f2cfa7e90f5
d714a9993a58bb81caa371f8e750339eb08c3547a7f3791d1117a4735f900b42
625c1097e7520f225001718dd7c71da65aa4733d9f982ea346f6fbcff6c9e476
fb8c81145d7b924e07ceef65a7b74ad6d8ee636f7a8c538b2f19daa5a059156d
5cea0f00d0017182e29b77c388a07fee10ab99046cce8fa31ecb59893ca3e034
6fdd36b370e192f389ac2226a6bb25fef17076f73a492072b97af107a03ee6d0
b38ddb7ece2a30f991908914b16a4d5b4b97562e1024e177b8e81e05ee27f83e
3f482ff96501c70f47fa275f19084f75e376d0bb559a710b08e1179a36173eec
c3cb787fbf4f471308f4d04690fb33fac3f3f80d6cd713d0cc5c1858036a0bf8
947537d63ffeea80f3ba680d4c5f3534476bc9dd7219abb9da6a2c671860669a
599e7cc50d8aff363c187b620b97ce60c358955afcd2c695149cd1b147c06f6e
00347a1b6e099f6916eea2115619e06511c3f619ab4c65f169a3f55c25092eb7
1dbcdc7d18cec3d8362139b4e3a325a55aa8e41a790bb81115d9e7af67fec4e8
67a9e3eed3a0654214f49066712b5faf457a19ffad7921559bc0e6062e2583f8
0de68512cb8050da45938b7d8c2ca738dc2b465e82e4d28f6d7502c0e91c8233
3d43067fd2c4c66fa85cfd0dc3f6583e241eb9974184db90c156d11db7ce14c1
74c0de186df1990bd385b83b763223eb0478e70a1c3ef0c74e8b2319fe58fd7f
618c907f6b144a81a6efcbe3f3574e58ef284c78fdb25c8c862898b3281b759d
a3239907d00fd6fad3887d4b32b525e8d44ef091bc9a6cbd06300b017f7eff45
f08c818bf8d4c1738bfa3c227d8f5d11cc78ebe21660088cb03233f5ec12e014
653c6f44e4ebf94f523a2c85340086fc7b54676898b49c06ed86e7b474c3b03d
cdb53b1a99a23b8ad73283b7d019d95445f13cbf4da801d6fc4fb5a4028190e7
5fe5c092d6939bfc67b6d2e2075af28febc0d606d24e227ef303b59a09aa4df9
1f216ff8e5602ce8868c46d116ed94576aa672a0a31f686a7377dc63b9e2567a
df7cdf45adac31f2a87613f20f58781485f4f18bd61257a7af0c4ba37e609de1
08e37eecf3e1d7343d559704aa81237e7347b32f77eae63631bb7c155a51ab14
e762e04fea6d0cf4e2b57d1595a798e8e3afd46588c7a539f764c60d8b80b6da
54bcb786f4749ab9f5c3c2f9c2c212d7e29e4e9cbb708db834dbfed2c20c0ecf
8ee743c6160e59371697fe387ddcd00dc7bc2e1cab4b86cf43170e5414171b62
be9a20815820a6d694d98423d5a77d057cb11a483ccf59a64adc8cb31bf38fe7
3d3f1b3034dbb4a2ba1ea3e6557ebd08e2c6b5c8f6eb2ec12f1cfc740dc46ca6
5262fb27081d4a0da5992e6bf996e3c52e96ddc019deecd3ec32a9c6ad1ae3a7
d7629b7d513773d3cb6f9099b86f9e1a7c0b98558a402eb236d57d06c41cae47
d53484020742d5b9e853a714cff0b4e2f80c38c7b58a779a174076dfda9adb2e
143c46ee7c5cbcea1ed90d088c76e5cac0e12b9c51cb89a325c1342a1bc1f1b5
2384d3cb9e916d52efc84dc5d5bf3750f3cbcbf29346b3af74f2cd22220f259e
14d0d39aaaabbe37bab12141538d12d75d3c10318fc8452fca864a7534716bf8
10273f14379620493ac74f1504e36da63a9e7fbc523671094e918000d314c44e
b60f7735fbbf6ccf3fd62497ebf9e43a3c0e44fee3c2a9657961375f4aaec3e2
89053fb353f75f901a6273133744d276f0909ea488043b97e4a012964e1c8aa9
bcedab674bfe81d40d03837e16605d28225b06f6a2317c08041c789d8c77959b
6fec85e7784531dbec03e3c61bd448c3dc9fa9053eaa10147c6f6e38fbf15e51
642b9145179aea701c19d06c1c169ba5a4fbf54f90c42324486969f875077ba1
47651e46b82d351855b2caddebaed062034c2ed47318e21ae2978b6f329ea82a
2790fc39db04215c04411f45b2a63ef6a4c9ecb6932b8244d2a8a93693c8949f
7bae9469c3467cba2e83dd650674d7c8715a0d7ef10394cab75b77fb7c9a0f4e
6f49442008206148192c5159aaefc536560893a3939828171e19e1474b8be0b4
422783d6bc8d757b6b04d0e1e9da629d82e157547a08467d8a25a0791257d0ff
d54fd011d70bbbc083681c39b658793c77238bc0aec8cd1ca787a5ed859118ac
fcb01b86ae07f6754888f70f9f3c64dd88e0d9c7eadd275f2bc127483d979d4c
6440d7043a3981b810f9d000ceebfaae9e82475948e3ecdef6937077c9d32f12
d58a3b7027115167f8ecb33c2386592c7d71f964007129496ae9980034828563
3b9d10e4da7a513de08483a08fe031ee5bd47c219976805936fa9c5ccc2ad310
19700f4a59dec3bb11109e16e94048311feb51078505eb6a29530f45479cf80f
c12f019f60f7828821805d986e647991e20fd9e3a18016aced3788709ae3dc89
cedf6f505aaa4c65a229d56d29b6bf96fa2f989eebcb16589eda210c4cd52655
2b1e8073ce43981ded6ac274bf6c2736eb3c2dc4674d467ae855752ed5cdabd3
eb7dde563dc430ec9b2f52bcd789662e2f2396c19f39750eb4933a90e81901a6
dda1754ac1751a7d635cb5110827df051b47ffad25f0f43d62fd9021166dff11
343f2b5a46796dc4c4f498f1f03d47ba3021b3f0e50b92dcd6308643ea73968b
b1783c5520c5970f18ba82dd4e7854c6e054742b31ef342506b8ae50dc68555b
c461962e6388e8889b86eb8e4da31de98474d37119d3342f5e0cf3c972289258
104c4abc237d749292a6118afc3406d5fdecef553e480dabfce9087f62af1309
27c90b821af5277e13e87518a1d27a29366ca1b717033b81b9e21aaab4fe2eba
3a3b2cd4bd5045201075cb3b39cc79c8852a3b0f77596c310f9ed336d4dbd102
9dd8a550efd99f3a79a4f34971618f3914bacf910994e8fafdfd803b7da2be1d
b2c83b135ec733bafb79fb27782ac2924900c38132c7fde5f861b7571f579af2
0a6eddc1ee6d81f3b6f4bd1da5c24988456e44403bb477f9a44b56391282243b
62f2ceb7abc036eb8b884f1bf98cb73a06446e656b9b1e4b22ffed6b2a364d62
75f85d1ccd5ae84aa910d24484e5be19f9cc93c7944f048836134783cf938ae0
ab6f2dcf260b3112ee617c7ec4200e6c7a7f0484f60de50ad7a0f59cecf129a2
3137c601643831112ce61431552a63f709a3003a6f4e998815f05f1c9c3ceede
c866dd8a19588e3db7d1d1c7b745d1d9bc31e694b57cd9f272f8f1bedba36ca8
4c6c9f8fa5a6cd50c79940701772d7115dd6b881e6f9aee6486529a6804293e7
6fc88cbfa3a3cba1a0ecc621d41822913e09e8e06f3a1c1c8a047f68c6676021
4aee3a3a974f8ce09bad8edfdceec3f69bdcb6435254d54348811e4911c2a7fe
aec969be588742d514d552c66e60f5a7255d8cd023d30a3181ad3a1d31e04e5b
551bb1825c214767058ad648fb3efd72be87b366798468bc730489cac9fe7084
b9dc307a73061c0dad6d72efe7455eba27c057440ab7977c762ed9504c3e6d12
980b8251ecf4799511d2b510633e4d793a679644728ac2f9a3f4bd673a7a3885
d4e2bb19cc0d0ee38b7736f9f037043f06e23fb0428318e0e8961637e7138101
049b9530a15a13fd9ee1aa34b29a56f17e50a8743b373198ee19708c2d1ca442
6754bda56a2f7f3c4cb34387825de4bf226e6ffbbca348571a77d7d779eda627
76b9605dfb86f64fdef0f13a8f61288632ed6aa0181c7f0947dc84cf02b7d7e6
f582c3db41c857a10594a1138f046a6db9d89a91624d68bec27dbf24ca38086d
8c5a879035524522696d4a3d2e4bc01242bf4f335a8a0292635bb9253013902d
ee5d4b6eaacf697e644ae21881435d181e2452536f2bfc93eb82cb2d1cad33db
17a821ba9debda697f42f18e0a0967e2cbb4fba4025d9130b65ffa87d3b93907
180368cb76da8936f862474e651b436337ccb76081798e97e571467e94855561
17b36c337498b8b4ecfffd29a90863ab2073a9f96f84d8c8faf4283428b3929e
26b9883a8db3edafe1ca4f3f16f4578efc263dcbeabc6be462504b621a42081d
bcf4095246c8e86484443ea6098a981552150420f70f81dd17cc8b852bd289cf
706949c9a1d7b447b0c0624abed4109130656e7d9842bccbd67f0eb5c32cac4a
af413971f55d6d87364307309915ecedb27339851f8ad8e0819e5d1b21a2db0e
2c8019fc9532f8c4e01e5b4601591ccdf0dcb1b9ac11d76121b2de6d96ee5a08
145c5adb9b044140d238c9b1cc02f3d74fde0b07028c81603a3079b61021c60c
df4ee3a852bc966fc034e23a076bcd5115ffd9685f5384107ec27095ad4922d6
d052591f952c1c733363092ffe41278745c96ae64b5beb6b4467cd45b8067c2b
6378d83c440bd79b1a1649406cd01340a4bed3060db9126a6691cc0d0e15331d
7bb989dbf10c8b02e1af65dd4c963785aa30c16a3bb57f35d27f4887b9f0a04f
9f65ae1457db643d8e9b3de0bc1a1d3586bcd5ef79f5afedfcde39e9bbc1916f
ea59e74e317889ab64f9d92567534e59d1f434910ac3bc797365ffbd3295a534
c1a56443c43287773ce624f0903f4806329543f068131ad6d9140bf8efed987b
f554f6aa54300b586519d1ca9fec345bc538bfdaf4e546f411b81f078844c32f
f9bcc55bab3e9ed1ec44c01d8ae1213868144ce7785c50a37635ebf0d0158f1b
006328bf63b28cc20277fc32081fbdc46ce42f2f5445bf4d04d428cfcfab9f44
569a696539025e2c7e8524e1114d35ba4e2a1f56c545e4741fc2a8e0997261ca
54e99e3abd35234a08a70fd04943769d4303d502cd2634fa777cfc3a78ed9629
7be0b559c8c8ff6f40c40c11b5a402dac99541fa21d1d1b8ad117413864cd9ae
e4bd2fbf05066ede920bf117635288cbc3863953ce8894995c2697d9fdc6e911
106244247b3ccf48671ea3915a9d594b743553d519da7c11641f2f5883dba391
924cf2a2259222d694a5c04e8438ef56d99d60e131d726724f39a4badc4809a3
bafb6cbdd8bb26b907bff73f034c71444dd3062fb7f035b13f189c10f7d72b93
7fc16ad929cf3b9e1fb95b104430701fbdb128d2c41f9df68e4a96cfa2880823
0d5ee35c9ceecc48ab041037f923ae9d1b661ca8fb67fbe37cb80afe95db4833
08415b09832d96f7c15248ab4110dab4f214c91aaad251d5c42b10b3e121613a
e817bf52b5daec74be2666497d749d33948f5f297f7fed470f0c34c5257a0232
8bff4393e4a9248f5e0d2f33f554003888fcfa0f92fb5eb7dd40034e981a18d3
8fa1d747072b699c2a6bab4462222d44dcd382f7d1c0522e4924d6ce6775e290
59586f6c9188f018e5f55ec2cdffed2e368601282cb9a840f8480960cf907b22
e2b6c57d15a55012035ffc6d3eec2644a3a9dfc5a167a79aafde6f26a414dd3f
2f97ce591d5dfcbe7082881fb24c4abfb2ef24e48a5d815b4687b78df035159c
0907373bed6e4700bac9a3df333ea6f34c13d8ceb31b225d65a9d9357b2f1fa3
6541c632168344bc3472b932b34c4c2d20216864215217df3fe405cf5dae3ea7
a5c5b61d05e370079c2c42a8d2211777d6d640098e3e029778ae905fc5da00e7
0aa432d959fdc71c08f98c8b1e172ec038a171f21737c8aacd8a7c9fbab87810
87f68a0dc4d3764cc619304825a005231d915cf9c3f8648cb7308290742a7518
d4256907a58754c95cb11ff48224a52c974c2290254b894bbd8050251061e668
deb504d349810fc3327d43d34c76390144ee6f10a304ba1fb8ef95633ad38433
4410dbdc2a2ca9514b1b18f948a990b4c7a5ad911c599e99e8a6bfa3a7cc3922
9b1dea5359ad3549e5796de48f50fcd890f6bed37f6da6c9de49db4fc6654736
04983389caf27cf1f668e7b97ab8f02a83a16a272ebd9c9afbfe92b50a42e34d
37dc1503eedfba6a3c4124c96a268c7302a3e659672ce5e22ba02e0706b13a91
344496fa56ea1f3db111908bc8d64cf0f9d998082445693275429f345895c44a
0bc9539bc825136f6589330917b46dab10b9726040d260e54a3490895d49f4d9
a0a1200020f3278a55538e8c3724282b3ccbabdb130e85c23a7c5231d1a9ba04
495411b6c44dc841a9f886de4c1bf9feaaf5ed6939b17521190024247a3518fe
b9177978ec859860905da812cb481564095ad51062986d1a5213478d2fda4c1d
b568d66112c216a100bf816d31e5152169bcb2568f81ade6773ff7147307ca87
65aef5ef94439587398744ee51d1f6f340e7f23ee1e3538f1435ea1ef172a46f
409c1abff3af0baab17352561518cc7d6af8f2c546ea44feb1ef7373f9cbeb2e
6d079e8490d45a85631f6e33e483c02f138625ae5da5134d479d48a897446302
26e4f9973d7a37894627f50a8582a21bdc8fd2dbbf9b42851a1857bac74a7272
0943ce1d3de017783b2de73749b5ddbce2993ebfeff7a11e12a78159f2ef9f63
4bdc8afdfb0231bb6e26f11acafd45582d6afafe745f0cf4971a71fe5cf3ff48
9a44d7d9583030126807fe5c2954a75af8b7c82dc18d5a3506c3af874701d632
33bb88973eb68609ba7adc1ad565873a92ffd4fc4c1475309eebfa1c4a5e9c40
7a871f63ec425f92ffdf083b5410f1f0b54c8eea1e2b69b3086e5c79e526576a
ec5ff38cc28229b8f5a71a5f10a603bab449a52455046dc6afa6b8a084fe7223
a39e51afea6932b4faca45f5eeaac6b1d9fd8d5995e0d98fcd483cdcfc609a54
546f2f3fcdfa60dd551b150ef13ef5180c7e507b7cdf1264ae9ed4a51d865ea3
e3cecdc2119951808f47d9e1ec3d063be96210e331f33c835689743f7cf07b2e
96b4366e4b447d13fa34d6cf3e60ca8752f0256662b9112e7f13771f01da7cdc
959fc86c564b161bcf65282ebeac376db2200a3347788006d105776a23d6f3c8
8ef8e85e3e359db8e400b2b8be789a35bb709ddea6a17d8692a35f7fcd73b0d3
dc697967f4bc95841af8f5513c78ca328d106b55aacd73f2fa370523f59fb845
65497d00216b846df039fe831bda92dc44a3e334824d401d909b6f56edd9903b
61f5fe29e175d49e7b20ff4c38c2c2cf3fd52c51012be931e4b62f00f38bac41
8c5b9ca6ab4d20743d93c9a8cf6e716269e89e3b869a0dc73e0d531af38af2c7
b4f074f15ef8cef1b865a10e7c5b1a0eda7af01fad3e4d0e80e3cd1a43e1de54
ef30e365510a906d8d4468b316e905cc92bb231a6a9c6bca003aca011b5f0276
90664370304a0e34c8be534f7c4f2b126e697fe394b2fba6a9a25f598d185058
563c0d093b054e2bbac5f22909f9a1725c84caeff067087b879b73fb612396a2
3a5b7c32f5de0ae7872056ce41d593d746ac832d7e8805dc70f1d856d6c1bb2a
744ffaebf98c2b0dd8beee08bb2432bd08e043d012894436d30a1b2eb69727f1
2d44cfe56cb6bb419738c88d02fee1c9173538adaba709657e14fa1e9827528d
ca9a8688dcfbe6e4719f0e7532177481ae2bc279dae24ba04279481db27adfe3
7e7325523d813961542eb422eb147597665833021ecf958bd9d109023ab0c7d7
712d7462f6f15cc6dc2cb1a19a0b7329fe23e8d6dd3cff5f1795148cb434e6d4
a3cfeb5bcba0e44d9cec017f11ee4ded65a545001fdc8a324ef8b1899546702d
25c44174f626568148ee3b0bd3de7dd0f80623cef610ca07ee9a3beabf8d4f3f
f6ef09e609c290e9a3c1584ae723301e83de15e043e9b8d1deb04e2cb3b784ff
4b0274f1c3b8bf71c34b5078afb918fb23ab2a0d59409da99fdb05f8d7f23a66
eb1959af307e1bc690e5fa4113d87bdce4c1c7927a818644d2f46fd746c9d5fc
9b8679bf4366869db97f0c6aa87ba61457448f7e13f5006562190ec8c9ab1b01
979a9a7c37551fef8598cf925f5d9bd277b56b6c8e3a1a4619255acfc415943c
ed67255b89d7657dc860f88c6f478dea0a0c91ae2c88d3d45903fc7d0c2f3b61
694464885824eabe5b917adf13b3fbd28707623b6f7b5784810c7941eca13c7a
8e7ee11d26240fa270d5a8ae7409197ca52a8075e40c95184ba30697013832d8
68090a5c303e3c8c836c1784000e47d84c24d7ef520293cce024d91071f964fe
fb5d319b577297682ad3823298d26302cf09e66beb6180824e6263e9eada7cb0
6219409e9d325ea93d61356dd9c03293806b86a312dd4c6abb031e979d7e6a56
3c0db1fe9ba19e35552da6ce188bcbb8afabdd6814060ed1cf36e85c88bf9b75
263598879b7acc4e5baa672246f61a3b809e41e5a8895b1badee482321b9597f
8251cece519c7decf1f0203658c7fd66999236685fea9f7a87ea29082bdf96ca
fd23f1aab2ec8e5f54cd59fe2d7abb4df63efc3298570b99d7d208d6cb1f5d66
914b08f4654a27bcc6c926c020b5033d744c9d0bade606bcd7772fbbb1654312
1671b77d887ec49d5df768482b01ad49f5db59aa76dbfcc725319ea4181d6e0e
340a2ba21bcf59514771a7c1b8bee3f780c7b711579dcb1ba9cdd20ecac92b05
903d0eadfae2715b0ada1c974433eb082e6ee46041e37d4876f7abe42b51038b
deaff7ac1a17029cf956b69f9c1710db0dde1ee10c3588de2cf8e7c363441ee9
48c9b57f19aa1a5efb5a5b6064f351a180c9f0bce457cba7294ec0fedb281d06
61f92ca09e0da19d4a9c79f37a088371cd5c459417dfb04335c1c450defd1a66
7e76c408492cd139a9cecd352d47e09a5e6d7cca1601267f27c32498a5107d6e
c53866caeca644ca2dd972ef5913dd50cb3e6835aa1894cd42db599c5b61eda3
3e6adb54cf4bfa210b00bd01731af4ccc39a9c7b21cc6d647ff45b0315f4aeeb
17a9649c2da84c2f9efa5ca467bc9fc9c0bcf11933189ea324fd048aa7b31b21
6a835a4f680e5053595d8f3a1ccde16d51b3bbb2891560e2f74cf2fbc0fc9272
fca8f7491afee1c52e3b1a3809bdbf6b8c51ac919a83901e69c1a0d6fdba76bd
bd1b96eac30eaacd1ce42da4cb13eb7c12c799c3e5781cf9d9290e2f64ae2cf1
d8f1c3b200d15f6d2f9852b0c391f8f394d595964cd6c4a005e76cd60e91b2ee
d9c6e421e2cc751a7d63e2cd9ed5f3a178ff31f1301c53a4cd7e221917e877a5
03752faa79c19299c4fe48c3bb01397242a8e4cf1ab9f1276d64dc392632be0f
f7843f41f4bbc50c0c733207dac8c9397aa5900d73811c78953d515f56652fa0
c84f09172f40c57c8c60bc026fe41c79e51a0663d3598e3138a760be1d33202e
9a03c9d5db3ade8870c14fabada3ca275829d93482f7bc5dbfeb2f665ce2c815
2c61a42f6a1f94d7a599cc489b9197e8ce53ac73d16d266beee3015b023d367b
911d16ae7c18bddd5453fe0394fb6a082de0be651785f97cecc91885cfedd75b
c7ea78b000a1cd75d277e01249a05f2dd1a29636fb9413f606dd17c58300f25c
68825888bfdc6ceb83f5588834bc7540f649d8ceed32e198566d34c5a591afae
6a448d9128caeecfe8ed2f6ad4f7067aea1ee977cce70bc5489bd95c18be16de
b4f4f07bd2f1177a47cbd8bcfa1c1873ddb14507512957f8bf15a164d24b2a87
d4d1b1f59ffbf420f06757f7519d9363b6427fe70984de9484d31b2d4cd9a072
0d261663d836eda4abd567f70a1d4ac14652cbae527a2a817e84713c5988408d
b33ac0b8b67a569d4a2947cfcc99da380ff6917c9809253452535def5004ff03
2ce75022d75a40022d720a8e9330a8fbffdbbaef07324358e050ceb1679c3a6f
d635c1ee555930a220147083cfcdc4db19b9583023e90a923a1db609c690f8d6
d6b08567223f387dfa1b269c8c9e898d645d183767e18e327e55afbd2b1e5e0a
a8e46ef294adfbd9224a02c2387fa7b266fbcf985991781581ff782977e7df9a
6e8a91aa02c9919f99f5a0f9ba5b057d168e96f53ac2326e37f9b093a33993f9
4fcb2b32e7e867cbc963ccbf94854f9943109732109ea5ea12719822fd46ef83
fedce6adcdc61502d389442daca3b55ba9ae7bae3ea099062a78c5a0e8164504
7547c7dc57d9d8326ffa409f4bb51451c99246969441cd0ebdb9bba53544c6b0
3cbaca2d733c622072f3d786a82c7dc1c985c936476c2d4f8a2ee59bb816ea6b
5f81cbe638cb5ee155bbe6d8257b61b2688c5f3e925983ebbe4c2728474d4163
18971391a73f54b50052a9990f11aa65e8c1f5d39464cc5e5c47c79abff141b9
962dbcf19c15409ef0571e7efb8eefce38e6eb164cfa923969cb16db5eb71476
d086271c835c4794bfb9f6fc1218c4f61d6edf442add3f15295ecb1f21cd993a
b2184e65b4f906c0d41fcc474c3e4374d4a847b00d3c670a20285865179b79a6
cb9521b56bf46181e172584a6ff205bb503c8fe35e64c802e0f1f8b3c344f39d
5f604e40fc0c6a6150dbc09b44ff32f7e501f9ee67b5d4f42d8d79fa3a8efea9
a4a15806a175dcf96b86fd5d921173c5cd2f7cb9dc11d8b95b9f31104081426f
f4b37756583fb78125ff07c6c9e8eedcbe9dfd2743b28f3326c2f643488b2ebb
9c008990b7c0ffece6bd9b801668b1bd508aac2d7afd10811c4646b68b1a405c
7226640c827fa0d1acedea81f128261a793c5083824759532e1c4e1717a93821
a9611fcb9fa16004b5e5f2226db4ea54167ac22bae530b0e7f6cfa7ea83de3d1
37838cdb341cb7dbb946641f524f91929641cb42bc3f099f79ee4050613dc638
c2df4229018db4e4785e9ccb647a08b126a1dfb906d501e09e37e8c02d7955e3
57c94c31bf4133e2dd79c5400d82a4c03b733a462464d24f2570b864405f56e7
db3b0a004f20c5479bc63d105a766f20d28ed89bf21505933da1d11f583f4f1c
17defd8ddb516181d8316e1a1d8160e5ef2549b3eebf6dff5a518018552d401f
eeb998c2606a555103b59650f837ea66e4febd975b414ec32ead2ebb37bf1620
de12a68a5c491cf6bc413a32f432b0bc7d1d9fff071e3c4a7fe58114aa401a4a
ad55c47150c4a09523ffe0966e3040f43d3f72e3fcc453f4b5da88ba899304d6
87161c005633dd964fda24add629d5e0bdead02b272fb364b7c23e2950bbed90
4c25f600d3bde258d5e27b0f61ef7af3ec2b29050d2ad0b4bd44b79263fa20d4
98471b717b337c0f4802985a7d43df1ddb987058d9efb5cef37901b7a326195a
5e879c5a3b08fd0e9eed68602a6933295e8f5dbcad59f73e9d4dafa866cbf0bb
057c0922d59cd711f55ecd41b9a8ad327f399c99306dec228e3ac2f960f5c022
0460569342451b6ca0f4b65c1df9a7a3697bfd8ef586b3708156ecbc57b5d89b
f28a01027561f5e6d524e65f3a32eed44283c35b13b0e7f057d61e75bf70c8b2
911e9518b78bb830fbb66d361b332d79d2f78f43c3d9d90d5c5d0a05af4230cc
4f32eeb9a7bfe9e6bc76b247643b9c34f3f6fa9cfea6ea9426cfab208129cf3b
61b5cd9a5a6f0cc21cf1576f5fd7f2ddbbac3d45ae6166514f31e7e45704efd5
6adf14bb05202cefbe389b68a29cd56a875bfa8b859e15538c3e4f75707b0514
4c064b49e08c1873f4127aead80ea47b8c853d38d76e798c34a0f092e512b276
42bccfc9abcbda6b659d8b6caed6056c993c1bb730cc0305b273f22fdb9aac71
9ec5f546b2e7d28672f2fa387e6f0be19046a116d1a47faccdac6fc6cf6ffa82
8dcbc422e97500c38fb775e2492bdfd85ee24cacf5bd5eca1b17d69867c44ba4
9608337d50f6d26436ef41737febcf20172b394dfd8a2d7abc5a8352cf00e9c3
43ada60b0fae732f3da60a2ca5d1d8143f2e609f119bc449cea79a75fcbec8ae
ffc49bbbc371e6e6fb317ef7ddd357b191d874d20497c3830e04c1eeeebcc574
83df0b73c180eee7001cd9ffca8abb533717d7a641faa6bda4884cbed2b24cff
03f90e14698c602153e7af84b1bfd76e42a703d6b228064e4a9c274dace1d5d8
6915ccde4426b9b5a908c153bbc7c789c315b909b7e7cce59c6911fb2955407f
131ca5a986105d009dfd78e30d8b12c9cb0e22bbd0c38e684039e62bfb255625
796df03cf56ea7b04555b5f44ac17c0e99d56b230c11818d3e2a4c3e8d209330
a2fdaa8dda25a6e587f31d459580d81dd6da434bf036194a989f5fc8954c52fb
d9f4717282cbda2cd9d2518d937a8487c49eeed61b92abe4d17563afbfe9d38a
585fa275376345d1df0198b26929171d11d22b4a6a1fad9fb109dbe8a46a1561
e60c4180ecbc46a4685b69ee86be2516225f2dd56d54f16359ff79e679052567
281dee47f23efce23ba70b7efa2834efcbf0a6e1a033d320df90fa44694cfa38
2bbba156f34b2d1a85594151e4b705d1a285f0c6385e169088018cc3f8be28eb
69f028f3436b748f239550c3b2c3f40191dff3e9bc0135844598ea3825f16be2
a2f3deec27675a2640e2716fdf40c289f81561d2d0d1cdd7ef1d5f8870749534
8c2062387d05dcf380e9bd4e7c6ae04f638c53aacc8185e1c49941389618017f
3898df5112cdc9bdb7627532a5be3724127db81fbe09095cff5b4cca82787c92
f6f7c020c9f4ebc0f65c536f780fe781494bf4fee82dec335ae229de666277a5
491b00955e27aac9345c320c38ad2c85387fcb833039f93d3a695a5a5ddc0c71
c7a2123054abb0215f4a50f0312c17d4319f74b84b9dea5e809180a31ec750c1
73c2592f03719d667e0907949d0de5a6bf60452922e14f2c3730b09aea035038
ffa57d77def41ad448d69a8ec599084cccc513e31a107bd6645041dc6d489510
68eec9d5b0e3645780a9fc81e522fb2f1734600d929d732ee5912b5a90c9d27d
6a5260bb6b590fd8d5d47019a3ab0fb1ec4185b4cf2e371b43c66f1c337efd8b
e382e9b1b7e12d92b95c179707faf378965b271a7d945d32a55bb0f2e6b5e054
548b1827fd141a26b1162803f36940faf4acb3330dc5cda5e5972716de0f8db0
fb5a1098d21d9b45a1d5f5caa0cea736b2032baa82a16ceee48d04897f2d90d9
fc012a0f046c9a50025b7ba9874196a55c409b1114579061ae67f3b500443d72
010bada88d2d9a32b75c7831fadce5ffc786809e92085d613ad457c7d2cce4ae
434e14c2bb00984f9d24b0146fdc5e26fa95f9037d275ca451b9cc3a65e2116c
59cbd535af352cb9b1408314597da7b806a566c7a505435212136522a3ceaff4
eca9d9bf96cbd472371893dd8f2a806c1f1c77f0ce799bd2117305a24db44d76
a153b666f6763805d7cd32ed17e97b1fa7bbe25dedfe6aedbd066158bbd1b305
32ca2dcef68b2afac4fe3ed7a19207c48b110a35d1e6a1ed95f234e10f432b54
4014fa0f6d3b4c63d9e36ea84c69b1f6dba8791a9e2f65cde72f13217b0f48bb
d760ccec97956bd6a9badd1b11e5e334c5b6aabc798ea34d247e6c5f98d22aed
be9e8d02f202aefd4262ed122598a1bf9d3e5e08bd5d86a06589414e0a866a56
0538488623062df79bb34ef60a6479ad56886dab5a7b8e99686014d0bd3ec2d5
c17f0d63322931537ce007aee19f7c25a6ac7b5a0eabe47a630def345088c483
e4d3454458a2b9c66e9e7a3400712e1514a6d2d99164faaa4b8a24228da5096c
221698f9fdbe73f8af4d2fb6faecc990c2e89142c1e4b1dc8f7f2c9f57d9224e
44f0e66e0b3d56be4f818a77aa0cad6e4cc5bd97d325db418fbc914c020e2b9d
c771cb79a2e227b8a9350fda5a198f99b54ab394af4923b7f62cdf6285b34c54
f02600ae0c6026a570310a22ebb16035824480ca531d5afaf1baac80766d33ac
f7103679f2458e8535e6cb8f60970740ccaee1e31cfb6f2ab3147f4edb443392
0db0e67e1e924bab10839b47a0cd1af91e8156f59ee70f53cd7950ac7d75a977
dba203eb7ea8d5c32908a832f2a208ad59cd1c52d9208a996e3a831309fe53fa
24d7a9009e36c6cb5512a0756da54194459af7aaba9cfae07d465973c163e513
6fed0cd3e103ba2667ebdcccfc2000aba28c72ba791f1e0ef63f59753f0290f2
1bb710583704b2caaaa21b878e64a5d21c6cd6769b6190de769e119094e909d6
edbf05bf0013d9ee8bcb9d13d5d91b6135f68941d313dde2e997feea48f099e5
f1fcb01ceb225d287e2425a0904b51aae8d3780caec17003559d9feb07ff9574
b2559a24fa86cff0c2d905bf09bf4390b639711edc9532e5eaa215ac8288909d
68266b7ba1c3387340a128e37e30c8ca8579d7fe9229436e5a15436942350b9c
ffffaf31b77e252c7a85a2690beda72a689cae9bdfdb31aa5f1f975be25b5f0b
b7483aa39d258c69951493500c2472063279f672dae2da80667efc070c4419ed
f33da2e8127a07fef0e5b10ca3c4333bb6a8301bac6c4dd48b7a7bdfc2557491
6372db22757fa9d3247dfc61f9c05400e1fd99afb097546459b067ec3c6f09bc
3bd54579044df1a01af8d9f3836f0382f17accd3791d120da4a846e20fff14a3
51d52baf3b896725841f809ad7e511f8dbbb9063b4ecda02f451689179a7a999
a43c6ba28a136925b49ea45982640a27b2551ca7b61824b892b572211d0ae0ef
ca21d46d8f7c72a13785a74e91fa6af641e403fddc1abb8c03377bca47ec66e8
32daa7c826e9e005d460589083985c987efbe0c1fe5b6693451569a3aa02de63
ec8551436cd224c91546ed316112a0a5d27e88235b2822fc712f3d67cfc03d7a
4146df19107b7c9c1507e5ae200d3fc465d6bd4d5aa7be3041089b0acda87f69
bc4be64eef3f5d38ee0b24c885b37bd4256a5f5d9ca241c2ac3b9ad3959cc2f5
cae32f1e9d97d0336ae03f1ce970d2814c0b8e49f2e184af9b54150eb77b6b15
d8fd645d896a31aa18cbb95e71e8ec09f846d968b44f95b654160e060d3100cd
e695caa2203b60c3c798a0076063311b29aff78b9672f21ab397285058f20eaf
c542fd539aae1087a15091c787d1085a1fcb3fe0716f17d54b6d4b76e5b79208
dceac2a7382b8788f4afa9b3058beefc7e53c897e57a9b729c5109fbb73c06f9
616f7756f6367783e9e3169bd4ad492b4e0ebdb3dd4282533ca3c74fb9cfc7d7
7ab9dfc0e15b43cc21a35e2c2e4b871997fd8fcac6d503c338a28c4f5a8f2cc5
c2e572cbd7f84daf859dd0f5cbf842ee5f64e683a132a99612250cb2e56a577b
58c9fe03593af2c8805130d08953206bcab1c6377106971297d840ef3bd11eba
5b4c1ad84b693e088f834546a5dedd4a39d03259411cc9a4ad0c6a1bbb105e25
51653fcfd9ba6fd8b37ba8bfea32f9b09bea059baf0c3697ef2367098dc16e4e
ca1c9bfff791319a5fa0e78918785f6fd180d5c502f1512ea162aab5ba19efc8
73008a43edc9e8808757fe459e76c4db8631489b46bce30bfe384e62cf7b2339
c2e346278916ee4d58bd730e2a0532181c6380b2acd1905ba2434f44fad3cc3c
2e733f53f0c941ff9cf2e2ffa036c1189e617d3dcf0badc8c4242a6e84c1ca82
c9cf210851c4b38af1a8b9fe9b308b6cfd04ca9d73dcf8b98590b74d2dc393fb
2e783852ea8b26cf8c9beb079452e185235baf6734e592e08be8c0e8749e5fa9
ff17b02aeb9ef7a46aa6836c1c60e55a9280aa2e1145c2444d133973cfbeac9a
2665e47d700721f38427d72d511b67e88caaca8923c93e48dcd8e61de788d4fc
942698f9b9e8c18d6eea7ad9a29cefa45f77ec7f684f2821ebb527206d741ee5
34252ff3693c1464c3a9366172c29128fcd68907286f5e4a4b868f9e487bc85c
51175f698b18862533427001b0a435c8c3f7fab8ed12b59f69112b544d8872ab
71adc347c39b2d07e4bff0a31a08459e74091e7e54b046fb88064eaaf3944adf
5758fff95dd6bdec68a98eb5357b58a5897ab774a595035e0a0c4ab1aa156ff5
17fc68c2ad275361b4b9038c240f4fa58e460e74084f4efb0155c442fd98c166
975ed6e726fab4ff04c47b28df3bfbc5de3fdaf4b1785b5add653734b308a6b2
586bed24f52db8d5e84fbfb3b7674eae0551635e72131d0e5902592f2151ba3f
6afc0afb753d172538b6f97cb4ae6360bced7b049b2e7793443ee1afaef4cb06
46e8c4aecd7938a98a0e8f63c8acc72f409f6fc5d62436d0788d032b8d234950
1a80d19bb9e3f3b4e1b466a5186feba305b086b62412dcdebbf302f437c4548e
c7d7c4f67a473095c4df1a21c50b98284085c0c0e386c07ec962f75a20d26a50
e2570073601eda0324d4a0c9944ed0f50d4e91445bb71cb7e20ec12f872fb097
1b5ac70039ce1dc5cc28104234bf3f8824f35eeafdca8f149dc4a477280033e1
c5873ac7e6cce535dc80369bda7bacb145b864eaca2a26440c44738d1300db6f
1475582e53c93b8bdf94b8596a59a3b0799e5bbc82b90b53fb559272d409e6e3
99cbddba322d1080f90a14f4106394dc6ac23e3f469ce06cf4a5341622d6e6c4
077270b4ef45bff99a3ec56cb2dd57283538cc628efcbf8dafef42e1da5fab39
6f8e6fdd99e06388d1e9f01e082268e82654252a8a9be160f28d694099de6fcd
72c76dca496444f6d82f4ea26bb2ce3c271d8be3d7b50e94d244dba81dcfeb45
47790265c09482baad627280c372ed440e904ca8509147a1486c8f723ab67326
6738d72db48fb9c909e2398c40212d7630e26f5528533041437be81739b74c20
33d23a3dfca807a3af26b1f3bd228b4fb70b7895f5fd871f8fc1c4e08bd68133
75dab488c11535022985c4e47759d4ac66e36f196425a1a5d9854925b55ada7d
37c5ab5677992bac4e58998cab105f0822b3663c1209e96b24998a05006bf908
4bcaae5758fd3a0d58e24087aa9e3e7061515815beb6daf06267f1a1939c6904
35dee6d24c7686f285ddd6a2cabdf99be0d971163fadfdd76173bfacd102b7a4
5838afad1eafe8c4c8555ee5ee340a111c6a9315327d2d0eac0d819d189898cc
b51d3dfef8054af52ab55493fd744c9a9969afab840e57b90548d22128ef0487
a92fab73ea56b5d44c3b4d0e359e6f34d31618edcf39c300078a27a161412fe8
deb48a726b3763cc6b013d22aed1277cb64be07b3c1a1d20ab9bbd969e724330
a0282f62350c558c6c73436d8bdda0a1ae4a5884c5703e44fb9d7a02e0655e0b
b65c2bef2496a1eb74200f84725f31037555f14a7c361f6810c9f67e838aa523
cf6691ed7a2d2a6b657291ff99a665dfb0ccc40f433bc1685b0154a78344d95f
c8e3d7c1ea993cd154a48ecd7e40078b30d13c77f4e938ee5e62891997245a31
5a614ef033fc587bfad0f16cd72711c117d9a86de95bff98d2f906d47c37d19c
3a6ec8752471d01f74d0c69fdd9e4b3adcb75b05a455512518d256d3444a55d3
e24bf1cc8408ca27212d61730e7ed52067bd3825e73d0ffe213789d5b1437d18
1f12bf73332ad2c03806eb60953d265b2d8891184d73b199b4094c9caee7e2ae
6c8b45d6c7e3a585c50aeb4a4633195c1e955a920d9b471a21b7288d30c66c22
3e2c83fec9fbdb6e7adc457dba12b02e73974797b7dfeec8937bf43e206cae23
bfd73aebbc812c8f8a0068e8f6db6a90e5a33ff6915631782f883361790c10d5
42aa33ae7b65858f9096d51355bb5edd86911c611e92f37e26d1a87d8cd96a00
535b26188a7b2d93a0d018cea5e55fda3d3ce4758e15823fc4e4fa83e0c47fc9
35b0d79ab78fc4cba8cb6ad47b1692b54ff2a574bb5ab30da452c0421ff65e11
a66e516ebcb0e84aa53fa46269dc2643603319874ff9e3a77470153ad96ee5d1
f03ffeede50ab09dd5e8e85753a95dffa5860b26d8c25cda944ed8f5405ea3ad
aff5149d19c66960de1aa9f542670d306ec383fff48c7916a2e82ea61cdb29d1
c54a7b76e093648ca07d21c8c07f73b876ca702fed45751dc5e535410bdf9160
542ab7ce39c8ca76bb00c3400e67003c89fbb8ae231ae909336fe41b414a8b33
5f5733ee085d0c11a7190f451900961b4c7881ca9a1742cc0103460bd930d250
eeda187495af6aed1bb4d8cac54a929c1bd5207311fa31d050dcc113b489b0ab
b1ad89ad2c0eb9ee33e745d319d307e0dfb4a27468b5e3da1494275e382753bc
4d739c142cb0a920f3b24660b9c9a15d7867fd2cd624f4299f96bf6cdd712259
ca98ce427a407e38f640d9fef0a057aa4d7e0722f8fe1b1af691c0177302f767
9bbaaa01c177cfb55d56c9e39d793e6945b934c814bde0a3fd5583d36c04a2eb
4f139f9733897715256cb14184c89e0e6360a5456d7f704fbd48b5bbca23f44a
d61eb5eb0e4e4cda58596be48655b71a157cf63fbdf1b605fae92e33cad8d7e6
9dba4d65226d680e918ca199bd722de43b1636a4bf9dd61ef3c58f8685f01346
0e63705b4bfe93b57098a16a6aa7512a1a14315c9e38e4dccec9287f87712481
4719a915453ba84c76fd9349584f2188a077adaf06aefd2734f4640366f46193
97b2b1ad317e7b8c1e555ff894de39047015bef16540e8a300378ab4ac21ea36
ddd749fa53937323f5bf117071585c428c112824a880806bb467560bcab1da2d
6fbb71ec234d33d0bcbc6683a4b35c8cedb548cdcd890e79b347376ac7eb0f95
0304bffb05eb8264f177b659311c968edb67085a01b3b59b47472389cecfc1df
ba1e91f577232d8cc8c89f0e64afa9f87730ed3aeae8e5e1b5d41d55167fe604
cccdf0039cf8e51ce03577a07a12308619db29a7e21ba711f0d46f1eacb62586
99adcf4eafc911459d53524ef3595ea9d75cd5051526f428ab6da4da40ea78fe
b65378aa3090c1c208c407b7c4dedbd1e9c3f8024a8b75afd551bb4d39652f5c
c38e0385e192ae7137dec6bbef5891ef89ef130e68adcc2853bda269e1fdeee9
27da1c3ca5c855ce3eba99a12005909aa5c5c8679f73a8e33e14e5fe2d903f7c
6bf2fe3e133f8b1a355e7643ec589e80d2909dcdf7760dc8391da8cfc48c3519
604b52a7d725cb0074361afba3a48a49ed4f54d711bd0938b6444cf626e4860c
36e297831643ce90a1c849b24ae424336e609a534a26222d22f3df73db85d33a
ba0dc5c66ee5c44f7074e6d151da17a04c2e742f97a5eae47fbc41f534c30500
8c864a75b529406ae3f20994973e480eadefb7dbf543c2d1467c638817c97052
caa7079e86c43c4ed0c6e6a3c9569fe1e23c04473feba9cf24d0ef754b1e0752
c815625795a3947edb8d43aab921ac875c6312fb51f53c0ea24f52ff96196e8e
9c81d72d09784033f2d40708aed825317a9f06061f302aef3bf5a58e8066bc95
fd28ee03a1b0514b467fb52f3849f73b3eb2c16593ff5c02771b6d82f1b40c3f
4e6811a045c1affc30f10f9537a3caa7b483d1022f160b953465ee768693be12
97371d0adc14d1b50cf4f456d7d286b925729fc7328dc0d9da80aca4014bb7c8
96ce4c08bf301232be6a53b060305eb78846029e05dbe7b65648dd918e9e3ab6
b7987ef9d704a6cff43a925d9c353a924a08ad6976fab084503b4e85c669046d
fbf0fac1e2d97bcb7858fdff2f4fcb339c16e6a665d8e227fc918a90cc8387ef
0062e88850584d04ac8ae952ed917955392d26bcac6bfee01fea48864c230bc8
ff09629c0c970c0172e0192f464fe65372e5f81c865c2b548eabaa054c20bd7d
028ffd607d2a3f0b7e84c69e44025cf2887b7d9e99e0dfab466241fd26bc9857
5675a78ee007f4dc3badc86ee13e06472c1bc8a483be23932db1bc9c977ddb4e
ec1f3edcb80b701fa7f145956c7f1cdd22b0695141fd47594a04fadb8b0d20ea
2cf9b04c5397b6fe15955c6fed8396c6c5e845ed5ba55060b523a5db691cc5d7
74428de878412531e704f6041ab4a25749e20232809f9e189e9b9fabc9f8cdc9
a0ac0493104581983324819a6f5ca6aaa97d6423f57d7a000f29f4e5741603d1
e0db413b347c1cfae3622a99e077651f261634651e7ce0a40405168eb9fc100a
1fb39a208e191243a8b1acd58b85cf41eb81acf41ba5cdccf7389b1f9cc82827
856841b16871b4771ed56646192126ec2b7633ba79e6239020783f2923e87605
33ccc94040cabdb3f7e1462decec8ba7209886fcbaa1efc3a67d0bd20de64f41
05a5aca06002cd44bc48ace03d3f64781a4138bf2cae4a3ceddcd0231e0628ca
d46af544c7f800ca1ce8462236a092ab068be6aebf5fb3322450561151ca0b5d
01ff8c894c709b3a05131287fa578ff48203d0adea05f0e57fbc0664e773e8b5
ac0a77be3ecd51d9cb0d1ffcbe22890cc581481f2cf664e50b09496fb2849fb1
25563cd340caca3a5d0a7b01bca0eacd31815e3f25226cca37d2348081089538
ad4ead93f1f377ec1cb86b933d171aec561149709c8169aeeee0e5bf88fe532f
10a10a0c127ffa80dba1324574ab2c7d40991ec68032a6d690c86f12715ba179
a8a8ada7a09645e36a9fba1a9e54df47394f8a882040f4ed9ded29e1aa68dc60
19d4349dbdceef3c167f8ce296e2326810c25cfb7db6492ec68d853b20b6700e
91fc876c181a5714fffb6952347278dd7d28c0daa74681d0a12da9630126ed69
3a32e5a6cdf3e4843763f877137377d27ebd4294ccc88fffea20365789f280af
c1f9d717c9b553153f1e7b89b56f92ae20295e03291d212f103dc6fef75cf058
fca6e1f65a8977a8663c8b8a5daddb8a44ac24dcd6e25af43a816eb75437438a
a9b875b4919f8d48d47e843750c82a68d18af901da5ed4ae9c6b55cb9a55b5eb
434017bd3ea8d7a3a7b4c110473c4afb23f869da201bf765c2a35e886bd6f67e
7f3461d7dee5b11c292730909be238646878d6f4466ef73bb9206f5bb8e8c2dd
c34c2cdacc9379e70586687ac76ac407abf9556f21823d58a57f04439c0485e2
8c4afaba4170c80af8a585ba2ab581fd45f0836daffac5b7a9899b55a52840f6
8c19923018473c434cd1b9b3c5288947f5e493e679941813125372caf846de16
0892b57f1c3e0278f1c686214612219d6212bbcd2d4b9eb3ba6c8aeaf1dc2291
0e5fe577ff1e65e587d7b56823dd196b0eb388270eee92b424ca722a75be5f64
7b931ef2fcbe710ca997e46c83ae0b70d94669d28276e99c85fd4130f2340b40
d9eda776f00373be7fa1da8fc953f33f07fc7f1f47abacef41266c23c4e7e914
e2b802f8b23025bccc0a208394cb26783905e5ca4c446fb76c70cbd426cf24cc
76a642a9ccc1439c25a5222bca358fcf59bf51fef0e7186c035fba5018227d9f
3f2cf0b3d78e1f5952afbf6bb0d49f11a0bf2ac1cb15983958f21a48b375f66b
1c355024884b6269186d80888c978a754bfc6e355215851cafba6f69d051d10a
8581e7e468290c2d6360e03a50e8041484b22095b6eef06268dff712e270008d
cee17baeec3cb43090156af521a5d8b3b2edc4718893f67d20e21cd205f51ee0
c12a9669562be380a1facaeaffe7ee06e1fec9b1577ba8282768f744e5f4c553
8071467944688fd15b7bce2034450c4029ace8bb139030d276b161b013643251
9d736368b51638ad76a3c86a475adf7d360a9240946674e7b5e72c93691c60e8
711428e904e08763a78751066fa4219f40d5dda1e2c9f0eb9484c1c4bb0243b1
41197d6a27cb43507676e9394a9d0ae0dc03814da514a61b7d7e6e25f62a5d43
11a778f4fa8ff8bb398b46446fcd1354e0159e7778b0abe58461773dc9fc97ba
adf3be8dc03e33ca38889855859a27c2bfb522aa8e51fea5176e33d8c6ffbfca
eb5998fadaf89d7b30340884475c1641d4aeecf91012004c9547c90c6dcad026
bb59f8e830d9f0e134b7719bee12f6ddafde26e7bd6c38e5dac7961c629a859a
80459c922fc6fbc253f2f6cd80b47b2422a4b905021ef91bab547ec21c7750c3
39592e6cf0f82c8727c112259e243a653d04d9db52e521e12a889d4eb4415d14
501cafe61ed1729e4f90ea3f10767a6719ac5b0cfd5c80f86c2ea8176dadb058
0f623e4d025d668fbb3a957d1163e5ec4668553593b4f77fe6d64cff742be3a0
fde99e03375a5e3769ec8198d53dfdb3e826094fb922c576839da0a90208048b
71c2098df2e95d3287d77b0c95231357dc152c4010799c4380a2d7b0023d4928
4f3435c590fea856e64b1273523a3c5d47dd09284a336a386dc62c8a927be8a3
8e0ca5a2e648f7ddcadb81749fdb05dce2813122fe91bcc3c1faec663d5632ea
d1c6bb27e90e89136af882abf4bc19dd7c3d405e15f68cac85ba4b1e74a25c18
b5a02aefefce4e0b70f96a6e90c1c915597cc394bc0bfbd8c8672f85c23df95f
baa2f4cdd1289b9c55ab226c10a043ffb64c52ea6f5ef8f89846dc064382886f
db1e1ed5a0dea6c2c88a92f01209d8e96a3212e9fd93b18305bbe186905383b3
c97a3e86d726b957823f0d70b1d5db0bdd8f848da043826f249e81655b519451
2b68fa38cc48bc43772fe122a4d82cf6e4180ee021eeac97d291de96c9c43f80
4771c36fe963d88d1474b597f89e05c0be0418d07c2f095e6e5e136b4bf9e5ba
9e5b26bd24fb3846ce6d06f262ad4783cd62c0a55509f40baf23d72971e2bd70
00ef82fe27adfcf79b0683bdd7c0001aad2896a95b2f9be5408fc8274ad00f1d
11cb898e8a3bdd5787328a1aa4e523d545fe2c666fa0533841873c0428738ed3
3179a5cbc5e5ea009c7852a4103f41b1266ecc46e0a410473df7c92345ffdb28
5e433749db699cedad4d5b69d4cd8ecfface7da665d4534bf9c344ac0d6017e3
eeec522887146b9d772c3652e11337f8fccecec7933477845fe2b1fdc1f2f8c0
d54f9efb955ca45446625623320571094ded6402cb182ccdcc4f33ec1bf8d683
300011e27027aa0ce017accd8badae52789495628e3f8a6fd8e3d2d9df12d40f
e77983291f2287016d104d2b201b5705575d3baa41751a3ba344efbbb2b95ff9
b1fddf9314ef3e984ea14903a940808c4b6a60f259cdcb219e0d4ae8fda60e76
538274cb3f385c08720ffd4ed376f17c084c6a7321c4f906fba50bf2f0bd3dd8
9e6e46d675bcfcf0edf2347df6b367278ede97d59f719249f5230a88041feb09
c27d84ac8eae7699631530485be75d314d866566653cec6b7c85b27ac02432e4
82b618d0bb7abe66e56a9748be8a2aeb5b4bccfb6fcc993d1d262cccbdb17b9a
a154ab79085cde6be8e3b51117dc8c7153a8d464d64aa23f758408a5e16a5bf1
4b3aab31b10e674dba824aac4498693f1d4b0d4e8d613359a0b90022329af453
2bbe61e17974325ee2b9e24bd606fdaa563cb996c0c49c3080e92b38d67f34fd
ffa534fc4f965179988d513b6d0d500a31e88a324bec42b9f6a2da5220b0a3f5
531db445d4a3950a1a2b7cba528a9d973a6408293c8de29087e2ed161199d698
64d090f303bad30776a555696426d9d7da03e5fea0e28919a7f754116e56f171
0b9c1cc1543070ed73d3aed05ca4c76dfc80667fd17b513b5de18bfc89c340f8
05e96313c19fa0a305ae21faf0d217d300d67aa982b00bba2c5cb5fca5005418
187cbc26662cd5904ccf42c9cfdbea54cba09d4d80c10af4a3c0996e3cb4551c
d73ac913183b1ab95e6e68ba82c00be36f3ee3b539ddf52344c54e883575aa42
279edc0d07b7ae524a90401a95175f41d6a1dba6dba4f29b77cd9c1046ab9b85
78165063c253e41abac5d9b631c54a4cb4742410039a2c3df4be0557e52cb91d
1912ae1644c462d46c520f80da6bd8b984410ef38a4044931e64ca1d552e1857
d6c37f9c9caa75b2b76babe4f6b1b8dcd1ca26b1177f31f62204fa31015773e2
36bb8bb1384692fb42c3c826486eed92ce4eb1878738086a21a811c02d2b91a5
196c45b64da68f62f1515ba775f088bab80c0d9d77da945c61d2b6a9463ba9dd
54ccca3b4dd9a4615c5f6e00ee40741b1078e7975c468a56508697326667ca5d
2b2ac9d74327e1a25bba7d87343911fd037306b343541986adf371633e8c9a6c
c5da03b838c5a91a5303ee106ae68e5e2194cc64c90dfad58452ef71e06d97a1
7570da46c9f2576ad90d77ca6698da9436a7a8dd2aec3c1036142492e9c6306f
311c1b468270bef22d6794130cad4ccce658cc04b3d76a024acb16f88d002912
8d4fba7b4453e82273e1f43c9e3bd2ed989758ab581232fa299ae4c15acb333e
5d81321cc6edf4586587f805345bb9a392d0ece97f945551564b6adf68fbe1d8
ec4b0b8e9127e7c10d9cca4c11604ab098778a5073437a8d21ebc61108f235d2
3f42e8321ed4ffee68bee2ce54ad21feca2af00b38f9d475d529ed43dea5dc65
1e694a94652cc1cc30e833b2a1a376dc40bbc6b31f4f1edbaa1f816b7a8ad91a
1a05ba3847afb784a001f341b8aeec594a0d2bc1f5b4986f994bb656dd9d1fae
32854e55cb1b26c31f5f63de8ce8bb05e85d384d0030f35904a8517f942de115
c1842c63cf157106e9259debb8dc8c8197ce58096845e4298f227158d15d4e27
2397f53fb83179ccd4f9a9774a164957e5f3d98d3bcc71c410e9fab5313fd3c4
5d1458d58777439077f926efa726b839efe49c460b5c927cece22258f56e4107
84e48cca2375d25fd923b1d56009d5dc7526727ffe1939bde9e1664815915b78
e86e93fc20e79ea13f147580b18d297cc954d0fc53b5c950db333e5b15e3b47c
899f187534bda8ab009c709cd9ca3083e80ae586d59e51890a2d727b6276904b
8b53c4458056c9e72bf87b703027e249fa64b655d4c1058b4d1b8a978c4ae951
72d5d4efd9b2b7d6155b6806f475e4f1aac604545c1489088a69e39269d2b49a
1aef091e942ac0eb385fbfcf854548c9836fb77cdb703dc0cf8e77e19bab47db
cf3b4384ba6e1c681ff62e7ecf1e329b4b2a37cb19f59f215dcb91e4362059b4
0d57bef3c4979ea8ac4ebfa748843c828730cbbbbe4ee236697a1dbf2afda6d0
c92229b036f6e97cb247c1fb98793a507ac766096ab481254a5ae10da2c685a4
7913f049f6fba15331a42ae89b4f54b8939932ad0b53f31946af5da0cda49c19
8f516baa32a37d2086cb8cedbde3da8080928f614c4d344dc37234bd2dc3d039
f7555c3ec1166f073583f23f2d0774660bcde2963f056d1ad16f17faf77c2914
6734bcd4c9672882c4bf8b2d883c21400876ff544c37fc6422c683c9c3331dae
d0359e8053ddeaee8e79f06b579ead6d50d756fb4ff96b6b341f548d0168b762
f0805ad886f38148eaa6d04919f9af04e0ce53f6ea4a432e33f4dd96cc8438c8
31062c012508105eba51477bc655e213834e18eae9921a7dbf1a750c8968caf1
d849b54bc53b1e9aa3c40eacdc629ffcc0e5423376d3e3b0738571ccc4bc83f2
6dc5b0c662d9adfda24ad8961d14af46142c5e13491a6acd16659fa13a4af99d
4b36f217bbc9e5daa23ab596e1787e92f3aeab8dee1841a6d0ca9938ff7afb3b
a4f3bb9b2e1cd9355bcfdeede18c8f5f4295afc446530895c4bdc64c19c94b2a
864ce233bf7e59474e726386549732d8e8708ac37905574dc2ff77113df0ae92
24d95a1536b4794982bf863fff7691d8a1ca43d8a10118894a34e674d862ffb3
78a340f5e3e8b9d844476a7f8580979f28388e4862a1c3375ffb070ddccad0b0
e25320048e5bbc054a8eb8fbd29dde120bd70d273e1e73e1ee53fbfdfe2c8324
fcfc209f752fc11ab86c7773508548a17162c7c0c714b61fb22f6bad810ec5b4
114b3abbb2502298a7d893e8d7cf2a5ac7f4464603b4df05850d1cd58d05c5ba
72561c1e91e1ea4d6549097c8b3358eacfc85a6543e96237bcdd351f62743772
86616c785d48b5a3a19cc08ef5c1c7e4ec591626c337badfe54e5e6e477a1f6a
d5fb29d9486065a3b916a6ae65855d7ff1b38562335ba86a1b28c53d51653bd2
7654a000dd5fa7baf01a49d88ce42a0cd87a561f266f144c66c2eb8e696b77b6
ecc4b391078e11508891d6df32b868db84b310c61ce48f1661186b4cf72aa5f0
8d727f45e854d19736b83677eeb779f81315f36f66529c52096f9196985d9b72
bc722d289b3ad7390ae965d538fdb2d6c4e271aa7c5233fbead4c0df395b79ef
43e5b1031a3529f9dacfc5fc821f099017451a2dc2d1474ad8565b3acbcafce1
08b9cefe7336e103fa9991557f0da42713c34cd4e2cb551ca8cdee80eef7f747
6c6321a3919de675734bd11e9be75fe04af0140ae94267828e185da2d2fd3e09
45857ba8ac367023b5a4879f17b39b3ac527376beb4eabed614c124c788c1db7
c021078292aa2325d31d07be53622cfda585ab0fc7a6cb2efa69f21d23b6a36b
47a0b1449c3618db77c2f175999ade574103d140f606c6b0466801e16badae44
197bda595f6c360876dc8a537a274999fc0ba72d72c6e15a95f9655f0280fb01
f0d7df00cfce3aaeb3258bc08bd39f32700c0d666151b0ff22b0d54adb2c4bc4
f83a9c285d8dee289e91ef39071b8fdc386b97b49b01c6565c81e5a3ba0d740d
d7f30b6620bf8c644dcbac64bd4e6b15707955be3adab7ecb7a965b49faf8623
f99b8d688c5d8689299732bd89da03706df5e754cf6254f51c0b1ae9e3e5ff14
b31f0ab5f2c14d7debf10b099c353ae313eb0f8777a6841f9579a73a0cc480d6
58a2852ac8f3dd0b786799a05c3ae0d5fce3aa39e5ab2936686bc01fdebe1e6c
75e8cd139b1106fd5671a47659ece5d4418b2e21faaa037d0d80efc7aae4521f
d250333dcaf9ffb0b640e1c92b650cceadf1303805e63bfe8a6f212e180a7533
be6b3a72e94a83f0a1efadd790fc0844a90b772104968fd5325e74abae33ffb3
5ad75787138f84bd655e145bf0ca655fe362bfc34e2640d1dc6800e180fbf64a
809f34daa266c0933b3927ece4943074b809f9470b9eea60e550747cb7a84718
ec5996da3ad7497854862275e02aa73f84c899de57108ad5c28b1df678235835
b0ee43932958293a48a6f84c20c3429c5a7b8fd2ad30dfb6be099fbf885d42d9
2fb586b8186c5137f4a093c5d73cb97f19e128e208f8f06b5ff915f489855629
eed3ed46d1b5e3a1679985ab0b28046f043f60ded4eb06cd8d46f2378e3ebe87
5309e5b4ff8be39bcea08934f3e911ba76612460deb36fbce942356528ddeb4c
3071de94fe48004b936e71642d58927b79b7187ec7fa481f037a43ca3daa2c6e
2b78aed85c4fa16a6f7bb8b7324102c3e4e94b44ac53439640b9dc9230fbc13d
ad82f10a9e2e65eda02dd4209ab66cd9b0b01bf713574be5c6f162e5fa4ef1b6
63b4e2f15c4c65415e4951d95f8278465a67c9ee30057ed359569b5304df3454
b240a9c9f210aba8e1c9edaadef4610f69f97daccc27b69bbdfec720562d2989
297cd4a0a223e0a48bba38eb1d6137af050f0f0f617a9b64b7540f6f64b589d3
f4cd34d79e404e0d997f08058def591727bb34cdcd83c569355351e04ed49e5c
f6563eabd2592a6c577405152f9d9745a4315ca01fa73dddb3ee76561ca066f8
764ef57944d7fdd3fd48e8d7ca39ccdfc8e097c38047395d4316fb0a151d18b2
fa7c716450e727edc5af2a0046833c9e7e7c4b55ca93691f59b90cab92c6cbf2
3ed62594905329be805be07ac202d9f8c2067ed29aeae5192c51d8ed6681c491
bf7a13209bab8be4b1c422d737d0ca01f09e21e4b209754c7f90156f5cd3eb73
3c317c164dbda7a16c1a2c1daf5245f860e5cb6664b38aaf9d54e7f34d7dddbe
b19e7082c6a4be0aa1ab4da573f05aedec9af17cc523b9f27ef756c6fa766048
e55062be56ff8667ea0f9629b904d87c5761a0f48b05576fc763d9ffabc0a2bb
59d079397766fd1d9caf017958745fb6bf3d2635eb63a9f39335edafcfe86f08
777899471b103bab99a70dc8146f521691d0ab9a33918c6dc307786b8bd7595d
cf070d42a4ebe597b6c12116c49834b786fe86f5e88b43a600fb7141303c0785
e876f9907030a6ba943a83dac84b8644cc87e51e1eb2984862709bac0fc25dbd
a876200c976d8605239cbe41a8dc5d726f53c1a75db92a9a9116eddd7e9e437d
2d4c72f0fe5d2450ca2774c161ad5b9c58547216b3ce7e3945f2551ae795ae68
b66885159aee13cf0b89b95996422d00802206be31f50ccea1d7d4576e73a8ad
87350757498cefbb918029f1f8fbf67a5cf1081473c04dbeda7a9d11cb6dd2c7
a54c505717a0d8c30db184d4e127f40cefbfa34ca1b5fc8f82a8aed7179476e9
c3a731ef4f20d122473f688ac5969575fe35acabdb1dafb0e505b39591f4d010
db11d1fe8dd67a51fe71ba52ae1967c2ae3f26405ed271363187ec0b30f19db1
c2395bdb3c902c226fd9471f69422fa689f543753553a4e7e6f1bd71b3a28777
f8a9bd973a7dd997b243d9a33ae08970524c3bc6e9801c9a92a8ab04813994f5
69eba8fb10b1faddc575da570db6d2409099d72503f184f06a1f940e2efe1ca5
394a0b47885012a21e7b0f1a79b079b8653534cf6db260f261c3809947824f70
6ea028fd5dab0d1764a3398c1d5f03175524871a09d63d4858a2fcfef159b1fc
a91d1465abf805eaa87a93ff16242d0bcfb3c80da162d9d91759801072e01e6c
a7d64651aaaab1e206717cad9e10afbeba205fc8c77459f2552a0edc0c5ef137
eb5b5620662c0351547e950338720503692a8ba8f6cbd876005c039f8ee8c1cf
186cdd680a3c76f4bca92b4affa691ef4f65ee0759f8549bdaba580b2a41b4a2
5ae0739f3580c2992461f3d1a82a9577b45d8b4cbf91f7661997a52c8abd5dfd
05fcfb20ac10254e026532909ce822d06bcca7c56fdd044618365ba5f403d082
978fbd9ed12aa5a50530bd89f627d04c3f4004232c22eaa68d2b1be2b86440c6
d97a2895d3f56461111f936232b97962c47e22cb90b8945251b13b8407b7e61e
0f0beae00af2d814eec0adbb9905a189a99c405c39ffe58d3a3631a9a725d589
10ebfaaf2db35f87bf45537cf45a29a9c327f03a9b31f008a24cea9a7c67f17b
d8aaac3a9f753a9d227b42ada628f9d9c270ea4344f09274531700236c9ee077
3fad1756c74830f27f3bfc9d022948639d456f3389eabb8ed2a4d131f381ba85
7405b0efdf0e411574a7f949460004d58ed3006210ce14e3115b2780a3ea22e1
86d0ce0e7cd7321541dd438959957a4691883c5d0290e64a329332334cb948d7
1c7159782a7a5b936b78d6b43c2e7dc5550408a14f3cfacdfdbf91bf35a160d7
11aad9965b0dd6d5cc0207c7507786a02a34ac91215832e4bd80665f65e808f0
58b7380f806b899f2c48db64534d3667bcf1d2d33131b0448df1955757e514a7
125933650bd91f8b5ece9a8b6841cf18aca90c5a3f4b2234c79c6022bdafcc54
e1ad3407e70b9453441f6b736c3eeee8821c657c4239351f08c5ad261c8f43dc
dc32d21d4d2c2f92e2c9b6fc6649246debbfe835bf598d8ef506c6b54954f0f3
5578782650564eb29c36e93649ac6defba6de11d04d7583c14a04646dfa4a896
588de4861e7890d11c201008db2d563cd5c87f2df272ccd8559263301f22a032
2fac3acc62fcd23e548e6800302c6a4e3acd967e0fe4c80b3e21299cde25ba46
90e3a0a400cd506f6c950e64f2251c9c0184d052242b413d5d3319d0e393160c
21e294e044a00c827e93e19d2d591e45f9819161583e29426b8b6d47b1b1a580
97d03736b52358ed074df87adbe6a8d5945b395fe60cf79223d78baf43f095c8
9f59cf53aff26846bc258c39b6d1558e8dbc8bacac4edec879e7081d98de2317
a1e01a9f56d56acf2d75c7e2af2a3c410495ad2ef7cf27efb17671d321135d9c
2ac6ae9e5535416a8472b3f79f8a59a7916c90d7f305e2558a7188b5357bb7f5
46b87f03b3a4459d5a7eb64eb493764739c0566746bd19a9040fe4934fd4df58
976cff7e24147d927991763f34f4b78b727af5f267e886eb8ea790c14cf8552e
9724359f58bdbf6d1a04756b172cb64a831c95e4a0d8c287339cd76e30a837a1
7305f2def984899e638db04260b905431c1de92af1c0c1dd2e71051daa6b9a71
93d3985cc7109f24ffe6aced99805273c306a55592191a1fb42979268a9e2e20
c769e2aea174e39916cc5f7490c592ae845b653903332538541b002c31650b68
bdb6ccf52d529405d14c4c65c44a58a43be81f92fe1231939eff309122c5246c
594529efc5194dc5ca1c9a20acec335c29f9d437e7790791c3c8077c39e86e17
85e1bb0dd3f47fdc3ac88a2e091bf6080ec75e2310fbc250c1c9c67ac36bd357
146a490c50c4c3f5f90d4dc7beaf3c14bc5718adfeb1f4152f104333507cf6bf
d59c6a80e0617cfe8d76ae1c9ccfe506bff2df3b2be19f87bcb04588a4008d74
d490216f2224a877fb504708188084229b57d92283ad3ce9c7335ee6672cf512
c9e6fc62d2713a6c22ef3f7cca5af300b2577c5ccde291121515ea1fce9bed8b
a3d60a6f0d78b16b6dcc9d711c72497f5c201e1b561dd70976c8d8d5a39c4af7
bca4a57466e61a8f7f3dedb41284f9358873894676fa15970daa4e30ebe2ec8f
cc48e731b61c5edf80f91a54b05687fb8d881626657324cfab050e58ffaab2d6
1a52260a7cd3a525a9ae1ff8e474606d146a8b77f3f77f9dea65d509fe14e1d7
feb37f4784e8fe6d2e2e6d381c0e37b89c00f968d2658121b631eb3f882ca50f
fed5e034729df08fb60ec595ea40d8d17ce21db68e96c71d4f24c62ddbc4f654
fd256818012abf90eedd163015a18c46e0269468632d2b49eff77860bcb6c7f1
3cbd9d92dec4389fe20f4052dc6a1aa6a1387470a693554c1986001b3e1ac571
3a06927d85d1d1f06184a657417cde22cacf0e4291c38e1b7768f94185122f07
435ca725bc7011d5a5bca1d0930be5e94f63742a9c8a91c08c50b328a6ee51b8
f1e4cd6513b92a5c4501da1cc1455b0835b81d2bd92992316fb28cb452f652ed
d41d3402cae6699dfd4028144b996cd14c21fae4b18409444872f55d8dc4d054
32d0e6e9fb1944f63ce4ea4fb246fdc0873cf8b7cc5eaee31107061a8838bcfd
498529e9617ee113bc614517c50ccc45d071337aa10f79a642bcaaa7bc4642ba
fec184560b6b01357f68fc0256dbdac3bfdd9ce7bfac143289d1122ded1110c4
7c0a5e7a6d17ed143adf01c848f2d7987f46062de72801255f9afbad32078a35
800981e0a6491d1d58d5a5c02d80a3001e3da7aec6474ccae83f28942794261d
89bf3817e19c0121d931fcef4dc7646e6e2458845734eee53ce089916f074557
e991dcd523b38b5dbb2a3e951bc956592d565c3fc5196681b8edce7b6260b709
58694c35f2d083fb4d0740b97b2669b9633234109a4c85608b17a3c669ade9b3
f63622cc7e79ff7384850350e78635a6dd0d7adcdb9b44e7e89caa4d1fe18e2d
93866031934491227fb18bbfd6d8c6d444d61048f17c5a4a0ea884f4288529d8
d0c91d9e8e4c5299e0fcbfc990b8b3bebedc47171fabf29f9775b943e99d08b3
239de3b41a06bee97e14cd8f45215fc04d83eda1a744d7471c5d44519faf6a37
e4e4cacf2c2595fe78020fd040f8ec5c39523a8792ea5b1d7aabd293b66160a0
860a3b781290162ed094802aab2b365833b4faeb24fb236992660e962f3453fc
5a11a3c7818f2d1af95c561fa5497c32937f83caeecfba333e5bd6b6587a4e93
853fcce73b4a7188d36a0c0f5cb412c1977b131160d49dd18fe9ae48bd52c27d
b52b5a3b2994a8612e7ff9c638ecafd5b4bc63b4c4c90def403e813539ea0c16
3801e82eb54d4ca09d969f641a001a50590f19caae7dc8ee7588c8ee1a8fb09c
d8af127409fe137f0920961f23e56db730929911a2c97a88c47733a48593a0fe
016ddfaf7d7987f2faea6981c2aaf45b9f169b5dd4fe38f4c74aa49205198087
8ae37077561fe909cb393b3ac133f39edb89156d81c30a338ec80deb9a730488
e421dd313785ceb122b851e361e8a7504afb2f2ab4287e1252c615695559ea5e
961cbd14d6d10e31ce08c83bfcd2a4f8fcdc2734b99518a67b56261cdd41f129
1845f424c7d91154d48453e82d8582aa64080c5849a29c45eae1e3ffa60516dc
ee5804f023227b408d5c9852facc1b40a38f8f06c066f6e4541a1d5930f31b0c
7bc368007a5b0e2077614fa060d5e3895ef54923f098832ca3d511f66f9b12ed
a6428feba35e108b6e7789afb198b8ed09242655149c62635aa332238a8e2f9a
a42d1bd50e3ec260a5873ecf0834a4f4f1c77dcbe1a47b4346187f2267f658e1
836d1b01642a2fe994298d0409ce7568816fbeac820d1a01d01e5a48b7afde40
45a0e382379665d08cb0e38777e8dfbdbf5229fb97f5ae118803748c445110ab
3cf4fdb9b0969ecc6336ee896085eb73b7a7bd8f75b96a12a5051b7f37e8e5a7
18d0d6255a2244b061e1a49499a6d0c2e5acc1b6b80431e542b8a0b5cf1f08ee
37df330e5ad3059ad8a8fce4504ea77c6b05032285befce0f48829baa3ad61d5
3603d858de9e0f3adf85b9ce1494fef068497e4f87cf70199accbcb6112e9649
4892171334423b7fd703490edba9021e06b82f38b6e95ec646f9f90e6db38e0d
f49a95ca69fdebd57b181b360d34260e390230b0299e692a066465356462869b
46b04e519d7a1058b8f026b0bd0012d1d077999e6e8bce0194cb1327b9a4bdb3
8410a81b2377e5bc0217e6fc4a8345ea43910e674ef1de173a8ce69a156e98b4
eb4482b21a137b5b728a40121384b674c05865fb3f27a864d5800b7360371587
9f46096061d16f67f3ed9cbe0feaddf7ce256168599591b7575a2895c2b0470b
5186db078cf9f4a379048ad9b98ac8e6241228882ca3a2330234fb2a850543bc
732c086e1c66f827d842d9a4bfa938432365358cb9b2ab6d58ac05a68c2b61c4
9093b782ed02fe95e7e8ba00c8a37dc40fe1ce61cef424eff3630b396139d419
cc010bd5d06d8687891149dbdd9a53887596d14aa338b344394ca23375ff43b1
1d90b6d32ba71b739780ff3a37f37f74303ba203243a3abe7cec21acf6aeb3c5
d657440bbaf82aad9f56e74841550a772ccd6c6478e76dedf77ef59d2e5746ed
7bd18d68dd98c84f8fb1f42992ad718e7210d8dd81796849fc0d042f9f908422
c4e2e2bd5f419c15f90f0ff57cd13bf0a211fdb563523769ed7a8488c47fa7cd
460c50dbf3cbca9cd702bd59afb0f5b11340349a4f2f8d7be5eb38c7236d2e9a
ce317299927a62bc4180c5e41e5252abca7e155a82d252fdfafbbd651de45d52
758040412435c029c9c94246b1b5532cb1795b6e1ec31110a7a32e171f5995d9
dc2f055b1f1b490bebf155809eb49eac6cbee99bc5bd1d934541838fbaa33b2b
eab3163c7ff55bee04ece9880749a368fc9233c01c3171f138f256d874b56cfe
f00cc062dc1a3b4311d77013591661fab99488991c7b4f11fafbf6ed9589fe8b
768cfd48a954eb3383ae2281f75ad2ca37118cac8e376bb1271749eee95c5fa7
16170ec054984ec69f91f8567496008f75ba99765b58dc73419d6c0bb8af3f6d
77febc6d211e3971b9a0ce9ac4858853fd7715d5575e38ece54cf6c770e337f6
3cd8b7cb530ee0b6dd5f223ffcbe572726c3598c16f6ffce16f3753f1cd5923c
f92bfe50add52ed6f432237ce677194d04d6bb1169b2063bbc102638d894770a
aca7388474786624d880a484ba876f2ae9b292e543051cb0c44dada4e2e2e7f7
3d0aad3b4985d57134c050edae56307f4ebc4007db4d2225787eb63292d95f6a
40cb20d45ff64d4e1946d1318a52bfaac029242c7d33c1907ee05b4fa3b03f24
0472d0ea6c15dd655ac51ca7f319122b58c0c6373edec801564967eb3eb588de
5ecafbac0f38f4d528c0c017938faf45cc1e5f38f7f5ef45bfc28ad81ebf70bc
1e21b275de690d5cf009f59e48b8f8711676aa2b9449615e729bd42af2f65d1d
bb86fe86f5e88b43a600fb71413520b7c547e984c85718fe4f23d7352282cb7e
adf80dde3621780e174898529ef59f2070d573a37a714e306db3901ba14fb07b
8fa1f916e330cb2f5351bca28edfc22d9397fb56afed05ae5a6cf31607e5274e
88eba2e58fdf28d19ee2980c0c59e1ac0272b7dd961a1dd81b982639f31ebd61
541bc6bd3b3c4bf5e0e1fd9c1c68f4ee797bb2f7c22433c6532829037b87d88e
2f7f90bbba4b50556c9dbbfacaa9a1ce99a60ebdc6fdd2ec4ccad91c76f5ebf9
58e635c2c6be7b34b6991a4122e6f2a88c62579bed6379cfc8109784d346af60
69669456f2825d173e314118cbd3e0363693d84813f4116fd1ac7a8926599e7f
0a32ed21eaae01470798ec117fa8061d28bfab648c9ef8566e4e678fac19dcf6
3ce3142c394ea58097d03736b52358ed037c7472cdae0bc6728163a179eff3cd
b0d4ff879f749e6dd3eaf1cebac7b1e21c827270da40b1d4ed5657461162dbff
85cd983516a3e8635e35451f925e2641070c7905c42806f755bf53ed11f37fff
39d190c3b0dc346773438112f51403d3d7ec1221f6fbfe20fa8a10ebc38d2ff1
d0f88bc21932f1416063b6f8c3899a22bb1e27c3d2a0ab004df2d30acfb5ec34
4449210117572644859a4fdadeec25fec4430f1b20d16f3fab3f5cc74a96f6cd
f3d4c8bf5c76058f4e91060a6048178853972fe47ce0a06d99a8ff0b66e88fd5
ae35d16cfa2faf60445752461138b33d70f051303473b5856aa60e4de0772561
279f52d0a0c3bc0a1012132e7784e8553dbd516e4b6f5e9adb8a0154ecaf4d41
42089eb1d589b4c2b2319b09d38184a4f18173ec5e40d24b8822fb56a27864b2
349539e20a7769a6aa033f51751cd8ebd60b8cd47e6494104836b6cbee567521
a9ff42915869f62cd443ed1931ddcb42b52ce74b1330935069932f3d7f85e532
907f95bbd139543bdb96ec23d16374a96bb3c17ad997e9d382b5ea590c93ba9b
bbbbad9a8ef1b8aa1151a44210fc0b94195229b525f3290c2081cccbb042912f
4bd731eccd9e913c09844b516f38ca103b0f2c3260e51f4e6fd509a7b1e2e08f
5529487a87fb30228dc83f056b23d49fe15ab7e6234b2c510c7de3243c9f28f1
2a532e678ec55a1aa2ffa31bfb8c3e980ac7b811f04f36f2df896fc2333d1613
1d4d554e5839bd67d39504f28ec8669b55803cf41d410289f69c311c49d7a958
a59ea89bc16c0afdf948af963b62cab5e5e3253e741c057148266ecb707f7fd4
a16f0aa39dea6f01503ea0db7f80c85b5368fb2016b56b7578e2ba9774211607
1d1cf0e0e009aeb14e85aa99cb802e41b372a3b875529d8274f6847f304ba130
477b87c2a9f1c35f17cd9830c6f8850da7a1e7869859c14ceb844deba3bea401
d9b4b0d04a3df4b4c2442ce676a3bc30e4dbe212d607111b56fcc33b0b6d7961
2e8c13fcb79b19eb667d35da5f7d073fb462758c0233231ea6e8e5f387bfa3a0
98fe314fe05895f1b5340523b2c2a5facc78c4ebb88a6e2aa1299cdbcb7d74ca
97e6bbcbfa1d787a438107d744189df2253dcd349c3adc82b8cf06bdb14c51c0
40d9fa128466341c9e642ebb6943c97a5ca2023fd3a9dfb40b323173b4d39b83
468ee46174e047c229a5e200eb71e21a45807356a5c0a7b3e61bddc2471b693c
fdd07dae4ee64df08c942484ae8ba218f1cf06520789dd64e26550a644a1ff5c
e57a5fee2a6f88bfb18a20d1e27843dcd91ab096194b618337f1cd82e8261e6b
ab65fb0c42ec32feda855f26f57c593140b1cee27a4758b5c87ed6d3c87a5e39
3e6be744bc8bd28d3ce5b019d5d299a093eb18e0def41361b75a040692ff9039
70542d0804065317cd503b7e347b21aff375f004dbe7c02bb6607d1beafe5739
ef329dc47a4b87e7d882ac558614f69953b3edba56d14c6773f14736815fb63f
99d3c6a417c46ea6a550b209f351f3cc7849272470d948bed6e83c12d4015cc3
3fad35fa4c22fb6513e814fcbdfc96ddfa0f1606ac8be9d85bc52cf0c29b8ed6
4cd8c81ca40632f5135f3098feb2b7bebfd66ec789c5c1481bc4e7b1a05a2c14
e1e6b7feb9a4ea0b08ec8dfdb84ac675c5d1a2372cb2f5a729078dee052d17c6
824ef3ca68a552aa2f9fc909d44350eb6e881c1307903ccb614e088e411a31e2
6349becbd891bbb7794d9b1c67f2218e1d9d1dfe75a53b46d52accc860485470
e1b1113a2eb8643021282f1ab0e7ab96abc54b7f2524f863387101e9fad3d14a
0d9d8c235441cd9c2c2ec9bbac9fb3e1b14df20a3c2e744848a1cfed04dd9f29
b4f3fc4506203d30cda59883caec8be04351c6b45359a76ec5d2bc56b6684bd2
9a51f5273dded2093d30f0e49c598ab6efc7cdd2b0589912ce1c111d70d2f3c7
6595d39ace4a77b7f63489bc44da49a929fffcacb8579ba53f8e525d841efce4
35286daa1484360410dbeb7386d128e25086e3c4e207a12dd3f74dff23a95eb4
936ac18237bbe201bc5d78677ba7c1ec658a4b34ca419db7e95e464aeb830f32
b18e3fd9e670839081560baa674fda6455aaa68b0c630b3cb276f41328922462
ea7e119cccd623c955ac7085baf26c20052b2d206c8647baae14a1525379bcab
1b2713533210c7bdd9fb8f3990f1e9f5dda1aaba0258d204a9fa33ca4e910923
2bdbc71a1030664946bfedaa73f2027d05ffd75fa332259cc7713a6a9acbda60
f226d8648a2a3f7b8b3820f9d1671058333df8e7bfdceabfff9cb91686cae21d
f79262f9c7267fa9022b3b44f7c4747ee0d02e56d98c75b8e4d66bea0b9961ee
80cb6694f5a6fbf802048484bcc0095a32a6bd44f06b1990b06bb0616291e572
69089c54971a01a9cc9a61860599e1235a0b4f8b66292f92e7704cd1de412cc2
1ddcc52aedbf4fc63c590956348ca25049cd847cfec2df96c79afa3f287728e5
89df1dc912b50e974d05bd1e280fafc2c24cfb9939063fb40a67c4c563c35fc2
aca8c1efec5aca6872e9acbed46a541b922fb8ea41ffa0129267152ba1a29cf6
437a796fa60a8fc6a208377eb88a5258081e320faabaf074556324ab4859c5b7
3344cd1fa5213c8e3e3c3d4f1eede79a06331e184d41df24dced68a4b7fb476a
b580841cdac0041bb6144bb4511a4c8a4e0f40130a38b9aa96354d4b0db2df3b
ea7b5dd4f6fb479e9293aac7ce5e7bdf5a6f83b1ab84a3ae648539e2341b2eff
15ad2aa2950bdbc901b4e45d35ff0bccf28abba330e81f2296b1655e53684824
58a30bf6a93029a3921226691cf78a8266042413abde30df00d2addfd7248a1c
701fc44bd0ab4efecbcfe5bb371884971f40a6509a764dda9c30ed44c969d64e
a84e799039f13991919b6f05e36c7d342320002abf75065847900fe208c761d3
6ef55af155d40c9f43fd717abc1d75e6f34a84a07f774e25bde1dd5c58480d10
5d05c596d424e14a9ac7a0c7012a15bf53bf99da38fe98adb7eb722a1c01e028
37971e78ffc474d0b170f29630c0c28331c93ca2978f09a03c2131505afd56a9
29933335743a4d79c2078d9f267ea0a9988936721e29dd68d9a4d107c7c7d8cc
de1f4a92ebef9482181b7fdf5f06aa1e2d05e388b9cbbb61093af548296fab72
07c413db50567cf63d1f9ad78ce264c572c64bd38467531eb073990dc2611f25
2da2b42d40243f376815e372c8dd9e87e03aac39a7e0e366d6f78de685ed0cce
ab2fbe3541dbf4dbf905435ea7d4a1f287c64c8b9335c922fb8507fea85ca20d
bea2da7e5ca0620548c27f7abc467205510d8496181da0ce71acc1867023e7dd
cbab872750d4bd49787c509e56107d8b33dd1900d3eb3c3e84e8b95d804a20df
27298c3618d174bfd90f3b2da2a7ddad3dd1881d14911413bc11c503857130e6
02576d4337190c3aa3ce0c7b12d12956ecb7f3b7dc552ba9beb4526c9e4cc6a0
d869d58a9d1314afd545fc29e32833ff7645fe5683277cee8ba4953bf1ee90af
1df70e3e7b1569a039d7162976c668cda410f7614f782eb9677bffd315eab683
05074779d064e853b12d7ba8e55947805108ecba95b9169db47dcfada896012a
b56edb8baf3346738b5b30ab8779a6db499cafca0f6ffaa480e9a24c6ac1bcd9
91c796157e52c007b65e8a60602b9a75f23391a11c26bfd7eea9e805a8fd02f1
7bdcc50cd808fac8e26519d0dc7e44ca32e72c3f3a5e09a7c572c1d13450d90c
2d087a4cc0ec88a96d7f270df71f2b93252acd89aa38f8bec7b54114970073cc
4eeadfb1290eb1a5d3a04c483d1588b17699f12cad06895cd91013c41b08204b
a6612ca31108533b749c88e876d08a241c6a944368ae884f7538b0f44ccded6f
59710a18f01dbca0743f0bac66c4a100088c19192abee78d5bab8f6e4e513f68
40b817e8156d9c84283a67a423d1d27db7c863ae64edf4d3377e00e0ce2efd60
f7679d980e81995eeb143bdc7a72b6fc0fe79874fcb71945110a8e39b27ef93d
eefee0c5f55b8f1beecb2f37beb5aa7625de6204e4acbaa6942f5a707a137663
eb110898dcb47a07ef99ca784395164d5abb8f7a9f1b32bf0a6ca234de14819a
f903811b87966af03c884ba7c3ba00be7510829672cf8f29742866a4f423d6dc
2e402140d77826fefbea8348ec1335bb326aa8656547096028f4429f2e9d0b62
28195ecfb00b7dba5042548e6ac023a40d1876c31eb0c0d6d2515d5e6fa591c1
4c0e29ab419f956ca5a43efb8205479ed267047f25000663c892625f2f7e60cb
48514cd12ecb23b51ac1f29751862fd626bb4ad14c9efccd9c41bcacf269da8b
332dfc78b86578111483726d74c13ddee4930b96aa8d1c60debb788fbc247a95
249e10bb35648b5a9e692945f28f54e6538cae96938d4ba7b9493534a4e77686
1e4133eb48659a6e572285bb70a71a394d8ee2f18aa9a276b04a33809dc2160f
bd588494d5e9ffe4abe586f7c2623e9be09b4726eb7f8ca90aee7da2bb3c8eae
37fbbadb5d822b3ddd8073948b8894119151f403cc42fd301d83b753584553b0
66401c670204042620f2d487afe7d89bcff93713e7a5d370c932cb84d9a0ee59
12cfca3d8265c13049c72770cce3c322f2d2917a9d0f150600e0c25352db4785
b5c90c47daeea24ea1121563d51a1371bd5dd0e3d85884efefa14e5985459ee0
742e3a569df0b18d1515d64a4face2389d359f6cf186feef41365781ade25b7e
14187b1fa60fa6c2c597e4f5fa705983c829bfe230b45d13cff987e73a0b683b
7d1d14305b133ac14be61f24b396df198563574f04c7ac66cfc518cc131c7669
8b66753a9bd8ba17fc6aebcbf58c86bbcd7f380a589d13434804a5db4d5cb3f0
ea217c0de9f0840ac9335e4a3175120abdaecd2a4da3e6b1da6fb3a9805a35c1
29caba93c505f12787ba8aac3490c65747aaa2edd46f83220ad6a8f928830aaf
438e9acf914a90c71a26f91305c025d94ceb5287d3ca0a3a59f3007c97e48129
34bba7129a4e016f29eb25f9f8edc6fd36e4157eca83b0469c0b67c943315203
7f007b84948297a90ca564967e2f6ffe0248f96bd429a0a9577790539ad2a926
104b2d6f1112f84d129aeb8abbb376e2f4157192c8ecbc09f8360b7d6e6a9222
918beb752a5e3c64a52ee2a53721311b14fd5f0065ab125f7304901baf30cad8
1d4fb42102551b463e649d3435f1b227ce1eb0eda4c91f69c582ab5290c737fd
b7ec320428647b45e83291b48f91b1130143025441f47549450db99b1e721986
796e543b4d120d83f252ec5f0c38fd0dddfd5842332e0f3cf6f2c90be3020ae5
ea491c44a68b6defd2933ee5e57798689a82d4e667726c032a92b0cf9af4cd2f
48ca27250e056b9c1f408d90eaf38c6b888a3608b7ef7b3b31272c19a1f586a9
43ef817fe67788a8791441bb24a83d46508a00e980d11b1d516571d95391ee6a
953b805f8b52ef72e19c6590f33a70c0a7f636c88f1c988fe60af008803aa8c9
a5e1f7c06bd94f538ced3446efdf94680d04edaae67f0ec3b29831af077f533d
9c320cc23490599ee2baa947bb25e77a750dc4745888f19518e49ef3159b2ab4
5d80a9330cc50b7f24c8a90f16a8f0ec067816ada21c6c7febfebb325716d79b
be012d87fbec5e58f97035666c5231963de0252c23fb70b4de736e12df13d43a
d454b209d43aefc4e202a5035f71d111221e2f6b2796c127dd3fdfd9d32a152e
79f29fd1b9e82b0c7cb4864bb724282f7cd34352c146b98f470c06c007d2a6d8
181161c7cb1e002f511efd6e096b873020dc52a62720a0586d89d3723397a0a8
48d09e8be4a6e973feff9fa60ba378f0f459c8208dc855702217000ff9d0458b
5967ed3241ffd72dce1fbc6f262ab207528fd8a00e1c81aab4b2c3721a0ee278
4923024ba4f0826066b2d6f9b1fb62412a188a04c81650b317a55565c55894e0
97bedcb0f6f4b03a0364a83296962a14943534a0e4da3e0e24f1bccff82c05a6
fe7c11602c7f5e4639eb15d5bb9631163a29640cc079fbb64012ca18944e944d
1e851e910ff0d857ab560c38eac38c52413a45d0df37e48fb8f3145774955f58
f281ba245368384dc2ca15d8d7ad2a081671e2c05684f0c21c68cdd0e5826645
ae60c7c81b68e9ec8ea8b6c3692a622f60c4cbac3f7c61c51357323ffa63fe50
d78b15687067c0e9898b7d9f2da2e97e467cb730a2aa6cf5d9a360edb5aa200b
8867224ad229c04af80e05ed3b8506621242756398c8555dc11033a8a3cf005d
746c6788a843f9ac41f3f7045a26fd17fd7f5e8c6a5afa332ec7a329cc24bca5
4a08e9923431f1f194c19df5378c247a992fa8ae5df70ccf1d40ee3be0e25eec
2c7b3ae5ef921ee2bbee77c1bbdb158393c8d0b96cd407c5f5786764afbb9e0f
dd29f1b93bf806b0bce597f51f67708f89383303fb5e86a4aeafdb743d760406
d0d82abaf25ecd7a6591b23d8e1f91ae9781043dbb1c2db1a3e3cf9dba2022ef
b6aa1b78c6687237ef1073bc6bdc065d154633401ed2227705f489f6dccedb94
a16c9ee7127f4e13827c05eb7731fd6c9b4ab6af9447808622ed9a31ba39f2ba
65501a6b39ad87b169c59b5e867d093078e5a1d5f5f4d7250cec2706640a05a6
4ad17e630ee0906fa1c3ec41387393d1c51dbf2fea5721f43f1cd62cff4b1e8a
a0217bdd4a522d4614c4343b39c62d9da80cbc691e8eb3e8884c70dfc799df69
fdd4fd71d130808edd06c3cdec3307c0571de702c287c0af724d933ba3ef6e17
a52098d83c9d2afa6ebc72cd8c88396a41f709082c0357021cf06b56fafa4c82
afd4735191d0336d689e5aa748cc5003b0d27fb37ed173ea9b57bf008d57f28e
51e6b996b2443aee2e433084d78d11f8cb812fb7bafebe36ef84e4400905a208
a2621240b94d6f6d1e78ea2f790ac1a601a50caac42ed6fff4a6359eff0af249
681e481c6cc72431b96d0eeec452fecbb8f12de03c8359a140ab8b448644857d
77c698e773380cdbf0b20097e5baef9736b34ee9e5c931550d1e5ae2cc1a0fda
fea53b2b7f0145c88ff12aa9fc3cac0ad4ff7eba4c023b638650ac2ff63f8c15
247a5634f7c5f52d40d50f0f838a481d871c90a6177699d56cb71728f7675694
143bbaf92cb9c8187f0673f4027afdc3a82e1f1d132c0adad1f1b5a5d88d3e55
fbcd131decb8aacfb987ecd2b08616d2872a57c092e846850af87ae9e5138e8e
e393a897adf6a604e419e82567554eb42c0eb4d986f0b15d5241fe394dec0b14
5ba32711a7551846088d1cbc6df53751bab7bf41f1bac7fd103cf9ef5a013f6a
554aa367dbc2f60d3b18683f494dbefd7fa6e69f64509f2fd17dc2dc56675b22
562f67799eb23aee0601d58bc633f7efd496eb23156d2508cbbc5e0233468031
abb25e7ef934ba1c1f11194647a41a5b8564a2f7074e51ead191e07eedfdce06
4531206d9f45a4d3a6c973da7d4179970bb23ff7ac306a9d8a86f3f193b02456
99d5e09371aaf0abe0eae637bbd5c2e322d05792b8b0eddb55f8ae1a29c8f893
a44b46f09fb51f6cca07bed247cfb79d6e165428dbd6762fb852a0b50fd71bad
c8a67916b4e860c8ac455b8700c4bb3d9210117188431ac09ef81ed59532eb7e
46b995e44dee662453fda4a035f114795ec2b24a9aed1fc24c2740a66182d44f
4c887bd5466bd0423f187cdae256bb2ded376e6d01ac915f69b46a72cb7701fb
e39779c789a6d73e09fdad1fb96cdc15b5f12edfe4cc6d4683307c20f4c29a04
ef891fb6c9a653b3e590954c37882242dc0263e5e78243a01ff1b7f617b51541
026ca87b8e1767ec650db9a980a43046139977af540b557d833a5f91dce1b4b9
cc2987180e36cfd06ac898f9fda09e7923379b544cde3f19e53087ac5520d6be
f27ec7fdda688fa2e2521d9aeca7640cd0c67fc4de3b78a58f2f2713c596790a
5397b4193dbb7836e5ae4e8f730fef0072d80d5d08db0ea77aed7b777a043169
1f7e4a6c19569395c8b62491d4773558389b3632f15f279ce76c4ea36d80ca87
50739d01cf9ac150cc71bef46cf5fe7f5b269494b2e45c36bc8f6e3bac6d4ed5
ddecf72da7a129261ee1668f0dca9709912700c218d6c75995d9211d027997bd
4d8a5e783fd01a609ce491b0a3c5b9f1849d3c7af1ec29b552422f4cdc7ffb68
a187231313e5bde29a14434455cec6e59e1fd22891b71b8b27ab577b1080f7d4
dae4b70fd59a2618275639cce0ebe8c089e5199743447b147d2862a4f86c0d94
acb7912cc3e7ee94e13ebed8740040502cf880d8a936054e2e3f49307a96a482
e52c0adb899a70b2da3de0d344bfe5f26dc38576fe0e49725abcf892cb67cdf6
3e4ff64ced264130113abee27fb917e8b01061a731558a7f0602ddee53f846a6
3ead1b70ca3106459f894dc8adfa42c0664734ffee165435c3416e33d7985f15
3342fb711620de891e05dc47a75fc2159eca7aaf99ce9babdeca2086d29b2698
b4bf0e59ed9a4bb1d8abe07d0eef91635904a2db297f52373b013098913984ac
b4b691a953923276693a46072ae22bf31ec035039a2ec831da15b787d45a0bae
eb19a6d51fc981371be12af2991fff9c34fc1a3fb33025e9cb4ad28edb6b2f24
6d80492f5b16400452e82aebb9d5356a1b83166efd47e8b3c2e85d967978c69b
c97c80f2f86f308b8ef57f831455e565a90f883952feeeaa79524e82c46fde1b
5637e423903fc5ebc87fbb87a9296f4934a8dc25d469f23e0dbcf737c3f91b60
578fd778c9a7cee3f170182a43a625a8267a6d31481d30c1ce760469e099c081
4efaaf654d13d115ca56bf18112332ea987d95699d42513e118f0fa10b7f667c
f5248a7a9820ad4c4b3004afc941b56d979196caa59808d6835ab662e02c5638
3fde509873c0eab21a23bbf820754fa3e4cc97319c1a22c137880cec1be2283c
67a5a60c693211f6e3df953db459a95b2916e07cf78f0a9f4aa7accfabde245f
8fa91de3b93139a1bfead75d282e1480fa815bf032e8bb7c0be437aaaf40e415
114037973d8d7f090ff00aa453915bbfe30d5be907fa62dbf142c7d06de34a02
9e60b0f5a9d818a41dfb6984e145ae53e27a10ef3e801a6fab32b732b6e59670
1a916c25b8d6dde4ee6f533bf86a29228c32be0a7391168e0de2d33a19bef7a1
21575558146e78ea4a1e918906f47211b23bff484d9e8f5c74686e071395bfaf
1cffbaee544040ca5a773c778333f4de2500fe7e754f013626c48446c88e7b7b
09b8166c4a35e70b8a23e54acce058aa38bc03082996988734c6331b5fc936c5
3144ab1081b9f0d2640d3a5c56c6ec5e841da4cbf1addfbdb69d78ca9a030a38
bbf1f50fe6e8c17791b5086e164a844cc12ca8ae77ce726eb0426cc567d4a1ec
b2cbbb56491fb2c61490c00950f57d3e7f445f6893dd943bd214f5efb64d8b13
e59cbaa2fff2f469390f7eb67d2b698cbc1de60240bfa546d062da830580a097
af74715d9e9faed2796bf01380857b3e0b25b73ee233825d74057355f7bc0a86
96f8caff67191b8854b73baf714f33ae8db3c5a088994764493bcfe3b1e53a29
c851ee125e57cc7acccd16e2ddce3205e41fb1acdb80c8309f0710d10b47f85f
fb0d99166c9e8d5c7c2a03fde970761a9c449fd6b64b0294e9f1515920ab8c73
6e30ca4805e04e6e8d59e2b64fa4850758d4a396fcfa1bf861dee3854b1209ca
c27d7ab21dc56e64b1e8a8c122d4cfe4d86488e1191bd7717f2ed275467a1513
5409eb9be53e64c7022959fc4062b0a8ae2d3e8c3d82acb80f7ed0de5bb46de3
052a570aa8510a3c61e84dd46de67b609e5af4e21744a7adab3c84f40b20e12a
4232d71abd50099fe1aa314b77cc8e9fae8c20667b51ee9e2c014d88b5b3370b
5cbf975dec8e0518bdbb0facd231c9fc79f75ed2df84aa12910da5b5821a1d0e
941b471f6b441431f90681f34901d6fbcfba80728f99e483e5f6d261da010062
d7f0e7a7f28d51293d99d55263f50055f08390a5b2d19d4e7d21e758442eb2f0
7b36a574f3704b796c89b64533fe4b56d7466ce1169f35519b7498563c328600
659020840f2029195cb60165303aca82bff39b85543e8405ce605fc0e4c509b3
ee03da4ebc2117b8c53e9094404309ef40772eb68fbc53a9404f8856a6f1eed2
c19ff3d37611157b0c074c521ceaa283fd789693e67935807be66c2b8c9cb463
5635345c8fcaa617c720abc2031cca53c8c9f184a313bc642aae3277025c1fd9
2b8a3c8c6525ce816e79bcad7cc3a0575ca1c15e790da9278b7f0d52161d60d4
accd6524a200f8f0e28c58492a73aa353ba3cc5d08b50d4069e0d4d3ed5b89d5
26bd2b0d30c6ccb0c81628b297dd0a11bd78a4197dc71b8e526a07f94119c41c
31068f5b8577412b249827a0cf9faa09bfd2c58d1895e9152789de834f17e0a4
b289661753560e126a86c36ffd623a16905b25a113281e4a5e4f23ba18d76dc2
c4eb55b4b2adb37dc26f8501b415beabf99a50724676f752508cca4f2d377d8f
3fbc4ee548e32b2126a1130aa7ae985b67b0f22f23cc5d6a6ad91663579c230a
eac6971a114cfe4722dad2985ca3d8f177be6d25e3b46791d076e7b41472119f
2630a9b127a41d23c4856a62c6d4ddbde6f60854645fa885385edc4099501890
444e1f8bc5ee304d61e90ef516789d1332503392b58a1f4edb6e3e51fe46f600
255e6e67ed8a1bac4a1f664d2f6ff7eec03662aeac04898137b77caa4a06b39e
1d02a2400ff8edc0203ff69b459b34ce1893fc9f0906b9bcffd6cbc16031e287
81ab8fcddac8d46766b2fee7f1cc1680c761571630ffe3d98d003b9c54ac600f
f19497f857a87a8f094de272956c34236a0f7735a10f4d9046fb5be505bf9155
c8ea406dc75397ac3a39a1dd9e3d826ba947f3c2d9bf86e562f784f0ac9c0015
6ac966d82db89288f9fd528f326a98aa4ae52c01f37ec35edec50bff538b1c27
c12b2a40d381ced5dac57265b09e2b10e8a8be18512d86c6caf0bc4ed62d85e5
7c705fbae9a29ac2cdd04a39350f56340d21f2a574338c4812fad0178fbe6bcc
9addc2ca56ad4d2414189e510af6ca91f972337b2089ccfa039539e501ca93c0
077cb632db432e8f763f89008b54409e9a246adde329b1959c0195a65a19dff6
6f2ce2b29598c64a4f9f403f4875068189c37dbd26d898b4d2036ee9d66c0a47
bac97eba09e6cd35efbdcd8580e3327607c4695b955603d65d49b27020b4df47
b5856b82fea411f32316a88e1588deda3b4cd8c4d380f6d7e4985b1e5c56adf6
8c3f823377629c6b7803bca146f598d9a81ac8fd24285e04848a7cd04cf76423
a75527e925a56a94d34aac1c4f4a6d6fe5d7abbdc5f8e13b01e629b07227c482
a95306475af166614162b3c959943128659d78615af9436c19a024cb9ad0695d
00eec8af046c1b46903b258b4a96ae75fa79f11fb500f112dd7e898f529e83cf
b2b0f0d2c362bc6a3131588f45f716d03ac26d43ed6e59160fffc7d004438066
9e37ecc78d570959d9b5966dba2d05d0c1f9da72f62d4590262a4c20d44e489a
e5e71e5b24e87a5f322f07d2e3351b9e7aa51c722950905bcbdc781d9f5739f4
dfc08700668b45eedd07fa3eedb79d1b874c75a4ab1eb586763a9ccb902312ff
0d077bbc7cbd50c3468bf6d3a8b443516ac729b0ef1c1d47eaf28f1d2d990978
d442c274e7244cb2f3581618a8e03528f6aeb6693a95674d084490e05ad99c33
1d29ddf587dac92964f28b0dc417f469e5c167373307a25b18e1f79b954a2f87
530c3ac4f3f386baed26b8eaa493881806a3ef2ea94a0a3e255a9049f1d2e880
b22d7b80c68baef9cb138cd0e1489b4edee24aef9bc1f575211718b7ead30ee8
a40080ca72908a94f4988a736b98579cd9eb7fdf2c5846fc366b789b96623db8
99ea3d6d645e2c69ec2d80c19aae44a5ad075ee4263fcc1eca9ec49b1f238cdc
8b34cd0ad8506f46af612a5244c59a24650c82c78f0b55c5f725882a03f6ab2a
318cb837d391332d2972bf91059641750fb6de030f3a9d2586864ca66cde6889
1fdd091c1e1c6ac10c368c6a1c88cfdce80c2f7784f5e0f3fb5eb7a5652ddbac
de6f9411dcdca24085106a903aabd550d6a60cc254a4ac9799102af0058e69cc
967336ae463af4f5ad60d7d7a0dd1ea90d0a61c54df53de73dae1a47280ca097
6d72df4fbf3e279099e6c15080c717436be36d6de66620449dbf739cc20105fc
e5d156569c93998022adb75efc94e759cf218b1dfc2df6623a05ab83e6b33c8a
d68f50199dc187e32e25e69a3078401cee02ac970c9d6ef83043dfe89eb9bcc4
000a67cf53b56ebf0eaec01dd44f33009962ed178a9df6152d72d03dc2c20008
f6e8b0811b3d6165c094dc9273027eee868929c91b23481325e52317194aca3b
afc9331178c5bc7908e554ee14a5f26d1d156883c610ce4d7b73a03d9f5ee6af
8a6a3595cd5b8d21f69311e1f6e427f74181ca00359e849f2b5641d5fc44b02a
605b2e5ac0d84db3f9f8ce484f75d4c9e48b4003f076dbf8c5e516d2891e04b7
0a7d05927b25e22008049536b853eb1fe560cd7f5975e6a60c59ba852e62b800
1801deb36ee091af53f421dfeeeeea56ce5ffca7fd3864e2ac597b18d733d3a8
1fe6b47a9a1163c67db6e5b354e4e7a6f32c5d52585070bbd44344ab9a3502de
80bbdd0f1acfa5c8f291a531b6a0da0501973ee5c124c957c18a7d912d6278a7
25fd86742c7e8908c1480176d0c9dd6987abacae3502b1397e3214fbc5f1c52c
69923ae1c0be2e24d5dacd3363f5dddb08f14f1c52f21ede3aa44e96a62f67f5
dcdd0e4dd4e4e097796e39a10be6e53b11eb52738702dd87195239da0b2772b0
5ec1ff879098de5fab79cd30762efa1f684cad1d48da21897c7c0640e66eebcf
92cb578985a3ef8a67f4e4f95157213edb573522ebf1fb28c8f8bd668ab9b065
896409d8c80ec49766e2f919cd9be26a7281aa249ba1ce523539b544048d2737
c1a5c48345b8662e1591a5c55ca5165bcd15d4a6bf883e53e15b362c1b13d59c
8da24eba5e3111a84b6aa885c503c0476194093e3f614724971332522e70bdbb
5ced7f3095be6e771b22c1e276ec900417d23ef3782b597e7689afaa8eb6799e
0ca951fa47420d8d51695db70e405bf5efc0781bd390df0f3819e76a789f7c00
f31ca62fb375065d6f1fa8bc9a0b181641e190450a7f11477c460543ea27df8b
880236a38e3ddc221d20cbf82414ad8de9dba8467c81a34d85ff496f9ae08dd2
3ad0c8579891f3b2a5dfbc5853e42ecf6230c9984e1f204f315b08690151a40b
17d8ef3b070413ea6a8a0326ae595f5fe4c6e3a22b9d4febf4aa7a5a380dc7a3
6ff60d641f350edeb361583074dd444f8054edd567e0d6e85d0bfc54db7d5a3e
426452446f90e3a3247a6d107e5a50d7b3c7c3e7aa95eeb00457f19f6f036c3d
fb64e29dc053bcdd0c193cd3d64db4e5deff4c0ae25748eee15dbb3e497fa7f2
30cba7632ca40dea5af07170c067b57c0246a94eb5890e475bd48d5f3fa78c92
524e56a86c81a05a996d78f2b396773431039ce486f061aef34ff2036b374cfe
7360472f81032826ad1b683614dc8bf1b1c839336a5b2b4bc34dbcb931f9fcbd
0898b5cec6c5b22ff48dcca5297b8c31ad901074a668efecd2f9fb2a48e99426
38694ac1f53d5f66acc5ed80ee74789607fb5ea4e876d0b666ff64dac1473e32
9526650ce6d86e64ce7bf4ecfefe2da01e7c99eeb701ed83d03f5070172d2beb
1c434c5896006ed7a54da5995f92857c6a6da196b54cae99bf858e1fa03cc06f
7e2433b5f657bea37d794e6fba7f01ca901054f3dd7d000ef3ada9ac7e81c787
36cbce2f36b1c19f1316a066bc0dcd0459056c0e1301d0831e38b372ab663a95
dd07dd9b6eca6eaa73f78e6ca1e49593370c6985eb11f52b2579992b727d251b
3115f5da655ebf5a8aa608d762adceeeb5411f96aa69f0401ddc589f90ef3532
7d6e34000d64205244d74a210b8a92bb9d531aa8c694a6a0ea624ebeb3b73612
6776b0832f870eb22a19c79f1e75b90dbaf8f4ab11a03444456fa999163f322b
be6b3466eaed84ab9305c8f74846f9f0757163f8a2dfee372356ac735a957fe6
4eb512388d999f3c0268ed977bc850db0b105db6e9befc145f875dac99526dd2
b60737a1bb5522c3922d0aebc891c50a2b30835caa96efb4d9e9460f184605a9
99bf4a132b1c594f4102cde6f11550df0ac8e25c8266b418b0b38fd70f1b37f7
6989771afae85d07f2121e4b98462c24d108744a5277ae24e2db55ace77d2cc3
c4e12122499d4465edc53c62a6828328b914a534b4b02e4551cd873bc567b3d2
b9730f39604333a1e0f031e307977095cb2203d0638d224ac389dc14685ecab7
883ef38674e2a9d297dfad06e2c14e2bf9f73faaf88c23ba68948c53f284b942
1c2627e516f813f3eb2b8a0ea098c4b9bb013c7b7c62a678bbf9c2d0af808a5b
15a9f7805469bcc5ab68b0f2d27c981f48f22ff672e9baaca27cdb1f20749252
4990e6d5d47e0098c9a7f22e01906bd1b19441c61602012790ad53f22c8a3533
79bbd448911a8748c23518c2e8b0b2e456310deb8b2f2ca8fedb39bf641e7564
f975914f93fb8b87bfdc4d222446c3e0d3f3eeb32d3fa90da1958719a1e5a508
138e9ab8612e9e700b83ce0795a0305a10f07130d5ce8dc8336a79ff2d1ab7d6
4ac1626dc532a58f104dc699943f13c32292fd2d1e4a41fedbf0d3c490b496d7
69d1ab2082956cd35158ec683fae6c310535dad230cdb895d7b0fb8885d13186
da27c5ad119811b61d54159cffce674c443302a1b9309cd5ba0d1555354d4885
1424e15cf3d014516c812e3a8f443dedef2cc42f1539da7c76d459a10dbfce38
9a81acbaf5906f3243131a12bd3acbfeb932f5c2c6b9594c111c5747a089208c
0ae1a9535b8874fade4afaa16f8a6cb832b53e643e097ef106dd8717e5df11c2
9cd83cb9107ec6e6e9393e9b7c61bb3661ce7f99cff2c0eb2ac5fa9974cf8158
fee10e0bd9a658507df01ab39e453cc29dba4140633c74c1c65b43bf97f37693
7b3204f988a4bd915062ad2a4ea217afd2527773453c6a903ff2b19d6bf5174f
0838ebd03f90eec3a12d8823363e0bc3a605b2d96151aa2acdbc97107cb85cf6
5d4d6e2d26a80ede34a67d7c2538b7d6a3f6a7a4f3a7ea77923ee2d0e7f59c0a
48602ece66234bed99815664ce266340701e3236e8c19ac18ff5f1817438ff3a
f7002c947310456dd39941f48b1b59612ec17552c2eecddbcfd0a1d3f3f2bd70
524d32f41e05fb5147f6e59d7de62ac64bec4b1b63cba4055f41c554404d8998
24c08306fb669a9a9dd9999f488cff672324d42735143066412611aae08a6f8d
119287d1fb56d03c8b473e859588077dc1f63a2c9d1f7fa508a0cc07d677ce0d
18866eed8a9d2dcf94ca6087a250769b45958893a50cc478cc02adb094da5759
457c2c8bad7c93c56f2e2bbabc4d476bffb4700b9a1dc9e04d0bc1e51471f883
007a9c80c633035abd43b476348358698af7c26765d875a186db668366fc1e55
cdb493ebb8f97a13a704a291733261caa9573651961a15f6d880488eba84bf91
6290f5712cf453a153013ad5e26eae101f3f2e9d5057e1ebe192e0dc1dc40572
af657d659d64b127d0a01fe8bc4794cce700fc5181ee851fa83bd28622433da5
c2b7ad1ddbe4f78087f4e3674bf8426737b1680d293aa9171c1ca9455cb34716
9bdc8c9ee6f10d4631d2c62071e24fb560e835e2206cabd3bb31f264984b0858
0140de20af70220206d6bfae0183bc17dc38fbd7e6e1050eada46da9e87fd482
9685fece7592fffe2d442dd1dd29cac19b2ad56e21456d820d666fe3e291ba0f
37f27b809e9d0b03277ebeb5c1db4d70d12ee0b5a053ee711fab06131a420fd7
49d6cbf1707165357e42eb049dcec1eefe81d53f4feae5a08238da3f29f30cfe
c89cbe40fbdc618653f2bc20fdac4f17a267ff38eeeddaf4473583f613352d56
570c7f92b1d8c98a3764a995c6d077e032d3aa43298e4e0c71bfeb968cbe73d0
db63d1bff0252274843eb6932ddbaf364832f6662f03e3215edff938596900bc
d3ae6392e72427efa34648354d74ac78c786418df01350886b595acc80a83e0e
8899dd616bad8ce7e39b0cfbf2f51ddb412924e99c3ee6196e2827dddbf84360
5e26c7af61620261cfb40619d6a6de8f62d687a1a863875444e60468c1e26f51
2ba48a0ae46bea5f321774099a6cff80b4643ec9e888ef4c90b53a46bd6cacba
12d8c0f7f8175dc5904fe0b8d33f7c0de194092d0f556d58cd04c95a91fddcab
6b9ab1ba04bc76e127712bd189b423ad42d09436953615a0112279b2b51c518a
f91d1a93f96678cda3be3107261efa45496ac55d438dfc0eed3428e98830f3c8
d32a952727a33da34339ae892bfe98a03f28c8ddd6aa93c207f198a7a89aa51c
a8a39da48cb73725656e6a405d4c2e4bbbb704e42f019cdcbea48320e940a664
aee67c5296d6f5d79ea7ba7409a3b09279f9d095659adf8b0387d8a93074ea17
a209a06f1b2abd4100b1db36cea1183036f5a2f381d88334a07e8b1b7aececdc
5ca8b47f36a1ecff41249ad8a5c73ec35dd9c7565fa965bea54928c1abe8a142
7d86904d52f029f5654df6b7d8ec9c371b89a9e001628a845cebc9543c5d12dd
14f37db7a8652c5e9de24b3af4f6e2b63c4b89e1290f7ba24df68676ee6c7c4d
9fdbf11dca6151ca96952dd9f8582a8bbf0b2e0b0a53ce8c25e205652f94760d
1d0baa9f8ea1105859913408cea8d998b6a4a2fa5160f43836b00e5548b166ff
b046899d08166a6a13bdffcc296345d813169628e52821da47838f6cecbe375d
ff962e2372874f32f2ab74ea4bbf46f8f69ca4979e1e711524c3c798d1b1ce16
aca1e51773860a5c78bcb7fc033b2b33fab9cc4f6d4eaf115f061a6e8e5eb59f
457c5071d0836e82b1a30f049ee38be0c4bc888c77a05158bc8f9e1c6c5d20ce
b5f95b3e291c5d8ca5d1cf2d5b450a897882ac1e7a74044442e73f88e1bf86cf
686442b7c2e901432fc4b1810fca11f6c7e608e4b4d0c8c3d55b15fa41d42cc3
c5b5e5cfd57dfd535437a599e29529b1a3b72c6f4ef01310f9e9e5325eb4a11e
c576d640968109763a07bb6663f96280380e7f8ff5e4a70f89bd959ff898978b
694f538bd1c033981cdf04593310d3bb25065c528b0f0c4a9b18a0b9f6beeb4e
80c8c2f3dc52099fb7e6e5a7686294060dbc7b915b96aa103f5e881976073914
49c849f5b9531437fcafce3fcebf6b57f4e6f73815bd464b01faba78485a963e
394528b5b871d1d4d1e3b57eeb3a394e51af78a21f28dd4c99d9e9bb9e16e8f2
de5648bd78c223099df4d89515c7482123cfd12b816314856c8e376e8ef8eb3d
7ac71e2c5ed5ec57038cdf32e18882955869375acbd0ff06b514146890a5a37c
38e86bd788fb00343c0078f7ddf6af86c5b7473cf433d4d79b2bfd6c217775bb
a004d173549a00b1e4548d2511fa5c1fa6647efe64e228e76534eae78e17d9f2
3c2b3f20122ecfc9d0c58f58a3b5e8071f0fae6ab18612501467c73197164467
64891eea4a97c5975550f74c8a38417fc2f7f62b0478cf8bc656a32606229dce
fbfd62342e7657e7628b5135447ab9ea76e36fbc16bc4f2a85e77d15fb077b63
06a804ad7206ecb3cac99d8d0b883187122688f577561841f9a7ae50c74d7d5c
0e6ead60679f833b0226444dd6457810b5d39e6370831295c1266eaca067626e
deb640a50c27d6c7750ce8038ffcd47d042998c3877fe1086363fa7ab281f524
e72cdb2c4c6da8a896cf427e3ad9a0b221fda14990709c7747720a71deff7edc
45c35888ab0b74df3951c8772adf2b0aeefd00820dea50f1c9ccc26806d5d7f0
ecf5ed236ce610003e7e2f470fcc3a230fdaee3a3ff1d79c7972017094163d83
9644a87b6434e32d1dc0fad4cdf61ae72440831e305b4d96268cde8c0623bc43
b4f93bff4e5fac36230ee08d1a281e3dfa52e9d7648aec003a73afbd37478331
ee0126a432f3c2eb5b15213eed4f535560ba679c8d2bdb6f1d213ba688ee5b50
497e7620d0ef3ed914322291b8d3b94d9a33aaccc81d7564550110bae09713d9
e9fc0decb13968292c56aa893c438ba7bc15c93036144a9e1ebabaa49e794c8a
f701b3b616079663fbfa33d78da000e4f1c66b7819c3b61ca31f5e46f99700ba
45804282a1648001fb44a80ca2a358ef1bf3f3b9a7d52b80411fd6bc3bc1d0cf
0c30aa17f8ad65a8d0b34b969417fcbf2336486b07740b51ccd275affdb8fa0f
3c903789c1de2b5f9d91f045ba919a3fd6fe8139a653635c2e713218b8e60a9d
e60ad81723af4be4a1f17a19be5ed92f2710d1586e1ef64e3c7764194acdf120
18024eb8a1c3651514cf13655537bdde4595df6415530aaa2aad6302a308b7cd
c4da33e90194213fb469a46efedf800e024b26db0b3e2e72db9f2c596b307a7d
d54e99c65a4b0076d9fc981b8278102434ee0537c1bc2d38990a62aea304aa97
234ad5004aef195010314cc378d5719b02c4b4ac6065c19d670febffffeeb184
84d4c4f3ffd1582f28e8bd23ba8c42293ef757955021b665aa9426b0bad4cc6c
e3285d627458668a215e595e3f103e73797e76bc7f83be1e9833e31a6ea2112f
42d75e3ed1db104fe4340eae97e4e9149df1a5e37d62afbe6ebcc3cb13db3451
59dde711e9f1022a5b13dd5e20c9ef109f55c2259fbc97eefd747f302e3f2aaf
dc39376d27a9baed7da4c851d61c2b1b952715406a6deabf98d32743e3e7ae75
d69f46473c0d070e13c7dc26419a1f411b2111d496092d7d27619542ce30c4e1
1b31901ada9efb21cdc492089cd61e697c9a785d84dd234913fabb2dc5abcd72
a24ff0f3bfd7d2b51a014adf5d60dfe706b5ac8807965dd2505e555e798156f1
7d2d185fffd848770b2829a0365f5091dfdae92f283a1671474c66648751ddec
04bfaf5e34e46b6299b8f7561c2352b275d77d820531bc99865d943fa8318263
7d1ae620bc7cd4fbf11521d090ca3d7ef515e9af1b0043d137869d99e251ca96
ec500ec23d14d00edef32256da66da6598f0effc5121a526e7874934dc9ded3b
3016a6bcc1033e4dc8e8be06c80cdbaa0697fd2ea2c7716af80390cd914534a3
0376b855e4e3ed549806d4bed85a6c211702c166cbcef308ba4ce7de0b784498
f90c2cd6e5957245f99ceefe09b4530066df44bdb7b095e390aa9485daa65697
782224a05e69a1122c82673822cb5d4c8dd0827e5196e8dd4d531928c1de61ba
5d8905a6941c3ce778e74dcb8b399adb7f6e80d143bb4a73ec52db117a2b0332
ef1d4c0c97ae26d5f7ac089aaa19803c98e7e8c8393ea3facaeb24f98d543e17
d0d8cdcac71ce7917940adbd9083f307e17d8d24b8324ec81e6290c30ca9f465
7b2671296b51a232066bf70f8b29e0010f9bfb50c47aca95b6f6b1efe7a39722
092eb82acd6252e50ba450ebf29288530784061c3d1bbb87e1ed0621891732d1
021ded3ef6bc79548754a42694a313cd90fa89fccae8fac722a4b22b033c0186
e9c950b1982663faa6d388d8a5f7e6aaa3c601aca3027d9aef7cbcd174850c6d
ef276bea2f5c1f3c7fb26cd8781df4879bc813826c5fad2b5912ad997bfc8987
ea38fa165ed37d2ea5fe86bdb5b493250a3763979a0e262959745c64725708ff
710b5ae860b4b992e2ffd2f465a2f7d2e453882d5f559482f6530ca118d561c4
f71d01fb9c7c532a11af2502886547660493505239570a939dffa869a899bfad
43101bd4c110534b45d419d38e45d2cb3e9d01e0af8a12dc4620bbcbdba29be3
a291eaf7725a01a52d2efb5322d3926133d6543799662fd0f239258b5ecf64df
efc96a446a795c1744e5c7343a9cc19288527464cd8b747ae0d31002abd6e539
fe7efc11e68364234cac2aac1bc8f87f1e3e046aa6de1cbe17569a2902bc8d69
539f07af0803e76343817d6953816bbb2b2b21b7cbdec5057d411f1349879e39
cde59c5578aab5901be1469569b4beb8d4be9af44a6e2573d5426dc9e1451884
7cc49abdc70ed44cbbd458e626275490d75d82e6b27afc8651d142efd21e83a4
eae297c738737a9f38691e8204ce9cda006479d67954a211e29a66b39af61b1f
02ba32e7f9572a6ae856c76b3409bdc327c1fede0ff9e87542da474b4a810717
5018ecc796a2e77aec3d2c3611b6d3604f54a4ea16a273392ec60d104bd55b7e
e1c778793279c9ecc8581bb7703ed6030bd52b3c860b5bd7c7218aa384ba5888
4c6095d82ba1cdf3795e20d906d2916dfafd0d3fd30444596459013a72e35d2b
67002d8cc78b07afdd4f1b37ab0550a603f986d35a772670f27dcab52669f295
70e702c0d4eb95abdf3c41814622d0d4c31da62dc4e6f9cc41fbaca520bf948a
5a35c12aaf9241adb51c851d4b46ea6bd3cea8039f31bbb4a131b8c94eac7ca4
1cac05863ae0b857bad14a4869c2cee624f3c49d6694bf6f1a8ec1d97cd4b41e
6fcda3b3afd064cc1946daa86257c938bd342d194dd1e48db1943248751fd347
27882e67720e2625dadeaff7c0ad7811832457ba44bc593ab72d3e69348fa6d5
1fec0eead2cab806cbed067eb5d0e3f33ae60a282e3ebbb17c685db92d723c65
91d979431c5d515e90c4e150e1c27b9c5a2155e6da57d1c6439519f900b63813
ce526cb6341fd975feb3ef4302f444ca4229026e1f3bdbc88c66e843504b2813
d5332f8b757eace033aedf0dda92b6ae8e212af47462c7efa82b4d86e51275f4
e9037316b513e94a5a7539f1c0e53a054692257436ff8b564aaa53a43aac6199
7f73d27f241985f5c867210e20b3a3e561af8067f78320edfc39faef61f956b0
6beeb31c2693d71406341dc9500d2132eac64519318eca483c96432e26eb7fd4
ab00d2c3dfaa66080ac049d3799f10286b18a41e7dde466b11832a37d42b7f6c
9581983684a5a22b28c818b6c0ac32385e8bdaa930045119e250f99981681166
e9cfd7c1721b3e6884d70389375e016251f19c38a3030f6d22e2044dd1483157
fe1f57a62bbf715a0d5ad74f89a085ec08f1712eb694e6b2ef76c6d7a2cf121d
082e096937bd8ce5462c5fe32534a69d09591f7dbd8d299fc44b77fd89e8a985
4bcc76497bbeb1046d6727eb0c1dd1043b23690791e936b8255b822bd76dbafa
f4bd616a99246420a2c3258155153b608f40896def0234ec284ee8badd86a985
2bb24a852c5ffa8235bcf8c79ed119c9a19fcd0bebed36f0a7d02fac143ce27d
8eeeb66f80f9bd29a71b3042fc955fc9cb1a78521a6135a48d463452e7e8894f
15c313f727821a2f1f0b72e348a816fb65dad9877b9f11fef4373500a31650c1
8c4413a0b77fc4db2094993a60aa29f85e79d847854b6dbca8f6f044a8b5d48b
68dc57f401f9b6da2b539f65038765d40fccd8480bf0dd307162d6cb55a0b8dd
acd8e89b14a8f59304d69e1e4050b75240143011e99431b912e654a0ae657847
0dceec2f032ae6845a7c98f9754ca2a62b0766c14e4dad330af53014cd3fd038
0f63c35b66b94fe2aa3bca9d7727c77b8a890768e6f5b2971680a3e27028faba
af85513d4ebcdec02899e3def1d5db3e5837baeb1c815d7f9cb693a6ab2c52d5
0ccbd9f2f6148799e69f565a2d8a9f2204ce960f0a745fbd4e429c9d17c59fd1
951844b5119b538622586ffc8cf24a07d8552e1573c7d40e98f8ceabccafa506
1aa8ba8af971980dd30ab87d773c9db591693ac035b25e051d518a563e5883d2
78f6dbcf4c1e006da5935bdba57d0a7d5a7d636285bf813427841b73e4037dbd
bd4c5298d36a06c9a5099859065bb6020b09fdb77bcb2086adb42ffac1c3ac98
8909b3a32a462023eaa240a85311224e7cbecff9d313effcabc9fdcecd1583f3
cede24b89f955efd642ebd2ad4a2a7a842efb55b9d864f222d0c23d0ec338046
e52e364c8361f358a543fe655570d022c5be557647188f9a68e5f1cea915640a
d315926ea8fdd565443be708c22fd737969bd47b5d9792d726e2d8c2d0efd4f5
9fe85a83443296cf2ab1c3ff08daadde7b88cd109b77ad93f1fd9e3dd993a7de
c4830c6506db3116e927eedb49346a625b1de46556c17f6ce059a6551ca807f9
7d9b83c73587c8c0d939b224fc60555b29d720a4672688f6aa05def469339695
67c98297df8a5eeb08b2dcefafa1b75ff490d89dddb904e8626d9712eb01699b
c87e29e4aa4b5cfbf75bc4fdb82f6f68a43939ba694522ca98c06e9ba78c3a76
f82b3aad62318ce6ac528a9dbadf3e7b32cc9b76453ba08f40c4d08787176e60
b7237c20be1748e29ede557fa294c91bbfd41884d62c9dda9d3600e29523bba3
40902e133e0347026247d37f1423643638ec5d4955bee51b90f74395629bdbf8
39cf69947057935f20581403a3eafa3dff0e5516135f38451777879268573b11
d0b7af0ff8bc2233cf7de23ed7ffac99d04c77c592eb7d0be542f5f7c5523021
6a5dd636346f512ce9d0bb7fd8e90f688ccf4644d6ee5f3dcd260ad9757aff78
e4e70a75ab9bc484b122a1b6cb0b244b271aafe367daa18e9bc63ac9893204f4
292549d2856c0e6c81c0808a24d843038af49a501c0720e8533e130bda9d31ca
e6df0fb5b0296ae9041f7e305fb449c6976a4b57b5eee5b317e9fd637ae1434e
96286e5265a0ecc7c4ce44255fd3054d52a7a5e14bcba0b46ae88646520c798e
75c2c836ba44c610da75f4727d5bfe702a4ae6b3e56bc3b1f961ac8aedaaaf59
298ba1abe3b08e07e54d1560c435a02eec7803e0e5c295661291638bba48e9ad
2b4ea43e0a32cfc059ab86e45b9bf0ec2bda2a29e0aade3ab853e69eacd6e36e
3f5385f8163ff6e093c3f9fc9d0f4d7f07347e3dc0ecab3f8d896b6aa9ec16e9
712f2013d965c8cf58f9e58ba960af228bfd868a58d7f48b852f390cec924f7f
daf27cc778cdad0d45451571d462e7b67416af910641c23e569f09ea6c9f5124
e6f94c533f0ef97fd8baa83d67005573beb1d3a590ea5d6de6a27c67ee29ee3d
fe523c9c25730e613c143f65824ad0417e08c7044d62d6fdb5121359e2ce3d4a
d43ef742418a8bc1c2621ecedd92f3163cf465d2a497efa39031ed593ba6fbfb
990cc4305b317516eb309b75225d8c07f29aab63aecf69dba066093c02b75d1f
ac8324253ddedbeaa90bde3847af539487080773f6859ac0a29dad4292732784
554f781fd7b46afab4d590c3cc3c1293676d6bdbd258c5790c2f77eae6360a08
284545bbe5737849a65dc618bace5fa758c83a79aee9cc959520ca8cd61d1ad4
7ada73139125649c52877660942fe51640949c47415beab31dfb1289359e6539
0322f7d10fb48ff72faac2dee352f9c309b6b26e5227956a51219012d129b58c
9446a3508369a648041f11580f2233756785e691722760800f915e2de4a2c213
e6c31c79c75ea18ccb9cc64ad6fc3365e37639de9e6b53e7923b04a8999f9bc2
9687e2cd109cfe8ed19db953a2ddfcfca9b37cf2c0da78844ec6920a7afc7f28
4c538391d427d035e810a72fd6e4855866f16b0593a14091ee9a9d4fef2c468c
1a5289485379221302f80b4e541675fce28b181802dbfe6f76c37e2b1764eafa
11a8b51cf493b76ec87525618ea624f4b7d882998de31eef9a1f5b3e7f81aa70
7352936e05c375c36005a3b9d65388c7f1757fb7df8411de232c94cf44d7d244
73e4e6bc3de5d0cad86bd53e4a4c3b95bcc4cb4fbfbe0cfa84571c0657c49f5d
e910b205fcec20c651691d823671ee2b5f7f4e4eeb1ac5093056c60a37ea2952
bd8d4955126289ebfb41fbb82ac44edf7e91ff2c6a47643acee8624a82ede110
0002e0be55f9363787883ec6d3dc4bc81f6102c18c2cc1e803dd69f9214fc6c2
52715b4b779a1ffe77aaf46206feed7e4e35f4136831df49a8a9f751cd67a8f9
2907158a129d59240b8e3e299791236a86be2a0a5fa32c41af41c5f850808155
94361f3d57597bb790218a54bf5f9ae42ebcd88eb79448eb3fbe8015e81adfd1
68e8fb1054acfd565322a0ff02da434591965b479a9d352d9c550d1749404011
96b8edc9fa03cf1cefcacda90656530ae86b7f46b69130ee7a92a6b52bf71f87
c629b0c4ee4f77eeba9f46d79bddf2feff27de687703ccae5052f87efa14bfec
37fcd11ff58a1bace17795536ed0e8579e6cf26c55299f6b869b3b744c5a4b36
4b5c727f099c76628223489dcc57da394a59e74d684d8d7000f9946fa3aca43f
939b4a1f7aca3ea362527c64bdc3f8602786925d449b2b7284e9fb3c7ababe06
eab05990ba0b079c084bb6c82d3bf8489f312a71f4e254ff44a2096d7797d502
87be3a74ba1e807780b430d76693981b60b6457d72747cd823f38ecb4d37a33a
82fef1a1167101fec09f378e346c78a0a85ee7e9f88677943cc71dae02559ac0
8c87c631e41db4bb6ce112e3ac41abcf9ac40b99f5e11d3c53cd1f0292b75e48
f9be458a4b54c3fae6ccdba7cca231cc08a10a95bd9ae06f7bf5d62625f7b8b9
31495bc51db6e5961d765a157d8f14190605a0229dd5dc00192e383372d647f8
87f97568f2d3ab020a4b4fdc9a00f48566d6c1312f6930c9c040b1144363b5a6
1a087e0fd84b09097e4a944e8e1f1f5901791b513e0eb2082bcca3002070917a
9160496591cb3fe36cb64469b193ed9cb7135721eff7289ae8685d62a4066954
cc868413d2b288d14820431c00c343b4e9bd1e619fe321e1731a90c6612be130
22f4f4bc5ccd248feda0cb0d47622ac1957390f56cd35580003c7b8f78f4fa8d
013a8009267cd8533fae86b051c680a7322f3787e7d4da83bfc94dc64d8234d4
1558d8c79c24706a138ccc3f53913428b9b4d2ad8f749c492578f21f157b6e19
20775c010c80983e0f9f8f06a0739fb0f8dece6ce631ec09230aae1db811a355
10736e838f3678324f94637e2a324be2eb60c9f24968b9ce4cc1e16b039f6449
a295a30901652fb7a80093caf7f10f03e76740e21795a1d90d0621db3f573d39
24c5f8f0df68db375e82905a71cd2d2e99bb6c4ce8ff547523e8bc966667e2d4
2dfb1662b35ca0e25589cba9662aeba0be554ccc027d8f8d3447cf6e3cea6370
2371d28b0239cab0b78771991ae23984abbd622c8564c7c44c588e90aa9e4f0f
e983bd947ec600753a37c4d9a40ad789c5a3eec66b0a9c01a41be1aebd38c08a
cc8c3d670f97e06ad3e620043e7a338a3e921537b1ae25a6e7ad0a45ec874782
64d3baab23dc6bf3bc40e9d4370ae208a72a5c02a6dddcf93d6c5d328920dae7
94c6c0c2ab912f5aabf7fccbf565d1be1d6316fe19cd8a6a292382702db55c6b
c149c91b4fe92d0bd37b774688178e4cab23776e44f126d7832348a5899f775b
f49626dbb37508df3d6b4dfc3717dbf9a69ecc2703dcaa779e62653518707910
4f86dee2495405f97274bec0ce9a9366e1309e2473f33c2704d5eec468a82d55
b2fee058eb3d2c983782383f641cdd0c8dd6c0eb44f766af1df1cf212c431b4b
ca9c0b55fb34ee2de1034d4cf02c5644b0740045d938cd9d7e680c2e7fce694c
6cf4e25840f70828fbbee65cd386136cbbb41756d558c10700ddbf0890528eb4
979463e9f3b1bd9166170419e64cc9a5aea7e17aa5de9ebd0a08e285c0a3ec0e
476d0578a8d6210739144101518edbddf9a2de8a3c49998846e342bcd213ed9a
52446dc5ce7922aac80280653e48b54bc1031cfb41ebc683046f77f1227c9177
d8a5a2058437b859cb307f46a7f4d4ea78d171affd63793c9b07c545d8f3e8dc
7815e7f2a2ab2441055e56161e3173dd444444563522d1add3e838e9dd28a587
484b4128a3ca09fa8b4cfd2147a2b372b967a53767739a3bce08bcad802a0ad9
c5dd64e641bf02443d8bf40bdd869f461d2628748657ae9f0c5d7cdb12c647b1
1315a877c217bd934ac71732a162e1c6dca5f24187b2424658a7b93c97aeea7b
9a7519f3cc75354a16dd98b3a986d9b35b3d34bad04936729f189fc09618902b
e0eea75f635b7f820ab491fc1bdcce923927a2235e27863f1974b808a66d7edf
8c34d6b737ed463675466d9e65d594cec1fbd0d276df7be3e8523e6cd5e7032c
99f78d09abf88915f60f1b0de31f21d82411ee2dad972b33d9419b1ab3f72392
6d61c84916e1dd33e285f49a4d2f1dab92c04a957b4a9075e7b5d14f5b0a584a
36bf846831c2942a72c0a9185603b014e96185499df98f1371c85814854f7424
bfda071b254df65242009a9a506564f87cd8d2f9bdf0f31c5c985a8f3d0a49be
8a9a9b897723b224df5e8e88ce936f69096836f5425bdf5036b8345ca925182d
b6a56347650d5e65c8fd80e0d4783fb0b0c9af0f2c4f0eae52f5aa2432633dcf
d2aa9cf520a6a3e879886885ed151c44d6ab8de5f90509a97d6955970ede100f
1ce32a7aa51aebb47e0419020027a29e5f35586d3aab94b885b9bb3ce4ceea70
6194a13aa978a987d139a41002cd57c87a57dd477ce9da0ec49728ffbb335f31
1fedba39fa29483efd5cde14058603d8e0043dff247bd0104345bfb44b22cdf5
f5cfa8c3c541585e92a147f18fd6b2d4f03e6b1978b89cdd41d903d694b8770a
365d98a69298ea1ea501bd56351d979feced59a0024b3be556ad1e81b1390c12
df9efeab577cd1e155aa54c9628866ec63d1c6c5bf837506122956a1df0fdbf2
fffb5e8376713b1273b0ceec888c2cbced3b3506bc224ea3b05064544dea6125
53352b7e891cae0bb7290aa0dc589334e15aa1b736c93201fa05aeada72be498
fe464410a1baa9d620df2995f77552abe07025c4cc1e34b66c070297dec064ae
03a0199ccbb75ed74dc074b86063326c4c64383749d4a02a6894e02dda0cc301
844710df68e311fc9150e0567be4d73b30a2cb3fc945d2105d0346c244a303f6
2343f91f1ece25e95bb29a781fe21e3ae3636f193ec8a103bb2b0ee375143656
465933d75015720c59e54751c2c40ff8ccaaaea8dc05925198a30ae7d0226d54
052185ceecac7ca5cfce3e607f2b1e8308e69edf0b44b03a3f6b462301ac6f93
7fa0b5404437880a8f5ccabe23d3099c54eb665fee3e52d505bef591880fbb9f
3c3d80adf914cf997a13eaaaf07395ad87456c4890804cd727f6de0b2fad77c9
c86e942f6b5913fd56344e6a65c9510bc1db2b45dd30cffbd83530f511d4473c
1df2329d588dbeb6f681dd1bc3e7a14ca218547a80f159b1d89d5f8063361911
a8de278fbb85969f27966a3ef8633a97aea2e086de15f556c8175538158c4e98
f24307ac0d00e9bbe74cba7b02606ceb24b6c4f7412c734d7fc60edf4fd70c37
03833049841c965c27dfa3a82eb628fc23f02116e3691c82711decc69c5da663
6e688200b59ff4218006490b46b11134b811f1d38a56d8a2596bc5ccdb4b5df1
49314527bc0089541874ec6ad2a04af04eb39b6e189721d66917ca4d7886940e
d2890b573a11e8ae2bb390de23ff1defc244ec6f8e32e25ecf9b7d9ed86059a7
c32010fb076a2087467919fc9258289cec569b79660daa8e8c228976611743fb
43163b8cbeb449a5cbd4cd1a8bb003c3e22588452cd04139334ebfed56562fbd
70e441367ad1ace14cc0f4b372e0e71ac6e0dc1942b64a5210f60a7d7a3d888b
3abd1a48b19a3654964b8a0847de2fe8824723625818b90922a9f26092c1b732
1c66e7fc20ccf530c19483b291fc52d1c004053d1b70b67304b4d11ae8bed407
13b9410fded393bb4b3d4c1913cf7ec0504d7c6791719fc72f233f763ef3d4b0
ce72bb0ad2b2028b0a5e71c7353b00961f7eb62fb149ac4f22d07c7a46aac3d6
e2ac600e3977d4817b436e260896a4d68c6d31e0ab4b3fa0b9d6d0ac6b70b8a3
81f0c382415441f9054e8fb8e53f2175c0f9c04ef7f5d178412a0b0045bdeedc
e459eff9555a1da7e1372c1943df4a4ed97e4bf5fa9a9122a20e4dfc9f1abb61
3cef078b4db8f7a7c261ccea2b38486751439a9162da1429144fd86261192404
f45f175347b8e02fdbbdd451b25b62e9d16beae4fd11fd6dafe9ceced0aff22c
d252aeb42306dd695cfd5a6bfa46c4d7fd52a76b5af81c59c6c9d285a6b84457
1e990baa876e88ba0a468db923d6353853f916c41056998425e660daac13c90f
19095254d2e3c73dd46db8af2ffede3cf5ac03af433b2104c4ef481df2ae4d45
f74ebf804703fb8f7338c02007d502f439400da62b15f1c5b3da6d6228c56551
81639bebc630b40cbbada0c3bca606bd89cc682049aedc29325517e8e350e5e4
218560823c42206f96b3d54761130fdbd5f3b9fecf198af1c21c9d861927b282
4ece8b7d60dedb3b5462b874246c9895e9c13c755aada02ec06fb8b0815580b1
8530260de35f8cc177c051e68d7405c66a2ec35e11167b7f0054fb51e8b688a2
7724e0973b1cf31d4af3b4e7facdf61a4e1dce497bbbd70a07ce66bf4b1083b6
52c0ad45edbddbbbf65369b241161f7db378ea43578b7fdeba3b04e5606f9d83
33ded10f1e773f767c420ee62ca3f2d548d74f4f74b334de94f448edf95a0dca
c1570c0f367fb0febba08396a8ae758eb4aa9efba35788db21f0680c79c9e098
70d8081c8b296482c72b4484444a4e128703d412489c040e1674edf490242cd2
8f2183367729d51d1d6b52be4acd6161bf4370167e3fa420ebb1f38b7ab4be9f
bdb46c96cb9dda0ec204d9932ab75c71154b319bb71140b6ae7c17c88ea6d552
b4386c789ac0c422735e91de8690fcebe770247a0fe52146124082905c3e245e
4c820772d45b650d5a851087b44e17a1b4d373c7dac0208d668f7194302fd182
41c36548d1592519c1ad14336132965fea8b61948cb208670e9bb1372aa16d13
6e176a436071c15afa188de94adbfcb1a136693bee9534cc215ac4514dd601f9
0c73ee42455340e552d84d960f2e334ea30ca3b0aa68eb4624ed19531c944485
f108c006bbcc8f3acfae156032d1b055f124ebf1cc1c30cf4fce979255c53270
eeb9dd40e6da81552c28925fe4e0bec8b74eec438b1577bb2dedfa4930daf2ab
7ad8960da141e0e3f47f67e0ddfb609e2eb36fcc9863aed79c1b4a55b99efa00
5ceb757f66dd7b8ffa48b4b98d0265926adc8fd5749aa3dad48de1317bfbf3be
c34ef921191ba3c59cecf455bd0b217ef8e096ef4bef98a9f03e8b37901dd289
1f762475ab44f86570c211b01bb96bf0bc7ed47004d63f541c38eaf4c3c383c9
f09bc3f4f9dd1dbf82821d73d2bc89af2164b94f95e66ab531128df670d240e7
f283b40bbd36691ccc8c4c1575328780371f08c503d78900262f6cd696148656
c73ecec5e7a65eeb2dafafa97ed8a486390fc612f032e9e54db88a36b71bb3ee
174fff955662c0d5ddfa7fac9efddc1e4b6117634c26d744fd8b0de5af092ddd
33fcf422b28f60f52b4f6b5130abae4c48255e830619bd70c51cdbbc857b4974
87b01453fbf6d6cac1aeb48fdc01b7d2e7771b1308642a9dd279f6c90801852e
aa2bea899aa07d7727ecd2be52412c551385a1093f0d843c5cfd20ff31fece74
bc2f13575ed590a4277f12dc249ee62f3997514e1059bce5f946cb1e41d1f3de
b23894bccddaabfb06555e80cd29906334fe1c283143545bd6c64a7379e9c03c
299862427dbf0abadd28843d779ef4a9a6d91c3c47ba81e2f70a449fc67eaa4c
647063c144c94d784a34714e16318d36c599232d93acf6ae4b79f29c29676fac
7f7998658e1079c8b55b92d9f84355b0145cca47da67f7962aead4b6e27a9201
9caf13f8cba6cd5bc930f501428b8c3f6df7d249d39f942ee3f902723a0818ee
adf57d044d1f1f41c28bfda6f2b81a1ee8f25a50ccefdc771a817b15c860c31c
111a2134cf4a57dc899a6ea14f7e63d1c709be90a42fe25f30171986b3e60b1e
7a9630b9276486af37451084b1593caec2daac1d23d066df410fad091472445e
3f71585f50aa1dbe6dff2dd9c867e5362a81eb94f1795030b176a399abb6ffc9
0f7eb7d7944216f7eaed6f73926dd635d90a131c13f5b99e6d96e43fbe49dece
3dcec9a31535676e246d0f94494c95b2075baece90fac5eec405db0322a1ad18
38a861e199d6e86937ded01e3948d397d0c2571913b8787a983573cdd8c97c8b
c0c4a6b666809ae2bb86658b913a9c7ee50ce79bbd4999f4014c52d44b398ebb
f0ecea504784695b026c98312c3a8ecfdf3185186dea635b08df116163fa201e
533da9d8f0416500974156cbdc9c8f18c1997f4d6d6003d9e17ce8cd6d3044ba
1f611d4f8f816becdb5de3ae620119496ce2d19ea2d721adc130de49daf27a74
ce4a8657ed30e0ac2a49793f89d1aa67ec7ef8f9429bb3c303c3de1d6b0646a1
eb817f937588f67504107f518bd78183d64728bdc17833293e6054da44e2dccf
7323d8105af724f19063c0497af45819275f0cb56f6d04928b131682acd19e82
7e1acf43ba3a3ad7fb8ab84916245e6f42dbd94d2c29f1d3e9ebd6d2075a296c
5c7092612bbaef5585246208bd098b0971a34951ef7b12b28c5ff667954d9081
59c9b112ebe55c8feee17e6819eeaa5f7f446ae0e22e63249b874d0cdf6f0066
1856d28c13a06be645658c219b22c7f1d14ca739577cb13520a569c63c80ef2f
35d8abef83322b02eb17d4ff0fe7f3af471bc47cf504af1200b681571337a15a
9bdefa7b678365b3650ecaa93e6679af9653165a5253408340cef4b112a57e30
c6b62970222b9ef6950828bbbd831cfc31ff461114e76bd49d6ec5ede9eb8eaf
4bbea4e71b2d01042d2112f4d9fca3d09940f922f3ffd95864befb1b2163a057
7a431d6a1a2280f9248316f556ff69f078196770d95c06bb74a72d50dfb314b2
a739092f2a4edaad889871d93e36e6c4110f10990b2c0e570f23a1aeeedfc889
3026951c7048198e34539126c95bf94f1739bbe040da5020879eb2c39ab4c429
2831123d56e6cf783a7f7471ab5f07583c6d247f1f108b9b3d807ceedecc2eae
98cb8c8261ca40cf15adea9cff4b84e43b5be71c8b97bab45757a596e7166014
6c6a4306603cfb2b4ad125535e975c14c3837615efb5122c096ee06be2a9dd83
c63ff693de2067998121b320140bac205f1a28ea688fe0bbc0cb458ce59ba29e
11a567465ca982c1e66ce8bc228c0bf2344825c215c2d1223ee37dd5303b3ede
3b620c3eebc8176879b966a4546b214b85236136d5f3bb7c9d3ba4a0ed2044a4
f8ba73cc013ed5dd6914f696f1fe94f29a6ffc2df09e8e3700ad5d98ad4a0770
d36fb4ce079b81ce4ef3f97b09e29b69e57e29df49aa9965e99ceef18433a76b
8435190696e7646874b8ce2732c8f6b4b77927876190beb2b49b23adc3a2fc73
b1b1ebdadab9f63c594f7a902f17577fe1dd6a68265de694b4296e8d33eb0f10
de32449d14fb9f5c0f885254380af56c1955734711df7eab83532ce2ac168f8e
15b7d523d91987f683c779643abe06422d570978bec25467c0a088a54ead46a7
c5b3db8a85be2c4af15cd60f32fcd9c7825da3d7dd738805df56b9dff3dda97e
39f5bcad1f675d71ed3ba7b5c355da78d36012397f74992a63d38043bce83cf5
96549aee83be0ef23f71bcc7ea9e8c7e84131378d80d33ce9e3f3264da88d907
d375e301d7f0c434e1b501f24b6b2e674b509c2d65280ef03a6ce0c161260bce
7608a81b98fdadaaa9a42eaff0a3ff0111aa60ed117113397b5d424a68af11ca
e55e46a6f521e7cec54d520d07c0c7c0823f2cd0d7f27ffccb1fe6e2e64c7a86
b3e1c31cea7d108e2863a451a1be8b806b6dadab495f397f554f65e8e65cfc78
19e05925b5584818c5587e837fe9beab0981bb611c1d4d4ed9007d57d0ae4d73
1c298e1ae6e0e825aec188cbd01922912b360686879ac54e0e59cdfdb3683f69
ea0b79c4257fcd7db735e1ef9d00ee02a6f9f46e67d9e7c0c32df7d82a6e1d7a
975a81eced6f989404bd43c825cc0af4f358b5702127c97e0a5c1e74b9efcd83
feba515a4cce7812dfe83a75ed6986789db22364a1c466df976fccc9aed447db
38504908246ce9524fe9eeef741ae1a11ffff3ae23a15633e08fa15fc7a718dd
db73e9edcd5db8be1acd71d363b9bcdaa4160113c687e47614cb76e7ec21377e
658547922058641e564946f15795cb7eff565405dd6503e1b884a64af9f2b058
3387805f60c9ddd121f2fefdaf98915b32942b435b576be7ec88b2f5eca284c2
00077bd8b83ba08626b44392e8e7c36b764d71a17f51b885d775b88929562a3f
c085a77d2743501d2793635d6e2fcc7de05ecff6c9d449653cb9121eeffd021d
1ead37bc5b78f45e74af64bacaf1889d66d693826f93808c06672635b7f236d1
8c2ec8a2a353f5966ec4cb32bd605b6dbdafb5b5350d987b5fdca4810e7c4184
cad87adeabeb2b237e01d030f7744cafb754e75dbdd7aadfbd4f92da73d01c5c
459f09b22cf4b5dd7b3f652d43555e937adeafe81c700e4939cd8f8afa35ba8d
3e39b73636e20899f84c32b415b10613a2197d60e939e9801145602030de6ff2
dc3611c96b6cd1cfbae0d7a4e41f57b04182a75e0c1f6986106e2c6b6bec5284
6754a3c69d6fa27ba34031be876fbbf1801b35030c98e75b2562b588ab3be4d0
3361af3ff05de37ff99736d710d4c575c0e36e105284a459fb091699ad432c26
cf7dd7b1f7c03446e4143be36a26c58a0f9d8dafa16eb03c276ca6afb2c4743b
7ae3c5c95d9da88aa994e0e81056814c813c8d4adb4342a3035a4310d72399aa
cf5a29feae148639231f3fb1608f045e5aa5a9e8d543480998ab9b1ec00ca76d
0aab0e300a88f780b4fc6637586a5357976f2c84cc2bc6c931e3d833f488a689
50c3b8be367c6cc4363dd5142af9fab5720a2012fa3fd9afc86398bfffcb7c82
18def3523a3175a4e9714dcf87a248f16206e935f41f482b995733d80dc9ea65
905f9bbc33fa3695b2a51be442e851f7cbbc068595055c06d5fbf59d49dee074
4093088a535bf5132b5b7c0ba6f5e28daa587a51e388d2c88c9bb121dd723246
0746911057bf56e717eff345dee5b16560a91086e5ac071a82cfdebd5807b137
2237139d11be9022732d6a72423b2097197cdf3261c4ba2d6408d6746e22385c
a5adc849f8144f2de8dc7a45ee5097edf0a3ce6efe58ffe318b1b149ffe142fd
6bad6ff06373496a8c6caa9da0c997ecd19a79415d7d3fd37b80edc3d9242580
65b8424fdcf55d59f087205d812d4eb5fa5c83d48521d9b147ee9c4481f1c882
9d186cc877a07496bef6fabfb4436cb7890199bd37c7c545db34ebc47821903e
8932b608bd18200bd6f8c8d30f24bd1b3c0be5a26563fed9613a5fd37a473bcb
299767517f2f6c711c70d147ccb11bd87a30165c571b71a033e911cde364a990
06a819fe3e8ebef08e027718359e988d4f3ef7db03e65e835faabfb2bcff42e0
3db8097089f7eae6704ad2a5320d8da434def4ad51f76d12d9d9f3e170809229
5ea263851d85c822036783ae7b21e9477c3b54a5e5a515c11ab55778c0ea6ee9
a81f98093dd502fb5f20e91bf5eebe7cbefeb9ce198412fb53b693864d29018e
ee554c75c1f0e252ed202bbcb91a03ed9fd92ede010b5a05e6d3f5cb34cdc8f7
41a48bcd93940cf99077ccde765e9b67e84b512b467d9a8ccadbc3681366a6df
1f90b581193f01e0a43b5f937bc1dbd723dfc0bdbdfeb9fb4f76a988f92ea387
e715a57eed3d840cae3cd5ea9cff80090464f4c8a8feb83baeff5b90dd460390
30b0f29194d0978fa30a75c48516248bf0424a967f9572d0ce1a12c37984efca
2432bfba39ac86b3cedc1f1ef1b43f83d975cdce37aa057fd6816021a58e6366
4a9069047ef39d739fe1345b9bf4e708d74b239cd6b29f4cc700e33489fc8083
916ba506820ea06d9d664ac72c0253ff04440fd899001392df83a6b78eefe0f9
7c8bf37ed8181ec6c6eb7ed2fc64766a9ad50286a9dcca5a3c5e6766d800de7e
d06c4e78c10d9cef7abdf5fab9218f287b70cca535bb1e930fd5c7576b48ed32
63767107d2183ac57e8656a372400cf14bf8d37802428dda3048bfa23b0d96f9
8cb8cddc3fb01e82b875f83a85720f9f1105d225a1a4a9d12a5e70ffb4703025
783fdef87f656dba814b320b4107fca9f99d4e9e52389918ba8604cd08933125
90bfb2086a5b046e500f15116968e781960ece93b811d8497542c1f588b450bc
a03ec6eb53121807ffd4c7f39e0be3138ea129e78bfda2425e1a21651e0d3311
9d9455f44b92fb02bd5354a70989a9221fe3e0999c26402a8b0ee43c02b55472
65caef904d90958da638a81b4536dbcb3bb1ca8cca8a75decf75f966935f9e72
df6ff50bfb242cb5ab65d0dc9c9780a9f5406762cdb71fe201a1a17e93f2b823
c960766bd3424e69b4b63090f8988c67e8be73febfa761d0a0b63275faa28f37
f2b8b1311ccebf5dcc1b1b069e25ca489191d97a650b916b3b9d064b9b1d1e67
6d8b82c0fcb3979486d0aaafbd8541c9bfdf6e717cfb36c5179cb5db224a104d
040b4c8afce18eb88e00d26ec8ffc2c10160bfbd43e2fa5ffd767925da789346
cbb3cd8d271435c9b700fcc26797b85821432ce4f8650a27997999ca8a32336c
dd7f29ec58896d16bbad592604f639635f1d3917d64df59ed8bfc48b0380d803
32666d191cce99d4534a07f0787952c57573e8e4e928bb6b4abc973ab1e05ac8
09bbf98e0ba31323a4b98c93eeba19f6e21ecd51e3b583bfa71f274c57581698
6e80d2df935e3dd887b75e8cf613756b96da9c744cfe2ebbd52ee3fc586bb5dd
baa30d508432583fee51681ed44a1f8958094ffbe525bbd33cdcb47fa6402960
2d9265080fb40757a5a33ba5f414f9ab942ff5b88ef9946c84ad5be363866f2e
428848d90d4ec8036d9e3e52ef79eca06cc891c5c5bbcdf45abc5bb7d6af3bef
7b254250fdf492f69512ccf1b07ba4acb55cc4b56ee5e3486e809abd1f326278
6974fb4c2b74a1328b6974f854efa8e5bcbb8ccb25d18013a2d382c9e9616b3c
86c3cdf6f313084bb0575335b9b52c9aa539e4b7088653eadc57ad1518060ea4
0c18392e0bd43c71ee0f7a926f8c08e10322defc35e7d56c1717e1ff4c82dd73
4ee4697d2938abe2128d9648673b5a51beadf7573431a8068410459a36cc72fe
5f7dfc52516d2d0aed85cdc40f233fc8221a0eae5f5cd337fb2fcab903ffa62f
3e2382e97601f7aa9b8e2f2e49f185aa8c5a7ade93c0bc0ff959aa6990a5c127
617a5832c508dbbdcddab3b95f810dc56b7d328869a2aeb714fe7c205c2483fc
92ccfc09d54c027e2cede30423c1f4d5b4fcb30f4d9e0307fef7a74196babdc9
c264e16dc08eb7de7d844b1b3af1d5aa0539c57aed63c362838613905006524f
ffc7e8eb3947030fa7bda889d07c13fc6bb68c14771912102dae0c007b6d075f
8c4f850f85bdcd44f3faecdd17fa41963e1d5cb877fca97d53f86363df110be6
fc604d1c1a3e5a368b2bf79d014a2254419cbd7b9c2b7ba6423d535e91d5d1ff
a5fd8196575bc255e07c9cae2521a6837c76ed77abeed3a79c336baeb340abd4
c165f92eb5ad595bf6710a6bee4c4bc8966d9596289c268c2cf370c26894c6f7
e63f1243b14aab787917fc932e7ea783785e5090cd9fc3f3f8d332db5c75bf63
fa687a9ae08794c2cfed4188436e6423bb0b42624fd36ddd909ed7d46040c71a
eee27987bf5634b4121be94c0240fdc9cbcd620ff35bd057460219291b5c3af4
10d8ac4e2407a6310506a09d56026c7330eca9d2060f9430e995a8a9045b09c2
433b990b7c96efc3b6b6fd8bd1e20663dda85b62d63391e7aa4e5d568b218b48
67ad0120a58261116bbb469f3fba286ddd8aa203c81332dd6444159e0adc824b
f295a161f5e05e59bb8397945459963bdb379663be5f418ff61994bf35785cef
16b3613955294138ec9f9123c2dd5ef8a66f055b4d598b248204d7c5d1a18673
72eda707ceb2b4bd3f42e4127b11a26bd587491891caed17337ed80b3651f073
8350c2374279ec3d0f6bdc1393c71a330c027fb12a1ff2bc75e2bb9bcaccaf5d
aae2f1a33b53a61c61f3e084bb18827cc1fa358e51f45bcbb622f97795680adf
af3fb62ca060bd393ed015195845719e3edd3f243b830216b404640a13d7c551
c17892133f626612c7631272ebc0a1dfd19f96e3515fcefa4b6fd7413134453b
b7fa9b1cbfc095ff9c4e4c6f9025dd00f14ac8c305a261e8ac5c928fc96e7911
e47eff9b9f59674f08db69ecc2cc5bfae4591fcaee7fdcfb43105fb116bc5d56
16fb0e7d6a1d940f28388ddaf6ff0907ee55c6503ba5c45ffbb0ad5480277776
0e2d6513708766f00b2f33b8812546196ee7ea0c706667f885a422915584e84e
b12356e5fbe389cd4d0f3839e8ebfd1c551f59c8cc398bfc7f5a330b9962abfb
31d1051f91e8a8a5050fc7832f88d16e39e5c8edc532061c39b843410efa8c24
8e70d775dc1c680c091a7ab2664491a6453f45e929a5476dcc5d02165cf62e47
e7b8766c6b2bd280a1e1461a7c716162800b066320730e7f040bf9eead224b8f
df890a9cfc0c0075962ef34f09a0aa1a2ee3c15bad55613497b57034af41b8fc
32d288d32cd4d4d048e9b7738920b7cc781dee53db41ea2caea271c3becc9059
9185290bbbbc4cf012187ae92a34ac5c4d51cb9a54be63293326329c3a41e19c
75fdd54262ddf757f2fdc3c1b4dd90d196d9f10ab8dfd066d3b57117c57b8851
95e90e118dd527bbc65b68ee92fbaf9cb2e5a73c01d4f37047ecc9425f9c568c
282164c188cbcad80b547b35a4090576831d4f7cbbdec994fbeb5b0278d180aa
e041ee742eb0fd9cdaf233c2d6ce80a42994e9da7b79e4f65e3322ec0b944729
6ddd5096ff810804008a603864ee6d09b630df68e820147f0ae71b939a8af06b
4dd8a76ceb4ba5be1fbf229312475e4d91ac25331c570ce79c3ae600bba5e6f7
6657ba93ef953b342d9013f663113299cc21bfb4b8e8a76abfb29b2b0c4b5a2f
56a27c404007fcb19be954dd864d273123dfe65321ebc92ba1d40900a83c98b1
41f94d5684f05a109e1dd1784216893b61cf0bdf63b07b49d3c8baf2f80062a5
f4a435b92e1b711aa2358aa6b96dd0b0b457a4cdfdfb22834df900909be17ff1
9f6fc240e7f3bc91f658c3b76ce304ca212332229b8ff26460fff5b3932650fd
200c42686ef61f1dab29f5f83b7d69f3738488efb66fd885f35d3f596c39504a
ea80abfb9c6bc8487910c444a73f8440626e8901df1dd2662fb997e6db3a7cf2
0286ecbe59aafa9665dd1244c6c5ea8e48579f13a73908abe831170081591d36
2fa38d645f906165cfa8c5a41c3643d33cf6627569c7b868eec59e326dd9afe9
85e987bbbebb2ef1c52b35831ab3db495962f0d9905b93f8e45b4a54c515e91a
11997870cfff23c96c41d1786e477ae1bab69a01f512b11161768b6b9f1a539e
a8d6959207422ea7496570d6c8b9d95dc3eedc069bfac63faa37214c20876224
df54e63a962d8d1683cb8779c42a31663d2d45e40049adfe419e532926148243
f9366db13fd96820cbaa5b5b1497be5e98b69cad2eb94c8887769067ffa3d499
4370482f53b85f3aecdc9e2a81ff7ed121278f18613b11d78687c5570d1c906d
f6f9c8f2c7fab819300774ca98ba8582453518d14189037693e09f76a27e5950
8c1cfb3af2f66892f0977d9838409c04d2748ce0928dc3db99faf1ec9d65ec58
98ae59a14cf41890b445b9815c51b8a3e44c8d7bd716e5ec2fc691e53f6cf4c4
50e5b56c7729a5c160c33cf9c050becf5bd6c0ed75e73cfbc9976ee04f219a8e
be16ccdff275c7b586c9f94024d8a232e87b37f45ab608d476452b62c8c7d55e
b8ebf90bbb969856842dc95e864627e41d11408c9b7bd1e47bd22bf5265c760f
b7aba3b18c3b1530b2d9d82d7b6ca02eaaaf1a92473e32f9a936e9a71f055134
10141462c0923b5f9c4aa02fcbb439bf8a85c9c62e7f047325bd01ed7206e28f
4a0d4c94653338f8ae1efe7d54f74e96ee3cfb5fd8d6059b423215a3b5a4b4d0
a9a01164c7b332c2cc59296028d17c2457b41bdbc8de1e471aba244ec568e1c4
683d858ac988021973fa28980ecf4977d84bdba2fe65a77085a0f0259dba0bf6
9627b928cee7220984db614d1d3de04132d328e099c2c08df954b2afcac33f6d
4e6f019ff5b5eca31b707948d25bf1d341b4c30cd79350441c88c174cf913018
9671163841866d7d589adeda1a8258db67953f8fce3b26bab0c54720e4512b2a
6805e6f4cd54a1a1f359c96df919c83a708db8db6f549995d75e9bed46f32fe6
d148bf7910d3315f1fa633cf2a58bd3ceea0c56fcdc66c2a6789d0278b67f39b
fed662fae8413ed72dc7b3ee950f8ecb171265aa7f920891178c3aa6c5aaa21b
8711f83ee26c2af295abdb27e54edacd23e5785aa8df1b1afaa329df311db7b4
54031b6e023b0dbcb952f8ee1e7b443a17dc81124afbf7739b7daf4864686fa3
ee75d222972ac8145bde361dc0a61b971e38319b6b472b78b42b6b302b577171
28f6c36800a409ee443eabdfb18e07c69c0290c353f47b16484a754daaa16dcd
4fa367d8e02c9850d624903dfde337a417523be34b72b812848e84d8b571fd76
692b8383a08a0f42e92df79adbd06c71a7dd2de77deaabd08963561b25ccab95
60a729af35d30dbdb670ee02d74262883822add2549f94af781edfc64a744e8b
4d0bd6e493de14f63c117a09a15253b127115f4caf5d12835cb4291b294425ac
b5ca8d37721f949856a195ad3eaa4d8e97b987eb4f8ac7592eb9e3ae78cb96f9
355b12d830fc090238554b394affa8cdf4091791615edd3ba8aa5c6915ebb762
ac1b7c19597b6444c5be6b4e3eb01b73bd1646d3264a1df2ee5eba42293c62c8
a742d23846cc08586f8133c7eed40703be050e31709b8749f64454ffcd0ba5c2
a42da38f21b879986b841e865c32bfa1f0f132ce46155d2e3dffdbdda3e43b72
1ebd7ab0c8e706b4452088bcc903e8bb23b37c14415a3388bee7fd5b9fc69e08
b345e1ee5ea0939c95a7602b897c1ad9df8dd9ed5988188535fbf94a76a9106b
055a8fa2213c4ec686b25a5cbd8731aec154743b69d193e19cc3e050b4c45847
8eb8ff610923ff3e42515284b4fe54116abc952553a1757d796ecfe15134fa46
936935a292439f4d59f571e4bc37c98968be0fa8488b6736abc9e6c33d76347f
3261225a8ae3bdfb9d274a065b8edbf89364f63a982aeb3e7710fbec094023b0
9c9c52271611257a1357b23b8f38b157f445aedeef4ccda799f1dc3afdc8003e
6aadba915ce2bd42481a34414e2034a89874af9b34ce4ff71175446e9bc7843f
7de2a03dfdd286dc94cc625320ea17dce9edc9ba116e6785cf4200f9b3481c75
b79be9be6b8ba5c885f17e4b613977a9a9b55ca8e79bc8d250a88d6f7654b99f
76e0dca5d1be09e093b8c30b7005f3ff3ec69500ca0186e37a31263fff7f2536
7b6e70fae62d80854c1742fc5906622edf4522aff65c4d153759eaf766ae3b72
519c0885022d84f362df3a20f9c92d5a331ded22de0f667224be138d5ef0997b
3dc44d791fae305f961c02faa225a8471c02a34168d5d382197a0135450438c8
2bf877029ff3bfc55eceb6055da4e6d86bf6cf1356b572992fc7c6afc8c11144
6a743d3082c8d94e13b9282646e3ce1ecb88a613c2216a5317d0068960bcbe37
6dd5a1ec709c6c03b5577cbba0b92b08a5286ddf5fe6ceadc4be260f3c5289e5
c02cd3eaa04e07bf1a94ee8bac940a0e1e39f5638f99779234d8f35315610e06
f240fa98fa42b83ed439836a1af415d8928d85d8a3ec5fb45cd1e7500489420f
fe084c4330341357c4fb9e5654e039a85a8c870622ec2d6ead2679c545435679
92e9a6d75e5765aef046730eea705da6516794ae6a1223e23c549344a530a0f6
11b474324bcd7b5cae23ac678b34a9c24b4e82f85b6a2ef597f50578cf9e7e96
78ea32d98d16b745c8d8d9f71aad18c9fa583945b7a10465c2f1c9d430f9a073
81f489b5356f34a36f56cf94a20f62dccf65903b84211dbd47de26ea246ffce9
c12e9f58b68a5a1cf23d4c5a2ceddb3c2f124c9e9b7bc4cc758548ce324434d4
1673f70e3f70702ad2ef3cc6df9cf752e9474c57dac7e0ef6e924233e6978040
28038c64aabab908fd4ca8bf2cedb3599eabf8499b72a9372dc11e57fea79139
7ea1f666eae6bc7028876cdcbe0c6ebbe2519e3160065b639ae2ed3c7722387e
556b005486efd766b1819ee2c0316b034135b4c5359a3090fa06fe95a0be3631
d449057147e183d63d48a80b56a0f09d88a42514b2744a5cae1acea2c4371eaa
6fe9c98448967e06a2a6e74a3c47b35e75332f1c98cbea3a8dc38720cae1b542
d3697a446894d8510d25de4b8b5541c07e782eb0ebd936d5ab9d998c6a0297f8
985112a53fa14fcef525f7b090b2eea1ff613b6db855b99a6dd3fd2a76f7589c
95eecd418efd1c818265abda21f8ff8b2638075b8874d4e38e6e559a2bd8cb6f
bdfd3331aa5c3f0dbca74b82a9b2087a282c045da76d8e9d3930bf46c810f3d0
cd56c7701c72ddfb227afc053d6c12e773f7ed1e3f58367e71d486c8f4ae1acf
f9fccdbd6a9a9f6ccc90296e25f3760912c4fe0b3f186c70ba86b104b482ced5
ebaa4f0baa2528d776ed4f1f712e508c38639a07358e90972c538d0452a487d3
95b77a0e401c4f7c0679daa671cbbd4ec76b5b1d401ed9eaed28d0c28dbb2900
27dfac9bf2e27a05d2a8fe17aef8566da27ae1ea5d52f7f6ed5329c86487a206
b942071ff83a8a98bf4d7561f0fab8437f7ccd0708bdce483b67cc9cd70119b1
122945acf53475cd334ff935f1f6b1baa27e0614c15100f2df631ee443f6e0d1
52e3b0684d0d60ba854a75f557647cc6c0d3cf1e76351069004cf918f4820602
faf986fff0562cf047adc48ad6823658536583ea7e0700e31a09794ae8f73482
54a1dd8b6793955f051ff267d6be36cfeeac179433435428ed5dc6df6a93f779
a13b21903d552cb8e818efa19c0c9398eb56583c6ef74b03761c85cabac6480c
8947f51ef4fd4de2fbe6eddf37d6dc7234252c0572101a5ed42def296dd06f32
75c5bf213ee778a68820e8cde4bd4047f2799b59ee51e075ee91799c81f62703
5770626433609630e202ad79d2ff58a323d3d9291bf83166bc36b148b0575be6
8d2b5e60f4ce355ddc48c2fa550ca1945cbf4e004332c9f852471ebdbccdd9ca
d250ed2d35d5fffb0d41a7b127f0026566ad05502b97638bdfef8a789f4ae535
0c9fa77cef180c2f0c2d325ebc3f73f0fef46be6d35bc2bd78841b98299ec03d
23e3286f9ac58251ff29eb7b7887a1626d3448f703f0be7e289af50ad021c21d
ca7bc463a8f966a8d8d437262884f7fb72abc1ae0b8d37b4111714a6e147fbd6
742a5812d3d58be5c3edf5680f44d94ffd89d76c48c7fe4da8fb4b78d53cbf71
0f8fe70138177fda4bc4cecdb8ff588b4ae75e218def761a875120bbc3f0f1b8
dd61060e408e5d51ec4056f976637fb1ee7bfb608df8174ab48bbf5ba70880d0
8660263fc899799a0d943edbf5e6a0ca6162c0821c83d66b4fd365ccaa68b716
02b7f563e2398f1978df4c377779ca8433db5e3785a09b3f3f083387fdc80cab
a7cae1c8cc53a9ef24cbd4099dbfb92838671b0113de101d2f72ada171fd9268
b89c827ea2f5f7f0f10e39584a65ea58ff12aa4e96091ca3ac7010cb212cc69d
6b1013750af0ba7a122ea017f4faee0103b18d3a61804814709ee182d112a8ba
aa04391cb54a41645410551e0623c414c820edecbd38cca33a40a95696b4d5fc
99ff02567e6f1d2d29b37f8df09f64fd1c377ecd64a877997e4514c1da02ce43
5712bb26171682148998e63ae886e0166e85e0fdc458e919027e41fef2359a02
5f6f699fbf3b534f125e42856ec0f8a196d592199aec0750a15b2148931ef8e5
278d302bdfcdf7403c11ca5d1c37e1d19abac3cf9ae7171a997974bda357861f
143372f24ce69fe29aec0d11e26a403782b7a94ca2e25be83e68e73cbde0cc8a
adef3f82fd77123531d29f008bbef03492bfb4174925b1e8ca252ed0892acd7b
959f06c5bc192b704856124f7b4883fa96b5baaf6516fb913db9089d348be4ae
4051addfc663ac6437359553a6d75ec0dd27b8c5ecd522c24846b9d5069ff203
85c584ab8f692e7710279afdb9acad1a792ca588940d390164a7df777a89d8d2
40b5b0ff0ab4da54427efb6f295a10f72d87b1c23b5a6201feedd89e653338b6
b66d3e0eb8943019f7f6d8af47cf1c6007bdd2f939d6d000002cd0a48adc70c0
822bae7f9c1f584f253925114a410d6a0b1a120867d631b2c0fcdddddafbbd0a
b388b487c5acc3ed9595e87ae01a07059b7b304de0349c3b3fc05d540ac5bdd1
c12726a04bfed58d923e1ab08d2bb819bf958661579aaef5400b7cf0332c022d
e4b060ce4978ac23c711d0a0beb8804d7cf6f7d79e7c419a872a35c2588c5859
e78eee9ac326eb42fa7103c4b6332a24e280e157399116de64fea2b5c140b64c
de7dccf16b7a832cb55dc586ffc2e695733c50c90d33bc3e3e30ce4e2b51ef32
a22d938da61cde004a856de610f89dc8f61ea1086f118503ceb3360f490aa121
5dae94daf5d064d00585eca1e4c9be6af5d3cb5fc130e27940a4a08a5aef104d
663a29cea406a100431115b5d52d415719157a5cf2155dbdf3916e3825429b2a
788bee26f05c6976eebdeaa039728790f395bc22edb6c65275725e381afc0f73
7c70700aa08a54f5e5ca735214015602d1ef9f2a66475f1df9a4db268b3b891c
c1a64f98f80b79b2a5d4935fbf882b8f917f3d3a7bf824a5a8f1964bb19c88fb
7afe8725ff503e18279273c300536a4e8dc3db59a3a1693f28a654543444e633
e1549dfa58a14b30e7974fca29d2bba1a375e395bfa3bae2e6a972639d2484d3
d89105ad6b04422824a74071c7832fbb7ec3745258376c2ba25142dfb6e0c6c9
9ede8a8c9fa8ed598ca1137762d6afce59c913612d35c268b91c7f6ccd754314
d27d0cb62e54842a2839a80d5970575288b4e7903f3602e81fbb79ce98e4acda
8eadb3b9d7611def0318241a0b78c044b844a151cb8fd902b8d74bda3b3eb3f7
8aa00bc106b91abf53e7278679a745bd32e7d4484b842fc7f7717195e944d464
19f85065948c6d197919b7ae158e365b8282d79d66ba6d485035d3a00d75311e
98bc9d0c8828840df3becff04249db76b00707fc8811dfb887d4754b953a4863
de4df8b7a293b70288edd25c987bb4f5ceaee1c7a56444ef9b8e3eb00cdc7436
3cfe5e46606a8db084372cb003c95736159b8bf444e6829a9f2d84839a5b5947
37fb425167df9ff39b10a125e0500269504e844345a5682498d705d0a13042a0
809e797786aa222319a8a8ea47aa26daf8b43cd1ce59d324022506369abf1c70
ef010f03e4b320b1ad0b4d4110fafa10729b891bf06c7814f4158fc929d086ca
8a9818d29c01e054c5e68813ab03b9701832da3cc87af147e18588c0aa00b61b
8a27ce9b14a689455a3d48ef691bfc36a1b0644f622272e7207d9a5590c9b691
1c4b783ca02ac46737f2510ae6a6d32baeca42cdaa848929486024cb1766ccc7
475c792d429f9b48498037adcbdf8f8c52ca3f64eb98b6fcc53d2aa1831ccfbe
f78da021db0e9f1462856f574e59f3491f8d0a39c0f523b25b8e013ec903f919
ec3b712fb569f343d07cca8feae046c37496d1b547531295d623c8e10d75b35a
01cd7a57b190a39fa968c8c6e8bbeeb0c1321b0b1192126ced950de5f2bcccb2
54d9b1594528d061049e4360527a57f6727833196fe47ca8450549824bf0e166
169bce483b907a0ceadd5ac0584c2b8bc3212ec28208a1d09a9a12665a01a2bd
237828a08008889ce3a3746fdc7ef2ef2a6ef9df103cfb93fc31bb0441d150f7
b68861f2b709decdfb4d81199606616250f1b8e0cac1c66ac66db85a154ceaef
c1ca03cb9833c90a803ed6b2fbc7ed7f5c3abbe5d2334977668becbc1cb37af6
06da30ec604bef8c60fe111c496d8024c4cd98021d826c25302d586e17f8e072
a01fae536f077423989019ae47f7845f91e1a6c425e76ba73e0be3e8f2b541b4
980c5175a4d8d42d1f7ab5b69a49d5fdd88b31034f8f1836c8e215b883ccb3ad
f871818441807d64c492ac8660c64105f2b87f9149ad9cf8dd6f1c7fb39096c8
48cb2b3e30483ecb0ab0a166161aa02011c1b6b3d7e390928653739ff7c3db3d
c97e96c2efa247cb6858e17b30d29a6ece8c39a70944a8ef8e65a1921a1edaea
774d8fe7a7a654b52da3938468b1319eda11effb1f0e4bedcd0c65d355b49ca0
720853b8b21d5eb2229b1146a5a21f571e2875a2c3b03853bd6bb817b7ed9fe1
9ea3d77241344939b00c98c5370722af240c4b5f8e5e5228a1417c5412bcc4b7
359f8323aed60b8d0ab9e3c1804ddd823f839846258cca085330702f22e14fc4
d2641ae09e6ea5adef72550039d0a1cc28804d672e17a392ef1b9a98ea51178e
f30d4cb33c5a84ff66f5196cbeb28192e20104c293fb66a7631bfdc3a17a93eb
f2cf681a00702ec5c050ae70dc5f88a35992dad9e866f854f2375531fbe2a6ef
2c07508c8843fdd382a5c253e6eef74e3180932b3b3c5ddd96e0df8cbd94352f
3bcba1d7859fa930f4b7598328cbd479d9debee2ea34f744410e18b68bdbc808
423448c98d9382c445819ce26260a64682f9799e5c29248c3a3eb8301ea94fcc
700583ee6a5624d8428c3dec7789bcfbf173e9b81d9eecf4728d2d8933a608a0
948eca1285098fdb7e6ded1cb7907e88ada215a6357d0ca01c1b750c0f4e716a
aa128b24c1df0882b7c674bd1efc42705764b08994476c804d12843a4af19405
8a58280782de4abeb23f6f39387d2d67e50c9ecd93bbe0fa81c68dcfe7c5af9b
ebcfed8504e573e384d02df7984b2207f8f5e5c114503b740174293fb797796f
ccac78524b0e8ba380b5943825f28195f75669ab124d33aa61de3b9980056191
cc953ca3c9d7fa0bab7cc8ed1b1527afa2e52dda878cf1b172ae86fac0e9001a
496f7bc08d694bb93c10a87c61fa902538af48954a7cec2d966c7e745b054603
32b8ba7031bbaad5dfccfb4d8161db1575688a2eeee1291e07b3c22c206cf902
3a92234cd0c016c9585de87d401769de0f9a7eb2618fd39af1d7d3a95ad9d3d5
f3e4b8c6ef286d23701a9a3181e79b02fe7163b2c5a49b6b086e7f4f8c053cab
c0b525f775b2bd6cf4e944890aa549b326d4e14fa8b8bc188a35d107dea9aabb
85353c1fb28838f7a980b4d236795d75a03ea3fdf3524b347d92d71b875440c3
73f6ee7817df67c1898033a72c2c91168cdbabb3e0296eb4bc0bcc1af0204c47
41a1d43f6f4e5743ffcf3eec53e26dfb85923f35b5aafddad26a589a17136a14
ad11db00f1f1b986880cb6733ce011c0d727568a8aac00b86f9e68bdca3257f9
898caefd60ba1a7f6cd3648632e0a966fec0cbc7f01021426553fedec03002e9
cc506130c32abdd38a8bef6b9aad96c091891128ac2e7a9be11ef1b1f143f8a0
6deaf323a9d05b98f3fcc868241ee04ca222224eafaaa2d294f551bbfb338099
0fd9d2132bbc529f010addbde7328ce295d573373b7d892a0b073a8bba6d1ac6
677898876f94b2bb364678c2a153651b1d211a796e1c958966bb140b9ddede91
64024db6369c3af78aa0cc929ff8297ce558679e7114ec60385e889a941f3f26
75bb1f904df26658645f9a20a064042d16a177c90689a4148b7cb332746dd2a7
e3302f22b14a24bc18ba1ca66ccfc14773f783b716f964d95ea84f3f8db0e4c9
783dd8645cee8ba8e94d3fa96886dd11e44cf9fbe0d0898c780160705d2e1cb0
4425233f957eebdf58713fb9f8b45f28d95945dfe9cd9975bc08cdb9c7ad99a8
15a66c7941a3e6cf731cd06b28279d4407a6204516615d37590330474f0e1889
db42c1b54086e970a5feb1dfc8cbb83d43255f80d3ade27bb58f6f96ff3a3cdd
11b92a295a59d01e9ff1e099f12f904b799b150f090da6be7a795b2cc177544a
0820f0da5f4c1f794dac543da97f5955c761ba412b124020f17694e230a53245
cbd63560d06609627474e662f88666099fb8d7f61019d27c17de76c025965897
6f943214d753975fb18a3d4541ff0d67b7ed9288c439bfcdfc2d508edbaa1083
38d91252ec437884706008f2be5ff1f88090c97c8bdc1d30a611ca37fb5b2043
1326b3cc41bdb421baa84eb1636524db103681b6927d24a69777fb3597d528fc
cd96bf2ab49198025ca8c4d20b3f8afb3209527edcf62b0e033b67f1776a4907
267e9caa5d06c803ab23e7ce3d1b787831d68f641b19df99c7a6bd4ce8608f3b
35166289d0983e9efa422e84fc958d1f4b2d0c4d25fd99b95cf6facd4e9566db
504fe6937b757a8b6f1413f5d7ef24f37a05a4d19bfc38c1cf893b0d434ac54d
45aaa7dabf30821a6b75b60f3ac791f7fed12273ab1bae5f17005e5a2c761d0d
e988683693b4d947ab5d9fa0e9125ebf49ef0f16e204a784dc986c7b3f05de2c
a139d5629c6eb376c129f63df34d43df92cdcabb4b951cbcfafbce20ed105b9f
5e3af0d8148fd1c4a095a966f9b9865c66c04d84e03e152a0066a0b37800603f
26e117c59d0baa3d1bd6990c7022cfd55a6bd93d7ff5d18f9974f9446713de1e
750a09631ffe737f3c57390022e5e1ec559550a05257f8e09d23fc58a1badf16
2ccb1d86b17e7f1fd5fd4e4834bceb4a657b8289429ae7a5c3d109821905d15f
c600cebc29bdd6de98abe3f4bab6f03fa5502c2888cb6541c89aaa9f1680d8d4
c6d3dc918bcec92131f0b58a05c662a63edf904200aa0cee58810835e263f927
add8cabaa1f4e671bf073d3d9b441a4d7a64d1d6090079216649bfa73c489fb8
a325a48399d66edb1c5ef501370c892e97a1444df7a07817330a066c3cf31bd4
bb9ae176e4f3e9703365ead0ffee481e8823d6701e39bd4bafd08c7c5cb434e2
33d472f7d6f5fdd24100278e2a8044f74f21c206331938d06fc26c2f88fbcc2a
75968f9a644217326bbeae19724c8d4bc8f0a676d4e2dd57ca9a9f9a56e36153
b5517c0383f146eaf010b9454dd5c8afb41ba11a0de4f85ed733ce88a3d2136d
513f5ecf50ddbf42f48bf8c48e561a500ec6f9f1a20d7d0b6e9ec55965850d6f
8dc8302ffe75c6c64ec63c69a16363d5cb0f522b09f82020ae64d2b1e3513134
597fe85150fbe5a01082730320ca4bb1ed261d965b5ea9e8820405aacc2ff089
2bdce546cff8e52409e5b83587575d01e5f4351d5897c27ca34de516cae1f2b3
ecabf40b5218e712291b2b16576520548f7fbc06ec7bacc64e78eaf6b15efb30
23034da7288ad0fba033031eab61cf457760a7a23d1068745a21cdd76371d081
aaa4e0f41b6589d5a1a17eb3bbd5252b34464103c55005748b293b8e3f1f46cd
025bfedd1ee0e2a9f735fd44d34ee3e432505bdf8392530f658cf1ffa44f940a
6d5e6d0b9f3e9370b05bd356981adf6bd945b0abc5651ebce0621f8b36cc487f
27a1cabfacde136ad72365d11f2e3ec422990738b14c2d2eddd6c64e63de0475
5d64bb2679d7db151b56fcb9f7c4e5917cb6377fa45d74912210a67004b398b5
15dc8278798464830d22c2c1405b2bad293d844662936a8d228b5ac2ed09e9a6
cd8fecf9981d689670ce7a5584b6d7a025ec960fea61326225de792eba8f8927
6ffa02bf8e67eeb47735f3b4feac464497555e413acb0bdfb444cb20827f41c2
7300c281de387491f032ae7ddb24030b10091fd187de3bf51b0d8fce5885d095
011f5e92b6e9d589a231eb880bcb72ace754690ad3852cbb7993b85d1e2d1cb5
75c2cc48f11afee06fe6b7ae66ecd4b64492e9ecbc86b49b92f1fb9baa493423
2e4721279b984f294b81f91ee18db135a16f7897305967e4c95cc54af64c0965
3bab157d0d40cdc515fa9a36a97ac3bd8d1aa3a19b2a043a3f755f772954bd62
b83130c4c675321a3ba44a5ad2e787bc77dd43bff0c6c07b8274e49b20a5fd9c
4eb000b5c7627fb500ed91a328ebab522cd96ce3ab7c9dc96ee062e6fb7b60e3
89cadd958ab8ab507de8523db3535d7ea12faa58720868ed445ee9fac6486ca1
8cc9c3096531a3428951c25be9ceed4612b2b2c37cb0c490163aa3e33d67a64b
bae2007f39b770dd5841e5241320f1a350e111b17a3297a38dc68b9043ad3b72
f94ec5fb751db8e4d9ae46e565e14c59de95825c8b1b65d9565ac2213dabe881
e22069d82c28866eedbaca8e93d54e6adad042f8c83eb20f7042006c1137b56e
843443d41915fa1629266a6ca92f76eadf509a1928f3e0ba73de7876e4787369
9bd6c2997df74e834091946589fcf4585bed4d6a9b5cffdef64b7f65869b2ed8
e8e257a265512f706554cb0707873b1198c2cf09e884ac0726fdae32a85d051b
bc1cd32f131bd7453f106eac65e3e3da6e8b9ed0e0de0e2a6881140309f3f195
0fadf2e6e1a2269a604b8d021a39396bcc6e31b2ce92690c49bedf98213d0a49
2932fce6af04f6844f2199d963cab3f6a9f1061e968c1ec2d946ad33e7145a15
6eb5c519a7759cabda69fdfd457277d044346fb31340f085d54a765529dc5264
1606903643b2f14f91d65d0fc93154ac4e11136edc582ab9cfce9cd3ce292eaf
6db5769cf34216e726114a9686378c8a0d868d04ee081dcf738d79ee0e58ac65
1d55a0a87ed1f59812c204ba84c58ff2d20f48cdeffa69d766b226d08e30796b
f49ac5b0ab5e1f3f7ae8aacc9c0f3482be807fe7db0e1072ceca07cc620e36a8
184d182c8bbc933cbf0f4f2e506ffd1fedf7ffc9661054e3835337a970ca18d8
ae3e375364d180e13f079e615169dff791d45d0805b42218d496de2038b20b8f
46da3ea0b8148d2f6dfdda31af47e2b55054457783cacce62fb0c031b00ffcbb
b7193b2b7915aee203a14b83175016484230a3c53cfce018856c3ce940a12742
c95bbba2f1e49e68e6867c032eda9add349bc9249fe2d0147bd585bb65b15e52
41f9d5c8147264bb1edb528288d7abdbac2c0866a0e6e98cec009049f0908e35
e3c5a5a415f7096cae749e48e8572a7d22e6e6e05cd455b030bb44f7f04c79bf
1bf9ecd096dc916ea1d1ff65efba0a51bddc6561161ecd0dba1e7c25062337dc
1c7da0dc1a07e78a9aa3f16a731d7a31fbab5e95f73105caadcc10fdce03f71f
9f53339f682dc0066a4e278d6598e9b4f8062473ae0f447e49548c3669e5a50b
77dd41458a4310bcbe89c0957cd944e12e0751a7f390239523e397e6cadea8af
9e9a69b3f3030b6a13fe9465d643ede781cd04b40077d2e2314ecffc9dd543ae
a81d5df9084e905712552979767b0b2cfd133976ee4f654d72d7abfe7801b466
c95915fde2a914482f8ddd2c0bf3b55ed7b1d488f183605b71bf7ed6247602ef
536e68bb30d423bac91995b3dfafb1e75d33347fd4be4d650fe300b320d7dcd9
73342d3b1487dad2ee85f7786665e3072d7629f14cdc0a6005a5062c13209b3d
7df30fc39e0eba691c3233ebddbbce3cb5ce694f662169045245820513c4b7e6
53f0d3ffe6037405b65fc13fc0a5781f9f70737520b270435f90fd92af75474b
1bd34e5ce8fb509dd651a79fab845ffeb44d815661d2db3f5df48bd68a690c2d
d025c6aa2c1afcc495670616bab9eb0024784eede635b4fb108fa4c9ed850373
78cb72bae5ca62c4637c61715643acb9ee86cdff3ee2066a227d119e7ab2f762
9831ef5c971e3df9aab5b2a9f6b0abf29326b61de0cf79ac4876668639484b8c
7219799eef4e9b2b761be36fc2cce77dd3e20bc006018a075014ad733b83d562
17fe03fcc11297d4cbbdf200edf4147bb23f2a78f7fbb6fa718df1655cd81c60
1b6258d260f6447aafae1152cbeaaa43eedd24960e3316d6f4e08690695952e5
39d2e88e96520a825c9517bce1bbd65399481cdfe7d3f22af8d5e7c54076ff86
91e8c1faeffedee6954f4c626fb9cf5b2345855d46782e76a2aef8c7ff057a7f
5c5c599371ecf82fc45284f3bf5b20e3d9d8c11f63fe2c48aff18a2627029b67
5270033f0e5c2f59e896902c1078c2807ac5f4d4af5d2781837fec44b56647b7
319a22ffdb8803b1873b6ac964212326219c4a14f8a42856c1a97e607d0c3716
af61e5ec008fe85599eff545d29f0a539821251e8f4e25ab158392cba2f23979
453893d694188efc402a4ac191c321e46d747875d209ba1fe0e1f14743e4ef29
0d5fc460127669a683d0b81cb09eab4e689ea21cf845746dba03b27cfa564c12
b7ad19ef2c0d1391980eeea82d0db63b708d735d6d65e5591819359581a88f8d
0e95de724abdf0004028ae7677b0ddf7712fc607774ff7f829b4e0c218e17dc6
d8c22260ba70e2950b43db6279c697560a6432bc81571a9a63d0803f7d86d221
4e9cfd6fee8ab09d8fd3945fb4844c8e7ae523ae7c06fc1df04020a40d8d2901
0d3f0e19e2089433ba3ac0fab17a96193ec6636c80c87091d7513fc8c52513bb
de5f3b1232064a58c6713cad3ec7fd9e00652c2f0ddd8eba42977975bad905c6
815c248083112021db3261cdb3d74544425ab8f1655b532f090cc92162065dfd
cae42008f25dc95d0575766061137987fd17e23768371ca0e1a5e043285bf709
e82028a3107dbb2f36833e679cdde001c538e30b02a48df914c75fa2bc44ecdd
9f6d12bfb2ec1936ae8cdd4d3971fe782c1bfd9bb42e1a1c4ab837be1cbc1e2e
d04ec719005386fb1d2c441c796a772cb37c5288290b75331868555c11744a5c
026db40039c25bf452e6aeee94ee8ed61aba62c26a25aff6ceda9c64afebff24
6415ce50e296f0071947745750d70d7ad11614313002834018f69d0c9d792c32
f1babf896dcf002039153d7090407181a48857ad9697e2578aefad079ce6bc4b
b328f51fdee74709eaa6c9aba8a3bf78526a0a0f30f1fff3ebcb7cbc42f6c3ea
51a05cd0e3a51f23ee3e9bc218e04052efe1a90eb2d1e6dbc518e02f802356ae
3490dda5ffb6e4c1baf07efacd3b54fe655b9ce65c909bc8a1a483b00dc67291
311ce3d8574b34b85aa00b0ab1d21ebde302570c2b999fe550bff2180448645f
c040a0c8ee193eace7f13490eaaa07d3ca1815ad1ebf7ed8ed9ed5880c0b8f03
eadac8337407fdc5174c4e327eff2c8f22edf2d60a9d3de10b97c81a8497c0c3
96b8e9fa5f224872ecfbc904f9c88c480aa5e07a5db03e6b738104e3b656d472
92c1457f45918d9319306d5806c234df4e571c097368f31b8cf9ce1fe1fecadc
d0bd390ee96cee7dcd1421f7d72f6920ef3476d4764c2608f3528078f6abacdd
c4ff6b646ee6f5497828c0ec3934b76e04052c9c093ff4bb69ef2843b9373844
e318bd908c67811090b68e86913ba7fe7817f48ffb08dd99131dcfb3eb22e5e1
6f17c4b40212441dd05c65b787c1d3bf8062be7e996ef463bbff89dfea6f9284
f6f278167c3dab1044db77915c13bfb73ca188bc9c32ce6e6d920878f1a1a143
458ebc73adedc2799c9afa333beb2a63413552764d267004fdc27fb5edcf4a93
d4924089148da0e167ec1bb69b5486eb2fee11a4eb0a1c9aada7f6007f9f7429
2736f1ad06fc5abf5c5738b01e22dfaccaf19f752cc05c03ca24559e8cd7aaf6
97e89c35b724d5e94145b6d5d5ee210358824b6b0873142ac2cefaed1986eb0e
d76b2b2fc280379a6e83d8cd8aeb3f2e18216d1a7473be6c2e46704f539db1f2
ab5d013da05f92687c40eb999f2cbf8d6290fb7fd5a71d72d2ad37ab318ba339
a429dbac49de81b0aaf283c071ae3e15b92fca4cc86d6080279d9e4ce6854379
2a83bfc370bbb160fa097eac651b9062daed97e85d527f52566b572de3c7fd32
0c3102e82b99704a72cfc81a5dd40b5b7830cba1b688b207bd4395a263366637
a46891a322cea854dcfc359b531b96b8bd823fdcea4b5846bd926cfbd03beab6
8d78021cab30f00dd75f0cc8581b614b1e5a19e6900e97d8a8b3ca8c2b6720a8
f292deef0cae97c63ffd4b423f7a3138434054e11bbc315788a91695f2ebe894
32c349eb8d978501087509dfd35880b5e92796078d21d2c7c7cb172343c8e7ad
d7bcba55e27c3f52bc12746bf9a13b69d2e06910d433d757156c38fbfa90facc
01c1b5d5be9c267c247c726b7b8a9f30584ddacf82384ff33e9c5de9f350a220
fa625fb3df38340057b09b9742853e3c0a0f52cb62588b52cfd0bbb4e64d12ae
91e04e3ae07b2cb9edb9d57b38c59824d1b7ff63ed747ab343f2b83c1857ee84
67d1db787ce363d7a3a83cccaf8d913ffcdf291a8b0ed0a34a7bea23d4cfe11a
37472a0667b3a9369545f84c5979f240ff1fa2c915ce402e1dd4b9c5a60577fa
2d5a51517341d71bb13e234322052f94533424460afd245c7d5189d0fa113728
8e5d96ca5a6fd4a4f497f08b6a3ecf20e00873269af37913fe1b9df76edb071d
cf1cb348efe42427a4271c6d7042d0835ba5d4e02d609df78bcbccec25a7f1db
2a121d71369304612405ff4e8c1e8d59eca40f018cea57784106812520d34e09
f3baae996fb3dbcb1f994db9ee22ee7f8c325373e673d02980aca10288e29f30
1ab07f96ea6faf8b437ddbb96a3c7a1a1f1de913aec7ead5e1f26123e0f6dd38
45fc98ff66acdb2b634ed201fbeed07904f1c4db21a904f90632e59245b492a7
13eb1fee2121418d8a0e36cc32b474173d7ec91efbfb40b5af1a23da3f50b86f
a6535b9a0d963b59e9680b3a2755b5601d926fa5cb80251cd4cfc7cf65c2507d
3ec861d4fd10a3437b79b7e04f20490a04c7b92746ab45d34529b45fa0e4c136
f237378a2f6c686deee33b2a60e59dff4fde2c100bb0c075d5573dd06a8da681
1ca894b02a716734625984af42d9b3c8a947ba3715eec2fb1c5276827a4d9535
6e02832e17f91e142e69d2d848e562e8197a97a074dda0f7584a8e65668f3443
8487246f4c346bb2463afc145974ae66d555f631ae5931bbf41118049830200f
cfbd6152f433e44dfd48c367217d5cf6b3643d9fc4dac25829d0a7543a1e2c06
4b6fd9ba66e8bb7ed922b7f2a87955d15b662c2759b82ebfc52595bc165d5fc9
905b8890014c1e83b693860401b794dbd4718ac0f6f83780c777f75edf11f58c
563588cdf25528ecfb71a79809b434c7fa530d1224175f6bf61b862f8e58757d
2989d56824bba490bbbb62ecc48586ddc8e5d786aa247df28f0277df1ca9a07f
dcac9ff058435ffd530b23c9f034356ab32b7632cd030c1862a3e3763e88861d
e9eff091128918466d13020b2c392429a458de9b0883daeffea27bc8fbf77cc9
cb7b3f27eb311df446a83b55001baafbfaa450a952d4e2abd892ea6d1f11fc96
9f23e892a475b45ce4a6e029c917adaf1ba304892cbbc1cc581c3be441c6ebd8
7918bbf023db46042c7674a419a2662f2c358dc40350ac6204a166ce79a69edf
e503a85b7c23642af8c7af6544e7dab0e829477059cb60e2a814c57d25af7576
90cecfea04b41aa6a3e0991473ce727f0d6fa9d3cbbf390ac580c06c61107a2d
631b9b6006947fba57327f5281b6b09b601a191d0b27f2f3e59addfa3270982a
5f9f1568ce1c2dea42f545c2bd8b93c82fa854237a5f302ccc65da6563eb51b5
f2e471d0cf21e30cbc45b8f14625e50664e201b8363d2b2eb3a155d25e50e149
6809ad106a6e1da82a6c5dee528cf8d45e5bee53b3f55397c65819802690484d
d567607492edbe4bc5cb8660af43e1e6180f07bd0523c530b623976c9d223b38
e71b02d6e1acef9699f7a91fe56d9bc081e259922e6e041396bf0f42d0cbf067
5ae72b87d7de2b4c789d9fc98ea5451871af45133ef14c762aa2be979e8193ba
710e5f76828a00fadbd05a8d0f2e9a81379df326d5ee66dbcb5065adb072d56a
439dd1722c75c286e07088e34a583b09b9059ae45db0abb4fe7d591677ba7f3c
3d22e28a53a344cfc9880330ee2419d6ea614b79ea510dab619f9c136cc1cf5e
86c8c4db6ab8bea4300b7af09e52766d80cc0eb6f6909ce57d118484ac46657b
517a6abd172fe960283a7849290eabc05ad21b4378224fc730d40e62af1f3521
c0abac20001f9d4e62df8f2a3240f1104dc3c2e4c52d090ff3d9ec280fb9c4c8
c02d3309e6fa4dd0a58098278e22b3aa9eeedd15e2c168b65fdbe919c3345b41
978604dc8ce5b05396625fef6b693e76fafb2de5caf1459456126c5a9d13b15a
428217f4af74ac150c097015bd63bb18f3734b972855d104dc08b0791b68961f
bcbc3afcc9081494b1d1e51bf01e702456539487d67416b061f90e316837acd2
3f12749c934a6f480f1a063853bb5ac3af30db3d09bdb5329e4cc80399a91134
966e40cc2db9d4bd9eade96dfe34122b371a922bcc738734c6507ec1f9835c57
9c089e2997f66e3710c60f2421c7291f31d44d5dc9049f5087bc8c0eb9965958
fc6048918c6d575d8c1027dd39df54b7934d997fd6c73036f4c5d4689e2de046
02c0c85f053cb20c3b553cf54ffea8ef817a55cb583ee044f233a0f9dc4cddee
836fcbaae0bec257ee410b16737e26fa54049e016c2693b3e46baa618693fc91
e799374bcdae1b86a0b93d5d67dc48ac827888e6b76b252bdcccfd49d29c0576
a27fb9c35e672ac403d8b73cb306eeee6b011a018d3f4eab866c26567cbe03e4
10365f5541c00304a4e4ebaab577be17fb4dc8378c8e05b97d323ecf27847ed0
17508d21e75004d18ae5f484edcb540bbe2fa21e88c9a54d5396af75154444fc
6533f52dfe23674d97b62173a5eb9faf6efd627279f32694b5a2c6da89e4723d
4a1106722253173c7ba8e2c0f051893d153c2b9f3a8ce2af1ba72100dff185ac
bf42eac2ef5312caf8fe6ac0964e7241954b6c9075d82f1cf767ebd2fdf54d3a
747abc508f32102e808aea06cf52cbe5b328a6bce1c1e71448bca15796719175
4927eb802b0e51444b3aefbe69f7b49298e56b38f155d2b28458a542acd82016
e497f959f3e1671dc01e7f48cbbf4208d22cf0af306481e6686e42b9b4045517
81bd3d8d27672103455def6ba782828596ecd26c7d64bc9108c5a1394fb3e2f3
72aa1c4de7e800bf73034df45ee33b3b070a5fca8756916e92c1b414f0eea045
c134450565d111478aed45e01d4e2cdfb3a2322e5df8b79cc0b589c96e9c1bf1
b324ef12dd1221ee50221cffe591889739193f1d124de142c467bd9cb74d3f62
a94e5f245b1090735585f10ca659951fe7e06c652a428d7fbf5697bfc9eac82c
247c84d954208e1e2d4555b9567e5731fe608b278649209c32031ed76fe0223e
103248352a9c86b960b5b2db6adf85a1bdbadda8a48582ecd3ad6ec0041282ed
cd0dcda08bfe8352cade71bd95da3fa2f37c2bcfd39da4801f9b307ffe73a7ea
a2fb50a8e4f0de323fc03d69bffd76a202bade84d521ff03e55f46232267319e
59997e5d0333f0d3a9664055a6a629d276d8d625e1884fb6cdd5991eaf8f4017
438a9aaeacd60dd9ac843020dc16188ddb6fb8757bac3fd8ba12aa5323f399b9
d0bbd602ab04bc94b320b11aae3143d2223b5aa7f25c38bacf92085854328e65
a7d3f81c0268eddb9e75849fe6369947f2b1b082d9a6df3e90101922da584d64
77a32f6ddb6ceaea343182eba0d48c565a8113819140b82587b7b364c9fea6a0
494583beffb0586228e215c801ce62c96660b61b51b89ff3d002574ea24b93e1
f35182a6cd4ce8e19a26e51a8581152c60884739034071dd98cd6ab1bfdab382
f91eff48b55e4acd241efff01018d503613a73572deabc5b2826e19be2b4b83a
39e1c05df902de838eb0449bb54a32da3c4ad826423980db40ebe37a55441d1d
74386532ab5c3313e122036ff9a2fa3a0059642b6fbf00a3cf049060df9622a2
1a4232f7bf4834584428274a312f12a7f7f4d02ba26e624eebbc1a21fc5f750b
d603c57ade0f2693ecaecc3a519186209263f071bc1c9b952b0d707a98e38d58
076eaf6923889e0a863f4eefa88969e7481ff87d65c4ba2461a61bd895529e07
c5b983360f2f304790042b522765f6eb0eb68dd399fbbec22b330b978415e7ee
dd46553407ee4f652365aaea7c4b66c3597ffbd24ebe955c69cc5a30be7515bd
40e88fb508cc332b953a7bbb19464b1fe77397f7cb040f4b18d59d526ae041fb
1b2aa9795bf8a0358b87b211141a57d805e8cd961c6deed2ac6e6be832895e2c
1bc94e2abc699e730a35dff2c1cce6571cfa718ff598031a52f38881dfdabd9b
2ea175fbfbd5a2d6eaa616c83531f3270785c16eb47d92f264c68d3663b61409
fd033334cb1296221fd81c763fc28be17ce37971682be28c3f1c384e2d688517
bbb4e1fca663ba516e64f9c66020330d8b05ac0d42f9c767d9ca1bbab7b81f39
61acce8fbcbd475bf1da15197dbf4ff31b027be32be0b01eb70f314e0a106b8f
fc0b07888aef113a9c128b7c3c67b120f5e93937dd7ac907df45ab80d30185b3
c9c0b169a26d3f88753e127c926f468648fb6ebf095e8e4115a7acd7805f5649
a9f19cd6eea8d686b767d14bc368eb2445b68a99ae910a68678e568332b1c94e
12ce2f70fc33e959e8a317bbc3ee1fa59c61540b58773f4629c1b15ad44913d9
d7349e9109d4507885afb977d195c455f2fdc0dbee200e892fc39b09431bed85
f77254b95ba3e1874ec2f4af4ce2be8750fc4a26fbb2e68aee39b1f0d6dddeea
693976d5048fd3df32c5c2271ea022029c463e0f15fddf86a7b051d79f5adacb
918b0968a98a61d2dde6e0c45ea1fd64a8543851a17920ba2c793318ec3e19a9
d6e081a75f992c5358518677c9eb01025a83528e1658130017495b347a1e6893
04b6def24b82a85107cc3d03cc72ed579680a0a63d1776961ec26af6fb07b2c2
46cb97a5fd6858b7e49d58e7af3a6f9980eb50c17398b66d5d4adb7232a8f178
13c301dac44e637f07932c0e9bd39c0157a64e0f8c529e7fa432f4356543e6d2
2d2915d1252d037462704801e0811d7587a24dc747039d8b46a86134c68911b0
e1fe061bc4a3f3135b74dedaa603243059083fbff65acf160f928cecb4c85304
3659cf5a994618a48a88a37693abdb28ab2de20245eb5b93e282b57160320420
42770fbecb8eaaa1942f2b8abdda4cdc5129b9c944f77a1c05eb15f5b53e47ba
5f605189ef5fc0c6c940b7cdeb02bba34ee4427ae52a736857fb8c4a9819293a
fac696a878085085692f85bc60e0872acf0fd1d1468c48804b609e1d362c41af
d0d988cb3759c4a598bb7403d77cad9221e75e7a86fa08c8395da8a0f08cd399
e47a570db952a283e2ec15b30d74ccbf2688b7a5962f9871aa9cf883bc607b35
a4fa3c9362e61940509d2389ed2aef23513748af22315b92163960af43a6c4a3
e173
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
cleartomark
{restore}if% End of font resource
%% Font Page 00
/NimbusSansL-Regu-ENC-00 [
/.notdef/zero/period/one/plus/m/underscore/C/l/i/e/n/t/asterisk/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef] def
/NimbusSansL-Regu-Uni-00 NimbusSansL-Regu-ENC-00 /NimbusSansL-Regu MFEmb
%%BeginFont: NimbusSansL-Regu
%!PS-AdobeFont-1.0 Composite Font
%%FontName: NimbusSansL-Regu-Uni
%%Creator: Composite font created by Qt
25 dict begin
/FontName /NimbusSansL-Regu-Uni def
/PaintType 0 def
/FontMatrix[1 0 0 1 0 0]def
/FontType 0 def
/FMapType 2 def
/Encoding [
0]def
/FDepVector [
/NimbusSansL-Regu-Uni-00 findfont
]def
FontName currentdict end definefont pop
%%EndFont
/NimbusSansL-BoldList [
[ /NimbusSansL-Bold 1.0 0.0 ]
[ /NimbusSansL-Bold 1.0 0.0 ]
[ /Helvetica-Bold 0.936 0.000 ]
] d
% Font resource
%!PS-AdobeFont-1.0: NimbusSansL-Bold 1.06
%%Title: NimbusSansL-Bold
%%CreationDate: Sat Sep 4 16:13:43 2004
%%Creator: frob
%%DocumentSuppliedResources: font NimbusSansL-Bold
% Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyri
% Generated by FontForge 20040824 (http://fontforge.sf.net/)
%%EndComments
FontDirectory/NimbusSansL-Bold known{/NimbusSansL-Bold findfont dup/UniqueID known{dup
/UniqueID get 4052336 eq exch/FontType get 1 eq and}{pop false}ifelse
{save true}{false}ifelse}{false}ifelse
11 dict begin
/FontType 1 def
/FontMatrix [0.001 0 0 0.001 0 0 ]readonly def
/FontName /NimbusSansL-Bold def
/FontBBox {-173 -307 1097 1199 }readonly def
/UniqueID 4052336 def
/PaintType 0 def
/FontInfo 10 dict dup begin
/version (1.06) readonly def
/Notice (Copyright \050URW\051++,Copyright 1999 by \050URW\051++ Design & Development; Cyrillic glyphs added by Valek Filippov \050C\051 2001-2004) readonly def
/FullName (Nimbus Sans L Bold) readonly def
/FamilyName (Nimbus Sans L) readonly def
/Weight (Bold) readonly def
/FSType 12 def
/ItalicAngle 0 def
/isFixedPitch false def
/UnderlinePosition -155 def
/UnderlineThickness 69 def
end readonly def
/Encoding StandardEncoding def
currentdict end
currentfile eexec
12d37711f3ef58d4b0160ca0e8a8b30beab80afbe709c0f3f0e7c12f2b9fc5e1
689c97a13ed505485a0694b1f9f5073a68fe9d62a62eb903fa05dcfad309712f
35d0572161bbfa0e34353d4dbc8eba4cb64daf302e5a572af95ec19155d8638f
902049d1de099da7c141d9f1af3cbca272682c2f68b6b73299a3f7c10c735c5c
2343c3dd08fc18d5dfc809764c249432aa7efd3423ee8bfb8c8c24869dca9829
d30733c8c6ab2b758a9e7b443712994d226cf97b4a0290ce438d6a26b068c8e2
2b1fafd0b133cf5729c70d0477a70dbf32803a86de61d0a525c98bcfed20dbf7
d88ee8d57298222054b31ed4d4a32ac1f2e28f0cf66be2686e270a16cefbca12
e1bd019c2c19ca05eeb47fb7cbeeab9be1803b792b75db055fbc90c9fece7e0c
f521b5e3680c546e2c05eba1144a0ed613c0828765d544ff1f18ee49c6df34e4
8de59c59398d5480c5e14dd9afe0793f1cf8e39e473d4ae1af21fd6997971026
ff1ee1366f70f6eab18ef2c48b665ffc4d478d84d2f52460903b1f18873c1dd4
6f9791abfdee5f715bc45909e768818bff61e374cfe1247878dbaea92a6a3ec9
5ebc1f02e99d80ed556fe7475804761e9650fb0e2cf892066a7e22962cb950a2
d07b52849a880514bd840fcacda5696ac2ab71b0ee2235c7b7b364ab1d2bb335
696db8a18f3e3a74c8a9c7946b3b8c4a6018b166f6b84fffbcbf2a77a023a2cc
d2648f077345da8af2be9421b61921d18560d5f5275e9a1018d6e3446870d7c1
60ee11f6e072870dc3e0dc28ee4e9c78f02cc9a97459cf3eb93c8d6dc362bc44
32d1f5bfbfca58a7d9b2d2281d53e3e913be71e189500960d2de46fdac773c49
d54e43f53501175b00d238ddcfdf8f3ab2d4c2b569e1d57351ef9e0699dda0e6
dd2eb21254a4217452f044762bc97e651cf39f7f171dfb9b4513e35e1d2b8e57
44b210449435a1dd7d3587f62eceeb667b266e4cdb6a40234894c682c6168635
da57673256c9b60cc6c7254a565a560840b2491a430b3d4414285ff0e1649868
cc3dae82fa82d60a95a48b82e4db40f330d657fbb121a200898595dc11e873c0
471f0e870aaa81df7257e39e039fb8eb43581712ac05da28042eb29c0a7a4c82
a4ad32255fba2850384ac69bba8c4d401cc772a518cc89481e8feadb7a970fb6
f3ea75b1504de159fb4e1d5d1e16012e67d5af21a4479e24be1c3efdafb2aacd
dd1631dfbeef91f3cefb83baa2a061a2e39b65d56ebe4a6766cccc0e8eed30fb
edfbc4e6eac5443f03615b5e1cef3420638f8b2978de6ecbe6654cfa96095ee2
974e6f5e07ec36bf7b416cafa38bc55dc9745cae8f77ed2f76c094387b2b0dac
de4eae0ac64628ca4a8453d58754c0b15caf01f5e1cab0be32dd084b63173f4c
64edbd8b65afc94347685188dbdb7573827868a9fb128f1529431225f94fb723
6008e71a07afb2a9b3d244931774989dade07e88088367c85f813d4d24845a53
6e90dd976f0ecbc0a0b703dbed8e55cf8face122d09785408dc07428f260b08f
6e2f43524e56f6fff7cd1598ef6046795a622ac54b1ed16481e84585e86456b9
93ff491f930c1351cdc9339fee2aac077510478b346ec14b87077921db58148e
2064c504f963ecad6962c3409a47c2e13013856fb62786aa2a16672f7547e910
60a482fe7fae7825d029a7c83c6ac9f2a5414a0cc5589f6166f3c351efc43325
69562fa3ba3f1cc7b5bf02fb79d4a51b502af6f1684682239a2254d6585e3731
e47951066cf8d0a41051cc471384dc7263dfb82b20e63bfd83767e8a23e734e8
7fc96f3c94bb19c8220e9810f4b8bb2cd910072785435f73a92f058acce10d39
633c0df683469e400c4935a918b43cb53d7abf34f32e6607c1f1715383a8ebb1
fca21438a494ada15c7b9a1b6eb323b1cb6ed435fa19aa0dcfc12bfe99eef8a0
29547bfdb4209a6c767cf1c296b30f2a99356fbcb06504fa881434c78d17891f
313c5d14ef2d65e7fabf746c14a74783c258e0ee1a12de774cdd0a70ec1922a9
b8ccfffc0a3185aa7465d3e63f9b33ce5f285f32fc4e501512a3ece6cfe66c53
ae754087ac277a608edf43eb58383df7ef4dd10c87f9cf385d77c435b1295e31
11c45aa579264dbd04eac244cad6f9b9ad46e53dcf5c2e9b748cd5acef992def
b8dfb8896d1a57450b383afbd95a0c44798838a3917fba1964e236f373722055
611b072976d5991088925f6e6c5769edfe76e1d3558963928d85b2a7c3a02dce
431a289c1403465a7188117508e17c4d60827ecba66c50880c90a0f36b694c09
cf052c610497d442e859e737a468eaa1f41baee4706b6c67c0b40695952c64f8
85654b580a57771b8ad9c1ccb2079580b29ac6b6ebff84389b0d1b5cdeebca49
760c5f6ed8e3202e094e6995ea806da24f7e4e0c285574e653f9c27f5d782555
f7aa74da7afe6c5a1ab0f1c8686becf8f98ae82cb2b372c80f59070ab6a6b6cb
229f9b1e48d7ce20b17decb0702c0c7c3ddd312533b39b795660d590a94a4466
b06b453316fccb8baa2419d4b6fadc8ed6f891848923e6fcae65457edcc1204d
521899361f98b25819b966c39abe355b6496088a0f775947dbf7264693f8e10d
7441766532daff48458c1719c88f7734c6255505ca8485e8d6285e7f2e9047f1
e2752958cf41efe1214677148556f187ed533d7f1003220ea302fb1f11d7c484
35eec0768fadabc84fe19a575a2411e5013d8a74a1179fdf6b19aec4c1476b7d
ddc6e37fadf6896e34cb677124ab07bc76fcd3bfe9b1c6da50b837fd9f15694b
8e88b0e114a782f0cd7fad5e24da7f672f6c8bb6651308365eb542fe028a9726
9c2880df8be16993652a22d57ec149a6a210bfde78477510a0e5957bca146fc3
5a9de805f057cbaa8215cb79528c2be33875159294616f506bdc0f19fa8ef3c8
19282af4204ec8e64aa8e1ad0e7816e1c212d1b347bb8fb8a5e8a2035f6345f2
a5f5562374361ca9346f34d3a5daf995a08948d8a4f8a9ab8eb830d2bfa2b1f8
16aad7a2b307cbecbb955212bf4e373b20cca61e6fb89da468fd409e4bec679f
db8fb4ff048a7f232ce3d44c71c875632e91d49c2abbc4b9d95d3844a6b0751d
3df978abfa38e8d2f8637edc186022d5cefd913265a372e4cbc21733bde3622d
7eab7c59438c42bac4134d04ded5c5943f8a74e22b527e4617bc41ab2ffc1173
936ca332b5b265a03cd8ea4d1f38482ed25201cf89926c933161820838e04751
c44c31e2b474da33126b022c6e38a91681e2acf9df01856b74447cdf44fa82eb
cf4e2deb56b03b8062207755066437cb4d6af911cee0c8d0a1d3f36f3e224f0b
44b9f1f93b190705b7f49c8cfe2c83859053af7637913dec2823bfb08a68a6ac
5ab6ff191dbd6c15b2dea92e629ddf2ba4d7102367ba684988e0e429ce7bb654
51c37e15069483c18f66007dbc02e23cf7b51881e25c01227ccf4e9dba48160f
bbf8803be5fa931fa0855dd798f931332a95774935461529f3c1c78e44dc614b
4a28f2a6ff6b33bd3e063f70fd54cb87a13a3acc33a8080a3c9bb05f4642f397
71fc185db7bcc9877091c7c7fe7488b9141560d46f873c2e721e6596abbc9a18
0597370493e02e6feffc74ac8ce7a3ce9cf3d1e153fbe3ea057048ad60666d8b
c9261fba1dae82b02b4e54f0e463f0f997f8ef881a3ddeb27b1645e2e43f36d0
6c2e35a4f199a1f617d11a1686b8bfe87fab2cfdd6c920762f8a1c6bcae7eb67
04e48bd3e0a0e19cb63a8ddb039c9eec84ea40dee3fa92bd94a394bc3580c8e3
41cab366a596adbfdd7deda6cbe74efe3c01588936b793cbe5c3cd4c876a0a86
22d1d6d6091ec71b76ae9078c28227d397d79f81fec2c2eba316f10afe920efc
0c486a8883e67b5625c135192443cd29df71c6f36e67cdfff1fa4c2739e42329
0ff87effb17b2c7eb3018dd3b2ef18e7d75c474c662b08743db4d5f358e3a627
73ce160f630fd001f5a90fe94429bf71076b6fa1fe6921e92c883b58de80120b
df2773db0972a3cc9a26de9f063c1b6bb73f07625e4772ccd444567e5608d9d5
0ac559e7ccabfa3432174f61d1ac2ab06b1c29b67569bf6b60eaebd6da6e5ae0
3862ea1773b9e20807dd3805d641abb927267a6932ed2f1867622580808b84a0
6feb13afc2bbba506777f8796a23b927227e51eac691c01d7a62c21602d3ec12
052a23c7e7e7fcd89d2748b96542dd54e28dada878c4fed79fee1fe4214fcf43
dd8aa2c3b1eecd4c5310af8c928e8a74a1a5c8985810182598bdd95a33842e5b
6f3764aebb47c8d12a7645604c4f7d0c3ee252a934e5300f1d377bd990b1c895
7cf8003560433537c084a1c4db312139c2a60cb29daf96a6d143a56d87041659
8b3e31f4981095294d9c8b46c47bffe24f06c78f142d8bf49e8c0506518bf6ae
76b61e23decad55e04c9768348aa90cbdc3d262aefa77ed4e3062f4e6c9d2bb5
04bb93dfe13cd9f34dc87d40e8ba194107a1e67bf418724bb49b8c450e2e43ad
5db67593a878e3c07812462681474f59402952c9231c38861c2d19e0b779b642
6d9ca219990298d2139ae846ebfee2a83926b5ca6baa4edfc3ab7bf528711984
cfa5abb53750be12c84312a441115cb537789d4bdbb8e7307627a647aca0da96
a502bc592c6b4e1ebeb67006b4f6bc6c8692fb78931db78c91f7899d6defc088
223c5b7690591bc545b80b6b602c5e15bf820b682330fe1966d36bdf76b97084
c59842953debe194cbb2ec8ed5f5a4f32c9ec2cd1adfbd2499db53bc026546e6
537f776bc6f06c6e83c7175d94a1984a54c1b5c64a142425d40a732afbe2e284
aeadcde7099c709b51392f4dfa771d716d7cdf367248b2236ccc54ca24b84b2d
7a0b45b1a72bc8a4e2362ea1848749b798aa3cbba9cf459551d24b1c64c529ee
d0af3dcb82b39ea37525a6c55d54b9e2f1e520e0f4064b24df2010948d2b2982
2d93cdfa026674ec02619ffa408c639f2833320d97a85f467a4d24263e81bcf7
58b0dcdc1477c15f09caf8d2332a07d67e162162c7565f2a9f2d430fa071fd7e
e30dd66c279c6a6cb7d1561f1409a7c7f5050c16ad3dd3906de00fae9d389124
08f7038f34c24a0d60fb786a5a55b9bf4ac2ee65d1c0233e3f637fee6591897b
dae7f6d76b0a814f6266b4965085bc59f30ca8b36ce9ab82c2379b8348044700
51142814fc4c87d01ea25771d56a98b9bf2d1dddb92917717263118584bded0c
fb141cdd351ab0ce85a90d0888b8d81fce969610a7732c5f39d46fcde5959b7b
5ee9a69c2570c784cdcdd079b7c50b1dcf69fbb58dc60572d66b336b84d6bcad
e6c525fa5730c4bae27fc94d5c78f393775a97ecf8c9409b00aba7ef8e640ff4
352cff863e0e39be1b856047e579b9249ac6b6da543c1616774c0b069c689880
f5079f45970aef1e7bbf44b749b32769baff59913185a2b9793c0f5ff5427ce7
e736bf55e74df67428f8ce55bacb994a26916391248b9844b4a67bf4c5e431fd
182eb48bb500a645e95fc2333e9b38eb4136f4c7079f1176fe0a260a386cee1a
d648e6479ee07e7dbecc5616a7177d7796fb95cf68f2c7224bb26bb8795b747d
6dca1676f0c89c66e5801c0c4e4917e79c11d9afbc409178ae62864c3531fdb0
7dfb6a27d61e247c6a889f2d8bc8c629fd66c321dac4222bababa3fcd7b94bec
9642bee92b5677ee428381cbcb2abe403f2e2a612a1df6ab12552ece07bcd880
7bbb15d3636fb9d3b06a85edc10445f92a1d33d5b788d3e5216935e71bb1780e
cbd90632790fbb5ae0795831db61274dd629f3a82d48ca829b9583f024ee6245
63fe77aedd5c7e735baa7906811e58ba334f3703757eb5262da3b961e42bbc47
434c1fa9aff45ab78f8f20f5e73493357680453d3c1e9a5350ca2f7e527c5d54
8a1c19c4335037a629743c74bd227d09123f6c995f45f5b254084f86f1bafeb9
ce7a4aaa85ff63fe2608ea6dfad2c02a8c065ae73b98f8203b2ae3ccae39956b
d485ef5bf55a5c26d6f9c45344aee8699b27694c1b81d581563369c72c13ac5e
8c97d4676219b3a783a8ef8adde1338e9fbaa5098e9bdfd16ec8d7b92ea29622
bd5cb0bd5434baf4a20135f0c73c49ce96f7781a381ff6dfe8dd27e5f3605f63
8d481e2fdaac0841537929a8d2c9f41f97a7353629661e08732cc7c62664057e
17d771c635443e41678fe8e3ddb053c3c138100ada70669c22d9c2c53bf8ea03
5778d9df7b56f50c6fdb1d1c0ccc126d94365451808a696f67ed391b862287dd
2a2e87aaba7b9dfce3ee77144a3269ee3ff46b759a3e367d6097064aa5166a13
d6849c200c588b93352e173b6301aa856e03a3e6c4aa41016197f8fc762880b5
89a356b74451abae4f50e0f3e30eefaf4b84fcba462d7834e44c4e7d649ac21a
445ff6550a29e37c854308eadd6ce899db7483980d61b36defa77541ffb1e134
bef2dd8e87b204dec4602f79b914b6737628e56f092f97abe83466dd43775443
7748222140cbe140c7ed6a7de1dfb9d37c7c80a98fc0b3ea3a0cae07f7e9bd9d
b95e305328187b068193c15a2a9bda8a34dab5b3eeed955fdfb6572cfeb059a0
19b99963672b7ced0cd00a3dcdf61569c165a125cc36d0bcdec339e2a947fa39
a355a3270beee907432dfa4654d530256d5c3699e155f346fb7704fdd4b91a96
765eacbb2ca681e42d5b2a173d5ae88a3b5b10003f0b290bc24ac9b7f548ec24
1a2ce1f3dd146c45649006cdd8927189d2d2a6aa5d9d0207b39eb5c7a8cbacfc
da6f8e328166526e70d749016797fb13fc7c50184fb421d079cf153751cd900d
e5a0e2fe285059dbd074a5b01fa3c8f432834c043dfe6f770c56480f18e8deca
fb4dc5dfdf720c66033f0acd07fbec8f272da433bbe8ed03a3d55f38dfab005e
67db8a021f37873cf93aaf74952309798f5064bdef162b40947ae314a38a9283
c37cf1cebc1f1aae318bf3640fb896dbf8b70712929c73c9cd89271966e6336c
fd6c2714b364f66257298043ceb03d2180e4d98ba0af91a866dc63619316bb3f
f21b505fa0c5c3e78626e4eabd9ab608c34e5b6b0b4c4b53576a6af1004ec02d
5cd155ca52185eb0765c300ba2864b8241f6e22188eca4269b092a9f491fa8db
20e143b76b9b3f7cc59bb4d67325306c3079b21a057bebe817dcf4427c4e9340
8c8ca0369ce588a690bf24ca1a48b97a394e62bc3f5cf4279d74438c9eb7c14d
850b52186eb09e2249532e9b1375d3b35b3d59863830b0c27def7528711535c4
a3e1dbd82a4a1baf8954123e6bc51fe80675ec732961d80f175ade8425df674b
75a83e2901f0074222fd5c406223247e845a80dd99674749b33c6e1658c1858f
c2ff64baa03b8ce5a9c54506cf7ff82f04f09ccc66bf0faa27bc25e01d0385f0
5433fb872d804df35da98c72d8f7bea9e489f1cb267b678a0d55fd358323496d
88825cb4aed03610f3bf961d47d210025c68e65cd380298e6ae0444f0cc04440
a591084ec06e047461ddff480aa009674de15870ec35533972fe6e1e8b0613d0
b3e6b9410fe7b69edcfcb878fa848e6791d2333a309e4ded441423a0b72c3707
6515fa51044851e2269ffa293ca9e8273808b0ba0be9d05164afb0b90a4a97da
7857e99566766898242055ef9b1b335abe3a52d2ca44a8c3f7d9823560831c25
fb3503ca957194fe50b4b0462188fbab714d59e44c0e2857950b64c5a984cc9a
1991142d4f220f20a812a7a3d0df450db1c6402ad692d22f34ede899a33a846b
f36e0df29037e30db8619293d680ae8a8ec6ceee72e9de0aff1f3c98460983e0
9aa6fe8b76218de43da423382b6774e2bc0c38446e72b111e8099cdfca0587d2
53eec3c03289ba41ed616ad4981c3bfce76f32e61f3dba3e0eab17d31c722468
e8c4210aee9dc51c574a61ec6bdb3286a6aef026a4e7183e2fb1a8c34f6c50c8
e9343635e8f15665dbd0796833fc90353237c4a821e329002535302a80d88879
20868d78958391208ebe13214e89e029dfb53e9ee13701a4996421d717ba7078
924ebc1f2d0428a7c60758a63129c789ae93c7e9340f8a6154cc00a148752d44
f552f40559ad0275b948fdd86f4a220e7217d89d2c9610ffb1564a8ffe3eeac9
f8d195d1c78619972458c1963cfab472eadb8d0e16af99b94e9ec3d59342a92a
11d171b7cb1a3883ec4892ff687a0c7a9523bb1bd9008d12ff06b3edf241085d
d0dbbd5dd24d41ce8bc36c58b7ed2747a7193ddb0209bf079768d1ea9c04ff94
44e4c45c7f90189cb4da4d2b53fd536f67cc6c4c6b34eea83699471c61ce196d
8d1b6d3d132644bf41c9a6b4a0ab36875e9130f0d279fa9515d92bcfc5c109df
beb12cea75a432932f8a5d396a192608da70a15379d29c827d1d060322b2267f
79589478940532e362debe75a38f9723d040fbbc18bf33e3886f62c8ca1749ee
478851762dbcdfcfce898e22899cb15267aefbecf7c77397d6824c894bff91fe
0903908342972ed8e7789ef98995a0e8857cea807c8d730c963bbde8e1e18ae8
987e2f73eb800b3171a9f4c25f23ed2bf63a091bd14dd10a465a6f7adba8bdc6
ac5eebb589d22fa96b01e9b7b810c4dba7d225c1f53713226d0a5270949a47e6
28f7d0169cbc17969f59fc482bba8ee8fc966cc7af4aa1f0965f920b26577b77
66f8dc61b490133d8c0694d81cdcd7cc0ac4688b502f0d87b613b06dee3273bf
1fd22f4032e1adde965ef266e63ddbd250bbcf55b26639f02b123d3a36ff7f2e
7b7640c2a21e8894d2c09da438073ee77786129299a01f71f67d5ecdb1703745
15c0c3248197f55fedb43adc5b4d7e899830d6050cc323732606c9dfd0cb0d55
06b4220f1f04860273f2e90f535fc184c9bf3c781cc4eb209f8c18d01d8ad4e0
f0014b6750ea6dceb33e58bb8f559c98ecd69a73b5ac6f4e1861d00638982734
c0d2ddf78d6a984a5788e95260e9ca766bf0428e48d04f986334e0906bae9c7a
25843d3e470101855beff23f8d96829d59f267424afab2cba3411cbe310e5e0b
d198b7d0605b5f20498c8fe1021e8618a4f3a9eca51743c536a2dc6bd96fd056
45ade0d95dea748a6d2e7958d77de5acecbe5b1e26b14baafb3e1139b32fc51c
aeed7c6f422376e818027632010405caa3af558b20afb317e413ffc57458dc00
7e55da9cb44938dc40b374f447100d969cf197f1bea87f0d4c5d2085c8d7ec43
c53cfb474efd15c2fb48077b1a5187c47f75c343c085b9c99f1afc9f411a53fb
f95649b8e4f0022fde51196f72328e5867552c27da75bf3a4b1e05e99bb8df61
6a7c479638356da4032b9f34a9cbeac3eba6518215d75034137968135bad63e3
6c28f5b7fb243ba3b4cfa1aaef1abcf382bc5b9331e8c7f53cc9a1d45c835cb0
96f1f3d7b1bc74a1c11e8255b83d0de489abc84ab576901b67495cffb9c7c9d7
d0be74222fd24d48d36a050755346351b8f7ef1ded5a1a70e88b64fceb795ace
129e094b4a8c5b05615df2caab1782c09b89ff12778daa51d2e55ee4325745e6
a3e92ede36dcc06be4107b3ba53a18385d9ed79992b257c2dfd61f9adb3281fa
262115890e71699cd9bfac868a5e51ded36898dd3034eb62d9588f8d6eced7ad
07294e6e58fd2692c82ecfc856474985bd7fd8b596ab02cdd4ec14de67dcd136
4cd63faf9b2935e6d7d1cfd7382aea5cb1e7871456245c4b9936f09f762819d1
7766e10f21961c7577a62835099b7a551426924fac329ede79009f69527a0f91
edf795234a672d871254b93589402e88ee2c10dc8d5c720e4c7f124920f46186
d0f376399ca80687c2e3f6da7e0405214622de8c7df71d4fa77a6f698db974e1
5edddfe4d3382967877bfa0b901bc254107cb9bb3e05f6c08e44bd71f80d9499
6c1b03197b370b4908b31afdf294a361c27d1db252e5871bbf6ccbef4183749c
53a08d6f2558c0baef6f3fa88045f51fcdeb9a8ac5be2adf8964fed0ab1ffeda
9c028b83b1d9d5275401f8f0748c75c8769fdf339f935dd174e10379616f0800
2f7a1a5063f24aa3936cf4fa0717290eeed6b668e8516e5cc593161e01d385f2
6fbf3b7533c41d7511f6fe5c409f25eecaf448276d24add582c932f59d55ee76
d7e9749dc546ad2d038b9f8637afdc108dd1ec24dd36dd4605d744810b54044a
a6a13f05a35c560244c3d5eae7fca4c34979d96b482181dbb1f99d8a93ce8c8e
2f397d6848ade52e536208334dbaf3ed9237c19e128d9847ca5577b756f37028
3183041d03ca8dd45845b9bac72fff9546b6bfdc0bc2ca2c47db109e98fdb616
aba43f1f632e03886e0cb1b1788646aafc293147fd6b72564f2c36d240c5da19
3e078fda357c3d5387e0c956f2b56dae2d20b7365bc48e9e9b4ac36f04d7a728
04d6aa6ad59ac21fc387e9ab114ab520f308890d06bcca292ec65922497bf611
0c6338a791d33674bc070c810e6d60d62b0f2f6dc19032aac93fdcd11c1ea176
fc9946806f81d29b4081a8825116334478fee0adb963d390595911a900fed40f
95546fa70bf98438c412e7ef4f1e14cc53d0f95614bcfc236a967c52d3fd134b
6ec3b4c2ab0676a40a8130f0588cb0a3f4167086881ca524f2c0bcd79c09a70c
73c214f9d3e864989cd3fd21a41d80953ebeb7a8b227217a2575aca9e6b34814
db003cd4e8684120c452e867a3adf35965d11a984d659a3b3027a19afe0e4a08
243d46a59acbf3dc71af0d12c1d27cc6328ca1c86b6a07cf12074bfe4da721ef
5c4c7de92fec661e3e128e3b04b0fbf632f92f872215581684371433179233ee
7850bd9666c7ecbe9647d5230a6cb0da75c769c90d569b00605dc5d845c88441
3a4130999e45b4181134cb38c42b667b1ebb88fcaf3c7e99857b0cfd099fa7bb
f38b320c37f566f4bd5b50b88af41f380976b27df932649a99ee1808d4fae714
2c573473ea50b192c7b95f519f7eaea5fcb5653373df47dc4ccd4b310422f59f
9aad3043e49d176ae29c3305080fad775f63a20500167afb5ecdaa96392891c5
38d51582cb56870e75781fa15ee2dc5b6a7c808d283b48776bfccf80a95c20ed
ab83f29b81b08d471a4f68e0fd8d706ca601aeb9aae1ca784e392d06ddc31959
5585d7144444d14a9d4d5f6a76dc36bbff11d17203eb8dbf9be3ab011371501f
96ea666e2d0a040b68ce975059f01ca8d16d9a2d6e64c047cf825b5267fe8a2f
6a80dd8b7e58ac08cbd7d42dd128a1acb46cb6ced21da7797f22f14efd9f0012
45beeceb358e445ea29aad6dd30186b961518eb26780a9efa9b69bd4dd307a07
97dfc4c677a8a4bc1d1a57ec7ece9aa48505a59554f6a6a0c4884d7cc9803e9d
4ab4fea7506699f7d117ea4c4aefe47c18056036351104b0fe46bf4a0f5825e2
008be91dedec4d80157f57e0509776bee483e0c6a10dd5f4c985f31451210b10
bc08d0f1093bd0d7bc7698cbc8184fdb18868c733426c9a2c7bd9c1ade9d20df
fc74319a2bb22682717a005c92ec84f66026e5f6589daf7f285a0120393ace62
53491213ab38b18e3121c6bb29e90537b62fccbd591d141191da22da9c2e961d
c10e0b85aa6ba6e3a1ddf7412ec5c6a3c784e1f5f7a453f4c39e88ece7a924c3
bd069f7f491a48ded20371fa6c32e1e7364065d3319c47d9d9504a2ec8fcefac
2cbc5164794a4547f56244dc683801d7e20e3d3d4d72faf2a4bdcbb81c54be58
dadd543459582a5cb99b0b09749adb136a31a4a46a23ae17b3a5f2ecef74fa44
943ec6506ce14c91115efda51375c36c4b30655b2d01fd4258d7617c6e5603a4
2569d163c0dfd3541b97f6f224b65a9c287de79aff0c7cfa81e27a9a386ec325
26de04b5e80fbdf21268a03d1c471396e26740e98894495da4b2aeef97104924
bee8ab02e702c1e0fc2ea53adce22c609dd2720e8bb7fa7734b566b61ab7eae9
47a88c2a1c6e744bad9bcff2d226c271238eb78fd4efb56da7d847876254eda3
8eda2b8fac540bd14e4fb9db9aecac5baf564cfb084b1fac16122eebd4140fc5
3c635d58d5bfff852e7eeb380df504792458e6fd28b98a10f4fe2715ad0c53fb
df5d3b23fa9549dd2db8b7b112cf7839f7360dbb207def9096d27d3d6dc78e2f
1bf3d711405c2607b77d18de0fe2e127e98613890ff23c74d6fd6bc149de1d1f
a772700b663a74f5d3b0e89e1e54afb4913f76916d47d2dcb502fd681880b3ce
799aefd0368cf7958d2316d2176a5d03d6b78c0ffcef50e2535ca7dd06dfcc09
487d98412372b11babf0d67eb82900489d45875e50b128b7fbf968db5c231d64
64b9c54edfef315301f948ea127728b08dd6e43090c42c12c9388c4c99bb382c
62b5759d7dea689c50362dbad9e8395f6556578fb6d6d2768e6d0cf965f5b4b6
97d3d1628d134058e779512c404ed48ff1299a77424130611a6a9812707f518c
3e39ab0599127db04e93f5c9e135230c41302a87b0d0534406014daf5af13f39
a6a3daad303748ce80d0b8dd786e290968bedb03858ecbae0dd1b5f7f048e06b
72248fe3c61647b49fee532ece174f874ef23e9baa5bfab0a9e60dd7f32d4965
1f5744a27dcc8307368dde18139e2447185a55182e4d7e9f59292e14510dfe13
d16ba6fb0f3824678468797241b5ba06e192a714e29b0428a71b76d0f868f300
d71ef2afabae083fb6eb4da37072111e7c3ae30181e955616c7003024b08e521
ec8fa7a2f291c2bf893762ad02ecfe849b9c0ad561370a56386d7cb1cf97f2bf
4640c0055b95d364c838b422461d88a5b0f3d8cf834e45e49ebbe98124ed50ae
a10d832ce12a31a08ed4547bb23e091fb973bb0948800458912b40d72d1c83ab
f996e72458862b5cb736978057219dac7423166f8e47eb07d78888fe2ed23925
5f38e106346475c37204346c0831744cd415f66f5f5c2f25d2305bd39ef97aa3
03248a535baf6e59932eea84b65e6440da97555a92ab9bbdbef25525430c7274
518154c72bf2de6b2f5b0be042c5b12d9c880a817c5f0ffc6d44971f95e16ae2
23e98e723afd17d0df0856c84882a5953c3d6a3d93fcc7af2e4c60eadb7e7b83
3960f80a262928176a818796fb9dbba8cdf19d5fc4c75297b04ff3e6682395b2
3578bb923fba37633f38119fa060fee24cd063afd386cdd6defb25b42a796709
5b4d6a35b7f81e5d4209daa4b7295cb94232fe5818e81b949f1c6443ab2011e7
c44888f2d7681feccbb4baba1f33c75ca9c5e653f920fed5cf21be7c009336bb
ac93853297ebfdd80a9848755978bd41c9864ac00c32e36e1e0f676e78bdc765
47a15556b46b067013c0f3a39e819ec20cd2a9a0cb490ee207a7bdc9ec9b8f46
0e2e52173e513bd9ac1c5104d36debceace519b690e0c889684de661132a51f3
73cc641f5a494702c40f493886fe9df409f39494094e398cd61e6a82ba810760
5433ee480b5bde0407c696fa660f58673d3e582d9388d47eea08446cbb2642e6
e29259311eca35df45df21835361a90919a8d773a792721330f7738e407c1217
d34280be67386f2284702c5f6beb96cabf54121baa5f64d3793364e9b5ec5618
45734c0733e7b5f0246579d88d1df0a39ebdaba5f3f8511278db3a06a64b933d
28ceefdbe6353e3ece51fde3a2543f9796d9ee018e11c9199521c92f180feae6
91d619fdcaf338456d3c2ed9b8f088d17816173c3e69f47405ba034722118f4f
c3e80add69e223eeabd2273a151f4b008a897544d8d3ceb7c2bfebde0df9707b
91c0c52c626e703248163988d5b31642280f6b62243755950907d8712732996f
9572e44b03bce3d1028317b975d228d3380ad391cbac1dd40837c9a1cf4e14c0
2b5b37634f0f5f3965af7b023cd578bcf94f6b67251a211a271cdde9c58b89b7
27fe7b03d5fe35fd6d7a1491c1d06444915b169ae467e8bc1a84845b351441ac
b215c75b6a308688ab33289527c8c4e05c24c39b427fbe4680647e7fda06126e
587e8f5ed4f12fea6f7e7aaf6c3c46e0ed692ec7b789aefc9fdcd71ef9b6193f
dcca2beed797e64b4c2d5a249c81bbccb88846c6c253e91ab2f0b7258fb2195d
2f2519d5110cdb250f51b547793349644d56a965644f3d198b275cb03fc693f6
557ffe142e69d0d08933f8c1d4e9a4233d51bd214b178fda1f2298ba2a10b031
f6ddc77e518c041e29a47fdbde2679a7c6bf1da681ce6af5644250cab986322f
d76e1e815a6d01420808841fc689aa262ece08bbd9573c792d45e618c306c943
b1e5ed9419d8e5e30fa3bff162ab4af6de5ca80f909b168805f0973c7356d1d9
be842d99c24653a62cea686ccadb88397db60ea5d012259bf4593e8c144b5db4
066f3b916348b1d61af476fb0af64b7ed5551a36cacc0d65e1587bebd96400bb
310dfc4dbaab288285cb3414381f399f517533f5ef81bcac6aeb7ee90525c116
7a94e7bf3e877390135908cd416d0295a6f4bd9692117733976840a4d7af0b57
d6378f17c5e2c67226b5d710791b7841879163be5e16d777cc66a05bd2b069ca
8d80059115f74fc42b4e984874830bef91ccc9331639c1cac1b8a3c9d6174e43
49a7ce18d6498b2f62bc765632cd8f7a835512197dd3bd40aec40ab655bbb570
5e68f61cdf3ee53398d418c8d726bd0c3b3b14ca4cfba5347dee0b130c7c215c
62f9b3629229e9c332c74d1eff085d96a76a55b218761c29d6b1e07d8ff739d5
c4f98371a79e9350df42078f466d34df751fd1f7904bfeb12d4c1cf6b690874b
c5511de130a9f2002bcd8a17abe72428bffeb9d7fd11ae92d0788a0fc63c6f53
b1087580d9dff8078e771c4c4208c51e7a7cd12b24da4aa438b5f36177cddc24
bc27bb4f3f103b7e9eff308b2253ee29d6495afd37c14f7c833d65db470554a2
dc6c0fd16be9b20c14cbc1bf274e46115d293912d65831b8e50c195d01dbf0f0
0dd710bf5dd15d0d84f8cdfbbc7b7da55b5018aaeeb30df9ef96fff24f68b168
2d6b23ace310eadedb0812dfd1e6453937b19eea259a1ceb60849e2b4bd1fd77
24cdb7d1dcf0b8ecbeee75b0c6f18fecc1cfd351475f05fb8395fed1752dfe66
9fac2f3d7c598b22be86d5a441973537981baf084857f3c816f91f54606009a2
c2ad16e04b1b42f6507c66f01f172aaef5f3c4d44cfccb6fcafa1e002f40da40
c25fa70652f4f773654379b123dd850598f1c4f31c5f21efe003ecf0dc63a950
d900ddbc7edf45730f1dd6f4c4423d10f8a4a8394657a956b6aa8ce49c5c1969
54899c03028b400a93520bd0d467aa3dd227c51d0b1613e545dbf5cc6357086f
0c9c9cdf536abd59104a89287580e3c5297ab0074f9380b744b30a1c4404ce22
9e52ef7c1f4f8e7782f5c5b94d7649046f83151d63585d57fc3ffb6213812374
0ecd037e3cce357dc6cbcc1ee0bf8651e17d650b12e95f0442305fc4a9f8b99c
a1f44de4abec4f5a67ae1ed295693ad4bafb3540e550d10b9750630646a7781c
2c48cd75d055d6e1edfcff69eefacf4e2ddfa16383bfcff4b8c8895c2d36ff35
e3e93fcb480268a0bdbd548771bf8134baf9314d07150c7e075d990bc32254ce
8fb4893cb99aea564e9a8a368ff43e12cbc3cdb4b909b2bc0123bbf93c796e46
44e66661660ba147f36343fe0fc5859bc54d8f5d3ae6deeb96fa2f16dc0ad8e3
8d8feb01fd142b447900fdb1da00c66dd2aef8ec62467e99b9add14dfcad3b58
846e4f70d21dd4c46a355287b4e9ec4227ed29b9a8cf29da9a5a586ba7d5a9fa
4d16aa46e292b26aac90c69e43467f381c2c8661b9b55cbf7ceb6f94a50c01c3
7395ce75d20dae42d9ab731c2323a7790c4142c80ea3a0b53d92ff2304657548
e9cc8b590e5de218554b7a51ddc4538ba471c66bbef2b93f6e556fba594b5096
e67078b4a165025b53e02cbd3d68e0a4ab6fe3012e01aebf58488aeb58ea632e
a2729ad7276813b350bd5baeb36810609f52a07f1972bd06daae68793ba510fc
82c8da6ca3ca9bcce7589ac06f191a95009cb9cbf29a12492b4dfe786554ae65
d9cdbc1e1cae1779504a733aa38973cf4cdeb5d9cbf0004dd0fed9442bbde57c
a84044c98d38f1554a7ae3b5ba2fdd1d3e41b9d76bbf0cbb95b97314fbd5c669
9a97e67fc3140320d0831a4700c72a2fcfabcd54abce0dee5c8da762095c2a5c
88c8d611168403f6591189388fa6323b8c05655db491bcc7b4e1d9ef07addf6d
07b54fed44b175e6af92f3a8b9a8a382a36eab6ba6f8027224d3e82e348994db
bf5323eca0ea40d4939a0001187b84252e04eba8feeca82e655ba87f5eb2d25f
a997baf803bee8b17879c06387caa1fdc9b0f09c4825a4272408d86df3f75c11
56ce1e3c41f60bd6d2d4e464fc6e82e2c198dea6393b9a1d564a6495a853b6ab
d31c6f0a2525a3efcbf622520446e2c3199eb2dfdeae5f45fa34328d15c87eec
9581da17cf6868f792d3571e4a9774ab4a0315c92a91c75f81c418cb7e7c4591
a4f7f97eb5cd7e3088f4d1c99603aeec4cd41a6ac1b6345a35981e1952ea7b66
034c16babaf70584ddde26c029ea0ba52c7067485e759deaaa6c9e414b7c80aa
1e0760cceb07ec9f527c3e700422b7c645986b3b35d7fff2be07235e3875006a
44952a0e6c62206eb3eb4d04702354ac349440154ab370c7bfe814b2107d1a74
dd4546a40bc164ffae66c0a9b4fb9b366b109921e1f8c145915ea478784a10db
5bfcda6cfc5b169d554944971d8758359291f83b06b1d16045521faa1e3a427f
9bf12c75c637504231b6046a68045510b1829c053d43121343f2c42410d7d948
427ff679d2d98db8e7addf86b8a117e658cced4e4574f8d3faa9cc2826b032da
f380f184571dc0d4a59bf74d1818954a1a4eff9ca494230a5517d433be11fa0d
1dd325f3e0f83191614f063d0c744fd73b69e94ded2ae3d39c42f5a4a980131e
4b6126604ba1bd39536ff3e2b2068a151d8543cd37b443b9a223a54c97b2576f
576d7570d2b23ac29c02133d950a393f5081daa40833996a39b8240f2fb9a930
e7e46cc95088e8ae014c26937bcafc453acce5e66df991fdd1065e57aec5b22f
d073701f4bff135cc554725a92978544bacb2b8d2c9a7f0440bad8771642fb71
c591c1cb6254c0bd33bd27e56ea5eb1a1abc4804c35671273824f98b76303544
5d1f877635ad152778292f7cbe982f75aca04dec01d377d553130deb2b120d61
e275f2546ec763f39d565a6412b17f0c1fd7529da3ced89e1ca906155423f588
36a8062291b5a79a81758fa86378485c34414eb1e5bf7968b8ae763ca4ce57cc
59845d9e94a32ff47f6041484e1344271173529372af6cf29cc521a582968532
b4427c9deb2e7befab35a4cd6b639cf3ff7c263eeefe2d917cdb0add125f3bcb
32e7207c5f9052a032be8bb3266a0120f84973a847723b6156e5092f3134b718
abc787d9f229bf98416f4e8a45a51f67648f44ac4d3c4da1832d7e532dd15506
1b0aa4a71b74c167a0e56fe956f619f2c2bb7e5072adf11fb8b9fce68e1b686d
625c5fcedf427a0be2329763b8c8193ca864d000594087ed9eb76abfb5664173
12a7ee447eb37a8bbd7ecf0479d8d531c708a3f057a051525ab403783f3f8577
2fddf94e7ef2b0e331de09b98d3cdc857bffcc63bf81c839834aa7950dea66a9
bf2bf5841ce9e2cd6aba43c997d077a4472a1b4582470659b5f86a17187e2b3a
f692477cd4739b5b10a07323b1b05ed7f3ebd1b44fff6de4bf0e83bf7c0c12f9
43c900d58d0ff9d5af937e985e7afc8b0b69b084e04e02d80cdf930692b1d5ec
d3c2238ee285cbb04e1be9895a65501e4933be041b1259c13813aec6f95b1351
635b15527eafabca84e0bfaba2ba71cdd2c54f26f5c9feb5e59ab8773e575a74
386debbd9875ad6ab25fed518f6b6140f3032eec83097f67505c722ffd40f5a8
7a0fb32533cf4a100b0c09c2c6a6e8f9de3500842da0e9cb4dc55909186d08b9
5fbcbd978fcf5a40c9286d069d2230233db653bb8cdeaf5d1c76779e7a3ecc07
95f59e8df4b9dbadd47852b04fad5147c66b7dc49a4ee76448d1cd1f496fb6c5
958933c5c4b7de94252ef76b728837fb2fba4915d4a4cc07c4ec6c5599129bc5
73f535755ffa6b31bcede895ca0c0cd75ca74b1ae4dcfdeb5989bbf6fc0afd11
63d014fdb1f60993b8d52a6546d69774f5c9e93d611b0ee9e36fc498c9dc37da
ab66cb4c00391b9ad5788bdaac9ddfddfcc6dd156803c99688c836ca9d132f60
3edb37049db4a3a859b9bb5fe7b325567b35ab3b8b67394836e78b3f2dbb24f0
3f06553acde1ebd61c67f975c26158adc81ada5fbf5522a5e81b78c1dd18c835
6b7ec2f082cb3d07b3aa7fb76848b5534461e5c023c137c45ccd793644148e7a
f88fd3ac51ffc0210c1305a1ffaf3d6e7aeea98e0aad58cd18f6523cf7b635ae
6382b685bfd7fb63b2c567cc96ac6521e35b3f60391d13c26998b54154e3cda3
d88b03e8b20859fe97d0a95cb25e26a94ba7c6bc40aa5aefe25e629414ecb8a4
1a5cbd9cf3c54cef2594c2593dde352426aa262ae7ca65b45c0ba636ffc52068
ee1516ef39af09784ed9c3acac1f7c1c713ba93aea88ae633202d18be4faf8d0
e00306ad981079c5b1fc968bef67158ba7f3e2db20c2d8530c626fa27552316e
16c3c658a0081f3791bc73fe9225a19e621f96978d267ad3ecc53cc85be3f44b
330c2bf7de5ec45b64a1f7764c3aba6569dac5685ca8a696200a4f29722378b5
f5d8984b2b1cf40013a32775f148eea9bf9d7641bd3932ab3a9ce81a03ead922
a392011b083e1fefd01103d28a0a91d830e9ca83babe929bd6a533b248926352
b59804c7ce885549b45e36b514b8949398df6a42ff090d29e3a4ce8df04768cc
0cb623e4e0c20e43ebd11b297cfce0338aba4963fcabb193cf2ea42ef780d1d9
fac8ed3ef4d4b1eab77d77ce64bf35afff9e56fd888185eab1f83cbae67e304a
8f85c25e262ae3eb6d5fbad96b899ab128f97a8ed05fb60a1f5f2486e85d5b75
7c656f65c4fc2737662acf05c7b11694b694508aa46ceba974899fc297be6f0d
b23bbd851e917f2c2abaa0c0d234975145bd5f9217fb0ed537aaf3fbddb6ef52
c72153e3bf96e9a3b39b39e29630e9822c48dff10600288df650516f54c844f4
5d8cc777f74fb51d5aa173f720057563bb6c20a88199c4e85296f2eba1ff56fd
6eb98599ba5bdc94105659591f60cd1ff431e4ec4f246b3e3a460eee6c832239
127f14e2bb020e97f450aa421297a0a34de17199b918caa8cef6e61bc784ac32
dbf454e3c5847d24f232c6d89b72796035fd9df19460bcb84192d3ad55c84e11
d7ed4a8b269dc78b8c44ca5a92c36ae66f30a2bdabdc16bab66e4f0859c7af0e
460e5ab6ac871c16ba69386f08e5508e071afdf228951e056921681afe45d9e4
9b4fa4577bff9ee69ac86897065446f7653445c00eb488a006788f2b5833e663
a6333772cb7e4dee319f0305199f5eb901c8bbfb702111f4b0e7169fdb84197c
b1edfd75caeaa480f411aa4758421960a357858935648988120b20911d9afef9
553ca57eb9bd63f7a6540f9543cc749ac8595431b530b494fccdfff0c507be6d
04f6c60f84005d82e48079ca3aa1abf75c856ba3518ec7667e07ba5a7612a9a2
cc2aec3b079c51cde64bf2902e22631036d7c3ad05dc5ed1b38ea7329de27556
3dab6df7c45e08b4f39a3242f46ddb4b0e4943ab7caa99c18d825295d0906ad3
bbe22dbe725f0fe01ebaf6d3067da698275a49782fc43973b38d3f4b1bcfdaa1
faaaa32fb1adeb641e165449bc3eacece121ec0af0074e5e5a137b1566d34630
0c34d077e4eeed50c04921ddab1651b1d86f6fb632f7a8a461d440a36c9465e4
b1f38e4e2b8e6b7a7a427187e72b273b7bf7e9228fc41ebc43413b0340f8c85d
2a1f2c28ea4c3f2ad371f10ba0fad8dfc90cb51098ea4db9a9cb9c7119254455
22f6a4d85db65b96a6152f91a4ec362248d616b447b0d88b5337a11f1678d074
d6673db2f948fd32f460ebe5de509c2af95162c9596aab6c697ad5845d58dedc
3aa5e19779139f23f5037d6eb2a0aedda3bac217ab4b169292aab49fb5ca6ed5
ffda2685c42b4bd48c1123aac17d400a1889dd54c55ed8504189b97f92ec6dd3
9aab6aea261372b90e72142c61d87c901c9aeabbc4bc86585724fead407d3551
468904ea51359ac09933734002d509c5b11c20bb49f837fc83c9deadb65c77e9
66173f37521fa97140c314033968f9962dc1a2649775f5801debadc2edbd114b
d0fda3cc3a8318a931d495deda7eb00a5c8536801e21b2ccb96a152e2a1421f6
b4a0d8bc4a44e02cb1d8b00cef3b694748bc7982beced5c3866925652b9ec720
72fda487a32f4f8ba54cdaeca8d56e9a362f1fafcf4e497ea7de0e37a1985054
494397927b8ef19e0bfcf371a8ab4e6a003d7714d825149f5238d73ab1d38be3
1b9c1afc639486e6ae747ad18a914f2db599fea7bfe9ca3962feb1361ef32bb2
5d7de3b40a241db3fc84ffdc4d302e1d070b51e720e33ca846c5d4e271265eb3
8a4703d45eb622443f0c099145f351f5628c633b9351fa2c68371a2408217752
ebfbdb0f04b473097b6d97ff23fb4604002df92a82978242213b53fd0e3ce380
7c7c8218a5b93e7d603d19d85d3fdc0abb95e0c51f53025175fab73d74265bfe
dc39af9272da7820b46cf5123e59ae8bb7818f68e465243c333f3700a128e7bd
dffc29734907ef555b19161ffd01a90591be62934c48376b91fa679bbad39b11
ab43f04a2bee307b9013f21132660bc035efbbf98aed60810ac033c8995658fa
37c7661695b0b543af2a86a99f4d557a0160730c7e14316d2dc0de91c18a47ef
4faaf49a1e755b5dfa0714fcad91036672a632bf4c142a58a08a5d15d133452d
3f741ce51cfdb50447bae053f11cae5388a6b0ed7f6d53f76f3054697de268ba
0a6708a123382dbdf4bc1d48c6e88a323e8c609a47a5e735725f6af4768107c7
4ab503e553366be92748ec494674726d5071e383503349b6030b45c2b00d10c2
03ded050a4914b9ad49a10a4c6f8a17399191d6750f4da4120550df0f5a414db
479bbd2837b67db619c52354be98472ce4d7fefdb7b698030672c53966b9b06d
b031e70612b985a25585bfa19378ca53acdc6560dddd7524269b29ee00d53c55
412d8cb5137597f9697b34f91c6bdeb309b4e5ecb4830b1e66a18cbc4957dc24
318c682cf45773d2796ad932ca3c497c1c202c03647abaa8d7effc4c7157d9be
b19e8963ccd5d339264e33febaf4fd074a29594c85e2aa783e2c01002464b9ed
9aef4d62de8dabaf21c05ecb4378b0da30fb70c7fc6b479ea6fd232701c9c4cd
6643a134811feab5ded91030783f8cbc195c1a4672915a858719931623799614
4a431ecb4ca5ae503b77c780a570318ff2f50d4e3064016e8554b9b4654e7b23
c44e63e903c88d9b47e9f21d2c7ab06e5c2cce3b4036b7830e1de29635b81a95
0e6678ecca710f874ae70c7f4a44621cbab0df709718c6e270dcfd8663096917
04b8de3bab1142516badad8cf8df891e5102f913066b7dc1d8a7ff76ce922c95
8b12bb304747c7c2132fb7a2f7e97795a15160d548b675fd5b8fba5fe666317c
b61ec2af0c4653ff4ddd3480a3b4641e3a087a0ebc965557ab33d2ee36bf55e7
1bb04e9987a5acb22d26b92cede81c0a43391aaf1f373425a53658e3d5c88fed
fc4c72653d9a6265432322a2b58ab04f68756e0bfdf07a5db3c6ab6d56b68780
0b4bcfa0b9c7b2590aaa4fe6196d94e090de7ddfee23cd7a222b7b661176bfe6
5e2d4c751c9865ba9cd05ec66284857517a5f51e22f6abfc9bb8fd8bcddd986f
ef551d64eedb3ed910bb9c78125167448e95c9b282db76aa3220f0670f6068a0
0542a37003d77b4516e250e0e8082ff9558eee5ea6e2faaa04f962d5063d0763
699d4cd910756e1d0a1f4f7b046bae0bb5a48853d52e63778cfff1d5b63e099d
484089ad2e623da41a45ab8916070fc4bf2db769c2a0100f9884da1ac729b0e3
bf74bae385fb7624f5e48cf6c2a204dbf8663cfaf490b6c371a5cd515b8bce0d
65c72d7d87de6fca80d64feb26263f9cb022bfe60e41c99eeb3053e28570f890
b9b2d8d0bf0823db1bacfa2e07d91ce17cee30aed458ac1645eec33e4c8670e4
111d9aad428bf4e1e69b2f8855f33b3d9eb693a37a84349a1f2f405111417ec1
bcf495677f19c419920a05bddbca5e9945c1442bffa8d6f75aed898ef9635e48
e6306cb8ef10cd88d937a2e1ec18663a32f7b5ad2c7fee10bc833320751d094d
9c0a610aa270c031945e5f850231885db82f81ab20322adec8f778cafd929ade
c0caa31bb1df69544cdbeef76f38bc76823f5b4a05331452331ca301ee8bfbd6
07c4460f74b4d9954203c2875a4e24504a1fd64d2f6d604c68e8d5df0c5bff35
f8a353cfb7de024b19eede9161cc8bb71ec4fb78d26d4e0d62b714e788754c92
b1733526859f1be5ac087a9d6fbcb073ff6966bd9320d4d1ecd8b71bc088a306
479c1149db8808b8fff65b737bb9ddf261f71b606bbaab48df805e74184c1014
f052e527c49a2a3c2009937065736cf4ed0555ec3589d0c3dbcc95e8cf795762
7f67bd9ef4c58ffbb81a345c1348d8102c60fe1db1eb5b7c8e31e70ff75fc4e3
49c22be8188a14c9bd42fe00fbb425ac5024e260f3be35acafc9b6342b4a05d8
052e32ce6f7a9d1ded14bcaadf0ad5e0e96bc0ff6be13588679898055399653a
a4df60dda75a13432d7b895f8888eaf469b9df77af30cf7d71980c9059c2144a
0d4e6eeb1b8b2ae6f2295dcaa0079d1d1d32f4a3e3160c8471f23bf13a96f3d9
f1762cc2667fe9586a18ddbf8ae42d42f48fac7423af92e15dae9e5110d4923d
f576c7c68904f91b54a06d57ca5183ec36de21ac8d5e90eeaa47d561b10950a2
493ab80c74c5a3a12d76b400a3a09ea2c86dfd1baf7419760020b6f1a044c36d
77de52f09d26252bfc2058a3f4d69d9f0596bd76b3d8e7962fa171248d2cf5ca
3ed7f5fffc0f2e068e2988648a873d82118a639caed42389662147d4b652a8f1
a7e0b0909beaf7c7f6703d851e84dfa36dccf7aa910ae40961c9365cfaca4dc1
f8f3470a19b5dff9c763bb0853229ea3821837e9602ed96cfa8fe94d72af447d
93c0eb4788893c21dee174adbc75b96e5626ac5e5680d3b6cde1e8f1a4aaeb28
a369b46267e18d4d378a129014e899b59450634c049e114667ab5201fefb18b9
8e4ba304618d1e75416b45e45bfb23fd8497d3bb8e9f045652dca55cca4d914a
714596f6d425180daf5c5870de824891390f15361c43711c1035cc1187d7df0d
ccfbda67f4caf9a7df6a550c5c731708903c8c943122d8b1c65a674a5c89dc5c
661c3851569db886f0e25e104fdeddcdb8be714abc1530371ffa1dc6c1a91af9
0fb701be3f9b298ba679987129a94646036e562ade5aa1b8326f1813feb4f5b1
ee7dd98ea2578f8a0b1b892fd68fd7076b14ae1b29502623158bc45214ae6502
2c84e2fd67c1eff5f8cfc253371c3dd13b562ca8bc26d38be6990a3c329496b0
7449302d77883e1807bd19495df4f08f067c6862bda21d0f909c5a8482bc3db6
00c219609af6688846315e4ee35e4e50cc766341d7bdbf1e7c8f408394507dce
5776091c5b55cb4c6f62668e6622a1213cf45193851fbea0238418ed0fda4f2f
0647d4c9f1ca6a2e8a133d1747a50f464a0e7416a6bd1dfb29eae25f7ff08700
bce4fcb2ecd7c15680e0130c265710faf158e9028d171e907d46409f6ece77fa
94318ac24fd12b2685f4e162567ed451d1d54d7c44cb32733792030f55a26ec9
bb5177efef20b5ea513b2e7d4c8766eb4f2b75d26014e44c43bd37e5473faabc
686983e4fd6daa251992daf5dacee6f05c249cfcaf6e4648db1347f42bac7675
b1e47da665dbdb0d646c20ec5ccd50391c808cc21ec24838b0905365c9b9544d
848f870fe7c734d80223ecd7152b0d62e50ea638311a6500ac56117ddcb2a58b
4fa9a05dd707aae3131b9b6aa080fffc2d92581f94f9ba0280d8604644f93adf
d17a7a355c00a30f16216479a8b9befb482d2195f3073108b9349b23e6abb132
f5b5769f3ff565c7069cd08287d863cd3d01cf1610378c25aaefc2d346b565b9
52a3674d2c2086557a0dabf634dca3e8ef1492d713d348403f7bef9005fbd4db
3d234b3886beec3dae37c73897a3af4f56fa2c61cd3c6fb2376ea2b16587b3d2
58e279576e4020883290cc54328361679c2de7eb1f6a3196c7df4d2be123425d
1dbd21fd586ef1825aee2c5a8037c57f3f42fbf40ddbe0e7d45c21a692313546
bff8f4c77c6c64c2685a68404d8b8604bf02c316feec6ae48dd4d38013579d36
dbf220e1679e21fd7a4474a8acc0017ab3a4dd40e0a0a26f904e3fab24957c8d
ff1ab7b1cd9c94a24eb0344e4605fd0640db65cb5e9219e1217619dadd5a529d
d723dfe25423d34da1db539ff10141dadbae30b290af80b170208d4c6f7e85bd
438731d0da714550c86f9a66238558348c41f25c80949a5a9aca86ee7c2c0448
6476c751059670464fc59801746bd60ca45a7dc47a257e7aa722b5b979e33d4a
c8e85a13f2e77b319dff51a150a6b31041894b236b0cdbb736ac0039e3516634
d7d316f01db50191468c72b0d51d7cf5518d0922772ac9e28ddfffc84cfe6660
b65515ed8903a4567ff54791643141247f3f927e8bbff193211e48d1b82fe621
ae48486a66c74062950af53c8e10a2775e20652d9d4da447b1de56e1aa1e436e
64fb0bbbb0741ac2e477f3cef06d42292936ab334d1362120deef3515f92da8f
6ca75856ec2fd74e3f327bd791212845a9c27e4cfe3c76c97f952dc8ac8fa543
c564e5feb237b5dada51c5316f23e50c94cb1948aaedaa4043f56eb21d683a4e
5e2e259d0926211edacf72ba715467566ef873faf4a4ace6a6ad214186f17f24
300af6b5ca007b2fa0cf4af0efda048feab029d5f6c074278b11b829e634be71
ecdd9c93d23cc0ab5995e1db629d8cea52291f29961e4f3e420bd915ab7188ff
bce3adb178a055caa667358a3c1f3e9633f56fb6dae2dfdcf16b13b03a285edd
56516373650397846ec97e4fcef493e6747efb52bb0a1d57e2935f7e6c91b60f
b49864a6ad194f4deccca781a58e8d02295292107ccaf52ff877806442197a00
b785df52ca811c265ca88dd2c0b5fdbc026aeac6f0efac9492933e1e6f7e6313
11521458871b0c8bd74a9b2430c75de0fa6f4a72c396dcb08b4f9b2a4ae79405
96202e9ffd4f0c62762fd19ba0526d38d3656d8b2ce116d79199f18e89c8e17d
720333e6f4c21b48d3c8808ff9311bb2c24435f88f91bf13707371c1d2ff0682
8b2e0838d6a0406f1fbdf5f2f26f3541f1d517099dc63442d9abda0b9690c4e3
d619f7e14aafac9ba93c9b8c6e41cb485512582c05b3fdc528d1ff75c8bc9eaa
5d30041f802ceef28a858fff38b6edd0ee20738d9c5caa4bb8fbe37ea64b9391
ecf0fdbea693a0aa7ba7d672d4c1ab8827da50a962523cb808e047bf88aa991a
0342499b5773da94e329e4c4679066a508d95421bb1229c88a89cea38e76e437
1c045b266ff717ba9fe57be4192208a4c3198ed676f5dbcfe4d29092f07618d2
a89a74ff5e642986325ec053d3409a21ec59eccfbe9b816cce4299ce50dfba33
e77c46d286ce4cd9c5075cda5a183f45fc1fb15b0ad48d78f50dd9a49b812300
3745450b544c60cfea88234888b9b7859f9d7aa69a5ce5576836a4b9cb6f342e
1dd3a08cb7773da9bc55d79f4e561591191c38675f11dcbe200eef4e11b78d50
9ce8f678ed9acbd91408475cea9bfecf62cc5e050ae67acedcc81d7540e6914b
16e513a24a3e300066b22d0d4b1c7fdfd2b0cbf0378e12c47026604a3be4088e
fd5cd6c7d98d69567b67d0857770100114f36997cdae9cee2ced4d3b908210de
7110737450d7efa27b19e916a7b2d64ade8f14faf772168df2a43a61efe7599c
4eb7ee0f09659451f83daa632e68cf2a8dd784c4139be585a22a98f4ef874806
cfa512c331660049a8df0d9bbc21836be2e9b84fbc6d05a7926d1a05fdb24364
c53dc148bfec95a9abbda39792407ea9528362fd70a0a2943cb5cd37d3f94d4b
7e09f8b7862dc40e95dcc8cb81c3cd8aa3ad612bbf800a23a43adf5896fd8a90
1250a4e2c5de230221874330b0dfc3a0d660b1402ee393f121190db0cd1a2077
8c9b95513e4632c3b05df34127f9de68bbef1552a08565f2df5c41dd996cd150
c848f208148f4777479529a85a2b6b4895d7eb3f6787bcc15fac4408ca3d9b91
99e3eeb26e6b50b3b2d2a3af123fbe07825ad3473eff3ff7b1feeec9e3147955
77ad0820bb4dc86e8a76e591e8d9fd1b3b1b47ce4d335e7d342124b5016879aa
508215c9b660518c4ebc1dfa3f18fca7b9adcdf1d79d55fbb989af977ff00685
32dea55a4fddc0c182fc059ee8af8b78eeea35103c1bf8ef14185e8c10a3995f
94a4d8155eec6888d07d436a9e3b721fe5e7d83c52de9d48243ce2768b06545f
e265d74bb9af45696d3c452a59118b9637581ad70805861c2ccf1f5ff86eccc1
b14107ad6281277ad8fb61e2f17edc05aa690ea00c32528f1e6e9cea4a89dbdd
8868f4894987e574214fc356f2d24b7129ca5537abc8c2b536d1ee499e2bb801
f0c56faa7d4f775985aff51f9c705d9170d21fc23efbd74bb048ba0c08e65c04
ee0553402d15db5b11edfb9771b4e40e881098c79afee3c6b5d1ff53dcb43f1d
8b8153bffc480ba302a5bc30c812fba64d4fdb94a775cfc11d750b8b9e9aec20
567ade427c2ee6c4dc4719d3d03770410d5b61a4fc4ac93706c719c8dcc7a6c7
5b000d0307bd348f51d67d07a0ee7a2a0e5005d5fe3ad652bfd8de6be1ccc33f
968f3f6d88dcd6f46fa85b0bb7702e5cf75dd424727768f72d99cab6d670fd3b
cb54de71a9ea8d54b49b76779f47da59cc296b425ecf8a1838900ff9c32abd2b
c7d35bd9b3bc1a6f4e815425621776ba5c16492598828bf88ef4ff6c03e2d7ad
a4ad4cacbe15924e0ebaa2bc101c1c19a159490b5a904e8c1d948ade2ccae05a
b25e28d1a0c3d37cab4db8af511cc66316a1d6471a1f3986ced6dd4fdaf64193
9a603d5711821582f9239293f71bc5f73443672f32f0e714f2bbcccc57821a0d
d0da7ef0030968001abd0d89fb8b3bb476b393faad0d45e604cc9555ba960905
906dd2a13b82548d7da8ac41c5d972c7bf201173c2fb9f02c50bc149e415f460
b606140da19b276efe8a073b8e02675b888c2277172bc4b681eeb6398349638f
34250ef32d43e43ee94a657288c5045266543316ddf5366c5f99107e1c2bb25f
61e98080f2576b0bc7b94ae82dc9c0312925d703d9a657451e362b4aab7c6015
123358de0bb74a7c750bf82dbd9cc3d93854dd44c823e764bb658afb7e7337b9
0eb964b7f0f043be81791419eaa11228810fdb1fbd8b952f4d445818946efacb
79f6e376e06336e65460b44b46fa559a08d8eb9895d8ce425cab57b96b7b063f
a2d0b5009ff269723e211e912fb50856141e012ed8d484610c216fd21208a87f
24cd7db55503556166d810114dfe326e26fb37bd789ba66fc7d194ec2dc34863
011d7f0948e70d7ad083b7fcf38cb3a19e8e3690b16db1cd3051db92da40355e
528b267f1cc2a5494c6e40590ad87e3cc085a1ec6befb2e00b1a909a241f6ddd
2f44660026c902c5ebacfcc5e88e4e3995bea4f18e5370aa7a615b154bbe3893
4a06b0b84b4844a54e13401a94fb831e2d7dd3ee57d250939a3c2c853f061b91
df0aa7375541eb5ced37556c9bfb417e07ebbb793a04697c055554862043e2e8
6619f0cf8f1662a302b7fec9747a938c69922cea1a7cb3843f5ea42d0a99a7d4
28ab21612f829682dabd5da82b45f830237784d4aed9a9216a14df863d291632
e1d7647a47ae29ff71e4b19ef41623e5e9b2203a74ca8aa2869bd105d11aee9e
3a4c858bcc07953f264ccede8465d859855a092c6dc59f3655b2c58998112ada
66ddb373a97abbfa7f87ec8d1bb7cea1ce98be5801ba9bddbe7fde75e3ae8654
12f78e032318140df704835b2991aa8916c60d72417c49c230da809efff2feb9
7e607cf2907108d829b61c0ee7c34c441fbe5b71ab1e6392cb5d117ab3cb78e5
53e2aabb9be130f123ee6d47ec3eba16aec321562bbef9152be9d53d4ee92a17
e355d5ceb828a26337b7c248b54508a7da5b2606d95299679517b7ffa1b57954
b1364ffbc50837112b8b6f97415779d8856331a97b2e424ef5c9be10f765aa21
fc107139ff93825e8a398c521ba5cbba3be900973862e520943a9d189edb863e
1fa6548ddd54b5bd1851142eac653b9331435db0300ed34d2d1cac68f73f9216
1c1d287769faf5339d0779dbed1782a67796dc6204d7dd5be756dc809ff5ff86
2865ed02fc1722730bd49659e71a1251d1aefcb903b0cf2b4ac2455d119e5cb5
9df7afca6049021ecf0db9ff7b8abcc267b217455a7f011b92b9a247dd7c5b0d
5ebccb22c620faa0b5e6ab4160a00c7b8fdad846d503f874257628a319b54d16
44aa00bf5a354d57b9862a2486372e054bea634698e2adac53676c8115592697
75325ea9813a27a45b0813b879bc00213752c2d87b0a01257105adb3e64e0881
f2f03f8dde33f1fbcb420bd3e3fbe02896d847c1ae53ad2ef67de52163461db7
a30cb056e02de8cff68f39e9d1c8cc7c6e09b59a54dd5880eaa5f8b3a99dfd53
9111a5d6f4714ce8d86c77a46953ed203bb02b7d9bbeb25af1a0cd7d9a7cb853
4483fcc871ff84afb9211685c6af7732f9ff24bbc031ab686ba4f11bd599bb06
a6dfb2d6ec2256fa44f2e34d79b351087fac5efd9a050f8aa1b838c8ed8df89f
6e4878e94d7674632802e21cda3cf9ae30c5626751d0ae7714c2c237d5b55b3a
baa29cd0504ffaa1d082967fedc72bf5ab897dc4bd5ac7a06ef5fae7cb115719
9641aa758ce48c1b9c94e935c2f5708c6bca8822d593309505553bb55af5c384
beefeb25f11883ca8d73c8d7b1debfbca550f47db195e07a76a3f2c8e7ec060d
4fc410bda47eea85c4bdda99541c831912174377d92a1fcbb63d157fc9ea86a3
e05c89fee9cba13bba34dfbbefd3f958d41585c6a6c346a0faec891b05e61ad5
1ece428173a78a37c94e281af691526d886f8b3a03bf59e197a65c685de5429f
d8437670798a8bebcbd2b813d4d0c212f21c1aaeb6f442d7253535c6bc458142
56b6df1c129e94af20a8ca931f62a9a151ce30786a7e47ef2178af4c0ec799c5
902f9b2fa74e3233da8e5d3d1db86bf1aad0993851fd47b58cbdb718875eb7d7
8aba0b4059d0626a2f05a92aea489836029e79467d18e11547ae982fdf93bc8e
a7cf8cd469715ea7127235f094e1ef4efe6e5727be359444a4e05e1f1f119751
f7ccc6e1bb40b866f4c7f28a4f41712253bb1b43a815f87408caafb52e454c48
66603f69048cdf6781407ecb828fa9a6f5ec1de7499645c565c998dbd705af95
f22e975ad1f82f46efd87329aea05bbfff5b46e08a8f3695f60964313bd1f709
a05a5758aa31489acc139bae691ce0637a3524a495bd6c100c375855fa1c2ac4
b1afda6b64ecf9c2d763d9cf21fd00569722056ec992a02eae51ab872925bb04
d7050e886d1e59c059fc55e984500ba2ab0634150be8b9539e59a7a1e75dac38
09f08965e88d8ac61f8d7e0b57ea410e0df10d073cb439298ca17938cc004064
525de8e368d9952a9503b2df8fa881c0d7a431f9fdd3fc76d863269ecc4b65b9
678a48ea0d22578b84a9d10c1fd63223c41697ee48163013c9a5cef4e957fe42
21395769e4d4bd6397ecfe17c8002bb0c50d1fc95daa8c298dfa7cb4be82acc5
6deff1af231d9e583cc8b2bb84f37864aaae63c386eeded813eb5ec8e9c262e0
fb4e312c030139ce1fadf54bf353cdfa29c70c894cf75c48d99897deb4ac41b3
c360acbd433e5c8dc9d935554de910872a9886d7dcfc40cf8710bca13710fcd0
f8d7785c8a98244f5511c1c91fe42b3463e1ef2aaa8507f0eb7aa8af75867f80
fa65d5bee6267c790255b760ab9d4396a2518890a1e37656ffdb80ddd78923ac
3c03021f9acbb5430e58d7d40c93f92abd38d329bb2ec6c07d380cf92c9f1e17
090f83aaf8542c9804fdf684fdf5b39bfebf55f7ecc6b28cd23f179304203597
0ca9f09ba26a91c27827bd8f6cc2d568d8634701aafcc6b98397fac0c44c05b9
4cc55bfdf586edf10263a96944786f1aeb595031e1b5ee3fcb42d121dfb8aae1
280a5ce2404db4df357c206c781e9a72b543c5e1381132b2dc158a9e175728ca
c8e077b3fc9840cbd57157c66fc671688eade6cb92488cda7aad7d8dab7042d3
32994343cd234301b3bdb3ec297bddd5365829b4f02b97f6c59703b5bf29dd1f
594e442a6ee72e766d2489c23d0086c55ce615aff02a81e11a1d2772479c6387
6134b2db3d702773c8583508d9003913f75770da6346efa6e3cb6689a06ffab9
2944e439aead778f08f2a6ae80b10ddf45280ce9087ce1b129a45abc37571d0f
d8c6ce5bdcbafe1aaea62e8f1fc7d7529f6be0f4545ef523a41403467cedd9e6
5aaa335f8dc44f02fb549874c4f0632f46646037cb3e2103879d51541b8289ce
832ccf7cfb0103867c6226e07f3df5430ae532485eb328b20d614b42c5155174
3ec2ac3671860829406853de0c7dc5793a8893307336c138f06c7e35f10f0974
bf74b95c7e9768479ce19abbe65b427a801ee78e39503582b10386fe4c34f8ab
a710802b6e17783a07b0c7d3bc65d817b4c222ffc9aed0375ad01d70e25fbd15
5001e1a4a4ae309b5d8283ef14135e21da67e318e8a17b4c86a62b38b519f990
fd444e02dbd467fa3cb53f2c785a10f0a3411dcf6caf9bc9feb77e2b6048c53f
aa7f100bc227d6a258f35b17144cb79d18d598df03878d41773c5c150c0f7e8a
7a7d25fd25aaa1387fac6f32ac1958dc1873645c8d76bd8285e47a78eff5428f
5eb2ed04005e86781f76e037e9b447dca3c2f88759a8b40258c5ff3aefb99fbd
a6ac45d4f0e70b2d6c976b779a238063e5bb0727ee67d2d22b9f62f077766442
7c79089b07b48066c8badd9c5a8aa33b87283dec68d38f28402b0ed042a896f6
4f0c08e88dbb07b5233ca3985c980a4a1b9ba2264516970e6ee0c6ec14143250
48c3efb5b2fd4cf933126b141eff1917148ea168c3b49d97115f05bed563bcae
243a2ebf2bef57c637ad3f307c9fc05123fbc067b05ad78a373c6facee9bce09
73912f44cbb8f07b9b36bfbd28b50a66f2f41c34d8fb083bc051699af672ccac
8eb3ccb3783c796c7d234bf80e9c8d546133653f10cbf1cc81bd490d2ed49e0b
e6ed0e9726011276601be60e1ef3717b29dc6777a08af7a6537543bc2636484c
036f4a617cdddfb1e2056d54406d79a0e42604c9ddac8b820b612750b5e6502d
0fa481fe0a217a5cc904dfacbc8057d5cecc50d8d996a98636b63e2f49480fbc
2a00c16026f79322abc9a1b31184c8b657acfa8c0c678edff17058bfc3640898
fe0ce2640ad5fd786f2cbe51be8609ccb16b3d63b4ddbb44a62b6086909a03f9
fa2fd0b1cfdae0e0669605ec4014be1f11194451f2f5b8b977cb7d019e8af76f
ca8345487f4b854c1dfb8a348da88e2d8b378a37ce02d3ce00e3ee1ec9091cbe
b64be42bd160a30ed0628774784889dbd28b6a00b1ae7b184cea19523821004c
6a5d3200d7b3f41ed681a46611ba1c600fea01af1aec9d5355a9ef16949d0757
f1f910c5aee2ff63fde359c1096704bf934659cbaae913ebe00959dd1d396a40
16982eb3b28720b1e4a43624279a91833e0bbbffbc7ecfe56dae153070dfa724
7ad91b0d8efc16d2192cf9a588d7e8179c6a1f814a13bb16d51bb2d23d3d5616
fa984ddafda3f61b750022f764bfcccdb7d7ec604187042c121446894e2e1802
01f8d83c21fc2ebd6d51a7a7d3140d8881fde282af96d942268714d7f091209d
031441dda64ed06be5fabe5620f4df06c137417835e8f2de86a624144ec53255
2252f87ba824641a06c7ad160d32fbd9de4330edf56a7209d42f7fb32299432e
176e1a84569ec9e953138ec8f1fe17d1f887d6e33158825b3a404e2721661469
bf86b4d187fe23c40407c80e815b3bfc8f7ab8585bca4db702bbdccec5899a06
1a1fca5228a6bcbfb814b0754a3313863a57e0ba74d431c335076e30b6c51565
45b011af98d92b3dd9dcd5ae9b776de77ab4ae5e6269a771f3f6d8de0fd86469
737d1eac1bed0aedda6281f2625ca45f63668cbc77754e9da1f2ab2740dc2af8
42dbbb5a3c302e7f62c1eecb9ff3900ce198d8063ed440a36c9c495ddf66c790
c15fa67aba99d790897c3bc90dde8d4aedc9c958c5f708fa1e25e4d5ff49acef
3cb56fd2ea40b382766c1f6f1ac9b549366f19108f7a92c90bc3f99b72e2eb3d
0a3faf1ce577ee026695261f8d481823987bad1a882f2391156300ed24f1dfc1
7741ba8995ef8bc3c796ed3fce2e1c54132796714977635f7d0bc80032dfad65
bd8a3fcb7407bd8c6551098fede9df9546c8b00e6904efb4e059b15dfb5a837b
23d5e8e21279279008956b15d627a8feef548abeb3425a58c2253270dcd64981
ba86a2ac78dfe6a40841b4097760a8d7d081fad8ea5b75439642b3c906ede5e0
c9efcbe14595986379db073716ced21999eb238222c49a87cc5964cee69eba6f
8557f49178f3c38b1d76133e74dfd7d08e670014d3988c9408dcf6d491c6f6e9
d93de46ab4c83b8ac550fb01bdf3379ba75e84e0b41820c708f0a7a225bf891d
bb41ce43cdf45821bdf45e0a88bedffb9d83996c254987503e388a695dac9cc1
9f383b2d08e4eadcd173865c874ef8dd86fb64e23143e1917ab3daf1ea308300
5b949045a0db875a96f1f4c57feb2541c3d22dec95cc0e2d026790c48c2d06ac
cc356845b200883043eddb7ede1c367f144a84abd3bcb152e0471eb03a782f3f
37ff33814ce1aed9ad5fac26a7c94765333daa50846789fea4fee91094359cb0
414bcb286e67fb9ccf2dfd4562267d193b261f69fd970e1f4bfbdcf34a664aca
0a4a609acbb334aa1ede8a44fb97dfc0fd439cebe088c5eaac3044add9829472
f3af2472c053485952a14f31b6bb879ee2f3e607468a89c5c727c748d79811d2
5f0c78b3cfb9d8f88becdc2fb59266a15d285b3ff9460424d8bf015670c00a74
e73c85be8eba62e325c9af6a9d5ee40cd84286ddfbbd4e93e88d8ed066159ce8
dbfec98f73064f591d4ce10537e87d09cb88839e982d6dfcf9290c8d99e17c9b
59dffc24a168e59c62fdb011883c490971ea8596865f8473e7ff32fa00707ef3
15798c1f2477edff74438e141c526c6c8ed74ea072b946a6cd3b17d406a84077
64b2682e6ab0a7279618b09b69e7d871acf9441130ee7bc1e50de66e3a7fd47b
111d22699279a7f6e2c696047c066ad775edb510432986393280e8650097c602
39bda8f1dbff38f6dfe07a9412e6081077c8628f99f46215f118496e191a77d1
e6b09655e2b61629ad39edf89232b3b664a600ba2460d6a17e8ad349053a570a
bb79e56e98e2265b5eb0b831782d865d651809bd53c7143cab2c5939b5e0d962
e42a7b4b4e6c7a525e94607be742dd9fe32cd309d3d973f591589136a3395a13
e7c4ce650cac5added87c2e8efd49c739d67601f6f26a3a7181c677eea31716d
39cb9fa4600e8ed9d8d5b60d7b1ffcf442b96f715cac0268b22d5df5fe3f07c2
7c2c2d184782ec28e60e3229a9c9730d09ad63a299c58e9caf266530da4f2cd7
6fa4e2f22035b90328afa3231d8cefa85a71b6066fc668d571e21009a8c05a4c
848fc42d455955ccb1b61f5a74905a9abfa8cfcf2d60fba2f6f0f9c5bbdcd4b3
589c9c2797c0a99a367fb2ba933be22ec8888bdd1831d91ed74c9e092834679d
e36a6a0d67ee60a8ab21306d564c15623f63671d1ee1326a244364658ee4460e
c1be3c7c50945e4cdfcd1822c80002f6cb0f5e9837bd5dfa560c3a4936801d30
960c095e99129d0b917add7bf7aff7b14d81588e4b8705ce6dc457afbad7ef10
9f76ed67de4ee7e8f0b3e588a8c849a4d9f0b178f9e351e12cda855d9de197b7
888a1c6676fa4dc706441bb6b6f3179eb436856d883cd5153430c624fc384e3e
0e026e593d75c0663fbada14d42738f7ad0cebb32e5d06a4d4c104180e64c4f8
edf59835f8d6dbd0c892fcec5a07015b37483bc2d6f0329e7fb67352c8425283
080be0f2f777405d67a7d9a9d1b611acdf18eaee5e334f98d7c2f7a684a7a6c5
c75a7478b65fa88b489664a3c03eff62fe7be199c34c81d9c6c5312b4bc7940f
b5a6500b40ab7b071e674460bbaa86fdc1d7ca4fc545b61106ca7b9ff1176ad4
e9d3cb2cd1b0a908f128f3250595a99d635538e92309d6f05aaa4cf041e27be8
8567429bd438de820e9fc13a4d3d8903f591ed6d0f7655f60e61a813949f4396
1468b53caae6cf1f20c23f1571e3ced4067a39b1757ccb9530ca7b2dde34c7c7
c39119a867f3864c8eda460ab5b71145a317d75f0d93ccbdfeb25268f9a16e34
8cf2973d945b47318be0ddae926fa41caa869df627b24a39269952a1d37364df
5c4f0348168fe7cc8765991f5d85ac6640d0a365b5b3d031d13d5178157a4c8a
19e031cdcd77d94c42a88ef96a8527c3ceeaa672bf44b9e9d5dd3d4e8990162e
231578d0579ce4b6aeaaa40067eb79d1d0101d4f96fa9f54665ce0171e1ec2c6
57fac4ef208302b304a3f6599bcda1ff2138b8354151853323acd72a0fbed456
7bc621607043d78488e8020ae16dfd9aefaee27de2d8cca2b25dcd854cc0795c
d7da4bca466d0e788a681a629af9629e06eab04b21872fcda50c36b991095999
deb1e94fe7bdfb255ba2b8ba51fc039012f9d01ce9cd094981911b9b78eac667
0854dddc30f12786a5e775fa5e89f7f676556c8f90c3a6c7bf4694aff1a64b56
c69a7df8afbe9ec27feaa51d2dcc5f7fd7d5717f371f703943e882b64be3cafb
1ef76235174c9604034fe4e47b542e3400e3d69efa6cec534412bd69949dce99
0ce200bfced2ca934f2cabc7453652e9643f70b43127e3601d7fe676f2d68b21
c3b90bfb8352a82a4302eecf2842d66f87445c21a72ffb7d1d4f900f3aebd6b3
7501e921d807d3af404b6fe06b5fcf500ea00ecfaef42debd4f10b4564f43815
379dcdc3238e7acc492bbd9ed0f4fb5f129f9a70fcde2d39f2854628a6f77503
195747f25c84b2f4eb32f4e4b023ba6cdc713cfa064a6f2706fb08ad84c78104
e33458a43b4d2dd11e101e30ab929351de0b5f082d25ae4c16a505160592b35c
0966a02d1212a1baebfa3465e8ab99d4f532b5042f3506e10df981104c5c555d
0b11fb23bb898d7715253e829e65942fc232d7dfe9e4841d1fbcd10f32343586
f196a2020bac9d0466477d0c988e56cdcb0b3c3759552c6189891c1d6f82a15b
ed5f9ef43f5e279417b4f8e30d489f8718c359afc5215ee3986bb059a764c571
4c1284543819437e8f82ad88acf7a22e4eb9c8c335bdcb152cc4bab3682593ea
c57de822198d184d2e73001b9376f461f73d4aa45a91a4984c2b3497d14d577f
94918a4e9788b3018ab694678fe2d0473f3c22732b284379a1d25b9978d62948
276b05cbb6dec14153fa2904a6a02472c198f6f394f2b626d9f2d60774a7032b
9df70dac99a90c29abd0086c8055e0ba2a7c0eef7d6879fdc804ceec2e74d366
8b00ff8803ef289e885d724886938767ec98fa11e8e1d65b6d3521ef13539cf9
7b6dabd5b58160e8032d30b2157fc07077e59d3701a225024287386ccd7f0d8a
b119c347dfd88891fc57d1cb2255d4cad260b4b7075f0d5411111c1a6fc5120c
531534552aae7e4f12ab22168a9f7074641f1c415a208f4c69cebd28372bd534
758387fb13c146096fb8f293d561797281371cc6c4d2b3b0e7f8c3720c316560
da1eda491041bb8e750db50d672eb1ee5858498bd4a0ac2f781f19423c291a3e
bd78f49390f458036503c171361533203573cc5401b3b7481e908dca515f1d49
248c896f744b118517c21916f30ed6e2de85a41d5f32ccf89d40829731f55d8d
887b1d1d0307453566a02dcfb8b636fee9ec2a58e374288d026ff319e267486e
dcc4de250c84eb7c46516eaca495d6604572539232ba911ab2334569efbe655d
a81f12d2c59c648e29d1b92b41922175fd970699c0e413ece527f7c96da6d6a2
6a7d1cb9b8c1bc0533ee75398878f5be562a7311646c2646023440f4061f03a1
4dde777aaa78b7aaa468e9c57436852b0f78a82e4b67d46a701e655886c8052c
244b06548f82895180e985912d59425eb430e90f8fbe1cc8a4d98e57ef2c0603
fcbb9d39934dacb4fd551e13738989159e50c3121905692b57daadc02d8806e3
a629cb2fd2b3d23a5fc0b4b5d65525b3f95563a1adedf18077e5f93afe4c2e4b
f85dc0ed19e5c6ce8094b7e290ea04720a2750c5a9a34d5d0920b131ccc0bc97
7455c8b70125caa21d923cea788fff2dd4fc0870706314d7da1124d27aa5e094
976d9dc900afab8780b807fed9c6fb6266c93006c79ee11d2ac35f4184773b8d
a6e4f57c0f185d97520d57f0704d33db702dbdf29b2fd14925b3a926cda71aab
63684f9ee0cf221719d5d692d73c2f40bd59d3d89c5a1bfb923bffe78d84f371
d51827aa8e29334358508c1855699c88c3d025f34c32a44014206b77cbbb3ed9
8ff850f4cb967ef6b5ac621a35ff2e5db2260bbb0c0e70c1b583831987cb0439
e45f05962eadbde9147a9f9d79a90ec071d82e0c1badf01aacd2a3c569de993e
45c1fd2d4214a27b154d6d6c51df3c6d93aa49fe11aaed3204a79b7a1dd3ee4b
6cea9a9b75ee89cf6f11de5d7dd5b66f11fe4f016b29cc080171a852a87fd61c
d0a429466cd97d73de992b953204292edce561f6a7bb7cb2f27d9617fb5f3f58
435ad3b21cac4a431f1d830b379c5e4cdd25b9a85edb7ce521ea8f750d8cacf8
7e6b4b115d0aa733666521e7570c001c9e4b8d5889f3f491262b620badd76d31
c93ba80379448e6c100c924e4b22e105a11a8dd7f96bb74f02137823f6510527
765e7d45fe2d7f551d4cbaf5c520d0b785c7a1bda4f190bb242d2d8145e3967b
c78ae2dbb32e0b246271ad2054f2ecc22bf81b0c4a1089e0d165b91bf2920824
7ce707b6c5667e04ff374748a7c411b7c9170858dc4dca610f0546f5fead4512
4d4131f9038da305445d1712686fbca849d9934196a566839cff5c9ef7dc2aed
de5d399315d2d2787fbaf3053fd89cc4dec93742e5322f7cf7e683725e2e675d
198b4cf9a79209398692368a41fafbff11e97fec3ef5cde96a17d143fe037fb0
e7acf890654c1ee1740d5308c5d8a7351f1e061390522686f02cba3ac5da21dd
c36c20916ee8cb94a7d0e9aeadaf19bb45b74d3011d6777e48330899f6b239cd
cf29dfa3a98a56f7732f81a8bfee34267b126baa260d3bef9335904fca37500e
9544ef485b636ea31a376f647ef8b47506c3b3fd89dc6649d85daf2b2cc5e82e
ede4cd070b41c960c79a5e6e333ba89c75e3d35c83a9d67a2413630c8a3a2486
3e1a17e6a04ba85d400a41ad3bb645337e4ff05fc2cd6465a743f93a38cf3637
bf4bdbbd2524cf695087f225bc45062be0ba88def29e1dbee0e84338ccb9ee85
1ef07c0a97e37dbd73a0116a9bcaa53b867289c28a88f49ab7fb57a8393dd339
0749ab0e23173dd0e49253a884c037b64c9854d3712a3d694da32ea385b51c2c
4047f1f360a6a584a93beea5a1b8d63a7baec122d83cb44d87454f834e450210
41dbb83f7ddca07b2bc01627f19482fc9b8ec08bfc031321fddc48bd8b3dc203
403f9c751fc513587471419f06447432d05bb6f019f566a01f248b2fa1cce374
77db49aab7f562150c66abd8afb5f9f5de587cbcb037566c5c7803b23897bbc0
aa7f37bbdce4512e60aefb939a5ee85b981fd936e92a0c0d25453118928f9b35
9f1efdefb5d61a2fc2006564fe53dad086d60cf6c575019a9c245744af393083
ae7c9bd6b9c45e76a876d71da3ae4587a00948a58f8b55356a13d1be2aea9a3b
9d87cb8afa90c940266cb92318089747c1527513ec662eabe9fb6a0fae364df2
fc8597f3bf3015c600c3a5bfc5cdc72d44e040e46443ac9435460ca38dd9d2e2
62063c3d4ec431dc83521a4c57bd08bffb02926d5a26e1fc3c2f7ce457044b52
38e7385760e5091c6d118cb7f874d04836acb3da6a876bae79502714a94cec17
79d44af5fd7a0da2c35cee6f5c7b45f977935de6cb5eaf1c8500216f07e24378
0b3ae2d0d555a8285831ad835d31ac9e572304711e015c70965a9dd7d84e6b1a
c07651733a370a892a7ae25ed238a776368bbf56f6ef720a1310bdead4879b4f
0827f18ce33012d3f08f3f24da49cd4fc8f1fe4cccc31838843f634a95eaa283
d97d73fbfefe87904299146c40ec3e0cdf4d98edbc0857751d94e748d892dc23
4d26d513c79f718c92b63800487d46b6e212c56328dc0e5912a44683e034adfb
ad65505a9932365c2ae70a28aa6703c2b79bb79cc92cf3fcc5a4817ebaa03e20
fc1f7e0dae03f959278227a3d31a1e505ae5e1b902c61623cf6e42e617bea820
2154c81a5bf08cb887da9998332849ea2ba8ab7e8c4826364f55f8911e9c33e5
71e6acceffe23a9124ca88404365fb0da39ac681378a79fc6f13c46e9c52f20b
fb47abe7544b635474bf0e6e6449b44b4ee83bab16ae53add3dc7a1f828f00db
0b8154c112c8aaa92f41c4a87fa4a25daa499127391cd0fb8c9e0cc3a0884588
c5ff9aedce8ce521a66f9a43201862fb6123bf6139a18e49ab9ac5dee08dd6bf
3be8a1a42934fe63b8a1d657bbaaf243753f6567672f622e828b6849a7068882
761f07e502e206da110aca4f11f8519897b3cfb57132403706ef62330013f5c6
7a713a0c07abea8d274523c9024764bfb0b2bf27e139ca12d5997d6c9e01bba4
b2f74d7728608c65f97e820f64f8685aac5415c06c9fe1176e120eef1694255c
e5a5eb73a87876e8bf5d2c14e31e4b77f8fdd446d4bd4bfd3e87b073d6c566d0
8db6146a96d9024cf1a562616a5698063ef49a068000299df8a38bd319d44f09
ac7e38b22df4b5ee768d34512f5ea3dd42d32998ac209620c9183662e1e35177
fe9d264008d31715d342e682f7f856c21ecb1199c5f11ae311008886d6d0cf94
88f1741f90404a62be843529dad830cc3a6dd52eb374939d8a8710c142878dd5
958f16fb5359b7362533c60f2fa213d42d0b84531d44b4c64e86d3782bd58cb7
07c96cfb99f79253aef39526d74620a38d313d1b77adbe3d8df21fc95f0143ae
7264368e2383a61417da50dbace08ec23ff0506baa92b02e403229776d6fb085
31a8efd704eb995c4b97dad7f7bc339ffff4ee087d2bd1437563d3965a4fd368
ef528f29b673c25cb39e041245edcaf8a81bba9b9db147ca21828f0c617564a4
faf17774b41dcfd24042452f3610e7005b1462ab6c563e9e029b897723b21761
8f6f18c08a28017e8d95d131e86bc3ab2b65bf4553d51e8d609fde13ecbc68ac
a675140679d6e8e8f8c539784b426aa1a3f8d9536c542a9a7f1bbd9df6261558
b29d3d610c2fd6a3906adac42bed87188da37d4a5f42a5d78eb1faf492d979b1
b7c6d26369c047169dee81c800ebabe3941dcd8be020f8124d3aed7a8b10ea21
e857e38b373c295b5101b51ed82cc4a1d0842d05ee141431c06f468babe7b47a
700f95a6cb5124f0d7e78e66fc3b9de8931261ad192a748867f30d1e795780bf
d5b347d4c1ea5a63d86290393f6ded11fd6ea57b5ae03b1114895873c19faf50
4d0781056e2541885435ae803e5c4b29591a776e0b1b69bc40fc5afd7553f784
0ffdf3bb3dc5645635a430ca2121726462a56782506efc71cc8ac06ce083ee1c
64e7eed05604ef02b39e0e037c52c26d8d564385f2dffe449659a9799e573a54
85401f807b810f4c41df4b73ca08e28380a752958ed1022ce50a4e2d10c832dd
63ad551895a04e0393a74e8b04a8d276b3bab83e25eeffa8f1b86996a9f60b48
a877a995f0d8c3533599469000c8447987df300fe709e07ea069f028d7a4d1c5
d89bf51000a2745dc7c84781906d9ffcdae26bfc54bda2e0f0c1eb1fb3bed0ca
89d68862606594af3f400729a466f95cd3daff7ba79641b474286aa6ad475ca1
ad545c31811b9ccae716805eea430148e54e115b9cba66693f9cdb244bd5d6a6
4d986ce8e00043a197294b823f8f4700746ff361fd6f00c350a0c29b6dbdac03
308e7d9cb968aab45c1b1d4c39b2e84925dd7b6d379f0e2e52eefa2dbc04c567
6e0cf7ca1e381fe301887292591b8e868316f3fde98c41bb6adfc2391c2b8698
2b32cceda7303b7e269c9fef6d69f5976866e8dcc558a57ab65c8ceee295bed0
3cb59bb9051eb6cf04dc5545efcf27c52d21eabf669d584ad877f99a3f0a144e
94485653b7ccf2d037136108d4c7a2f865fde8ef2ed4b20aa8efb04e564380a9
1dedc559a7d071eac2c2d4dfb56b50f2686e97c51a27ea09acbd76a9f9cecaed
c16606593309065b44af936a77d2b15da030d6bf053de02a8bbaad2690480ada
d63b0d744ae12c971edeefdc7c73bfade214d7af4f32db23d5c9f391af796944
e613c8fb1e00df435f26c7a55c9805525da8403c1d62d651020c16b8756d5f38
22a6e17ab5a2cc0658ce5f3684142def7ed5cada03394cf4993a2833133496b0
b58fc97d80d1720cb8e01b95509f9421e89d9447ce78a239a1e00b4f4dbcf2b8
3551a756f01c8039efa834ef682147c4f51831d5bfd149a926ebc9ef8caa1613
1952f9a8ada0dec2b958293c460e6569380122d4ff96cd382f9990b1a9113d65
b31ce179f09a550691295947c6c4b8b5c5e0b2922a5fbaa7f5bd9683f5ab74d5
ac5cda8018f5706aa272e56e5053e0a3489abe29c793f95c55f71d440f387cfd
c94c04243273146bec5b3e987dc66e1ac847fac6046e8fb0790908d5cf34f3e7
998226c1b9259ea024ba2ba74b8dfb87637a0092cc262f7f528c94523f52683e
16f3cd4966ab8f9ce63475e663c9e893c0a542be720581ce7431bc5f708a435e
37807e5fc03ca21d9b868f4066167aa920eaf08a15ba99a37265bfa009cefadc
ee401175b8e99c631cb4d234c6e8b2052ec7428d3ffa7f3495885e4af33db138
a4d8e920c3c0afffaa954facd61c55c8b3b5f3e93766e914fad04f02fce81596
49325ada05a4c7b4d6841994c3b20a7b5bd37b7d0539958494d57a541b7c5993
2b167711741c2ec1a05bc856e8886b903af7f9f547c80438841f1719889bd2c3
55df0724c351f925ea2d1750b3408fc8fd3311f94c1f8678893f9c9e92798ceb
9985f9c82c070ec1267c0e0e13b0101f7995aad35a86a894928df48702e85e91
fa6d0168fc4c19153bbd69e2d52dd9f4bd9612c3811a23b1e5b9c0e5e0ce0e76
c3aeb9a3b33a335dc2f8b1203bcdaad16bd892736a4f0c5100173c525b73545f
dde2aa94eb9e9d95bf26d58b2c79685bbf35a2221da9ba113d46e42bf4979568
e10886bb40fb691f7c09bf0a4ab8941ad9c032e24e243f5b475c2ba4186c59d3
ad1518f0aab70f985760c0c79322dc30e57bf73654f6a3c963ffb758b484891f
1bfd9ab757718a967827256835e0c0096be7821efdce326dfc574100a7818458
b66394bc8253948c93fca74d6477babeadf3f157e1ccffdcc30bd2a199d1527c
8ebb6e9304b04034ad45236327be3e57e8bc91cec162a41eaeacdff6d0198e19
83557406425b5344e6e764e61752d3768cd4156fef17cf955f19907634cac0b6
061a9ce6676639a1fac580576219718cce7aeb3c673eecbd0774b84ef8bb67ce
7e40ab40f12dc56d5d06e03be46859249d699be0cd89ed90e5fafc9dba862c81
c3156765adb36a96a8de94a46fbe67601f4aec75bc9182621be8dc484c759502
0513ab193f1e8d4a5ca277d09f9eeee851ed3839da3a3a82b27da1a14f73115f
23aa185377a01ef1addd43f45c561dc40b7e97a4681c6738881d9abc51ddd5aa
aba8c6a9ea3f08846b78c7cb7ff4efac14a7b29d2fc774e02581eac971c03b5b
07125026c45b31b00c3b182c27ac97c3c55c2c4dacf709f848dbe8d92f764c30
9db919028e96247cc7a3ee59882610c96812f3bc7945949535a25f91a7c0606f
109a7250ce0a2a6addcb341da007a07ad06cb70dc5f93faa4141b7737bcecbf5
1cf79be4ca51d683da0c4776848e66948ffccbe296c169239be3eca2694b8838
aa77a28a76016d0cf845ba83bed7d7c432341c6b6966a338199eda5225065d4d
5111738723d7c50aa469f3bd7c6de3e14c14ced4faa534123bdcc05751704d8b
7ea0cad8f9ba4181d1039233d2a9bd4d14952458724b3d140a870af18b619881
80950e9fc264064b8b2c76db487d5c568100a74f9d6896b32775b39903144dd0
93f3fda9f2b715cb01e6fa87673e9bea2497cd87599a4436657908c97d904f85
9c99ea4a62f6c95f0f28c5497c7a1f2f1613159f55f1a27dd499494f8366e5fb
11fde2c7200987e9254f3ebcfa541b1648bd6bc56b23317bdea9b608805c3b4c
356ef495bc6638606093fbfd9e012e4896711a1d4806fd7e8f5fe5d57bd69c8d
2613134089d743aa37ffe93d0f6502ff9031290893a2a9338e8f743a53c4726d
bd47901c352d495a0691b19951592b2171fc4eddb29bc4ee8dab4d9401496a8b
ae33497dbce71bb16aed3da393673b3e0aff9fa8011d69628cd9d9d19c0d648f
3eec20ff3714ee302039b134c74e570af81240e75cd7b1fd1b41cc7bf5336728
bb30bb71e3d21dbeec757455f500d5853180a65742c58244da328ae9c0e9cde6
34b3dcd3a8f6f00565535967e343de022b120b8fadeae85993022fe7e25a4c42
1b176bbd1ca0e3bb38ca06e94f2aa5489ba238d8c32ea92ec415be3dd52999f8
d2b9ca9701d7672d29df29e739d30f9f13b19a578aa43e416f36a79de9ac1a32
57568b7d8af421e7545fd863ec22962efd30e060cc87f0ff82e1a4e53888cb43
6c6faefe04e2d41a539395298aa4d5ab68436a89485ff0e6a34ca5732268b5a4
36db9e5fd17c237ff7a4ee84d5cb06dead8d0e9eeb62a867f63299dd7dd919fa
807b7cda51541a80a70482e4fba12067fdebcd127c549a8e2f09bb98dfc8e337
8e7d1fd53b25513076ad8b1bfe6097cca071ec1a6c955061ca960f084a8913d1
6498ada1b42afafc68e96cec8bb42302099ba6f245f6a7258696fb6ce5bd41cb
8d5c8f0fec9c7f55b3a1fdfd086d39695f9d9a68a36ef50f530676965a4a2728
3ac309fc7796b2d5f265be3676ed4e954e665ca95895e858e42d9788f4df63d2
ecb015dca07fbf30ab8d47f24868dac9c0581fcb615cc25d07d8c37ea06767f8
a3408872145e07d320476096ec45595eadab8459a034754f54cef6ae6d1461ca
87cf4a664fa3c02056e11e7d388aaa2f4bff2d51eb9e36522d2f683ed9c1ae57
8412aaf5782ca9837ac92919ea05fb4fe84c2d90dc21b1e3a248b3972a7bf550
b2e93acb755c1f68bc44487669223b2f7b7eef5d43bc70ec83fe2e6297fbab3b
2a23baf4f9f6418b87ece32e292f5d8495713afa39a81dab0494fa5134acda3f
6a86f98231fa488e5ac9915433dc6246a155eb89b8b5299f72ee498b75fc1f3f
3f2f66cfd1718fd6d327a26636de809b74dcb3a6a7b9a9fafdad8b8cee167caf
279a56b14b1e4255035e21d71076a373ddfc5cd0290b2d9d3bcced439f357c14
7b80a69269c8f5f88e7b749ae42e3b6947c294c9123f008abe8b5820bcd59bec
f64f3bbed7a50880db951b54dda093027393a1b8ef8df7e59ebc9bbbcb47a9c0
f3ebf56a334474ffe591b5a683ed4183f96335b471e710fb5a38685c649ae13d
b1bcd3371a4d3ea9c8e5c1c4e243a96779297e924207da69e3dba58492912b31
bebafca228110a3db0d961af7088b6a075d194fb19976c8caa7e39698990ba02
1c2167e701d42305ee74e2a1074ade4ea7ff004fa1e681c23c3fb3834cb6783e
95496f8e9a90421587fe40046c9b9882243465da325d490a2f9f4bb2e6c532f5
d68a944e5c5bbec8cba73e6af8b66511a9ed9c06ea0ed3e9aa8d34aee50987db
c3c6ca72e5520bccf170f81543f27428cdb1bd7faabce8ce11f3a41e4f867f27
fa308a189394370f2fd7157082d53655901f45ede445dd111998733a8e5a7272
ed00f66fc246539998b76121cbbf9bcf47b4735b0078bbc739a6d29ddc5ce5aa
d54d12bed6076612678a628fd96e66030f82dc4262224355626b59cbcbc261cc
b520f125f3da85c1df2d559badd49bdb1d2cf850bf8624019564122a42202de6
08d393939a613eb547f48ee7fa082c7c1d956b3f3a545181277bce02b4dfb9ca
aa4705338ab973c306dfcd2b136bb8b2393bde2d12d2d9e82b099e1a8d17fa33
8783edf6faec2b9633298391228d1244b77c13def2a51f4c49b88fde5e1c42ea
37075da0aa8b1e11df201916fa558b41b13f25cfffffebfae9aacc74196d592b
62585e6444c3510fcc32bedf6c41e27e9bc00ec0bab5a8dea39e51189fc6bf02
f79a685c326be76777cc4afe42cc2303e64cf9db737aaca3b5011400935988c5
e920c0928c68195fe9706c50cf8cf3430ee5f94faebabbfcbf3b34fa55a769a8
1f45ed493152d36578129e519e68b5968807f96bc783eeb6bb0baaf3d13545ff
32bcfff817a373670568b72c4e37ed377be4d13e5f4dafc5a106997aa1626bce
a1b282914b766b5fade9410be7a7fa04814306438e142705c9329ab5d7902149
3340776404cb836cd6d3911a729e33ef7e3126745007279c8a8948fb9c2018fa
fa9b30c5c1a2f7f7f641ad954ff659e27f3cb857a04a947360d34ac84b02ca2e
ad5c756abd51c49f31acddc905e56a3553ffb307f12ad387f2d73db135ff6d94
a0000ffbfa09452f6998f2c4ae280c7934ef051de534a2c0581c46d96130eb4d
f5dab0a31d07bd7f2ad38961227ff9a76d12038ee6062def1c7c87527404204a
bcecee1d1fe39edead4594e443e8602ed96c66ad27ef5efc907b2bd5c0925e64
1283e89fb60fa56a1c7c35c68a820d38b0c0697d608bfb711f9c786f60b9f9b5
cb85e9fa200425c5597c7705e3a47e448cfb08724d83a3a861dadf6900279ce3
627790dbbb5d630c352c9f6a9b39e81275b460695a56fb71a41a317052eec4d9
4c6d1ee723d40d024c5fad104f845aa9fdd3516c887f360e90f86d583064e493
23f92aa181d8f0c2293c6ad9dd8d9a4e6a0e52283a90dcd5734ba0f395ddaa25
5a7770d7c41059d497f8674ababb47ca51d81a84ad418231ca24227a592cb055
2dc71077b4ad02bc6df20ae7db16e2f3df5891af68603dde953df260fb40f55c
7b1d72e236fd870ffc59ac3cec47931a77d75b73f68e238bb4b62de6814bb42a
f691b475e4730c26a779d29cfc1e7c595e2ae63308140eaeddc98ed3c9b708ba
edee8c7a076abf646da7d0d8a6d87a5f63a897a31b3b3e87b5ed9666b09952d1
eca9eab3ecc7bee5745cbfe6cc06db7cafed3e2adfe9ffc969f9d52dba321d5d
4408ecf8ec057c9e3898631701209e0cbc21d50a2fad0b2167c9035352ed2685
890c62b7d18760b8f7cd25812e895345f53baaf7db06f9623e4bebda1eedf6b5
d0418370a9da951b6f70f4a410ccef079ae4bb64f8ba28d0dce9efb55584a4f7
4f26e9f87c71304eb203a00dc13fbdf961e48447f21d2157fb9c632583f06f25
f7f85074a09bee313a368b159fefc0a344480a1878b37136d8ebff4d13830c99
635a3fa92ddd54f67db8d83137726db8001f2f3b67b05e5902f2880fd969f591
b4450cb4335430f38887c975b69e3fb02a50e04e0e988b76f5c0e96b4e3431ad
4ab14f969913dd0e771881fbb7c8926b40ce945b66db9b9d7bbf7ea3052198bc
9c9cf60ffd3ea4504c787bd04b69636d894c3d6110acb9dd478b5a51464ecae9
65416d7b56342d76117c344cc97b0a9c771a6c0659cc103cb4573f8324bd9cd2
a865cdf40d38919f7c5ac7092cd25dbff60a15d8989ba9b3345090b59db6e137
de7a45cc861b42bcb6dffa599158f21ee190ea950df02051ced7334d075533a4
2c53bcfa715e17222c3fc277ba4c242d418434a7ed2dcc69cf4cdeb28170c2f6
a12f18cc492c0ba0dc42c9e06447e905aaa3aa9a67fdd10d3be777cdf000e848
6a1ee3069c2133e2b149ae06f20c6a9a2744a8707d49d3acf2405a28f3029bf8
25e2861568dd957125a0117bb746f5cdee1e3c35f89b6650f160e0cd44c0437c
541b7d17f16763c0e22d2c175d731e00e1f932a4896ae52f209e2a1c6f5bd070
82cf331dc739f052d8d1def1ec8ad88c4a899961e8d43f7f56aa402664839e08
08ba455d081a8427ebd7ac20811cd1e7b261b0c73b73f7ab225c17d115842cef
20e566b76fc465fed677c0f6e8ca1bff15fb55030ddbf98a94263bceebab90cb
25b6361ea65c8a514ecf80b728b7907f454bd33b3710157018f5f9ef2d7cf4a1
fade45f27e44161adee573d724a7f603925e34d443cf213dc7f86850a2eb52c3
5d2ade0074daff8fac8954a83f329d3a5c5eb5de7e1bade2236e85687f5fef6e
67f64bc1fcb23246a657d6766ac995a5c593848f458c280ddd8d81e4c4550a2b
bb89e833ab1643e4c8a71b190195fd3b4fd01055814ecdcf33cb57b1d8e93f26
cafcab3995125421e6c796b0bbe8af33c08e32f310e08a50d45ee623634af7d1
68afdf7a9a0aa464b6f89360e3909b8e65ed0b2f430645bc52e747c09f22f0ee
fc0f4681fb090879075ef9a0eeebfe9820b27eaa542b4870bed049129df30878
b39cf3e54ae86058b9b6e80ed61fb82d38f7c20c42a71a828ca6163473334abd
9b58c673129ca242b5dfa794a8d598f24d27b5546ad480e9397a238e5cfa02f0
3021751912e142ad751c3e3b1fd3f758cf52437585acf62633bbfe6bf4eb404d
a0b9e680bb568b94753577312ddaeee444b74bc4cfe88832f6f01e15d67e4a2b
71c3b3a51bc71b385952532c2c727c42fa2c77c8883b1c5e2b0553c5a39bf8e2
b4684d5d4595d128ca4517e66038941676f46baa0b2e7a250591f65798d4e15c
a3ee03141d20540fe95da7f30dac762def247ffa83e9e44e3159dd9a1bb6cfa4
c435bf49f201c92af4d23a6d06c4f339f0e93abfb17de722f2fc74a3d0a372eb
3522df0f028b4f668d0e546835e7631c20de5ebc27806b2d8640b599bdf60fc8
4472a6550c85328f43c4086437f44838e1f4765268dff05e7c8744155bb270f1
f016b78ce84bcbd54bd615d61e3e2089308051fd37c788bafd86c4d76996a52b
9b20c702fae90882665fd5d6b62b0b70e4304860fc461b3f7254255d17a90581
15ddb72e8f3a20f8b722ee6f4fc8f084e9eb43037b30ec55dd98dcd4fd69d73c
21253917c9117837d221b7f6b2af9ef2d021171d18f65c2bc09364988c16124b
c12a0370773491ec191589c152c689a723793d8de5309979c976d38d895117da
484c15ee91b1464319e5ab26b7e82b02aaf4d5af00cb2554908e4292e187dcef
f00d62438c12d59af9a03be0a0545462904c02588e6a7831896993f88a9e2dcf
ad6d5be1c5f44e51984c41aacf8423aca81397174c8ad81ec06ecbfbb51c22e3
2e4bf569ca69fab8454e4bdea2920f3849b52c3b9ef1714de1f5547da2179782
714bfc14bd15a47600ca5ffa7d3e83312e0d0ef6bb7c26048a983b2ebb26c170
72ea29c9d5e13122770eef90362a04c750dfa66d3adff53e800fed5636ec7959
3e47a5357ea5b00b9bad6f01fba4528b0b1988ddb1dd8d12998808c6e9e830fb
7ebdb0efcc7a00d946a99c03fb11bd621af56d7d03f1f4f69130ee2cf694a76b
4b3e3c3b5cce86c00408c668c71ebbb6cb542e44e5ce70da2bfb1a08fe47d815
8afbb4edbf77a13ea1fdc92963611fc35f229974533f9266255be6486831ff83
eea62eccdff1da6c464f89bde5d4437bbf80e650cd6cdc3fdab3185a82d4a66e
31f4d8b77e1e4ef852fce4f6ce552a66cd0f063faa2219a2b349a99bdb82c01a
b64615194a8716dcb0090d21e4f6e9d4010abd3062c917699291cf3a90ee33ad
67929a53b6079a682e1d3fbbd95a7ad95e313206620c9a6211c64fec52f707d5
af2360c260ecb5d34677b30c2653d89079a0d6253b8a6448339d7f8bca72fdc8
e8279280128723e76317f9c05923900bcfe213daaa7eaad5d35a86ed003366e2
4d08e6f4eca91fc4840491c3bec93be0a8eea69e95bce9b861ed69e397b2d142
d48acd892fe26b321e9c395cd4c3648e429750227207d87bda5116cb8fd9c6ea
ad168c5460b8d51e727342d8baddff5d4f40600649afa3d93385b2a4ad4fe0ab
0c3f8bdb3addb086f3ea8e45a76b11c1c89270c86d5ac0193257905f35f48a9c
824f133dfb3a117497cb91fb824a1421b2c1d9f4c4a672e41f847ae8fe113e7d
1314e3ed87d699485a12a1e96ed9f2887e232b1515082732abf14bdc4b06d741
a0229bf063b43992550eaa90492343ccef1c929e29b0fbf0df7d784d682b58c6
e32991b467cd2af70cb58c60dfbb751850a310aec7f9bbe0370c80e9602c684f
3a623ec2aafd2fb1f10fae9c984b4650e02f3d64242effd5e5863000211cf27c
93f8777c6690a63fbb1d2b974a48f54a9bd41830b4739f6d6a9bcad8585e884c
759828fb8d7d7ced612028a8c73fe37f7cab820fa21ebc29f3ae3f73f36ef090
a9abd0fcc664542459839c5d86944f12156eeaa109676981cd50614cdb56edd8
57eb95f31d25d34c07d443eb1118775bb4a943fbfe582fca144927a3e01779f5
921176f1463b97f484269b746ca7c0c5142b3d2d6ba64be24040f070df9e8093
9e5ca2fc80355e8304a73f461ce86ab9d06bf25ac2429612d099e1d9c88331e6
2e586f7f943b8e451bc06fd1413d4977d80c190e382f692d520eb31cea64a643
de4ad9f01f4c5827315552f493a08499011ac7929747ccd1dba08e9cacd6a221
cafe3b4960784f1fc0278c6030af8955c2c5a802de19fbe79f002d1b3cc3ec38
a31bcb4ffd8d942d5e71b50ba9bc0b9f872129d5165833fa872e8df58f8d8cd0
84cbb9242a186cb7ca8582da52060aebf3a2e2ae37815b8193a3e45108c9fc7b
6a879e26eaf2628a12fc22055ba6166af43a93b0eadf2c41209df7d3dcb84a48
1e0687073d7316151a0aa43cb10ced8c17a64aa4bc17289d41922ae2e98b2e3b
bea7d9c8598676fadec0cd2f8e3a64251f00bf2105d88b69e4e22f90e7d5b2d7
27293ce62b6ab5b070c9c7141966471b1855ea5c2762927eb36de6e79d12128d
595ebd5751d10f021a140dc23bd15846f4e157c595c76afe9a0853c06303a054
817efef816d88a416efbe10ae191b8af0c02ccafd4a912b2e0679a1fb45b6bf6
708ac0b8b9001a18e9f178c53e07df599389a538ede6c1b92ee1bafc50ee4211
90af173acb549504bde981ce635e4e8520128bbc4308c72fceb68ab7b12d8e47
d9183c4e0b7ef42da1bfba93476e636d50968c054dc5d0a6c5dfe7b0006e6908
0d9e95b350bf7337fb07dd804cc8173b8268e659f9b77e25f08d26cc4c3c018f
91fcd443797c4ef5d62fb8ea17558a4618c3b6569fad24a48477eb8d68321d24
208bdbdddb5951dfe24d9c1c3cfc48daef15f5deab1cfbeca3bf67fcf40d1436
39cd15d922ee014bd7f86cb1938b72f381efeca433d126cda4813bdb8fbea671
3f64a2bfc61d1c2f94f3152a212c70453a9e32ab55a77a39370909852c7aac7c
a202310fc5e42be095f140e74b3bd6950541e520f6a9f20a3fed918aa54a7eda
296cb325127016f52cd7bc381ed95b14c72793d3eac1bfb8108568f58773eed6
4f841014fa8e2ec1761fd40a08825ffb984e7f7fc3d8ca65fd3024a36be95c67
56dd89dd22fe8ad46273126100cc30621154ba36af673d15644a1a525d90ad51
957e0b9e1943e79fb0ae176eb19ce925f214d0a603d0aaa02c95f1dc39c30809
b0e36582d3be69580bddc0fd1c6071f9f251e532b37b3075244b83a821e79f1c
5a542043a85697372e64a31743e9b885b84293d625836347607c6564684951a8
8733d4522bf71dc9936056e71e3a5cbb5368f8ad1a341123cbcaaec967e91e00
3f08e5cecdd563f9325e1c77bc9b5e3464be6fe1e7f1d1c1937d20324ab2b66e
042f84c3e601831f4b210861269f34bfa6e99ed9fe753907c87269695b962f34
d25ae070bab43a5a7fc420a22bbab879d50171d05db9856c3a5aaf50bdc22255
ff7838d862247314fe36d4f8680ad109f87c23458edf7445708c1e1f0d578309
324af13a77556245800063ace38c336fedd64ef9fdec95eb08af45ee3e8cb1ca
ccff52747d6f00f4acc24ef4374e3dbd6413f99f14d3b9fde3b7d00ed3d5e65d
418f67ba896e0b99662243e5b460f13f5dead33ec530248a841e31c7552f77a1
588401af28db044a8443a63169deecc75bfdfdaccdce3f6491e7fe642e01bdd5
9812115b6c17b6ff44d0ad173206bce8eda2bb37e28beee31b714c8f3b5b4775
102d2464e81b0f837150db6a9ddb94e6a76f5109552427e1078cce431b93c19a
f2844f7f29934f6e8a73940e3b65aa056a0964fb9687ca95d21c848f54a02013
c2c7d63221a0d356ef2d42c636ebac8e15b5199b96a19172d6c9bcda5db4a53c
e79ae57a7260180c7b80a87348e334fbd230014c9ef4e4c43b6e1e66e07fa227
3ee080fb0929fda68bec31660e9d356b6c526c3a3a77a27f9cae24bcfa4ad4da
25309580734fd714ba88d24ba414a947c761d9e687561daf67e0d37a9737435a
71aacf09eaf96f4a0fdf7cf61fb644a5baa3b6ddce8d943eb83b46a1f2e9ce9d
ca4a741b8e5d2e7c4ca80c14d1671b5a36cc1c341b65df43cb50e730c7230ced
ab71bb8328cff79790ef5c970269ad411526f99e1bbc463e1aef87b62a74647e
d6b2ee4cf5847499f58bb7220fc16b64aa553af9e2dd414537a213333016d868
ee4c45e78a82bdc7eb4e67081662f2e97b5d4b7202885125f65e9424b3b696ef
bac5089455d20faab8ce48702d40843ac3ba7c762af95b135a2b9a5d82ae9712
86b31fdb92fcacf13d3bd5ad1381257bb2ac2223fcabcb5e22dbfebe521dcc4a
35071c372809d80b75b888826238ffbc31d98bb9b46439bc6054d86992cbae30
2f760221c8b2252e6c1d29db247704dce1c0f875ee703258831e9f9625151757
c59dee188c01e9ef65d866c09b4fd1b878370265d8e7c4a332dcaea44375b53d
65bf75d5f9020fb4b8d47401971a3f7c228f8d8096de344dea4281ec6bb59c97
9616589f21dcb633eded2289a1c8694fc9fad00df19886b06906ae90fb7542d0
19c6a7ffe598901b476142763cfca514786f2525c3319aaab150612031da0b3e
8a6f2d5e7215a8fc470c67167e862bb1d3b5c15ef798c40ca62f406bd9c904fa
d6b3b32c1e9bdc15d595348ca0014fef6d3fd0cf4ab4f5ffcbf45edecd31a557
117db57b2cee7b9d151f57258cc3473d82b6d090838988524f5fc95fb4163cd8
8e539953c0de5669294451f4e77a34152eb582e5300ef4cd7fd0b694419ec4f5
463dd59da496b371a9858ac4b0e8213109a6c7379f273151aee032eae700343a
4ff740e972b5cb92238ddc1b2738e0248c212b2ff19e26a37a99bc6545ea6d8c
78a5ca5968894d147cf488964c36b140c80013e10ee70a78ac510d7219003da4
f96006d16263d8bfb327ea707cb0617ede5dcc66ab3959eda7a3739e97bf0919
be727d6af4878530b612baa6dd2bca6a88fab9a0fff97c4895cfa3d389174917
2efdcd09bfdba633db597e33ab58282aa4adef0ddd25f420817e1b93c2e20bd6
55d6540ca5cf46c860784bcaead1c83d30299f07d681ec6f876bdf100ef4f4ae
1ac9741a52f522870ba814d5db0d979a44aea57001c988a408f41abe5e4bcdfc
224868b248798ddec8ec553efdc12f337a9853c8abc8feca2d0fa79271979d47
74945739416135fb8b92b9b8b528fefaacb5dbce3d2ab6a33e560c5e537097e7
0252995e05c298a1ba035fb9b72d1c79817006cb0a8830485a316195434c3798
5cf76542b526eca407579a65c28efd6faeda3b466ac294e8f39c9919197405a2
16765ebb78dcaecc67efdbee69dd61f143bf5fda8eba29494f8571719570df56
176c22ba37e1525d279da07097f15b8db8d8d91122e6942c4a4e2e962ac7fd25
aeebf19dd43a2e88c7daebc0dd1bff8bc9aaddd30b476ca78ad47880398a45e8
497332bd262af96c0f233d61f71d9411b279b5f9721326721c78a8667423f571
a5dfee23b82ea2a311114b8657833120041a657a6aff25df8f8138d9cd95818c
fdca7d3547f485f5a6266979766508ab610ffc46137c82498c75f5bc1c43acc7
ef910a41e76e35a5a0fdaa45a8bc260a8f484827042ccba0a9ccea1d3eefaf02
2168306dc59c65b235a5fb5b645b7091c7dcc941049811eae195cbda5214178a
2f94d7b5f48d3b2a994f2b6bb674aa7c45a30509faaccb918b21d6bd17be3edb
6b322d54c832fa9bc982551cc4137bb251c6c263b650ee710c676fa06554b362
d6d6c99309a2250246c1cbdbf6ca583f12dd0a3142d55b757fea3a6e02cb238c
5722859c92f15a5abadde0fd5dca9cdb8f962ae138e61445ca42ec01aa65fd23
aa113d032c49dd3bf9f1feb48d01e3192a422da4ecf67207d150a43be25b1635
1d8f9e4896f88847c619f6d4e3c902f19d3eb27faae0cb2a6c26ead8dffff44a
73a92dcab402444e0b1a3a5ab8f009ddff5ac89f50fe2871262153f57d27c802
b07b78a51f6a90abfb9a6329da84b851e8959368655b62b0f241fed524ee63e9
895463d9f58be52c49f63b84a562b26bbdc7b30fe1688d6628ba9b442519d630
c1d4661e843519df919ecfb94f6db0757874b7130670a39da320ac925537d0e2
0f87ebbd445cca52d8635f5c1a0af729c8700f0383016e70934a4b2aad5a5722
543ea672bfbc807edf155e97bf1f34f4b7db91f2bc601f941fd33f3fddb65169
f073bee1b134ae01a16c4dfd04b9590e85af0a084bd5674f65b25d33243923e6
875c5e939e149c16b831294213af24f4fad9909d0512b9c7b63c5765d6ba7f2e
8787065b491d237e10ddb3b71a5fa879fe25eed79e3152e8b23db6f319dd2f14
73a9ee018d328697041ea0ef79d62f13f0704727d79602a2d9fbd74509373b80
308d9a3e04f5e0cb6f3efcb42bc33a425bfb718f6cc30e220c07205b3d066e03
e9e3d3dd6950fe6891260d9dc52d3255781d9e47767651b3b9b6b1737ec33098
748b80f43eb3fd3509b48493bf419dc1ccb3b7115ddd948cd97cd23bf1577533
a4404ede210cbd7dda44b4337c4fb9fc5f09171adbbdbc6c1a4bc1325f25d737
c3f5b1538a796aedcd5d40d7dc5bdc0491dcbfe70a3a3c771b2671fa54bddd89
515b220c4ac83b8dd75750faefc45ae5d1b5157c2a81ad6a831f921d4f54be8e
c27edf121c322593ec58d0a63ecc09778805e0b0572325c53ecf1d79a844c59d
b2709e9737743f4c498a4dd3d482606490ed3385ff365e5f62b4be6fca9be6b6
2fb323c8ec9e350fb3f565a6e8a26a64e52dda85f21e2ccf900c68b2b1f00d13
29b0870c3918c20a7627db7d1cefa7827af44262d1d3eb4efa9951898861c408
dd521ed9394561083983eadc6dc213da8a4fceae52a82e34d8920eb3db83841a
57dcc3fd4d16b3c68c6d73a92e62079519fcbee3e1c998ebb121c56c2d79d88f
bfafb66f58e71390f3e769af762bbc5d9ed20ad8ae314879357deb88e1b1b417
b8dd630b5bdff0591d42435fbdcd36909286e4fa153d5904f40af6c7635d0fb4
7c2439dcee6f4c680ca7119331ede57645f51dc5f7ff0daa97e34bef5328a256
b8637c29720f82d9264c8bf68248f65b1d6bb788a448828fdab76c09001d5ce0
cd055dff9bd988864745c46b2c3ddccb7fb3e121c356294a1f472e3512e1709f
9ee64087928d96f24e914e7b112a481ec96e863c72691af2508640a3dadd3557
0bb53fa47418ecbc116d3cbaaf165116ec8d16d807909bcd1a646da7c6e7f13d
83a5fd1444e648111342b0c4434b897f1b73296120ac43d1fb2160b4ec408560
f7f73e005d05efefd15d3c37d94a03ac26def99d58abf9285ffc7e3e613196c2
da4cea40e24b878ed8e35e7628844e88a8de81b38e3fda4fb12ae73cab110c4e
e2a49fe8f6e49496367a7bd7ba72746e3e373fea260e9e772b4c124d6806baad
ca6b3b831b65eb76c24c1f8316ec67091525d941561553acf59ae718a1756039
f31f4a8926833ff59b1a6d8765cdf60176d825134c347e64770813c77fb6b867
e6480b1cc71c6b8b4dac41aa43adf87d10901ae970d406c37495ddb30a5c30da
080872fe6a1f85e01b9557927c9e945fe6c46b9dc06581054996f24f2f52b07f
ef71906661ecd36cbb17e92aed1137249ddfdfb36b4662f4facfc4dd4365e845
e310be617a0baebad5b309305b94cf53d10d335712f280c4fae3c331b24c8206
4241c8ef7a7770b14d9d0f69c5c72d876ebfa5bfe422b058a6b4690d3920804b
cfa1d3b5923e9dc1ac9e7cdf633d8d43392bd92a5065217d33d01d697c088911
d954a9edcb881f311e0728f2b13578964201e3b2c5f2a8b48948f5123896554c
62b34f9f72422883bad24099fcf48996d59e111633e8e9336cbbc32c3f7fc8af
4be5d534c8e4bf62f71ffaa7c784806bb93788e98728997564ee4bfc8c96ac73
b3f1b6484533ecc1f36e011aac6a9ab7bb426a0c97c35de530c3f58d1128a2c4
db16947217a4c24c872b0dd7c7e0c4bf968b939e1875229aa9c9606ee6095e1f
96ac119be09fb43b59668292b46a2b1923dd1024805986ee2cf86cbee5dd1f9a
830511cde05db6d133877f556425d07627d7806e3dcf80c40579f2bf24d3076d
bf859a16f6fc0106653fb551aec5c4bfa49a537e483d734c9b2d1cfc8f6efab0
8f3f5797ec050282c09d0c94ed14c962ef0996068804bb8543d68513fa6bd298
5df24bc5c17bbf8ab46741b049139de27dc2185c1fa86b7a77d2fb9b94025142
682646ad575405758d8025aede46ee8271f7f6c9c1aa02708de9234c86c23478
b30c726c045753901472b0ac4449b3e0e899fef0328bb9fdbab4dd65cc7b1e82
38603c49887932ab43ccb1b906c35a2467ec32542f10e8d9c1e41457f829340b
f5e04eca1d8ebaca5cb6eb5dd7ed8e813f4f196558c2621039fddc837db20c47
85ced64b2d0f45c609b786057d6294978ecd7277114d848b6f46d4b5ab898d7b
cfba5bf4ce2773a1cb102b2cbf3991fc994b8b74b43a54969149401653f54496
4da5eb99593ab33ebd43a87319fb8b39741e3cca5318e240de74ddbea1338371
7637f4ac1d6d04e8bba8fccec49835ca23ea7ec58e913d6f4fc75dfd4525b8b7
cb997dec64a828f32253b67b0408891034949848093c395e3ed5f6f584bca0aa
ed4121165c3867539733a5bb7a90736e611aa253bc2cdf29363a01f22e79ab91
18e4b0f3a671277ce55ff9c06b755e84b02a89abf86eec3289d0f05296f425bf
2061ba0be601d7464efe12b5bdf95f7f0a5d0183617114512bf94e5ee75f012d
d05aa6021f3360930cd4dd6acf0f7836cd51f2a06a1f3d1fcce92d60cce7a9d5
5106dc2681a42618522c87015d4085c0026cb1dcd7d159d60e86babce69159b2
1c9ef5b58943218c38304bf50a2c8359110582d2ba126e782804f48aa162fdfa
ffc25d1f52878383df85350ea77fbe1cf9df1755aa5644e8f499fffee6516fa0
13b38c36f56e24abd86ae58c37dd8c39fda477aa7894c74a8ff1799290b063ad
7f42d3c7546b21b6ae19dc411cbb5c03d0f2f751db2b865d635425c58e8882f3
4cacfe7cda3bd1bc3532cd47c465f5dc0bee74427796d1ad8ab3fc21197f0fcf
b8769ecb9d8e4dc1ed343b06d0811c53678376f842e40c072abb9888375b6959
d51936f9f19b19a4605968750a6024f10f3e03257760243f5ef4dce453ca37c9
d1bff38dbbe7a135f206739021ccafa369b97ff1c79b70ed2764f75159bcf43a
364b3c1ddad01f2ba58d9143c80542209a84788c08930ddfce5c17777326f165
7cb16820d64bd6077cde1233a61c64c36b21ec4e4b4237b3e888d5b6700192a2
43652622e0426bc0037708c7e82a770a174b97bb2b48447867dc330d061b9f70
a03ce9ed96dd53dd6bf0fae1c3a4b29f1a7ace81a9cd62d5cae9f081ffdaf045
9f8f3c95df90f1593d81aa083df5cb9e29fae2cf1de2b0a61297fe2ae8d4f008
d1d008298313d3a90f83d4e37a768414ce03e5fcd914fbe8f2c34a4146975c6e
9283c56aaa310692824dc3ee31d3c33e33296540d43555d371965cb06de700a7
15e057bad8660e25b2767b8b1c2f0af03773908ea2b29106c8ebeea2725060b9
d77a5331d12fbfc5c6533c0d9cbca595c27a62c66518a8aaf4b5f62c89862803
37629a0d71e80760e0fd5acb0015ec0c70384860c665dbf2e4e81e15b419c451
d6cfcb81c00891417ec11dbbce7a06c5a9dfa8167387372da7c2c802c2d405ad
63651d7a4c5784a9e16557f39fc99e19c5a6639a0206d8d89a329fd92a2d2e09
7ea15a5693d49b48c51eebb413b2f2c390e4783118edcdd4365bc762aba94c7d
73fbfefebd5c6c8e550d9e8f59b659d25f88aab55ae016c5f64e5cf1883421f6
040b885dc359d5c99ba045089c43b5413d94aed1b0db58de6bb4af86b7417a6a
c45b048ce067666b94a03afddfe3947307ccf21eb6cb2d7a49e0b209dc5f9940
375ecc78cf302a2872cf7bfde46e43fcdebf49592a065a3f8dea0e1a6fb6cedd
0b614bce6de6285003af37313f30fa7b19d7566552eb0a366508d055d661204b
e3b1f8b8a63bab018b0a33eca256c727574f20b94c420a2d89dee560eeb4b1d1
f6f1b8de4a068294ce447022154534c587f46f2af63628a0668f9ac05f299c3f
077ff3ec2f4ef7a2cdb84ffef6db8701a6a545e57462be793dee67f1e7152b5b
ba4212f490a6731e246298f680f624a13d61a73eb0f5f87027904d3ea0dc21f7
0b37351f5039b2da5bcf4b25ffaaaed739e009b344471d5935e749b8405da827
653fd93a9cbed7da17ce3c15a4f03e56a8415d234a0545dff1e7793957035371
4d63c2b04a8731b2bb9532d8ecdcedccb09db27606a4cee17de7d1cb9d2e0c39
91e919216b6c07f14fbe3ba2989509783ee11810cd6ae39c26f10b4fc0f0ef6b
eed5748a0ac9a4bce48c9b0b4f4083cbc671a3070d8eb50ef0e2e814a964f6ca
40250692f9acd5a56bbe62ae5912caf10cdd0d12feed4007c35320ed39459f47
a1094508043395bd191865bd9cb819e7d0b71362592acf58bae7d305b56c9a14
47ef7f2c1bf61c6486a3ca71702d97ce3a34b27973b6191e6c239bd50b8ae0a4
515c8da58dacdbbc7dd1f450e94ffd214b9b0203c23397d268512b61968e32e0
04a1cbf14e112c750c99be94c2395f5ee30ec3519fb35d86f8e84e62b0de46c3
e3c8987d7ea6677255638f5209dff5bba84811da47df587c5ff7aecf1fd6ca05
a4b3c31890a1e71f23560bb0d06876dfa767af96eb170805b987882412837a36
1ca79640be8be0483aa028847e4088d8139b4eb6fae227f09fdd79e0eb668039
26e2c514cdb5690e1ddcbb6aa2bcb3b29521a16001a7526ee843ca14d108ef84
c83ee40983d511e3a72ac6344977aab4cfe72da1d67e7cd7da34f98cbf6235d9
b5a8057478e65c4b00b23341734dc098b7c5493685376a08b5220c5eaa1a6342
2ad189eb5c2bd0cc7d86bb96dcb32ab24b62191ce41d104e920a38011dafa977
cbb79319234ce7be108d5d85607a48201701a45b00084e425f7e3d4a20c3654e
c1c2adac8f193cb01ef06cdb26a3ae1b1eace94b791d5342a886e8ae59ed3d45
64b17661b66e3367c6666acd19ceadf15a1030453ad1f2898113d64184af492d
6ffe3c65b23153313001e8b52ead5b517e08c6a1ca98d0dbe78d78890f02bf4e
3df83dc181c05e8f129610ae74056d81887ab5688d67a12766dfc50b2e4a9189
2c78af12d742247e187b630e9e460102079e8746f357e69706aae4c429ffdd9a
117d962e3ce63e5e4f81415077cd1683844ebdcdaad52c30acbfbf87bb584dca
3c4f36ffd27d21e59134b8c9aba7150a5b519beb808361032fb8c24aded9d3a0
0cf92a5b6cd85df58f180c2854a323d9b6990f8e46d5936d075af8cbace3ecfa
1d4be477a72ec2d27bc006f9f184b5cb18d32f14ae9bce438d526812ddb2b25d
9cf0b82c2a9610a95b6fb0e4d1a718a1b34173bebc40e630084603abf0b44979
b07c6727cdcc18ae246ed199dcc09b5e56487b94a0fea1a546c0287255ab43d2
6511ff4341fbf44840f3fa47df6df8154f8dee8741a61e15fed5cdaa64d81062
76522b87f2799ef755224bef3f5d381736565e257ea269832fbcfadfc9f8a0a3
5bb7d27c3e64c7c2c7ce4747088895ff0974c89ca521a74f4bf5ee3fce81eaf8
01f9f237c10d09b16516ceda52baa7c071a8b6591a535a4113631362c9d19e63
8cb5b69ead3d51198c8cc561ed46ca0479a3e3b2b839c7a72faa53a4a4add403
3dac7dfb30e09a2612d9614fe4dcf8f57ba6ee3007b318a5ffbd71e0080f7f87
0713a790c712c1c3fc3c0d75c5e9136ed2e6277487cdcff5015d2651de9702bf
4d455e59a42e7559267bb6adffedf669da0a07bf71370560b453ab46b2ab7786
849b048989fee33ea1a8d4221964789970077788fa815fc7871aafe8fca9409c
008fa148730f7244ff38d53833e95cbb1c577c3ff1dfe84e24127c3ef14d2aca
ace86023eafb39be4605d8b2c59b7f1a1007efcf67e799fe4e37be1d7b46f999
062c5836283b50e53e05556914254afbe367d2ca09387d8a59a782f0432411b2
5577db070b2553440ce3d39701b4723144f005d181a5eb55aa1a15dfe18bc3d7
14a5f44dc584b197891d154fda853a66bb8467e7b124f8ed28c00eebde8640c6
3f59902ec2952529a84b35cca822f34f49326db984720bb355b0221be5b9999b
02d292de493bb816624730dfb7569c4278c560df806b85fad9ec31b1fffa4ab8
b0f457dcb76d980320ba7b5bb05f35f5e9bda0875e638503d592ae405760ca2d
84d1609ee0731d85c28c26aab53827aa43f5331697003218354b2790fdb7b166
c98fef60c3ba6efc4d5fc5b338db20d603fa2ab6f9e7ec5a49eab6a78edd022d
ee56fce94213b1a21c8b001ee3d6599104ce282071ce1166be13dd2b00c255af
26b3681d23a3ebc908dc65fc9073cbf13559db9c3590fea81e61bea071698477
4b4acf9a3fadf261e09c6a5328c8cbc3a420d150c04a406f56d5d3836cb75d17
1d6667d1982f140a020b64db21eefc4e013ceb57b5ae60025446d0ba4b6a274b
2b60e68d15854f7f806f35ec4f4928cd2e1ece3fe145e64e913d71334a75c5db
287fbc0edb5f0a25e746439bdf109db66a39c597438ef51fc60a98952461b268
e8893049a2c12bb88090fe8870ad578a03f93a0e70fed46cae5d1249b83f5929
720cd775cff62848ee2ba6b26b8e783ba348d78c45a25512af42acd5ba0b5647
387d3e0c84a1ae4987692edad21b11e509a2ce5939821a6beb44fdec918b3647
a901f1d3fbf909c287b8cc899bafc718d90886d1e443dc2c7f9977903833fd91
9e828edeed0b53103adf6f8e639537ec25cd9fc7b00223f0774316301aab5012
fef3460a62796a9f47231a5159b0a55633cf269a879f59ebbf5d346e2f7fcd96
8391589bdca0b10c7160f9aef53b7454fa26fa2a304acd2710489ba877d00c57
3ce61fc23aa78859b3097558566212bccba7a3ebbecfc0f958f038148f5b94f7
8885db55b6363705549244fac70d7270df44054d6e6d030dd0e489cc3bcf7c99
15e3b7dabbec4b4d2809503ed212d8ea978769a1456a98c5ac55b63aa87a37e1
fc6480f534f885402e60074ae0b8bc9d3503e3a42034d4d6ce89e380011d2a6d
dadab8aebd804cc2d620fed306a7e49c9e8b5b186611e0056705e0903dab1267
3302e786c31b630be1ce35431704e33667de94a14bbafd63a192991694070337
4c39d2d6534ec3af90996ff6932aeb35766b2d5a12e2e34f35d9409e653e0288
5e6978ebd75b608865fed6a17ddd076e0e63f105af39559ba9179160b00a533a
d2b33f20f3805d4eb37435e21fc2a77c51a699426c417326e87668960fc4542d
dc4e8b8dfa2100479f5dba3c3dfbfb7b02011b84cb33541978b550c90629d413
edf1ab0f362a62234ad09b305d3776fd9fb1fc2f406903337b7360f3969b5f49
4f7149ddd69328970ed6bb92a1df837c12436739da4274b66b67adf4910226fd
e9f17be93fccbd8f7ddb82e28f5d51e4dcbdbe28218bfd160eabbeb633fc2e5c
618b66069d62ab9bd87c0fe78af0295ffcfd421c806090414a7482403767ca2f
f3a8c08c7ad59dc4ad61b8de48603aa3c9f5aa19d7ce46865f02914a2f71ed66
57dfd9c8474a24a678ba732570b25fc7f28429c2a6dc106ecdd2645efb803947
a770543c32da38e91807bab262ab20d2a1b46d826cb0580eac533793b9468184
24a545effedc4307ff90e4eabaffff5fdd175a090c9ebecb3d253cf5dac4b8d3
2ee34966aae2777ad98656c9c5f756fd13d0edb86a5e91037d4a4f5979ba2809
156cf741b918f852ab8d8770421dbc0b7b5261b48c791a736bc468c4459003a3
b8ffc95c9142f64e34b59ed42e231c010967faaeeea7f0861cd22343a8228d14
80afb795d4e70df03ec00c1c85b8b34681686e814bee84f7e89e7f1e7fdc655e
18bf79bbf56084a0dfdf5f60df3a92b6d216b7cdd5f4661932cc35cded19b8b5
52f7d4aa0245e99e0a7cd5f0ebdeef5e17e46caaa0a96e9251338492553bca58
74396abfe8664480c6a319f5e2f2c9c195fa93ffe3c0ba407a5d7d6e75b461f4
61aeafc1503389fc5f5cba017570be2eaa6c43dc737c6d678d7ccb53a1337b0a
26f17d9d7a4e351d9bc204a2417a0720dbce3bda8900a3e1edf615b24a4e778c
3ad244a19850c32f7959e1bd72d52aab945a3328e88c30da68caeb426840cef2
fbb4ffdc44ebbf58f237f28516dc91b298608cd514edc8bd44787f0d3e8a5f4d
86795974704e17adf23ec03b4c95c5682684aecb894c4496152bb4e6651aed51
789ab607002312454180fedd8103250f6ae97b429b1c48fe43b6e401252cc92f
9842cea08b555d511cba35c3a6f4b8186290f4253f5449a6343c68442aa77bbe
888bc7cbf91b3b290a3844c524d4fc16db82a4848029e95c96479158922d70c0
45b094f58fbccb4712740e5cb3ef5311001ea5a3614853e5c627c35d63f8df52
a8f12ae9ad658ca3ba1b36fbabcb0523a91f63679134d0aaaa6237c3ba0c164d
511cbaf3daeaa848e1f59c964c020e91ee017650bb15c5c48923c1179dc5bb30
cffe757f0d47dbc08a4042e58665cd15d9c33901f0d1f6349c0e47ff47c169dc
85d95d12430eb41191aa3c9338beb1b8d5b35ea71c2a0c188124f26ad15a6756
cda2aa9505fdcfec9184d101ecafe658715263a2519f74458afebc9295308a67
1070225e95a16ef9895785e8796679b6b716ac95552dab3efced7b3ce1f42a02
1d580f3fb5a6eb78670fb4409c25ae91fd43704de03728372ed05de27907fc4f
2abbddeef4af6076976d2b6f890fac0e84cb091ae8223d062c6e1c83fa543910
c92c65a4f105ea56650f56f4910688e4634643d5419cb435d90c53968ea456b6
c0e9facb06611d7d60533826cceac3d53c9206dd63df18f02363d1a9e8768ee3
c8a3b60bafe6637e9395589eed3b39922991d39881cd107bb04a20d4ffbbc9fd
35bb121d2ffa6664019e0265fdf061eae50e20a03aa7fcf6b017ab38a541dc06
e6e6ce83ee1d6def2c71ac3df568d6aabc732791185b73b9b0867a2a8bf87c6f
10e748f6e40757c62f830b494567d2c550e7e78ee2fdc043d296fbb7ca63704a
a293f941ab5cbe4779b6d9dcd80d209d837d46eff645de90a1e6accc5efdda8a
9db1562c1cd95354350f449f2dc6b44d646f8875654dbfd912f072d2093bf853
cb577beae9f446aa54f2cf024ee6eb700f3aaecaf55afc97309485cfff746a53
7e35cfbe4438a2c6c473e1510d94b4a77570943ef54d92d557037da57abcb1fe
a5fead4853271d602129ec523fc39a7f165f46153265ae43c826073e71f8d424
4ffff63e6338e25a82c061bdfae1b952e99757b802c47de960d7a439ec942660
5b42ef9db07a2b0309cd4723f828f59af890767c5a197990ac076b3f20dd2ce7
4a522b4d65a6e5fcc086e47c0a3b80704be8cc5c1a5f69dc0d6ad114f4e1755b
a9fc615c8213c2a7d102a6826692a6940ec1fe467702f31109895627615abd86
8c570b858f43cfe1639df38e0a2484486bb3252ca4952e747479e8c2dfad7ba1
125bbc11cf44101bb8846302bb6634cca6131d9b01f67b703d12883ed1705f69
1a332d2757e99784cd8c78deb7e175a4ce9c99ac7d958b55d0b2b171c5443666
f71bcc4e2aab13d2896b73e075384a9eb54e2bcd3296dc7fdc1897f563bbc030
5c7b7a1a68d11fad1621eecdb4e36624c9250598b675a76e90b744a380b11d0d
ae7bac7c16c692262571e2afdc6a480d1ffec29022a10834be17d4f5b4b983a7
6996ef8908aa16081db350c3c2eeb548b780facd34f8cd995cf648f7a085e47d
68471b52cd272ad7d0bee083944e732536f05119426a20e755b8e92fbc00b62f
9c73e105ed495c3d6e7863ffcf6af733cb18758b4e2e4030e3933c1377a72e1f
7ebafe10c391b05638a98cc99876038e5c75ea6e84c64e1d96deb68949cc56ed
56f208ebd0e6fc4580c816702001aa675e4c1acba58144265310f5de4ab76f2e
f0ebc44936b4aa9f7b49f6b98a5c75bf229b1bfb30e8b2dd5f53819a58aacf8a
0d2642bd9139306b7b5f38915208e7ff351011208a258fa0a2f63e847380b3ce
c3a67bf233d29c093070aea7aed1183f3ed17c06c5d42c89dbec49ec57290fc1
7976e523de3661e27abc03d950a64eded849b02b3f465bd4487aa13c5b5f6cc4
507309b29bbdad3fffbec5f88e8d3e9917c9ade8823e43c90526f905e313ccaf
f104a2385f3281b6ef160d3bd7ec241f545aa1115b64fda32da8aaac4d921238
919deb3c4476c9cc1d6b152aa8c97ae5bc6998501c3ffd2a9752dd246af48637
bddb29909980fed5fb9f7a0287adf561db5e256b316a08f530528e2001cf0910
a385551e77af9eb97195b15057b78466322d1a13b7129aba21a110eb34828bd6
10e934bca19add73d92604ecf0a143c4f81fb48c59f8a5c7958300089155e41e
19e3f61b26f41511aa40d9790cb91faede1a114da7cfb75346876eef36d3ece2
5a3806d93e84015f8ae7c06be19b41ad00eccdd0d9b59bf93c7e8a42d5916dbd
eab19de8c4671e950316550e5185e7aac48fe0b788d36fea1bd62faa907d2c75
4f74ff18c183ff19498f6ca582908004f65fdf97799f29312708c32c59915b29
d68ac31282112ec37482102d7cb78b4264cc04e165f384e3c72b0fb5262c3cb3
c51875092ffdda4d02ab88ea61c0efdd90383bd027d9a5411197903775b1a787
e4b1ac46b90a7e88868c5f2000fb2b579393d2595120ea63040f0556ab591a8c
fea8121e866416e9e6c064baef81aa8b5ec97b77e8762f9b8d4f583778057e32
dd7a1cbd85bf2bb57f905803219f00bc3b7a2bc89445cbc87b6a2b21ed4c63fa
41460bce2067a673fecc1c370b8018c99075e9bfd483ca06c8050a2755cf845b
36476177f84ca20efe627002cbbf80301f45626acef350981ed62cbb03bff1b5
263005bbb801d107625f824db30bff44d2d83f85be9e4d35aa40f302177be1a8
30d0463332ab193eedc36a568751caa4592a7e2e66e31e3aceda73f86c190028
f03f348d76cf4298e7724e1c8e59958aa8bfd1746c88892cff42ce5d0ac4c8da
f315f35a5867e499ce13ec2db00efb65b5b401e53e72cd43e9319daa26486355
cd3b04c1879b967b8961d2066eb62ab9ba2a712e7085d8157111c403a3c99d11
04b6fae367a3f88338afe3a3d15ab852f9cf4c7a718b763849c193e63041ad16
2b435ee966ad05e3374136a18bbf1e848b3e52d65f437409bb7ad97609bebd32
ce41e198e25547659b07982bac11832d676287f4004c27a71d6de84b307ae98c
a895a86418e0810d314a106392ac50b0c899eea0ff505ef8f7134da22d62141f
55562c224b158e524cada32f36254f830d0766079d6a3dee9efd2ee53f989b39
d61cb2f04f9072dff0d49997d8129fa4c98674beecbfec71ed933f1b8573d7a1
7cb62cee911f22f41814db3db677ad8f94f5cdf2effb4d0e4035c0a9b244a78b
d3100ead9a3b4d02748afe891d1edffe869dde37817579e0516895203b02489b
3d82d666acd3c8cfb8092c64a0e3d24e9331f02522bfc005b423d8f692c9813c
7cfde9f689065a77d34459cbd9dc090600dcda81ee723942aecf7b0cb19c79ed
251db52ba095eae2101292a2c197321cfb02432cd66264050b61f3e6d303576e
0206e451a5975cc0f244605b1472ab29bf39295875b08fa083ec97ebe64108d0
399b7e009cea07e7f4b1cc818ad78298f5d45da74de169d7a00a9304e10a03ae
12546157aea7b6b1f0fd644e58706165a3fcab70e66d1ab100db26ef30870d8c
8561e1090db5dc5c1287a89a9260e979706bcca28a3320b06b9137a439dd088a
c791f220bd6c4fb757d152b8d693cb521d6b63f733830a3327c4674aa4d004e4
a73a9cf1bcba9e37e07519b8ae5366fc3dd79ef212ad6c561129c6132fcdc185
969d1d6a39d3e3903b2bd52d52b0423c4f44ae57b30b5d122db4eb4916e0f897
5ffb1949928a9cd0edf3e42eca0c3e6a4a195f984e1127cefd5f8c988fce7381
b97ba921b6f3d4843a273fdfb4c0f7d01e454d0f79c36b0a53ab636aa3dfa517
5e6e215cbe69f8a5be2e6817a43e0b8e0dda1d167e9212c03463ff4598fb03db
f48f070f97ba56da2dae2f420984505fd9d41d8c2b515b25e9c93c814deb5f60
86369b21992ff6f3ac403a1e15bf97d9c680872f5d5b344661b8c9037a75f5cb
76933b513d0a47a9b4a4634001bd5927a65a27a85d641b545e1978c8eba4bc00
2f55fc07217f68f926a511b6ba76ef4e11b1e11a6c1415dc6a9ad7f4cba9eedb
d39dee26cfca8e355f3e5a0f90a2cfacd1e42745ebdfb30aee8a63d2b8eafbf9
d541768d7d3813c981aa5bd91e44ea8ebbe4a6c48b4939fbd9950bd290e2f6b7
7fd096957a212faa43e961a3a3dc7f3d9fbdde47dce5ea1a1e224145f4beb63d
03995817db9248acd170c8859e1dd4e56121907e250d1f1be4372e120088a602
36da4137ca792dc92b071823230ca3130e9fceedeb4ae09a06943c6b4e612579
d9566d2c3f7772ed47fccd03c7fa1f2f3873335c24253036cfbf85cd8c8987ff
980cbac938d2b175e71ffe501b2e89526340ca0a2d7aff2c24ebcbf0fcfc37a8
1a0447a473806709c890b9d380d51f56fc06d807f3f441ea0bc6daeefac71102
866103cfa43d69f67d891185fe8f69b4c8c2b7ab8fa5f12a6a6bb06b51e0acbc
e6bcbfae8c4b9c206fb300227d3aac83da92e83bb3468b8d0d63d496db912e9b
072ff1cf829c2d1b036be0d39b9e7acde3abb5853ee6feb1db87a5a3175025d1
3433aae2f090a6d0ece12701a7cb9493c8fd777e85b42d4dd2857314541ae9c9
d80b82760a5cfb6e8faa08c5af40268e3a8d06257cf5fd46bea0bcd6283da0ae
092c1f5243e69fc972a3e07fd8cd1a10d8f6618301bfdcf8aa67492b59133a1a
abcaabffd6aabcb3917277fb8e36012f366f049562452dc312db3f9b472ddb05
f1776d97b825ac0bbbad70364cd715371cb18199080553aa3a9d749ae3347f3a
517afc45dc9b19cdc5df36d8fce777b6a493d7b593f8e2f846062eb82634a8b1
6792f743182228d1fcc5edb186247080e5ee3ad8b2e742a6f3427176f3591647
25bbf431961e04de2ef1ba2698c772b25df3787866068429f92db179d2bc2447
aac363bc5816fd098056b593bd20f9940dfa40f9164cb3749d997d9acf6bea4f
14f0002693b60758ad5b2cbf8de7c60ed7cb7059f54e0245c9824ea54fb62f50
1e43195f2a80b152cee1cf541a75bee261cb48a47049428c879129c9793655e2
cfa7d776749d6c9c4582bc4bbe42445f6e28cb211717cd5bbd0beea2a1f5f051
2b26a52d99278da9ae8edfec96bd8372fa580ae0f7ea355b7a7b6314c6732f53
ac574127a72f7bf7a89bd68875b9ab31f7629e5a228aa3c2eb39d365fc668db7
4f638cbff46f5d45378ec724e0bc501e451c0f7c4a70c4b1e570c3ca0f2a4fa2
d3829bff7c6f4f2cf54833d22286108e69df6322ec093dc464401415ed94ca84
e01c81802028d62a59740f8c58eb99f1c353716753d5339d3139a5de4d447e9e
da75c1a0dd27925a9be1365b27aff00fc340839e0e025a7e580e9bab06ed8621
a88934bd7331b097dfd8c2b6d033c1a684dc4a70e50cdd9b6fd92ff1f44d62c3
c5cefcdf817b94f44056d9b42b8d5f39a7717ff9f923eca6f3fcf0e151b036ed
13165c9af5a50193b0856e89b9183086862e6f4af229eda3f4e0bd050d2f3a0f
6946897b19549dc52d2a1d20afbeff7ca538527fca33907785e0f0a6dbf22c26
8ea682e7651dcdd88665c84400f9bd1319ff7415ec7fd58b84073a77a8db2e99
cd103890d41618a5ef554cd2b8d9bbf29b4c844649cbad71a02a584e48178621
9c21222619812ce600b4d7b2e5e49d05bd2a7f19656801e6663e05cd4a6a8147
a7e3f27160f6af9f1a269dc20f614c95cc1b4519153f803d79d7b875e1321314
503cc02f8203991367219233eb33e5e59111423428cc3f914a11d11fa35071e1
37717899174f14bedbafbc4e46ed538e2387980626d8816118b5780985103416
b7c6467115b2a71e383ce7c2d308822a88ac27a5efd409bbbb81c6398bbdbae0
27462539045bf188cc304b5b460a259748ff702abb9aff274a6101957a32ddc7
3ce8b350685cc8e47107b779fa374c20a4e8b1aba428e7962ac9b5e0ae684ce8
1c1e54347895e6241d564d734372af169a4b06c290e65c187bba00ee4c902dd6
001319a5443069dffce68c09121d760d5c74d873735fb58649c99c5fcc3ea08a
26a84563936d9191775e7084f14699c7b19e4e1a08f86a8c049a180bfb8d3f4a
31383062e8cfe502ab7d1a5394e5dcdfd46d649072583a6c46f94560550c5b0e
cd474973a0c832ecf50a74157848d1b646e3d53880d3f2913c501352390b3618
2fb291918d66f3343d083c903ca68d179f16d6640a45c61d667637a30f9f9228
f890605141eb650079395f57c86cef098a1d781c8e0e822e0032057be728fe80
9f6c929ab9690e01fba6878b68904aa0e2a62fed30f684d98e00d4995edfc4cb
ea79a2f0495cc11fbdc10999b78cb943dbf56d87baab216db954718273296d22
c0f15570dc8841310bcd4faa72ba49bdbccbcfd44b4ccf910221e9d348a4be3d
18e6526e5255ea932660aabc5fb5c0b69be21c9b60070642ba20dbae2355d7d3
fb9c7297297c8ac72d9769d4edf7ba864b6292452cbb7d07e9c0bc1d12584070
c45e98e097f5dc983119eab940faef3faa000a832d4ece31d0c3030c1ba20bbf
059a854a6ebbf49850514da66aa00159e5379211eb55961f607b0d156d2eed03
ac7e1c5235042fabf9f939c662eb209f4db5b07a6ba1bb3a2f74c61a7b685d26
e934aff06ad40e524b739d7f1fc4d7f1d8d0de76ba634e21baee9976221427ae
07b7992a78939eebd1533ebb20a4aab5cf76fca2985518119754da6b56b6f378
b62bb5ecc5d27a859c7de07c798ff2ed5dd380d293c3ab50c376245c92219d53
3532227eb5980ce3b72d6438bfcafa1cb36fb30086c02852e8d7743a12a0a5db
9b3c69a3177e3e882eebd3edf289270e5c9152043dd427bf08d8f9df001e81c2
9600db572b8573ea51c2623a2ca792bcf626d94741349c42aafde6e36118fb07
008abcfe36468dbd04b3510ce159ceda794881be3ccd767f773266003831ea46
23afc4d55fae89c3b25e28d1d8e2808534ca784fbc73b772e68e618be6f8f3fe
2c1792505144c850fea22e6298e5e0ca9f5080b16a516457afafc5308d1c11c7
eb0ac49395762eb6482bd1c6c26d88fbbdbd0fc778133ceed25f67c96990d4fe
2bf441f2ba4c7b98f230b1c1c14194a6eaa6cc952125d2ae1cdfe65290e70ee2
54d49cdbf2ef70bff52f5366a388c0f2fb3efdcd43db813bd4829b02a5eba447
da87bd9af5a9cb0bd156ff81de4aba30a6ca951bcce3c907647b2670edfd78f4
6b88b8bc3aa97218a25b7225a188026fd0b92dcc683391788e446b3fb9162ce4
0e4fc4b0826bb82fab4787abb6c7400a8f17c38ca4f6d59bae49510a2550807c
6439b5c1fe264a1baeca31d7454dcd0198483691dab1b61571468015b37b28dc
9ce997b55700cb2c478d3bc25361856545b10064a8dc7c8453efd7a15cbbf19c
0f0e079e734d1cab29f0d965d6a8b009888578811bf7065790b805e75693ac42
77268c7f46e9d5157a012fb5e7f678ecb25541e13df9f68a23b43f54d948e242
0d89643cfec242ec7346364cb775ce5aa2b33f472390931952847c0ab08b3dcf
af74253532f94e8702e314ca1b2f3e954f6857006ace3d7220b5c6b60f5f2009
4dbd54eec1032701c3cc3dd0c536d179ff60a5bf36efe3e703c0d14f83ca7ec5
80bc95741d8c33893d1ad01f4bc72f8ee12f45fa93a9b3b124c14978d4425af0
580b6aa55ce25b13da21c0b11c1c6947bc15f83b928353ad883bd2bf9e5dbf43
53ac13282f0e4b2fa7a3dd39a778261c7b30d52bb177453ed44bc92f595bd81e
11b884ae961601b5b144033c70af503f06db40e5e56c68035d26777a77788d7c
ba873faecd2cdaf18b94b987596f5c3d78446decd3afe393471df3c4ad91f484
c649f69d895c3a74fb40f900f6004e9647f5487cc99bfeb6f089514a66fe149d
c0b303d2803e6e6e0e5dad9d7607ff8b9686a6dff7db624987392876b80957df
4d7133ac4627e206470dcdbb69800cf950f6e20099f06c62bb4aab4daa8b7244
e427b9b7b51f46201126eee2cd701fa7dcddd16d6a2be0c00c50c9f6b7d41d13
f4d2bf9dc85bc02144481459caa0cd17938a838fe049b2e063171eb080858671
337ac019c751fdddf4eacfbfb7410c78f94c7b3515faac678a74c06493941a3e
685b3f876281c103f8d6e93016c01e522b54613d23c762b808056848e4e2ddc0
d39ff4b560b2d7362cb3100ed739349c7bb65a96072690907aa7ce36a998c9b9
4b09b0e3b0172917c654fc50716a8e5d9c4f70fb989735826ac065368079ae0f
2afba202839aa6bc02f617353741d274ca2b59f700fac265e5463d7c77d37af3
57461d10f53af6a302048ec071d23dca0424df0b22e4900e717e50d1b8104c50
4149292e99a45ebbeaeeeb42fcbb5429191542fcf57ac9180be9e4bd146c7d11
91e48fb3f5802cbe280e8f22bff8cbd2b33377f9b8a57e54c6b101780bd2d8b2
2205423bd6c33b7475cd77523552d3c2245e79a17d1fd58c2c98719f3bf64e76
de4ceffafbb6b250b2814e5e609c123dbf0f8ff49b7a64fbfd7141471f2e85df
f6680ef228e42ca5ca3ee45c4cecc08b43f679020e8717127878af24fe621166
e526a421cdbabf3225d960ccf1d2edaf2552e2c4cb00d97239c1cef404e3bd5c
161c03f89f7a92feec21b5166257a693269888955dda5e94e6947a49df9dc94c
b5885a189e98f3a12e94a6a7bb99762226a51d215b663543e7b2afd930964957
0fc7cefe22b36cc1abf3497ec36f1f7a5a86b16ae9621b5d342b0db6cf94a512
5f498f59dc4d7237d50e3f4a4f7272f122871f24816c73bd4c9e2c457b9a08c4
d8738d1bcf179dbc06e4208fb598899261b83d22a20cc8abd7834f05fb644831
31bca5fa0553d95fb2931a8de3e36c233d5197558ce359e94206f4165cd0d065
43c34beda1ead85a95b999d8c5643260cd6f5871262bae3a02aa0e60420f766c
7e448b39f7195a309ea4eeeea294dcccac3058ec740eae3be8a072f8f7f4d506
a6ebbced8cfa40fea831aa9af0e258b8cc5b8fababcfa22d900f0428e1661a84
ca869c53f466bd56354eab3f28f20d0c129616a2fddfc1b70ea7118c4a87b51e
850c23f8ea8559b7a0c1a5d5a9dea7aa4f90c2e2a1e6b0bcf00d8ddb1e8c8b04
36bde8cc1a96151e69e2b52e39d85f60202335c4ff7241c930f1605e18697625
9ec74a95ef0ca4ec834db4f1365f537c2d3ecc8a068eacd9f96078e0faed0ab8
3c5cb58fbbbe97bffd95776db65481b396085f854074dd2a756316eaf4277df2
318b32cfe10b3b7da4d4096f80b4b5261d3fb87c071adcb91bc50b491588dde6
bd125407357860b5c26f38dc7daf0e5da4341da941dc9d93a7cce3e394978798
58da592569a278a365b91a99727eaf3d19292314f5aa43ebfdf5b5bcabacdc5e
ceae0e9177edfcbd4c45b403fee01a0d4cc182a7a11e8d0fa7e8a7f2b62cd2e4
9acdacdd35f7c2722f922256c0e1849b13af751b66c188f243f3743ad3fa0e5c
e5336928a111d544f0430a68c509bb256bd8ff13abc36b36005496486b027140
854a5a3d68261194b6f732c3dfb085c17b45b8cd0e02a4f6a9e829284cb7519c
1872065f788d502977dbafdc937056e9f1afacaa0147e9d01ddd3703486810ef
3253c38008f57a51de45006c21b3ce8c3050866ed3e7fd1906611f133d659bc0
e48f56e8d94cda3c4b30f7eaf14e846297760a60c4bcc568ca17c1243cf65674
495d8a0a3d2b77f60cf3986bf145bbec4d880bce951cb8605b3abcf8fbcb0747
c500c387c6ac9eed9ff4b65d03f3ab7aafa9e82986a3eae62ca3ac9332fa55da
b3eeb61317b39cacff1bc942fae33997c8c466157b5a3baea360c965a4d4a0c7
5dbb5c7ba3b47e75e7964b1afaa4bf296a65e6c0cfd9da120b4e45405c9db16b
bb2a7a3a256280b4084c77548aa8b4f831d909394c91b11b570769ce55bc2666
1a1cbb3a376b735d77e3cdc98d13f368e5847c318f817204a08d3b122028e3a2
2317ffd970d8685e9077b84bf8a1c2f0659e691f4849fa8111bfa9f37d576ece
b2d20f34384758d70e2f549ad04855881692f4682cdb345c69e2849022d0a826
d35dad6f687b0ddd30558c3b50e64c4cc421d2d5a57eadce74de7a7b27bbc72f
2bac8ef966bb4282b4a709e4c83fc9d6a45397ad29ae69ef3c32a6dcf2ad83ff
b43a866b43af0abd88ec9e3313e2bc13e4ab6bc57189a841baea4be912d49e75
8480a85bd13c36ed361fda578bacc985575fc0283b366cd76d4322383f1a3742
be2d68ae08d536f8896dc7d7b2986a4ca5b00b109160df694c4dce27ebc62c51
1d7f70ea38e300f9bf1734c9b282b788c26324a61ba8ac0f3e1d09f8d7d8e9eb
9d5e86ad85e62a2c2e3fddb73638bc57e7461bd2ebadb67669d671575cef175b
a775bb3b5ef5cb7307d70210d4350a97340a39824fc5e04ef96c114444f995dd
c8026774b18edb75842b43bac9937ded7a4fa5e74cc58171a643b189246c6073
5e9bc91c17bd0ca046f8886dac2a6b666f7233ef2027242fc5f7bf235f08a5de
d650b3e0b4da91d56e438f501c42417507eebd75d91f23fa8d919814d102874a
5a1d10fc06c6fd7d26c2e6bd7a04d5954093d971dc53750fa9f7f0e14ca8a32c
547e07e19e256fbf5a31054f2423ba9ebcb0458daad82654413e13cde7f00057
feff927dee1ae48afd1529e7622d4361e6a0fdd429d0d996f66193cd9724deb4
8563eb82117987e28c9ddc2563fd229c43e356aa94c5c9fb03b593b9b3e1fdff
82741488eb5bd3c0b793189a42f351c0a5e6acadc29749287a588955dfce413e
9a176922532e73d416762ba47becb90a1a43cf107cd716da1486c34bc9dca4e2
d51c8191a20d99ecb0402f66517efa977c90f357a60d5c69ff461bb67cbab9a6
67beb0b7eec6af602f01f7d41382ea347f00c34598b64581b748a59daa1061ef
c3c69b332d4784be851575ee15bb39d2191609f341a637ce0af76f7135a4fa73
168e08dda6356f3481dcb2b72730fdc30bcac857c8028fad73db0734c2e81a62
5e6020910508afbc804c10203cb8ea1dccee82b95a5b578ae5ac4ea731efc0cb
732ac63b65580612b3b2ec34793e436d2edb4c5563734d5b9436d0eb25bd79a1
d5b295b6152c0be537dfdddb9e50cd9f54c12d8d0b9dc2a05bfce0e5f41b0732
26250751126360d8e2ceefe1b022a09a826569ac794a802ac30ab58aedd89e7e
2003b7efa8754a4e4544105f4a8156f4f7974920ba5557394a1b7dcd60358812
e6ce685eb8286b0947cad18240c1e72f33bbbbd2d9fb1afc88d4ed369d44bf17
44de93e2f9407f5945e41d754290d56edcada4854cc8703802d66012a8598eee
64b224ff4b07c3996324fe55cfc540cf0afe829f819b1ba1d7fd905be63ddff7
54e7e79bf0c16b340500902c613129295afe4f467ddcfb278f4f28d44667f8fb
70b8fea28f45a922ef42e313293dc1dcef1593042cb6a1e54ff7b416ac7fa82b
feaf9f02a2b4d3089c64a26de99acaa2e100f8265a59c6b9f778c00657113152
4ec0aedefe8e64be51d6d6dfae4f1d87dda9d6f1c2fd81c2653d889e3beec24d
9d6d5e01ca56de31f7f8c8b0239b19cbbe2663a5c0dd8c75afa5b9a1fd35a242
79520260481a490224ba0ae1373155c3aa7a517ff27917d25e60d91a826388f5
ab82a5280f8a799cd87521db693482db964bd84b5f19f023b6d25f770c361fd2
6f3a3ae1921d1539fbfe4a978baebbea28ae48dee3e5bc62b3785a72f0a07cbb
9ffc67b7191989b2a3b6ae0ab47c61e9d7684d7004f020a63b1b424a58cc254f
23c04f9c351aa486e1711b6f3cb0cefb3582eb51807789d853c4856d39cd6340
4c23eaba2e2b090dae5934c8aac743ca4e7338895478161a373db7d3bc342916
7f7eba83a16281ea095a187847b37b6ffac66aab753cd9dcfab528c0e00e039c
074a5d11796ab11aeb3a11b9a02d017bd4c7fcafcff2999a198b3dc708390f12
39dc360965b5ef3b19bb23c102e587fcad7af287eb1aa70b3eb05789ff90b715
04e739364c87b9b8f6b72970868c5415dc5038762c1cd2d184ad55614aabff8f
e291c301f7fd8d23981e7c7b2baf783f9a7a5a30f61ebb24978137934e61a3c7
80dd1f087215b589145743f7f854079c2cdf8e8104624784a881723cfbae0dd6
dd54b2c0477c76516109586df63e50e4f12007b32e34e5ef1028bc3cd0a4516d
07dad53479bc303d38815e69c8700154654c099f7b64b9de11dc7ce042227492
8748f3f12f558c55c46cbfd6a1be512ae90a469f90ef4804b795aff0095bce65
81a4e406663bbf6e75fa0802b86804f9caa39eca1f6f5697b06f8295f76721b3
8957905cc21df69b2f7eed6c77e1403bf2f6d29770ca6b308159d2c1c4eae10b
208e1131b748475896d5a7a16084d20e30c1737d9e4ce863f081d6bf79124fae
aa5e9412d3630938a6765549ec888051ad28b6b0997f7a85bf2bc1e2346dd43d
0ac49b5dbdf268f74300e7033eae5559058060ae9167310c572169095797bd06
0671cc83b99ee1c4901257cbbc61dd6e82a83922aa7099dd9a6bdd855d53d707
56bcd5c3919049148a385d8aeafb552f1818d11827ef8b43139e97b6e87402af
812441b133d243200d6b3c5503a186ff8b833700bf409bc07a97c43a742b5227
9c49ae15494fe980da2b4c06e676afde929b75122d5488c4cf6521cf1a6765f8
c02a0e9a953a800b4d20a706326db04ab52f27ff957211580f25d1ec4e16e99e
892a0238272557fcbd74b859e6bd0f1ef2866f05014f1e124f1e0f53549f13b0
b127786e2988d670b4bbf2c9b2aace5e912a0c972c6c462ace58aec41e4f47a3
03e949f00710b4768406ff2e65ee3a8184ba9200e6a26f820584487ed8f7807a
5c51c998c11dcdb2d90d105da024eee08259e484c07dc9360679f53aec147814
d659de6fc9c14291c16518cf5ed85a4bafbb15495181546eeea63b10fca10669
34889ae159c1d015ca15c893f79bcd89c4d27245a64ad3b44aae584cd2f4c416
631affc8da5d3057d44e9cf96e7f32d209b45f1f4016f874f9576cacb78a28cf
51508ad1afc21e93e262bcd9eab054c2625e1c0c85d26e67d9a580adfdd2dad5
51af5d3ee8e7a083d44c28ab3325974961212c873c16a15ad6c3bc1a7cc62449
23edc1b6a163817942cfb0c1fec5e880ab4104438c50892046c746cf23f76e76
ff0ec2dc94e3b99e03dbf01bf538960565f720c8df4ea0a305582d6b85c35b6b
155148560e925243ddff5875ea1fcf464b5d23e628028adebd2f06a737be4bd1
2f36ec3876365af809938e31d95ead171376b8fbc147082f7e10c7821410b3ba
4f8ffc1ad2f7709c88cff35f9f20199cb892e3d323e0197a3ca67c99300946a9
4213faca651d7c333781f98c62cb3a893e53402af782800cec9996d7d9640bd3
c25813866d135be32ce2fadb654d4355c51eb22be3300bd4c41b184b855d204d
a73c552ed1d3a150a9d9d89732374904172dee8794f46f8c9bf74e65ac13a4bf
fb375e523c21b0638c5e0541f6663719bde017828b44828833d6342f27ae6b15
47864f74de59cd058f78ed5d55afad0b8da454560e8db80dd259397e81d7cc41
2ff7e8eabdbb9404e79dd9fe360c7d7694057b7cc4b4196ed34443ba073b25e7
b818a926acaf76259150964729ee1e6ed2d2aa0f374ee73206eee7b327592174
642912eeed48eefeac2f3c2c6ee46eeef0ce1be063d8f80b62e724c6ff9ea147
e68ef621ba8a1ca7a5ab4dc6348b7473717bd8656fab3d64075b9cb70f129c40
0d6d7da0af04eafaf173bf85cd3e5a70baa210a7fda2ab6bcd5692624d83462e
d2bb6b2ba7eab4ce010199e05ff28363a32158840e7a11e607a820bc3a486b5b
460cd942e21e23586198ecd37cc814ec95fdafecece620fa01c73f0a400fe04e
f4727a352680f0cb01584ab4449e528bdb02789ca75b0b41fc42c273debf4f49
e2ed4ee7f35ff5cf60f4de401b13bdabb26541469b541a6cfe0f5deb97a672be
0e5f0bbaf1877bfc5007859e01021ef0b8fdb1ce9f158fc65180d9d3a5c55907
0be8195ce2d1e6eaf85a310b7c5712d908034246cf29879b2ab0925f6eb600fd
026437c46ce46f2f3a77f0542ca453108c76afae6029f75f0d99d39f6b02e495
5ad97561e0a0e323872b19aa0af4777f59b90b4e3149a6abfa2f8c4ff8e169f5
6c5ad7b56f316dc0f7d614701de56eed5f286e2c0b086a2f61531a081c29fd37
4427cb9ba60fe50ca112a519abf86757b8dd09517aede0672981f6340d7151ee
4ef35098eb57c2e7176330b4a5fd28ab0cb497b125a7d7f334818858e7d86a3c
7ee8a9db2450244a7361351bbcd8304900122e9f7a5104412ec492541859ba8a
8c8823bc6b264cc4a8affa9a7e7299d7c53e6b493830260ba3d0aaa2e3a9de8a
93640a3d1eb0784720e8368cb2281c52af23dcef948f17b2d32e228c788871d0
6485c727cea636efa1c6b5bcbca823226a48fdfa9027f15211cbcb3e88bbc6da
4217813c7d166a1723896362ddf1725b8cb125a7f681cca9c16976f8cf254a17
e71c24376e92c0fc9fcbe3d7938c2fdcf1d5213c0ddc3eeb2b67f66bfb304b94
7a0d7eb7015a44177d3e7fb3801acbfd51a47eefcea3946923edf71808b27474
cb278cafa996c079f1367be9aae03a6e199bf25678c2ffeef32ba4a037c02c2a
b23a6d8411ac32a1d08294feb96f370f49efb7dc66437278d2aac44b772c9ef0
e66eb0f6dee033b2528c193f72b5974ac93d18d040c1deac33cc03c92e70b499
fd9851a22e63679151d12abe8c077f9a29b187cdd8ed3c3d24516c09dc1103db
df7c25a31bd87418f9ff86b82c2e6b4c2fbb04b17c9974d4e680075244641023
e3e9b583c5734c6baf903e67e4e223335ace8f9dc6d2ba2121ead210f92355cc
821e092e7338cf9e5e45ba054dae3afea2816b4bfc3b39d512b8ab056a79e7a3
1d9bb6466c7603e858bfbb08c0782ecbf0fdd61219b2a252248718816c3590e3
534cc1155a423506cbc4f6b4f09a34fc1c7ac513b485633cff3030ce09f0c2dd
848455ba5176d7bf422a0f7436fff9d6bde7c1b4b2f0c071f39959cd4ac72667
dc77cf7bab51e6cca12080fa9f0be68d47fbef64f676422e8c279ec93ddf6d8d
f7d51c80cce6c13fb6fc17d4859c509146acfe1a97022d17d4063fbb3dad1027
96e16f2da9b74551ae61e97dae9b7adf8163758c930905f42549a3bc1ddcebe3
d08d73902c9380235cf48205deb16872d8448467b6f328e7e2a1924a121ca893
a9c6204c0b45ff7028807e9bed996817e476d2cbf3d17d102e1797b2acceee2c
436c13902fc001c23b7a4efbe72dd42298eab028734ddb5723741548ff94f6ea
196a1dd5c4a7efef10992d01b13cdcd31fb2cb199005222a750563d12124de84
e5dc26c454a876599fdfba9e9dccd11277faaa6f1d4714e6b6e593d91e346b1c
15928fa73d7d3c8ab23cf26af16116c09173cca7718fb5ebd5f62244df741f6f
ae0be7e4a8b1a126f20af574d14dc455acaa7aa47a7138ac0bbdd8968693a76a
55b2ffd1a84dee82e6b7ea7fa2d1b25f047f59f989aa5b567dcc45f306092b4d
21d2926312955598b790d970d08db1fd098b3900b66a0ebc278123a83566f3a1
6d0f4bc4fbd5cff2ab44736e2b1273aec26f75e8526185a72d929f8f8b6dddb5
ab3d7cd6582f42b9e57fc9dc256759d5e4256076bd1ebed5da6756f120c93936
9704e6a49bbce66e13f4deac1e29c0b5a6fe48dee64b314e4267f5eafb06440d
60630dd7a5810009d92bd97045dbc903965b3a6c958412ede44cd0e460d3cb94
f65356f3167392f31273941adb1ad6e774c5c973a6c3abaccb4616b9c5dbfa72
f458e0d0649ffc509bcf9043c1484e4268e2471e8211e4188986f95744a0c77f
caa44649a5dfd24ec9e4cf9aef5815cc36ecc27cf78e392f415da04521a24301
85a37e738b98148ecb2833f0ab3476f7fce92ff07f0e46d2c39c151421c82e26
0f04c44056eb58c3d2288d2c40a55a8f9d3dd949503d8474caa9c60c2864ac24
3bc4cff0f919607f5cb038b089185956db73f411b908e89a0bb92a41a3f3e5c3
c1f473db103c7a9ac74ad70e27e1d7365683f0f9a5e309728ac54a38c7189f9d
7446f1b436fa23f1fed7fb9c5f82e9369678f31eba5913868e965ae0d1027830
030d2b06c01e3a06770901188b78e1a4dd73b1a7e59063888a5c993d24263614
7186e85254806a302a9f7ea3aff602c9744690d662dd2d1c87f9b84d108118cf
e9e3c39c847ae1602af1ec43c174b67075fe1b63c674788721b0b48d87ea02cf
5fc613f60730ca096b012ab30bf3cb7dca998ab68e87cc685839f1596213f0d1
9afaefaa590319de1df2334768b50f2c607a4e11f754103515ca846d961fc07e
6fd444ec64aaf3221416a929639eac2b064f5958e065e425326abeb186cdccc5
d4bd8c6ddbe3383430dc5fbe66546789e7c189e218ce130b0e34063f586818cf
ac4965aa222339f3fce6f7abaad151dc7f7f529052a5ec867de0d04b13b6f41e
c616d8e8e448bc5f60ebc06f4df7697aa330d28665840ac38dad2eaca41eb3a3
160869dc7fc8a6e4d0c2490e7b312f65f74a9ebc92cd19958be9331ada1b96da
4e0d67d5c1cfc52db84085e81c5d36442dac1925ff5cbf59e719ffaf5b715889
f9dce6dddf06f2974de443f74da30a2b35352f2ea86649c4358a24ec4754545e
5f5f28ec62af92aa634f69afce12900ed1d60301217474493e39c1c2dd6c8394
7de1c379ad2dc2e026e718d47b5599e6da4633f3facdbc4561137a3921347131
21c6b9a2120b74b22bc5d0208975329ddb15b1805123112d59900e3b88fa149c
0b9f34bd1ed128b75dab750b52871b33197767dd21cfffa76700d2cad8a173ca
ed046ea16155b68e5a4a0213ca859b1928c26b2058e69d6ae1bf4f252db44643
474738ab1fe4c709d25ac35981b579dbd5d6722e72698112862cd3974ac58bb8
6bf3c7c7c6c88da4595ea2d821c40d265b7c38cddcbbd63c1ebb6dcb39635f9e
73f4be6eb1ae495ac40bd087d7d0b4afb7850874bba11bfd11ceefbd36fc9e26
8c4d4cd7f51d3f38bcb0846b2b47bfee3d63317b8c7db554dac6833db156228c
a1e88dc65edd21228e71b5e93f5a037bbcc2e3032e2906ec452035120c2d69bc
d633dfc8b8afb6b0e28e54daf0a6334327b11c325f953a2a5434007a44b68b25
0f67af098a96b69beaa87e2c17798b4c87a95eb4022b51228ac957d4ec3b1c70
7f7c6044225db5be308e760c5e1ddc9a46415b51e8fa7e0cdbe23981cbd68f8e
0de9f3743c6556ba1468e723606aa4df0649331499761266ab8b1e5ac1166582
8f4ef9abab1b53a8ef51f96a37a25aac6897f0f2465241a51c6724358d220f41
a37c51b91ed02807c0b5f65d0bed027d0ba4279546e670ecdef864de09ac4312
8214589ef44ddaf1cb03545e8cf24af631e1f26109780f56259ba317bfdd696a
90c28e21e08bf88c777b6dbdaeec0e46137e006bce9fd1f81403d3d75f523f7e
65248492903417203c5799e79c56ab85a8a2c6f67d3f253caab00f5e8c08e959
2793d74dd84ee45e4d3ee405566c98133bbb20c83a94f148f85a4fdb8a52e43d
97a7d0348b149a34f4d677316694d2a70a9bef012bda9c7fc014a31516eedb44
8e6a20c9ec2ae8788e2ce7ad8a5c257c22bc6d83ae5228eb664ec4546c0f7fe0
ee7e434b6a428e3dcacd516b46ec0777953e6a7d1637c8793c7a70a383f6337b
b358db7323a317bf26257b0a185abbb24b309da45bae6d2c45ef213e0272a3cc
2ee957cbb29694b3dba20ff97d32b68d3d7e02a70cd0a107a9da3f0b6c5b538f
571807e9240236fbdfb92d7860462197a19a19944b437b142644346e648be33c
a6184f599597ae3b4b913dc29c8984a810d450f1f1416c3686718ee6e6b306a6
3a28354acd88a4fa87d6b6b4295b782e9c39c31473230c49299a2781d11b0427
c4c4c525178a5d63d8b80d1de4b0d16e821cafa55117a8c91784fc3455b9bc53
65fd99c4e94087141b411cc00fbf7cb76ec2e61d88a6b1407c0ba7cfedf67747
2f53a84bdcae063bc0cd717fa7594685764993d556f9b97367a150cda71f18dd
dbf660cef280f58f47ad5758f9e8d422e6640668a4d07f59135eee5266fb87be
dd56bfaa19e2de59b11dca789fec8678910f67fb38217555691416100aaf9b8e
55bf0dc6616ed931bcfb249ac39388838b7e06a1597ace6f466c8bc09ceb7214
2ecf6a7c24ccda0c9d6a1574aab79e0386d2ef0242c23d31be03d4cfffbd4ee0
6018041ed75f1ab1354ebe9dccc6e5c9a1bddfb77a569a59af7ae394cb9a895d
5b86d0fa06a81f3d33b860ef2e77e52e2a602d7d0be993aabacab3dc4ed76069
c18d25071db60fd48f2b3f49529ff080b6a7680726b50995bb3110746e1dd462
c9d4689f2a4ca8fc8950f92028363862ba02a12ce681a5447abe9ba567be64bd
778ac7942dcf66ce64aa03686b82f981b074670acbfbdd9cbac835fb25af8002
b7cb99f3dca2d0457dd1f9bf33ee3455c90fc7d32333db9af6d6e7ff7186ddad
738bd0b5f8e22905a5eb2d5bc34a4fe6c6bccdef95f7c8d166795299d8aa1e02
cbf586402fb1143843ad214b8fa2d7424a5ea30c1c0995ba05d84141b58ce693
09b7b06c1265a5c89353a3bc4cacb26d1f888feecb946a17c31763138c9f93f4
baa54bf8ca0807452952912a73b425e3496440b041573d5075f9c87dddbbb9a5
138a78430ee47ee1af2b40bb5c2ec67b9522a01520c55551afbc52d6713a71c3
0a066d4d9df44601a3cd694dd84d7f743f97fca6cfdf4cd781220145a61a2b04
c7709d3c6de1d0665780b32943f9b1f10423ca73f2627cc48787668ac26e5d68
be7df86a7a7751510c1be4543328a033315f57ee05f9a96e12c57f6d8c6e12f9
6dfd3b3c6af97d088d87137a62ebd906b431a888d474f5921e23b2875503821c
137558226f3b9f20983597d0219234473f072258ec2b7408a1a0a9342c0852f9
0a86446a5c860f0e6b018ddf6ccd76972e229635de692ca2d8878ebcd57fae3f
1d954e023a7eff28281a4c19921e2f966334274c8afaecb91e0bc748ad24c368
4dd75f6203fe6e9871c77deaeb61ba866008e25054cb4add093f19425a3a9c7c
709620647df71004103568d54e1b12d95aee16a0ccc0d34b015003420a39afe7
d8e5322189ad5d6112dbfda6b8fbecb0b0800e34eb542e85de5479cfacc99b69
5563aa95b21d03cbd94a018c173bfcd7ee4ed535eca04dc415243e840f2bbff2
25d48834e85ae5b93780d1af82c93b5cd628ff7983e2d51ddea50bfbdf10f869
60baac28b614d67c426162684be2d2142dc44f67e746356707756e9ab19a9278
ca88d1dc3a0e92a9bfdf3a5833343c28771c08fdcfa40b37f36fa11fca94130a
91e7d8dcc55bdc25b746f3987f17787b388baf92428f7503741160814fd90868
240edf67ad2fd4f1fe866ca04e200ee104cb2405f7531d31df1bfdd2ef632224
ed3d2c90436ea49f44995acdecdf610ee8924079f247fe67c841805b4a3777e5
0c58409ca3d79eb4c73f165bd65e9d07fa458184311ab4d733884aa31456be6a
b03a12920d54a0e4b718cdd796674fc3b3f53122aef40d8959aac75023826669
7886789162d0b8afef75af0eea969aa765d72991685b401014802208a23bd093
465923d4321018cf3c3fd9a0626a314abf24c894842013ef81afbe3d2c3f04e4
43017dd73196b59c3c0bc61cbb73311fe979a6dc2e6fa072216007598de168a3
0c2ec368497cdcc5ccccf642a2fbc529d2a6e64f4d479a267d127477b34d8689
e78ec2670aa3c95d071272a384f69afc5383b890e0935c3fdf2932d764d441e5
325923f56390ecda16d53e3bb3c531ec1e992c833d241f5304611dfce59b0602
d5b6c141426565cd31695891f5bb037f45d485d229c16205b003525e39622f6a
a3fdcf1cb4485832a1dff39e84e007806d23de8dd9ab17e18ec4698badb21166
8664653d52c4a37f2876eadc9c110590d44199e74875c44af8962b7a2feadbdd
71115529e8c9f2a6adbcb0713c60412abf74d6d59eb1b88c4263e7584ddc4299
1ee07c7c6282887409ac6976b045df5292aac30d83f1c19e4dedd4dd90e93661
0691b0788f29d59aec16f147710e7526d9564976efa332891de220be64af2c81
49b050a4e834adc8d59299ffc7d4837623dddfbab445089b4785dfbb5ed1f47b
f97dca589b6d43a2c1ec098ae536564d0f930af6532dde652c129b4c5acdc843
b4c0d0bed839d37bcff0347b1383e95afdb71ca61acc749eeb2f166ea348276f
78bacfecb211da74c9b1c20ae8a97060fe0e4b90f3457bb93349c6fada1b0a71
ec950b54ecb575b76c352326b3462e8ce84e2570e83c6bd407bd589a84aafb87
56d217a4a8ddaced4bb1fbd734563701ef7bd4586cbd29b923e4bf4dcd08d7df
f2680dc02f2474d75a467d7862ed2382e8e97b811df74d1c0e588af02ba99774
d7613ebb17b5a4172027b52d88b96b37c632f3211d52840921b9157af132d408
3a140f532b5348bce144791115cf2fda93eb1d086a9c134ecf46b7f089bba313
b11f66f6a681fc7426aabfebd28b9dccaf4174bf8f6c49a8cdeec6abdeced9ff
42fb8f63490e06ee3758db2c134449cebcb20efceb49e20c46df224302f75213
fc138321ba5a99f0efcb4d3bb6a772c57f8b40218355c655ef198041398e6be4
7b6594d8a1647186b6a3398b7dbe166caabec965f6efbf6658643ef852a217bd
7ae4504e3c3339ad3991830818b8b1fab87855232b8cfd9b38da2a5d22a197d9
5d88600fd6147340baa98fc5ba07b60c913cd444fd0d4faf24f5895a6f2f747c
cbd57106c11aadc7673c048876d6743a6f7f1ce6edf75d602487c56b6755262f
3db8752d1f354d7eef54a2d5c80506b1c6eeedf20f9732acef228caea5e2096b
45e39439f8f8aafd06d89ce071c38b16ca6360ce7f44e1fbf45656d9726328f5
8b1812f2b933c1da5f5769a1977562bc4c4e5922e83f43b9a3b21b10e7f037e3
ebea76b72b6437ccba2c8bb1a24020b5b54329921b09ab8bb08b6e6d39db9eee
d93783d0f146d480009e5caf01f7db43da2a03d38e2b5f6ff8f987f859c53dcc
7232662b995e9dce961133a640997b383c493caff36fb56af22c4418a499d479
fc6618fedbaa8e8cf54bd1d1be9d29a789d0eb119ceaa5aa98a26d2a852a6aaa
2def9f49ac2be0a25176b04c4b13628da5c1c3aac8562e9b653332c1c000d57c
e2fd0349a73eb126116e0deb546a0c582829e03b5ec01132dd4a85de18bd7b28
0b44b3fea78da4aabe95d00d2258b6e71fc09c5423beea4407646aa4cda86233
254c66a19ed9dd921ba4ce11c7e02f8fd475919865887d624cd9206dd56561af
af3bb93bd91900bf9dd8dd8ea738c4c4519c0c1451fad84b1029c7e5a955a212
3a583f231cffb9c0e76d3f8e2eefb3a5e60494389ed656907e2c6f02a7951f59
14bf6f379c75c5cfd1b380518839883d8e5f3585722098bd1abf37692d14dce5
84ca97cad81b9fe834daea590241fdc94abf973094186de4cb70c9f08ec92d51
43f4ca684f848f7db80e80ffa661e68bb1d2c2fd7cf0a2adad234896bca8b25e
680bd6d26c189f8f8e2e0a84d556277745a8936323a73a89978c396681442514
e905207b1e35ca7663a08c827933fceba994d7c7e37728c0442b9340734f5c52
d6ff465ba039d6bbc846dd14d52b9095df753d252f19ff35d4ab222ec0937fca
bdb9c386c5d52605ed35b936c575c9f49120b5b657b422c9ae7da87d21fa407e
e53791e30630b876c5213589314daace5c70d1a8bef0dad54fe00146acfcb92c
5106fe25c6b7232ae2606eb8481728bdf66f9c5f178009a679dc199967313993
3b67a24ef54bea396a01613114970967277027f2a5e8a9c1b87dec9c2f0c1d81
6638f3b5c4a1f236728cd2b8ae782958df6631c5f37003f585e002516cc8ecba
1193b7a2eb55daa6fe629132656d168059cc29ab5b0a366188d13aa7ec0759e3
1e1af8739bd56ced859b5dff0c09ca204b2a9657d440f76b670bca203ad18a6a
b27bb6b3b2359367834d32ddddbbe4a23795961e67da050f5db8f975d53ded99
16cb5a45b8fa3c3912bd464b680fcb85c978efc3a1ec9eee10d7c897b04036d7
522163c8f01299ce0aadb7b940a8bea7fc84b07b4f39472697325c3755bea8b5
0cd5b22d611912906151173a2427001b6fc2ae1931729a33e654d06b6985f778
140cc1c21c3f4ca3e5353eb509f3309cbf78344d77e3dc4743677b08540db4a8
8232aed9e3c89596e9713ee744899a38f03ff759362334de4de9b446f286a43c
b80d783ee925906aca537c2d30b6d8a459bf198417e687abea747aa4f2f9ef3b
f2a05829f907b58a861b3b5a84c3a749ed1bc5dd3793722977c96477f17e1d12
61c3691dbbf8e36437fb00fdc9e5bb04e15f17be4d3ab71059e1d1509627b0d4
05091ed6bc78d088cc017c623788322c31cdd83214b1e0d0a02be3a97e59b607
2646785984d294ef902a1d3026c027ac2fd4e9ed20d45f54257dc98fdffeae95
ec02cd768dd9d9a5ba809b9460e3ac8411faa8ade6d189d64874a81ad150f7a7
ba507b82dbe856a07da988e867a273318483fa8518052b0d6c270091b0722b1a
c57bb9ce24446c9ca0b914f8512d51ddba4149909610fc7008837cbfb4c87f82
0e2cdf8a97a1464ac6ef9694e7c4d10ff073e5e6c73e26149c4f54df3021e6f3
481aaa64c90b7465c4585598fe883a27a7d430b293975cbd9203ed018ce45e39
a57913c84c04ba6ff65e7b3715e40aa41d47d24a80dc14d48204b797e43f2c48
d65a61ffaa0a6a5edd78130bf978d251766e12130381bc7f4b49e7d2d6143ae8
364406f26d728080ee32900ff6d3d872f660b79c7550045112d3a1c3423ac6aa
e1f6915d71bab21afdda23c2bcfc188967eb07974b2555764af1e63d907f5638
436792938f54a2d66c211771ae132395bf49d05f99ba64c39367713d0cfb0b39
2ff2e2af68684dcb7d527424e87a56a7aa4fda6e35a986454b471a9fea6399ae
40de20844e9203732faa37c98590f0808e272c31bbb0b293bcce28c30618e5fe
16d52c3e3089a8e554323dccb08dad82b14db40d0e56c327c6e0906fdc3ed41e
2f592b39af6e25efa81f1d9205da1480af9c4cc34c22de4b61847ab0e92b16a3
c4fe08477419429ba18699e5e60fd76bd838616a3c4c7d568a27adf543878a99
01bcccb352ed4310fa9590873f66d1238013d1867ea7ed3cba2dc68c5624ee08
a525c2d1145a4e5643086c1079e93ad798df17bcba1525ac953779085f12566b
ac91a0c801504fd43b5a7d181cb5ba9ef160c7878f669de7c0b13f6c090f6bf6
e55555e369cb8b90abc6db22dd994738fd92d892f9ff4e729f7934372013bbca
14b37563a73ec29a1fb4e443e7d814b3a008bb4207a02860d9acb71e667f4e83
ae0420b693e272517486bce77c60ec63f0afb005077ae993690af2c58fc67cf9
434777a236dea7c76fc10637f94d7833eddafde391c5071902c4d25986095b8d
43332fd41c1c7c23fc477c783a8f8369db13b36ae792e115e096e36cca8a383c
64071f8b8c3ca4b489c5096ca20764b03ecb011ca3d627e8933f247efc58e236
4f9a0278375735b138ee1ac40bca5724aaf1ab3e1d0b878642b785a71d493e9a
b23c58919a5fd7a4dfb051b181f0a470396b87b6d2b1ad2e3651b0ef7de1e70b
6b3d8894fbf17c126305f037c325843f2b79e43e40491eb874798fd139efe754
c2cbcee3edd0383fcf7e990570d7daf79a5c169187ff32256fcb0e2bfb9d530f
7408c3c9d74740412c9db845b738439de8c1494b1bd3d10a7976fa49c227463e
3a6ed51e8f8922d30cfa4af9eaebbf49f765b684fe433b04eb3cade09d26059d
2651e61797b185fb783e495da71badfff845b6be634240bd964b921c4d732f24
bef244a8257431e0e4ba83d2bd436f6e82ab17b5e965ab54502a5d90ab7a6e29
6a751324a15acf9002a11de98d02c1cd3b39ae37b5bb47b755311b9a1efe1580
77511d55640cac5addad1f538e4dc7a7a918c8d646bfacdc8e116e8cb4c46870
7cbbd55062e7df4ccbe92fb13fb2a900562b178f594377b26a2f8c4776e9c192
a4ba44d58b6030cb17aec59fd59ad94e9c6f40a0d1715e064c20768639c0f11c
6c95b6a24a446452343b5ee7c061ce6f34f78491874e4222033af4124ddfc641
cc9b6d13c3bf85302a5ce11064cade150f9a052d89c0feccb904d39375a41318
b368bcd6e750de7f60b29b18fff4cad40f3245f90ece94193fc4844c0dd07eca
aedb8f58a064c0e7a2dfa0f0d6e38aaceef2454f19953a23b51c88273a7b6ace
64c3965f146b2923804b3fd3d53096ee3da3b188b53395c6a59e4dba2d3ad540
d4578a31c81eb6e36dba3e5e18dffe15e7d4b71b47052029b7b6a97dfd615eaf
edaa67a2dcb6be354c94a3412389a387c6b6dbaaa0f59ee9772e836cf3da2487
636b6fbb279235debd8642b25f87f38992a930330b8208d92eb7b71f87e82a83
3c22934d15c2bc759e96d506bdc3e7bd95d54d88ce77a7b89656bb3f1ce47f8f
d9af598644c91662621fb50fc1f85691af870c0cd8cdddb563cc7b192298918b
b4ea0522e5a29fb0865949b75220b0f2cda3367d0a042414ba6981fee4798db7
c6c5f9994bf6f1225c4e503bd2f4986cad4a340e4c81d94f18da4724a0fd50c1
277c8529bfe25e835f3ae06b1298a5df0b02abdb7a5cf9b936e2b9ebda9018eb
b39bfa30ad33d0695c1f5227edf2a8b2820b3708dc0878eceb583c4e5867ca69
c9d2f6bfc69000ccd21f56523157425f56e82c20a4040a1ba02875cc1a5362b6
ad86275615f7e9854ca5c6c32d027a3e7f934539b167a8567f6b72897c90682f
782e955dbe5cbc9759b8aa8ec9b2dd2c6d89e33774fa652a9cff5a282e45df2d
ccf5722aecbc5dc545e850946b47c4b7b9ee4a03a44fd4f49a6fc69ff6795a31
362f01364893350e165c8ea5aacb3a4bde3cc5a6170a06d0fa0ef2f81665565e
873b418323ff1496b2f5026cb32859b8afdaad425d718cc38e5826412fc0b9f7
27c402a72ccdab51d1d97467802a94b4b6f045dc04a3098a970f07bb794191ba
53c42066d3b91c594432900eaf877f89d4cb881a325150a4611d6f2082a40903
182dd07e3b8a67c9bc47a6a8de369f39d2dba5d8ae37da7bf8a0bb728a7eb331
eb4cc322e6490925d4c766787509f5073d3e66231499429482948e60f247f084
e754816f7a7681ea75846c12ad2ceed86be873e3ec17102e7d3b99e5fb65f21f
2d29d99e11bbca86255dd1615ba2afe476b08083fe754027e85462cedd66f522
5414a1fb3935887d0da9ddf4ee025d3c07f5b261ab469c816b706f0c2401314d
7c30b742b041b8bcb1fc415c9c4ba1c3d400d6b156bea3ec266a02b8b24128b5
a9ff6e8e9675756816c13158563165ec9f33574495ed05dba7a601056b0fc19c
15a1e54c7876ab55f2a1a2bc6783fec3062bfcb74f41f6dc7239c444073221e4
e25fd7aa1b951cd6c65b16feea627404418091422b4880deaebf1b1b74a928e5
e087d37360ac44d97414827a9b7b6c060bf46505003607d2ab6d0198b1b9624f
d34a6449649c711dfe5e1f9ab702f6e2e612bb49dd82a01874bd5b1322bf0ac1
9c142b3ca7df3224ce2e0c2d2d7ac0e82667a7d110df02a44e7a65217ddaa31e
ecdbffe237b85e71bb6373806704690b595dddb07d84123380ea9caa5d10faa8
4d61f868724a6bea3e7a37846f485236f74f5cf10d280c836119ac9a94e4bad8
fb979b977b329540b96478ad6300b300ba275f25ced597eaa817980dbf20b72c
c2d687efb04cb2b3a6637e8fa39c617d347ac8153d760f2f59bf111d8f933f38
01b7cb6d2de2c033f104ae6beac9efdef563baa6ca9512d109a2436fdc2fd623
2d922942d3617eaf92ea78fd6596ba536910c61fe87a57a5a8c6b93513d4fb92
246d42d6f77734aeb549ec9a667d931c00afc7cc693bd5fda7d4d953fa37536b
17a5f026680db05f2d4dd6a3627e5708dbc1afc2050da701b1ec81f1bfdb68b9
65ffdeafbca999f45f47b40be18f3e7c58ec15c5cff4bbfdcd190a1889e27a8c
1b9e80e126f83fdd520861fda30182d767d7a65c75be325fdad27105b3fa1f6e
b0f6e947a8d687c8e752119346db98b9f4664d7ef7b34bca3c72288a94818db2
3ff5f75c5659a201c6369210b8fcf8ea0f6bf54ed3ad3a2732639ba75153364b
a239e6257150dec80d9d40c9ca632dfcbdf2285960e9f17859c65c2e5c5847e0
8c8994b47c13759f70a74a77d13858e427fc0906beded3c34aea59c9c7400271
c96eedb95edd77c96cd87077dd4fdf62efe201a6210e6029586ea6a3496c9a20
5c150656383fab2391c4f3a19b15962779be5075fccba9202194ae8bb0f95544
54955a0d371402c1ed77da343e05f1ac135e983a8355b540d254ff464a154f11
441152501d822e9aa41e2798d6237e03b12fd80e1472f9cd58a3de175c8e693d
45b5c43de816226210deec44f64e65b241ce2903a09b50d6f045222619f8aadb
c73e87b7c319573321f8417d62b8c457a50c532d17d5e1f71d38077a3c373529
658d40ade13f684288f198ce7ca6d42bebd7a416e41ed78c354fca753240d53e
a9ca7ced5a297c33530575e3b78253d4b22b56b5ec1c57bea8f5bed0c669a350
8f7b5df06b8118ced9bc25f8c74c9d88852c9697c1003b888f140ee3d53f22be
7b8d2e99635bf5a07c91851dcdff31aa69e014f56bc9b4468110cbdc55cd5989
560cd4e0e4c951c1cee26a8ddf8c020fe76540ce13991dba10e0e348622c8c09
d731c4d463a1e113b1a5f256079b1d9eda03efc92a75f81d1089538dc95a3e09
97c012e2aaa5ebb4c2bd033b4f687bdb07dfc9cec72bb0ad85f7843cae817071
f1a1c18746a5204a9c21ef3e08f65815a82196225b907e62f1803a30875d05f0
d977687926040d26da1be397c53a3b894e2f2a42574180b900b94b130d18171c
4d38ab462bd23198bb7dacb76e2c2206429e50b637d2c367104f23462485c0c3
37bf1b71bf87271b5db1c4ca5d50fdd0a8d57f1b781182131a58ef8ff9141aa1
a532067e9f7434860b3b7267b08125e38099e1788932f375075e4b3b42b18472
92550607d20d40b5fb705d7e57b0406a0eb9a2eeb4d25d1e24efc0091870d9d1
c20fae0f60b2b01f46fbe082bd066a504ba734f65891aa180198e508e25e80e3
66ce6c1e59133c154187a12b259d32bff4c44fc929ba231c3dbace69e2d34bbd
8885be7993c6917e86e88aa9e747dd4c920c7260e32a22ab49fa6abcb1ce38f8
d375f7d3987ed59038cea4efc577b4bef8e07ae3e81537a3196f6ed559f53cc3
e540708d58b13ebfc1964c2d01d123a2cc274f3d16c08b04ed6ac7324c7fd0cb
5ffdceda8d2967dd5f05a7b6c95ef0c98ebefc8db716ed0fe5ada2f8fe5a9f5a
22682c5a97e5bab24b5ff1f50afe9c7e6adde9428f2b56c0f24cdf6e90c13bdf
3942a08687625a9da70425af766382b23ec95918c64075ef102010130c230e12
7ca8a2dc3ea560b78d023cffc12571866a43a8daff7e65f61c75477d4a4fd9fc
b39621ed831266454f1ca53dad3c49f1d1311ba828f0639f64204bc3309b58bb
761ebf69ec88a8b520667f158636afe49c3fb3ae2884bd3cfd244f089800d871
ec6875e31c01558945155906ebb64d0c30742c81ce1c42980f8a3388281d340d
8b6a6eceb75f314035e6a63ae3a2815890890374d41761c565fcfb1bac53f2b0
71b9d7bd56a346f118da924882ea753ff91cfb76ed522d4f24b10e228e9a1170
b1bb88b4643e1c9882ea8255b326c2a708488e164ef8fbe9eb03372b75ea4f2c
91c9955ca4cc9eac844af836dab12c56c7a6b822b6c4316357ec806e3f57ef5d
93b2b66a18af6409c97ffe0f14d7bf0e88e891008e2c587e14a1f1b24ae215f9
709c9650263e04753d988012c4c4a9d5b2ccdc76e57e0ab0047449a97ecc1c38
08868c5376faa09e2cf59e9650c14502a29b0bc1de5b9e4b0078fa036836a174
dd75f87b1c22c76e3e4448f148da27838f65f5ff96a492ce07b0e2e4852d8ea7
bb2fb628f604ff2088d68f746c037df4cf107e5b078fa44299c082d001ddf56d
a6077e70e4f873076d5947477f262b59f8c24fbf6d785552f1a05ce7c25664e2
32a0469c62e4d3e379a56072979bb16b362cba978699e5a8ec43d2aeb6565366
1e405a6184f8a556fd3c1740155bbb4363939255c52c1b12c0decb4da302a34b
b36432bd647595f785972b3258e1849e4adea00461f525b72a363e59e13c146a
5f49cd7b16262ec251119bdc9dbc7e2f34eb0a3aac906991f81f8f770cfbd4b1
b7e47622bd49ce453cf2f643016b6026d86a5266d49f7d3eacfb39b8390e1d6a
145a5ace0bda59ab2e896ed74948edc581b0dc012c21e0d468ef1c0f0d819fb1
8642d76add68c26b71b4f5a2a4fbb8cb340319f862771b92efbefa2194008d96
b38b8538f1cc0afdf9cb2e15fb9eaf96751888b77d81421e4b9158b8ea132088
7e39572f465ebf71a4f1990c454280f15b472ec492ea9ae57504503ae1c9b3bf
5c2529283e2989da4d524635416dc50f62f44d45dc279016fb3bd65e59fb542c
1589040d4bd9a28acb27b117a4e9bffe0452507eeabde439ac4e868ec92e626f
6651daae7d73dbbac45732b689aa7cd66275f75ac9971d9b9317239cb387428d
1f5b46ccc46f1d1c1616e1c65b727ff74ec859dc01959d9586cc2b4d80dc367b
140eb4a0207943d080066c51c2df443161194ba39d43dc57e8da88e1a3ec9379
4ac8000f46514299fbafe43c7212db107174a0f006cc3a97d8de9018d3573622
43106f14d82267aabb9adf299c119d0ecf326106c19fedd7860ea9556a7b8506
69300d0e1cc2d8bc2fc2656d2bb138eee763fa879600e8bfa5e509efcd7d0c7d
200351ad074dc9499408e8b6787efc5a08d1b6a1412718baf5f1fd9ade0cc361
cc64b5e0adede4a60d14e6718ed261e65df61e9f9b67091598a59680c1274519
f763b4bdaa6d53f9de8aa121ac66ec7d886367e977d10046c42055c7ae460de2
d3f13b8840db0dbc7f7572599d47251458b5032e953b4796f720419db1b6f64b
b59f5fba87d6e410d1e70c108964e2c97ee915920cbc1760a91e9564f49c323a
3fd9a657451e327f123e502d0af085a472382bd64e6e1218cd5def031f57bf3d
26ff59cf7ffa41aed1942dfc9ade078590f0a4df37584b416e8a9d95e67eac76
bf7dd5a3fb1dba0335e83ce2319ecbb5899a9b1a983c079696950d962df5eba3
b445be5e3281d8b1f6f9adc026449e5ce635c6482d888ab77f750c44b5f40e43
ad06f005da5e8ec062b3e8759a709c51c31ee99c710d881d85f5babd582e50ea
bcd845f3cf6d8b003f65c3166525d933b13a204333c70a7ceb7118d07e28b204
d98461e4fc469cecbbc3c2c5ab3867e948b268ab22c0f6d85f40981da7e776a2
903fb243a7e7e189fcc2245bbc206daadd300829642125a14003e5590e4b37c8
dc3c74f844566def7db8e6d3b36d3e938d5b2ef20b954dbc7ec5d5d995c5f745
c944b5fd77e9044598a5a37dc03a4ebf6068cf18b0a286b537b7758f3a98ff49
4b8153daabf36a968847c294bb72131f46fe43e315f101f8d39994f17f18c14c
c4bb285eb77bf0caaaa6c0e9a6dd1e13a76150d37514a783b43307c54be1b8e8
8e4bdbbe27a936612c2d2ffabe24ab5985eb4c327528bb1f806ce00ff0bd6e28
813346a0140f31491a8f6e110e3bf41bbfa3a4eccb84c3955d2f153a10b8c54e
9307f5a33d3d076f10602c7e3a2b400109c59a557cc4c8eddc05accb7f276414
7af2c6b5c4da69863d1741cae10be0fe0f0a9f4a7b91623465a2c213cb131116
bfc57a60265bc6b9aec3c3a0f734d342139e2bdd765b6fdbc5e50494b8f9e1f2
5d555559987fd9db823c1c09e282afbaec148ab42bbd82d708470be7707382fd
8d89c4fe9ad754befb2580be9e838985f69cdb4324f3c083518b4c894371d8de
9dab61f107ea1950a96f6f6d1870c44804d617ea948e58258fef096a0c9282f6
530cd6930c8fde8a39fd7f04abf987b8c264106d89e9e81942c9192e7bb95b1e
fcd3435fdd1c32f6251eb41ec12dd5f8da0c93d06b4179d0d698000ee44e92ba
33cc2e46b2789d522f96b4ea50dcaea2bc4b71005bc062b5ccc844116da5351d
17fecaca30e0f61301fd3a42e1f488fc63402e2247d7256c25abc623448ee1d9
2cea7dec7e08776b47fdf7c5293092abdbffb27963e5e2ba7f7d9c124d14aaa8
3937826d7efbe57ac975712473993a96201d29cfc0c05bec3235f15e6cf73d59
9ad26bfeb53cf47de827fa7de09bf740db9912660f674363c3be5b7633167223
ee231a9e6b1cd214809c2191528bc8e6b38220a83c269924139fb27057984ca6
0aa024ce96786c781361a1cb27890107de268e1200633edaadc040371bea7c95
50aa649d296e439268fea231723c8c68674e35057e6b55a4e7362f52a593078e
a8715213618243e44f11adcdb8b85c239b66cf07ae46fce5285f258b44666533
afa9f3ec2114d4f00ed582f05d88cf1b4d2aa0b774dc91ffbe6e0a2404126928
cfc82975cf290449bbb84a87712030f84659f36ef60564c236570e67017e7bd4
db059afa2ce6ae83671dc0e696a445180d964cb90f19f7d5e95c93d59eb8c445
a4b12fc26f9252c95070fed56a8c1be89e178a1489545187a10596e050d55bec
fc199592b819b487fc88b5aac2006e49246127ec04859b6c25b7c1451e598b55
2de33f70b669a26741262c594bd0e0db45a7d194fafde946f7c7cc78653ce925
58d2ded27c719c49bd954f377fd07aef6c8311f6d30129ae2b72fb99af54594e
95ad4f441f44142204688b72d00a02c5094aa68856badaa6cca2a2beb7efb394
795d8dcfc0bd64d7375d1979411383365a49a7460ba7857ed4e0b1183b433f7d
32051e93885476f2f07cbacb5b77ac6c823898db24dee267407d3e91b17f13c9
5786778e498c6ba8344e4e65bf65dbf0e333082e5d149640f2e602afa454fd51
60d222c5a45c308143a99b10d1e78b83217b25eb122cf5e3af4472118dff034e
5ded3d83c69d223d2fd5adc8e8b87f034dc7ca5d59442e28855d617296bc8aaf
d4f1cc9e72579c076723696ed84c02c203acfb359843e156ffd1601645d505c5
331849605573e7bb104d432af91a54f2701fa6ad99e8bea8fed85a082e114dc4
962c109f1c17f21f02dfcc67197f366089aa0b5253046d9ed63618b038469784
ce0770c4feb342ac6179418963e7bb2b3213846a9a6e0b532d69abf3571a2d90
134c4718ccbd600e89b3038570e64c20f9c9b1738b9c9d9d841033b3ac634b9b
6586f4adcfea701745a4be223bec1c87e455b5155379030b1358f60c266135b7
bdc2bc334de79ec59882f2017fd46e831626c6b7df49a916cc52effcfe0effcc
59dbd668d82d7bc7e94ac2b61f5acc796923249ad445818288754d469df93df3
88b74dfdbd32dc2648c327ffde29d0baf30c0cb1b3673d112898e25b97a27a09
15499e1f4c0000a2f9676f163aa63d7baa622876e81b41e46ec095fc309d022e
7c912f71310bddaf215bb6827e2f1ae04e9467e648d79a9acd4577c9bbf5c648
46e1f20b455ceebb5945ae3e6cbc6a0259d3857031318af426efc9e648e28f48
bd1864e0533c49701f4607cefe80cc20b67c90a6bbfa2b553cdee2a6bbd92b22
41639cf69411f5551c1c0f8d22cc64496d126abcef1a5b3ff2998e1377c70373
c44e4082688b73ab4c87ef408ef6aac23e137917dbed8c31577b3aec21c1f365
6115b95e84b12b237c3f10fffefc5f08dbf91c0fc3820ad674e5ec69ffaee780
0673acc88e60b5b59d637fb36b7acc545e670a1184a4f73d87818a894dd27c68
83ef8afe34fb4c1ebd143ae81efd17c7953942d80a7ed69646da518060cc6481
cfd281ac6d3e760f68e108921a417bda8266d59761e4cad22a49712d79205cd7
db35b3b8f46ca409ccc27579758cc59de8b31b31e671c1fd9dd57e0c5358d68e
e587c4a31456c9cef60c546e693c703935b5906925279de926a23e8c08b7605c
562ad12f9fabee529efb2fe3ce37ebf6389eda1f6f16252c527a7dc26d4f4795
9f44f7dd17eef4346f66ded7d48d6e7fb54e0599cb130b3b130cae9098b6c8f8
cb439e585538a8479bcaa2aa232b67b5f8eaec118f5327cf75bf3d85823c040c
978f59e58660d4cb8c7e0d08dabbea16e9d0a2ba3ad893f260740f533e8d3271
759637e4a935839cf0b77e754ffee8054181053e3d419ea9d1f1218b56835e8a
09815f5531fd8061323228f7a47e374753920db6eeab3247732f6f86a95f29d7
863de4a5f2855cfa2b6ea04775f8e72992ec6a992f340dd71f99dbbea8375aa3
2dbf68bfb67626aa332c1a52f494ba7a290f1f6058728bf317f19614925683a5
a087ff31b3418ba39d5c3758ab66957f5f8765e6bb2aef6050e7a29d61f158a1
9bdb8ab5896aa22465dbe5ba044b5774abce906cd3fa7e6d9c0fde9c728cb8c2
ec79b50330db677d8f6f6d91e05f40b5a0f9b2070d839379866e84a4600867d6
68198681684f9cb178fc833a4b2df4a21e1a076fa7f1a91175e8ab37672652ce
5bcdc3c49c916470991ddfd54a50ee4fba654da350df67afb63a212355c78833
e575cb6c3df2dd21cb983dbde6ae99bd907a36c75baf3541037be7670622d091
8c91762928ee2da2b38bbf8ad521081446a63c492bf57ee91562b1d40969707b
18ddc920bbd57a1779eb1294da9c643b6c33ed5977abd4882328cdc3026def37
e38c19981161d8f2d5debd2ec05658bbaac1b012d9d4eac4af9bb470b06546e7
accaae09aaed4ca145aebc5d2ae250415e96955741d81b38bd520bb5f6901419
d1296afeb278b33223f6292835d43a1234117fc78a311ed96164876eae2ad1d7
e919499a720503c65bfad25f82e2aff6d57bf76f6eb14ed648574b7fd8eecbc5
97533030a634ee514acf43b7f4e797f27bbdb007a9731cfca3e601dbfe9ca2c1
5fdef289a5694dbe0247c360e07ebb4ccc544813781900fa358145683b69ae4e
a4a0cdf52f2f8df2ef48982056abb85341bb0e066b3d326c7b63f87fb9298f18
be889f841ac541608887d3265c2063b6c6ee8895d66a9239df06ab1999abce0f
e3c748e070b03b5ee91523630e91a554db671d44ea0b02c3e96eae243fba6536
4394b38c32889eb603fa9702f4b7c9f94673f4e8773e16b43a1939b37bc4e591
5ea2b1bf9038aae992491d09e6ea7ce5eac48324409d63001dbda115ee0aba8c
21356a6cbc33d5bafb98a0adb813f6f17c11d0ab92c46a29748d0c186bf945ea
4f0bae00b028b98eefe51ec1ba9cb4ae0681d4818a5ad689b19f7786872dc264
c2fece1500de1618e77f04d5aab9a2a56c4151a6c92ab5e2d15c02e440b8a2b8
02d36bf7e889a16cf13054bf93cd0c6d4e2906939e6f0aedeba3e9def6ed1d7e
c9d07ef5759dc37dc020f5ede56c8985083682c8f72d1ae79e9837a904e3999d
2ae8d87780d655d8cb28afb72fa2b67351b0cb001fb3f044ffe98e801018fc9e
c0f858e900a11ecb372347a9c6c34e4b9f3941ea7a0ea1354d1b7e5243063308
b944e35c31ef29ca34efb845d63d13d597e9b6f4d0337679bdfb060ee8ef38e4
01cf9f8a1e2f1735b9a62f0d19a7f95a3d9b21086c6b227184d99b0b2ad96e0b
26e34e3abadcf3ef258d9f7f79dac9f267f23346a1a1bfadb9215c1754f6b4c0
c67ddb1e3ad46f038a950ab42bbcc90f5893aad29c9ca02930f9aadb61037486
7414e6eae997e111c5519b36777ae0ca24bd7d98835c1bc6895408f2d0165519
3114b6866c0223529134a04d40394689613dae85fc09d812e1e701fc74c67a2a
a7424aa0967c6007afeda0193172272a869abde1e1ecdb8c8cda8353ced8a3b7
235332a342579fa8445036b2326ab1c3d6b5fa887bada7a93dcdc4d53a16f003
6b03dcc9689e2ab5f59d40a1c6724f1b7f8819d4d19f74201503e39a3be0f356
ec67c8971a02221ff69261223ae95282cac6b433fb7e53b53616aa175ea608bb
8b837f7c289b4f63e827f6de86ddcb00fa91310f7d053a4eeab015c54dac021d
8ac35e41ac1ac8254375dd5069213572adbcf14c0c4be164c5e85383f76dd57c
e0f523e2e89b1024baa02af6bcdd045143e11e5f0f9c4d03126a3ef690374d54
60a3fd3b09f07b3b1bbfa0e46fe2e4a8358065a9dd3fc19041e213b72789a4b2
77f14b90cea3114e3f157c60582fded05fb4a8902b043d51a3bc9a32db25104b
f4c67ffb389173a4bd30aa0af0a9558d12d260e52303bde2403e83de3e0fab5e
bcdf3922b6c7d1fe4fbb5cf8f45924689df4a603a13086da38298882e5885518
0388ecc1ba6fadfdb5be768dc6a30765ade6c198b94425cbbffda2f3562825b0
03161dd7929e304c00875ca943875be0d53e104428d06d1d57b337d25853bf49
89675f835781d198ad338b7206e24c24aba0cbc4825dadde676ee330e770ce5f
1203a1c402227c368064d94ecf11ac2daa688fda5069661c53199e364e906240
f9c479c5667b33c8a0f36aefe16c034ec340cff4da1ceff9bbe51b0e19d091eb
eb66d7888e74016f34c7ade755eabcc8956a8cfb8b69cd33b45c4bedd659a0e1
d6498eaddae5606f92c4281a904d9d7c2fde8da2bd59df229ae2dc72c480485e
3c06e4c3c04a3182cee79b2256cb0bff951954f0e89ba7aa9d0b4d66aa66c8a9
6bb56ade0bf04c11b13d3e39f3e99ac839f840b28ccb5448baf642b283dc24ee
113e29a194936561c0ca197e6c0f1448e95a62e2972c103205d3d2c6608fdf75
1455f36459fdd6394288c18437801105a789f7ce46a666dbacaee88875e83b89
419eaef4c339b273fb237afd9ee6accb2d364f0049c7f653769456e729a0f2d1
acbdcfe6a21f760060213c45c7db5320bf70d85db73b168a87b08bfbf58cd50a
8324ada4025f783ad3bccf435681d1c3fe0aca5b4cfbc8bab604b85a85e2424d
da62282d8e91eabce67343850c056a622df06e1418d04777a957e12c85faaf2f
b6b7dfdd51d68a5c541f58be68398575dcb1f3f2dbff1a876cb599717f94ffca
03c17b4489de845c818090d999fd46dab1abb7bde1659fdad03b7b1a25084633
6e5e9e3ad9028caf55f34eca23749c17a2db9e0c2cbd76640957efb019aa3015
dad16218adf7e64912c9861867fa2b291b563401ab3e9f3cf7a802a845da0718
800448e7836dfdb564e1f3341ef1e065da22ffe112485078689d199b4a384df3
439a6228ffbe081911ccd1466656027ab87f8779e0edeb039354b2e2f9f97da4
f9bdefc18893c1d98f11c8d804213bb7e45bfa4fd2332566a398ef7edb47a7aa
71d4b80abdad1578f8fcf83dd38ca889e99103eb1548aae6f7a6afd262b025d1
18f83b57ad587ff192642cb8ba727a49cfdd696447d2809815908f2c85aadb45
8d27ea481af2983c11f22c8982096ea0c183f50e72e5b5bc086b3e49df519b0e
1fa34462641f4f450fb54a7d7ed40c11559b75a3266ac4e5fc1699daa5468502
38dba29523a5d0c58004806dea0724b3eab360833de767c80e835ef316f0f794
8d8c2be263e08598038c1a2acd899cf8f1461f7f0627c4c727e1a5fab9dbbe3c
5007eebd1c3cce4dad67fddcb8c7591b9e619789bb549d58739873244856b0a5
ae80c3d639a013fece615089d9d47d67272d62ad67b1f9a9fbc265b3fa6effb4
25213c205675f15992449c52a1b71dd85d9350bd3e6b0d4d0580ed513b870715
c01573556884b924d51d33bfa5a096f7bd953e9fa690fc56e84c99b975532af8
0541e5d4fc7939e118fc168b6cffed7bb1b6f41919640fa214c1cf0ac104e8e5
1b032c26e2955941d4a65d75ed55a252aade89b5457a0950923914e4082ae1bd
0c8693d511718db4f8bbe94a40f9336bcdbb19f405ead1a0cdea300527400d46
7526d08617ecae73ab6a66c6ac375e4270cbd24c2ba7d3224b3729c0035cc86f
7a569b5976b2ba105ff9756cfacaea78cba8b888de706771fad6ce3caede35d9
ef0811ac445cb0a1c145b3775f0af783e2e4c49a8908e132d078409af795925d
b81d26c37cb3100627810bd2d9b03417e05d279999553390e558ccd8079e43ce
47e16d1b5ff1b2477d201466e0727bc4fec955dff42bf1ac7827b161358e9bee
993270ec0d00cc3a694c7b706f2b1f015c2ebaf288aeb08561120cc32fa21d07
15b3a5b6215fbd0ec87409d8f8db1f9d81c7e07498f77d14efd86ae3ab6220eb
f78ff4db6ab28ce4da11dd8b29c52b2af0a7a2d1482a2e9e2457a3268e0b2992
d8a6f8209c9922e0bb1bffad5253be2051cf1e13205ea1f8f25dbd1cd830fc2e
e99229fde8ebad74e92b0df1dca5cc2f7128571e8e18ff35df4c4bfdcc1f049f
f7fecc7849271ead0ce67ea5dac98082d9ed93456a63005b962bb1c688d06f8b
7aa9cdecb9fe5edebb341b058725b6af4884cc3cfc25ac6776e79f342723d08d
72923e834e403f90e6fc6f3b719ecf60785f606c589d17404de35851529de275
95cf1b7f364886d7a83d27209e6cc1f87f4b51ba5d6a45a78680f60a78dc8397
e1b72a2924e4b4224fdafca3d8864ff4ff1f0aaa4256617f540e8aad26368c4e
9373fdce450a009fa866112c226f75637ecf8f16da55ba944b1c91468e80f8ce
3eecf856b13df798bff749a1d1d186d4040c18f85278cf9b0d3461a724b8cfc3
410601429cbf0f40cbed5bc31afcaa12186c57c82a49f22890f3acd986290de7
7fc31403e74f22c3488d822d3e3ff1168ffe68d1256c4e784128ea4b95894372
d438bedd9a325ae64dc081fb3736908589a05c9d51c3b3db683abb9d37ded72e
e5dd2a080d941c672323ba4d3de0de7f862ccff51c8f5670fa2e5f9822326dfc
2aede661d2e275689d14f9c48f382c9a747e8a17753b74550ea843a9b3e11559
c4245cf24d80d64f00e5bbbff633c02050b113c05943bbc948c6218e1a4e2d50
65504c31c2f1b07846a635c44c30c10de6f86749382b7dd478f4c203aa5eff99
fb5795158c14d79f534b071e1634b13b26fd5ff47f37f730b62797018c5f1bbe
fc87ad9cc8b31c3bfe9a2a7c0b9bc61a40b38baaac699fa944e81bf1e4be1623
14db805a7c709b7236b54448358c84527453b1f52ed6b77099c9e28cd7d1c9ff
ce8ece27484aa600d6e6cd8cee328febc483cbf87704b8c5fbd7d92f7ead01f3
09d999dbae2d97b0b250f9e78d9614754dc980550f44f503a71a06506c1c265f
cc49d055c71cdb06b67232482b216e36e9368ea9c8388a08106731703e2e1e75
b20706610e4f73c27d0a20311971a443dd7a95eee4a26a6d184e35604dcbf7a6
1380099b9ee40d5efe0784b3684370c091ce551c2e73b75c9042b89a8cc506ad
862eb60cf398977882cb0400df7fd9bf0c375b7cd5d1710544b4247106c93c2d
3fd7e35a88f76a75818c42aa046c842c2e80bcdbec3cb25603ab21bbead234cf
fe8ddcc1d41b11f30825fb348671bc8a6e0f9b475869fb594a15134d1e9156c1
c9ac8226966413554ca913a00df5aa585956e31f7c364eb89d99ba010fe33634
c3141c1c6504b18f7af1bb7cfad199c1b605715d409b17cdbf82cdd056d9fd11
bc7dc50fbecf8869e76ca701b46f380a4b897c9b5cca75233d814236470281cf
e93df05ca09cf24b4909d9ad74497163d6af3ed0ca59ba67f0ce48f7606fbfcb
fef9c53be3dbc9dc34bfccb2367f236e2a83c9e36b1b458dc4a3b10b2c8686ab
878cc627e12b3adf9eb3c858a210d0826c6cd152280c0919260e8765d40597b6
cd9ebfaacee564a9efcb4d3bb6b3af701f4d4ee1d88edf75c9221e3ca6944a67
7b1a61e357cb7f04a08b4bfe3b306104b61f73f9104e9f01d831107607b834e6
fc9ec0de55f29c220edbe0117feb41ef03125761021e7642d02056203a0907a3
7106ab63be349624bd1ea61cea20973ca8d18d277d24b154b263735e50c1d04d
fedf3cbb107a3eb30be8faa7c3074646ba5a5bc26d31ff74f0075aac135f54b9
a5df7eab5f03d48f0504aa80b188e30d7edfa5e373e0b8cef1afaa8cb4c6d77a
7a62476cde9c972a5784ec402dcebd7dac9c99aaf80ad47d0a4a62d6b3dd5a4f
36aa4df1f0dbae7a892f67d2b2774884dff5e9a25a4316f34b9c03f4c0ff4310
b5c30ae1e33d13472352abba8e53b773688fab84cab7c5bc0b99c80da96d3f66
b1a76b1aca76c2128bfc08761b863f65215d793529934b7d4fa2e9aad4dc5c6f
78e4021a78605e2483218829392cffa6e3f3a34fcbb770f7d33c48371a9054e4
1f768addc2a515274be63550d02098796e7395311a394043c3dd630a545b0930
2de48f4ab2bfe388d725b20245b379b946570d823670f4115d3a78a30a13f747
4ab650bf1a1eb5b86cedaa32bb50af69925ea6d5b180e161dbd854fced30ace5
f6b0dd6cd28b7400125fd99a4e8c8b6526e2c15faa6f5865cd879edf56ac688c
50c348654399097b87b1af330ad7667b8f4f50cb325bd6f22d01742ead076bd2
b14ff83802a52c2e20605391cc3e11e9a44c6548b9201b9297e2f6224d05435c
45654185b392c4479a8be88961a0fd9b0fda49f0c672a118d6b2010a6a2b8c8f
5029cfd4c4ea7764344a607b3c7213e10168bf34153d6862b731856ac57bd258
20a815dd59a193b2373c83be75d61d081f6105f24b4944114c445ea22196174d
6be1af82afa7d51e82c4a968501a9ebf7863af6090a9a4a62a62abe8ff7ac17d
b1cdedc1d4b1edd60cc2627ad4ae67a62a303b89597f1f3e22d559ff494692b3
ff62be5c38a0a198cb6c96fb08c4d8cb79488cbadd45f2f29a869f43eea2f90b
dc003661e149aec71a2a8ef62a9a346c8a3b1ec718384a0f1093898236f75631
d88fe33cb4b4162f6bca05de2e05d63f9f2adbed77fb400016c89dd135ffa1c5
8027518a72dd15d544995f9052cddb9a71c90d37408dc0daf19f760c613a2a46
4a71e0d394a5ec613855383108ded16846f9e9bbf1c60c6fb05e17476462e557
dc3f990c1f35f9501f5d87c75b1f366acdf9d2e92aa2ba873cbf4323a6dc3c20
c6f87e70c80964398803a5c14f19e317cd2aceeaee22f980599bc9709110c725
5c914249c7e8cfef6cf8660fe7fddf0c6dff29f066dbcb28119c8f6655f55cde
811f6075ebbb75b1adc8339c34afa7747478898c92551847f4d368252d1b46e7
ec745c57a0fe0f22558b8bd0883d9b9a1d07b184a42a69d81bbd0349726fc39c
4c37302b32d59f4dc6c133c8347e40235e41c89a018d698897bc0b3548108d0f
e45abec7817d4bbb2f21a31cdddd7445711669450f411878a7c938552e31013d
8a5db7fd82a12369058c93ecbd82a299ae092c3dfb29ed48c33f113cec22f074
3524787f3f826d378db1d53d0b0d0857fd91f88715023ddb1ac32c8d86b2faea
55705fad82f591b6ef78fcf6174070db68043e7d7d923e2f93bc328e7357b9c8
009f75794fb38ea55a7f16a96450e2b10a96352911668d5d347e2994f07b12c6
6b57b70dda27aae06de6572c27aadbc9b6541bda0e04c334907b1c9b57b6814f
8ed214313550b8dee34cc1d555fdfa50f7cc4533cdb1c8328790159354cbd25e
957efa5e8694482365ed4f3350c5c8c6bdbbc7cdcb718ce9bffb852f8132f396
5d8f3a81558ac60399ccf498c79cc847c98744b765b3820b8750840bdf2bbc0e
17fe0441fa4bee6e767e84cee0e362e45900a895c855b78e8af06f87902d5113
effad327bf5ebae0b926622c06f2139f4c54aeb8d411c95047cdb1adf2ff2430
3176417de4a5435aeed9c73bd982b3095e492ae6c79c8b0d77de6b2897246ea0
3249f60438591a674e787961fab482e27ced68b6a8de7ebffabc89964a7c7f3a
7c6827667f1ee4c68cc3d6859e44aed39f11a0e6a4bc5812ef98afa3935be243
57c81452ccc2be2dc3e38489def9592238d9d89ad4b45770a455f8f6e84f710e
8a1fc2341444c1ed0d6acd5e2eb34f47abcc27d799834e695d5a23e08c4c6bec
7a0f81cb52be8884790828e01487a65ea841faeae24a7f47e7d9995bd5d091ca
335724bef474ce2d5b0616d686bb1915e49ce54a5967a15b488652e0b20f411a
02b7469c603678b04bd3e4116286540680415455896af8d4b4858396971075c7
b1f605e5a3d06b9e0acc34613256f80e5205ac16372da82cb4136aa59463729b
a67dfc5282a9ee1b5513843defc1a433eec5f7170c1d03851aaaac6f34a0ff3a
a4236ee75cb540289f8f5e72c3624c55874ff0a3b56d00401a021499d4130bed
193a0c978702e0587d1ce1415de89db40afb001d546caf5c9104a27ba3bf7052
13c7d6a8e57735c48c773bd67e3c84a2e5b37603c3ccbff5aa0b09c2e677ceb7
a1389c1f361667848d8a79bf859942ccbe5398a944428dfae5e90f3f15b9cf8f
e47f268a6ac60c988cf77549ce50805b947ea9813b0b12dabff0479e3814dd30
f0a2e0daf302445b3412977f14121ce83ce060d16042ad8888688dd4b7d030cf
841e1c8e71c8e14145a0bd67a24b47df4517f477dd81d68ef2e1f7ed699eda79
4df9288b058a69d7a426ceb90d2f624f0d29aaafe8a725b8844b1ac8c140d8db
523d09b9eac8936916659794e8f1d35e0da7b30616b2582fd57020ad3b643066
120effa260662aca609902c52773d61981820135097768fb95ee5c4f7c8a607d
ad2bd1509b0cb60a88cbaf02c224e26d7f256fe8fa7c6a77df55b9dc01c7e7a6
87cb7f8b3896309937fe50d2dfba307333e8b7bd761b7e5243063308b944e321
eb149ae3906e27aeb8bae05d2b896af111944033548e58f900310327bde7aedc
47a4e82dc92764a96013d0123f781c0b387cab23130aa6e19d15d30fb4104fad
919eeed5cd8c0a9126b6b058c892a9d50bac2ec8df3a4de83050ca500caa8032
a49a9aff3f9485bdaf1aa4b7377676ccb97451d3da19e2429bc0832e6005d83c
6f311c1b37f206a67a6ab70bf7e1ae3cece591bec9b0713e1b81a7b9f2c81cf0
10065b7f56a1c1c27ab4cff304fbaaafd9ac741fb311f5d9fae8b5533b64cd9c
8f5f9bfb8aab2131b6d6d024bec84a69ee53e729acf6a1f288cbe25390e35f10
4e5013f6bbf260bd03dadbbbb5a3caa1bcb7e5ccfe91c4d5904d1b11683e25ab
33df2258d3b0438528a691c737d2134ba0ab9e55154a95b1bd0ab925e839933f
0a6605281c9c037c0bcf1945ad0a9fa46005762a4b12e9835ed5cfe6115c42dd
9b35c1654c2ab62fbed7838477a1586e7c217716f60dba76c8e148731539d57e
fd35836782451a9810e6d52d19af4adbd7c0a144332069d27a30140f3c50bfdf
9d5715509aa457cfa870e039c379d54bf840e0e2b18fcfa5cb16b653e96c432a
b5195735f092d4333d26dcd16aa003b4ec3d18817b12e2ae12bba2964725298d
b1db5b9fba1c5801c7e48b0577123e0fd41c1eeb51c9a670e795f86b36ae7a55
82d4fbbeba84f532b371ed78aba85a2c2d8a451422de486a012d30004ed0f009
cb9bae7cce52db06ab28005347fdf1989b3abab971a85a15ceb8d3f193d77e2f
58d18e5760920d5ebc44cda6c144dbf9ec2bc596f5c2d090621426d425c3f9f8
4caaadfa088999f8b93c28498180dc3b191c948a2b646b0d466ea4501cae397e
c0abbc0e2c46848fc385ceeb1e963c27458679dbfd5e57da61e1019d19e0f5a4
effdf0c92749cbbf9da7d7ca8e85adf68a0681a0321f189dc49786b7da565bfb
ed066783fde5241f2622a3195cbf632e2f72c9347e51f0c6ae7d8557bddb9a4d
afecdd11b0fc3abd02cdfd924ea3aacf47028fb783c61f2db63cc0fa87f00730
93f9ff44ba0a7d409e080c567d0fa97b5370bf7cbba2ba71f0c857b992665d1a
8fabc57ef7ac2caa46614ce18b335a96edfc8f57cc6942c4fd6a14b6c2f69f7d
0eb59019bf045728833e048d6a819b9496861f97f61104ad7eb7b1e49fb05fde
6b28fde18347ba253fed3e5c5969811eddf424614818e1273f56b00b3ca0351e
7fcd4300cee18a9e5aa1c532526425c9bed71c1b95a5fc0b392a3a5e1df06219
c931d896a6f4c9867b3106b83ddae5f01454c421dfc58b69fb0f29a954f04308
ebb9d0f86a1bf0e879fdc064a6e96bdbaaa050b8cc88edab1a1a7caab404d9fe
26146014024fa244f5685661e9873ba3b500a83cd75047ff0677b145db98317f
cd34daa29b32f79e8b3d6eed5c7c27d5e5ca50776f0703c4f58e87d80c7a9267
2c0860b62437d01efbc5b8309cf7650a6641dbf817955a9e7287051d1cd4980e
5c2412f10caa2c62e87cbb8f8e9fda04ffc47e952b6488f8c8f1843a74eda6bb
6d0946765c231e68f9ba4d3d396ade78acf2f6bdf84ae5e4f73b30dceb464e61
5dc70e61a31194360f0d23479cf402bea2a12d418cb7a0b50e8e07c1d090ed5c
192bfbb4efc752f24fe30211121aabfd942817b72d0dea1c2654a7639079ef25
5c3688779a002eb79e19d8ef1d7703d381b30eb2b0e934ec07878a8c87de8b52
29ce0457c32bd9afd47e8943133f31d80f1f2da658c67040bc5fb2c1ee44ca99
dc2a78e6384a7c4df3933ff491dcf69a724506957c2a7b0e9562b5bc1fb4c230
e031de8ae4049004a45a17886c49774a4f01ea12e69ccdc90f55bc81b7936793
0c1e698b13510bdf6dc8e83aab16dec9d6efdd386b3c15c4c8cee9ca1b19babb
7670abec2d117ca028bbfce1d636201028e186a94e83e23f0c06730cab41aeac
e940a8571e330423d40ff72024abbb32b3d3b62f4e8717e8978a79e5f7774e90
a06ca6090ac071832858794af5f4a352c031031c4bd35aecf879c118c599e338
cbfaab9a51928e228ab829112bf43a407523bf99149c9f69c3c5bd3adf1cfa99
fb7bea5004be8763f946ecb75bdaaa628779387ed303021f0b0a0ede56c61237
58b51aef609b9f7ca960c6c1dd1895826966d3efa640faf4f49340701324587e
1170e8f9db2e71b01981a94065cee7e6927ca434a01f84877703eeead94335cf
ca8a16a8d01e649267bc04d9633529d5092dfc3b2ceee1761f1de49df20b4b80
d79003eb1b84b3c1090201c3b549a1d2c9b977ed5d7e314e2b44a630983229e3
eb539c598139d737c9693d0f3a6c5237fe4bb98b1ac06ccf4f3473f9bab0421a
2f15e8b82a5ea2b8a6eb4dd74db9d1db80ff725d8732b9560bd48bb85889922b
515f9039b2d7c0c5a344ddfbba80e6c82b4c6fea6240022216cafe664ae88dc8
6ef59bd408dcb78a53bc87b44361cf3db6e462bd33ec32d003e14c5bdbb7477d
5aa84be29e9781a6676eb71798be47710a73461c8c462f709761842a5301c947
5dd8eb060acd5ff1ce8c7ab02cea58db8dea7ca2cf82d6334acd23a8e2e23476
c015c857c2a7563e402ad4e78981bdcd094ee6695fd934d2aa0fc18befc8547d
855adfd241e61f3d14f6e65fb49616c900760f877fa4edbddc1520e9a8cacdfb
efdd15d4b05803b45dbd92a3a5b8b4c1c7acfe5dce70cb05770f415c45458756
d217a4bcb2400d457a1365f90c5e68eb26666c49382ece94f4e99f98e9c84e1b
a13c0e48a1f944ba73f8c02a8602ab9f047108274de9b0095328a17b7557c904
972281863f35038ec9b9502ab63c107ff7cfe31b56b7cfe4577fbfc49391ed0b
bd2237542493b05c0fc9a3e244f5fb9dc47072fc73216d4d5bb96844e11c532f
efb73b96c08104d288017fb1be416264eae67ed584b7732d2cf6e82818607c2e
1739a5f33355b36dd66be78476f4fb4a7ca1940148d34de4b1de0c9451152352
a965aefd49f30f1535aaeec61bf50163c983cfa46ff7a20566cd089db32e03ec
56fb16bc08cf61cc37a05f0f6489a5922cd7926b4a872678595ae98ae0c61845
ad39b1ae450a5aa0dec60616f4c77062eb81bea935363a9318baac9bf1f463ed
5d035c0467f2539b7cd6b9c290688cc2a4499d7837ff9d8a8e383d52c87c98bd
9c3f11b0564e36b079cdf2c9c7d2430eed16e99d5f0a785600d9654b56c91343
056076fb5509fe43fed70b0f0718fca6e0dc92f40932999fe4f4243354ac5e08
16251b0446837a3b3b3d68ad3bf518cd7306fe11541eafe27c076f1ba91723fc
a596558a6856ba256fffd15d73c473fa003b263212decb8fb6a573c08849cc56
edcc163dc2db27907a74caf2297833e242480b4358d74607c2205aaaa89e038c
4a186a5996e878d16b8b4279ee6a12cc16258eb01171b1c7c3b96a53b4bda037
bbd6c03bf4f7dd6ec0a0c6a6747c550dd5fdb44cff453eb65d91a0e43ac484d8
518f861b346b78e488a3503a6b1d8bdb3bf9bceedb795e8d7a9776692c5bb417
f181f1ee706755fda585a157002a45360bce7e38823ff5bea7cdb8de8ba1e2b5
d058ed185cf11bcbf11e9266e6e588bc3d58840f81a5787a7934a2ad2abf9a87
4956e0e72bb2c10b35bf461b0bccf26bda3b4675307970ea628b5a082af98b4a
6b4128d8913814fe8e5600e23d262a6f291dda41d4e08b8bf1a6a88f2375a7e6
01bfc77cca7a2a1fdfdaef0b40f592d15376219ea02607cb02b41bb1a0bd1676
26026e2118b7e6b4070f82e56c9cc4900eebac437da74dad4801a047f1b5cde3
50a2f35f96504be63ca33e6caa4f784a1a5d713b321f49f29bcf21aff9e3e1c4
a419672ad3529f9d83b80190a348e27b0a0cfbcb4c12f0495326db2fa40364c4
46daebcc762e5fad9e68e3109bd59e8997eb5662514a7a4a8312d09834583614
b6085ed34969ad50d7b5e4ee8af4d26d76f8d9340ac69f31b18a7390429c959f
4b5d606e509633eec832c487a86be4ab9b866bbd38565ee9e9a89b8cac43d71e
f72afa481b8e557c27666a8de756a216d2ed2b073f58de029c9db5670f46e678
a9a5ea2e8c4662bdf51584679640a3384348defb4b67420d2d749737ca8e8397
3643203177e6af6b571ccb623d1484e26af5f9f2ae73c36f37f45662f493e684
a49f6e85c85222c517cfd25512348d536f3edc409822ca8a5ac71790f60e1a4b
c3662b96e56020f9fec581b7a7fb0eeac8ccc2dc8ad4447e07231f46b5691fe2
927d71ad15602937abb32b771d2b3d40be3eab6a5c4e3c06816e6ab546f1a913
03bda9504247aef4ee2efecac7795480df51a73ee7cf0334f0c557d0bd21e26d
88eb5b610bccaf73a804cedd646e0596c5b5c14de562b7be3a47d3f94368075e
7c1b144f87f0bc3cb73919e61459e816e31edd26d733e97e34ebf175131ff872
20c8cab192481cd1c7598f12d41cc56596659c578b194f05029e5215efaab6ae
66ad63fa6e19f18e71e9edc39bbec3f00c3159eb0333e4f06db1a0542f8714e1
44aa32a2546a85f1a890b10e2af0e997707479e10db3dee2e0e985a0bdb27b95
8e88e1610a95e861ca3033ee56b4470b542fb251a6fcac44fb8beea97716c5a9
51325c1f89e11921bd910c218173353c043b4b161bcf652586980f571a8b1051
31f389b231733fb4fe98a59fd57d77399ab3c44eaf98afced7b1a2db18b05dbe
2900d5955d9181b54e736f0e627e700ef19c29a21bc3736de73527ce291572b5
6a4124c249efc17b721f5dbc136e1b5cc73a53f583debbd236f7752a1ff753b4
e6c5314599959f93ba983ae93f7f94eabe3c677985a76c3e7cbdfbfe0e9fb8b1
57594485961a27a11ac4cd6e198b40da9a03083b4997f764c04503d5b2bde1dd
308da5ab7ee43919252c726e23923cbe22eda2184ab675529ef6f25119b2e7f1
6051d8fa175c39868d2d766e9657bb22663349dc32f78f89ff6a262423a74a85
b51e0bf812e5ebb99c035414ca9895fdf7ae2cc3547e5be2aa7957b30ac7279c
29ccdd7d54ae65f34d043f7154f88a249197f883df5d8d6b404f13ccb24b47c9
28429d704d8f5c5a5986b6a54e72c4b22d86352dd3281446c9d685d01e664cbd
694b87339e280482ef708f5d31ee02639940406f4a2c0d1f941f3c645c45afd0
e76e952e358d853fb9c87add69b46787519b4cd7e7441c5dc4d174e780e47c74
9250e3d2d82e4893308a2de57bb3cfcd0a431e1f9325cb10edec21b5d7ce92c4
5cc371159f50d362535f765cad7bb6e86cc791b976ad580ba7568a14f403c514
af0919343742c66f96d35e80613d0ae6cb9931801df4d47618221d85c652c0ae
1d8d0b6ecae4e2935c3dde52e941bd94035d601e94a1838f399d90faeb31b683
3fd0dc7fcf65851ef192d0b5db7e3ae1a29c0651b14644c03298e17e619fb3ef
c536c42a98b31938d0074ed9b28208d3aca22fe7440ad4d09d36d7deeab9d490
7c668a72c29bffacdac7dd7d7cbe501338830a9817f3fff96cd6043c9c982dd5
e56fd6973485b62cd697a4e27528590929f209bc2f29c19c547ff7d6bab3fd13
b189dc7eb1e61f155910cc6f94a64d08b4c65dd39e43d9fac18287795edfe6c1
933730b7597c36982eb84233ad009b446508ef770679807cfdc839089aecdfea
23322744142818faa6616808b42f36b2d4139bb7a523d9855e7a2bea7129b5df
086bfdbf31cc3e50714f53e9ac376d2f0e87ed04f8e61e053b77bf913342db67
e478de62e130a079771b8a7520b50a87d6b9364779b6d1130e0abc4eda0dafeb
9cc9a5a826b9a38dd9f9de6d3b65f8eaa79e83d755e98ea169c6630df6d8e2ff
de4efd107985807e8ba37292ca64017e80f8279c64fe6d4bf31e2e85e4de3077
cb2e5031b06efbf2e865fde8bd002e1d25acb9291f4ccd83c518cf22308277c5
60a77c28fead8b7ccb5561597984c25139cbfe49c5bb96dcb358dbf6d2630859
a4703f4e29500ab6ccb4eb3ac6b42822775623d93c8e7c7e4227e40a68e184f3
ec64f885dae9fe27200d40c7a2b03d6492fd0daca0d339cc9c948dff8f089386
3909999acd7dc57fccd535567ab24631133ceba92051b640c4c04ce906a62df3
948a5c127cd391b0cfeeae15d2d3a46c148a0452791281b52d89f6535e900e71
e8a4caecd74186724dc7cdc1faa564928a4bcdb7e40400830bd0d4ee269bbd0f
00c4b3b3949587be7cec9c1fa00e58c48993c193d8e990f6d1706473f7970bf9
37aba8747f7fcf05dda1bd9243d72fdcc0ef69c71b3d1809b2817929c9271246
7e08724acaf126c106cbc0d507c3d5c33e0ca14eaf5bfac556d71f1cd9ca14d5
24542d091402d0db8f697ed6f7c82724844690a4f4a233837a2b9c3e04e6b3e0
48578185746e01b57c0654fe1578d5958997d3b3db2f402884d59d5784cf90bd
ae96cd82ee1d164f088acd93ee3f2a8eab9c87ee191ce1b1f09e23853277488e
6a41eaae057ff7eef583461a2e7a82544a74cf654e59d4bd6cb4cb5486d4e5a5
dbe5ea44d0ed9ca59122e9e25a9b9b08e7eb8a8ecce1da2c06642a647c6b66ac
b5e88d5eb5e0cf10c30083e9afaf61c5aacab62d17801c6dbade2dd7b084210f
234b4a63d9b02db72ffa4640b487b94e34d682ab18602d3c969ae997b91fac3c
d90b2f8b1d63fe38adfbc09e246642e4abe656966a20f082eeb189eddc966b7d
bb50dd653fa99bcd4f258f870eaa0ccfb2b3ed1cd04d118f96b5e62c68f0a5b2
b68281cfc94c916b1674573fcc07ddfc79b7591024fb79444ce4d33b2c9a38dd
2239bc5efd6587936cdf45c7da89bf6ffabeb52b2237c62e98b8a8a193ee77cc
f7241f699a09d90f26edd997d8cd14d75af3a78bb3f4e0dcf5d33acece6bedfa
3ed75e33565a4bd4ef5d4d4c351df0b43929e2814c3deb989689fb98aa3e7a16
00cf1477c66c2851b81e316ae3689f37548033a5b170c2a90ec382a09d4f5181
ce3e12c089ed50f5034360889e4d90768b6da3eb9e9a2837960f9381a8a85283
fb84c649f699e197b53f97a16cd921751a04ef9df24f103e194b3cdc2ad30692
edec18a803d5c3747c6893b203b5b32335ad379c86750deac68293341ff6be82
03f842f49b3b9b2c6a1f3fe074a7fb0c4e1d89cfe1fbe8a5d8aaedea86363532
46cbaddec1be06797e2dba59b024b0cbe2c07b5ebb096c818eb6170ecbac35ee
3656be91774ab25a6e57ed46e67410c60728679acb4cf1a0680f8bf685c7d648
288dcb2693a6ec9b16ce82c2204730bb66c1ad3be2797db30dfeaaedd52ce3d2
4978ae0e0e0fe797db6819112ab8d3a6157f15204215282f50013c2b292d637d
69c9a55798df18283515c3ed16d425676f59a31e454fe190e9341b27411cb62d
48d542fd539aad42d9ab73d8d2c462968cbc306b9e0015d50a3e76c4c712a0b5
57f4eae3259eea89d914d1f9d1c80a28d72b5076774d1f3a1f953ce2e4403e74
b8b72c3fe03f8ccac93ddb14cc4558fc44997bc0d6a5058a9bfbd7bf5ea8e9dc
eb10256b8ba1f000c7138cb31a23b3059055cf941ce10786646e5a75a4d185da
dee17b866f2f0b8473bac0dc49024cf7ca96edfc6d21ce460345052929404ab9
a8a7971b9f85eed55f1a3338825573c48c6d3dc49528d13d8537a0849ffd347a
7f38d89799df18c65116f4f9ae416d9140d3f8ce7c2d3ac74478e8fdb6c045cc
25f8a1ddcf2d12743e4e24d096e7e2ce57e6a865832754ee8dc7803c00c0fa1e
5b97c79e20cbe4f88405bfb0702bd9aa3f5c6db8baed608ef1a55b63cb787059
ee42d85cba9244f3c1716f7154c9d7b6f0b6f8dab011d61b75ebfe0b70c66ea9
8325cbcdf74b84380466f40043f07b50aab86224a1fa16f859a96fddf453b6c0
5dcfb0b253ca3d23fca60ff7453be9bee22565fcafa4c0753231887f9b32f3d6
918de274c97dd4f4cb7b8fbc4dd45f1061ac2de0d534e8c7a622dbab77eb2415
d9507b6e3cea3be90fc0b69e97119e131d15ebc976a834ae8bcdbc9c7e4fbb9f
891f46d65ff694a18e3524ab69d9deb219dec2e608ab6018a5788bf4f9887832
19f69e79d7d5037dde8a4fe822311298bb410ec9cc718b056ad3c49941c14e9b
a89aef435b4c0cfa26f53cc00507dcfbddf912222072a83e990acdbe6ed09935
9c072709b5da135b77fd1a6a7f58abd4dc3147ccfd8fd47b6ab03a8d29706936
f681f25474ed35433277cccad10f1115a728218f87690d321f1cde2c554ca5aa
0d0480a6a105bbc403b0476818094ee8b1f670ec2c5ec37d8ce4781f71dd5d50
eb4b0e2fb5ab32ad28e3563d1b6543a9b7cd665bbcabf37dd68696fdbe1dbcc1
3eeb411375dc41a23c09624830b33ac29de60fc1fc4b6d83a21a40c872f28904
33ca34892110deb783d926bed6a3327074939f82e53ca97dcb11de715f3f87f2
aefd0f31c63f838611b04e7c394df9e2a197d0183ceb5f86885e488e0d4244ae
06e82bf5ce39acc10f9e7cfebf403b582ee68b8e213e9b891d48fdaf510f4bfe
79151998db43d908a87bca1ad52f0d208cf4c80c59c7221ed1d285eaac051e34
15197b560501aca4423fa66fc46c429423c4f079b2b26e1e7273c5f2b2a2371e
b416e6aa100bfdb99043d6c489ffb0fcec3b6f2395c688b45725eb92f2b4eaee
35c0a0a09d50a3b510f7f8b10bb60304d98fdd915ff1a7afd51104cc80e59add
9ccfae1dc568bd1f1e86e85cb13c45613156495845238dd0facb547b52c6b443
3b08ab06f62ce13fb52b929d9e7f6f9f909e9f31310de6cda8be55bf59a0529d
f68460e9a65c943a070198d8b73aeb1d4386178921e9eeb6efe7366cf1bfd4a9
efb27799b34bbdd9f9fb25133b03885213127a98d2744b8b3e777b37cc7d0453
c7b342ba06f76a742ac9d1ac8bf54da57937207e6b10cba21b2aaf58947c8c36
158a8e00b0574546dd97f818f8b7228caf76a63a739e06425991f495a52cfb01
f50d8878c94ddd59320ca93fdc5f6e7d70fb3ce15a233bbc218c2934d5432b44
a6cad3b978ab02ae4903d072b9753adb4d7ac16e9c0f5a67e62372f9e16766f6
7fd50073be2e8416c153fbcf3a7ee7295687c74dfe26bef89af8b3d7fa5aa80f
be3e9dc27fba1bd5de4e9e1296f2824deee021af326c8b5ffd871b34dd34def4
ad51eb0f15ab0abb5840ef7b4f79a65180f518869d890c2d65f842153de6a777
23948e4ccdf58bc1fd97fcd6eda9180ec6f030ee32adb5b439951cdbb28e87b0
534a6a5920a143d8bcc4de9fe62ac8b93573b3829d05098aa9b4100a5c8baae7
35134a337dfc3b9c1f13ce823ce3f02848b728b5adeaa2271aae398b4c914d57
a76283193e8617c037c2b83a6f14c610f52d0b97821abf7e45c17134f694775e
f904a012f158772a17b6bfaa03fc2f8d9005db88d2aae21651fbd677a4d91b58
ccf5a95d6d0c5ba3abec47fca5f1efa951c468b9d4c1a1922b1c4210d7c1e7ef
fd677583b5f5d0a1d1b5c8c156887fcc1d883a3bb3cf0dc6004554512db1bd75
9403fa2f4a9f1d5608b68eb9edcf23b4df2f7dda73b1733b7fc8ff68916ca6d1
622fb84b76b532b6ac834f6c4623dc2810523697d91e2760349bf666eb552410
ee5c8c97a95c51c3ba81507f52fe7b1a5855279e55f64dfa1a7b86692c305df1
4940a0ae033afe87c61f59b189d59954450dadbc3e38c13e261e0cae9648093d
f93010839a2ba819d199116b7f9a422cc1a4f36410ab7c22b206838c85b5a562
68dbff1a605ba49ce700d008e938b79c722803dd938fe21cab7f9514c598f98a
a020cd04956c3b0b2f5167231b3d793db1a678bf4a45cb46d758fa3142c62086
8d3c1f6180c750ea9a0a61a728e915865036315ff902bb6aca7d620218eab802
cc91152952f4ff7c297169d6486a967a4e3de00e265c831cc201ce42832367fa
9cc88d0701db1d64b81a722bfdcf43447bcd536988783d2a496821af475a0e40
3f9451ee1cd973428e8fd71c8f6552e5a4087166f96e152cdfe8f6038d174993
8d394b3b297bbf4263242865a0fa2b7bea46d051eddbb64ff376ee0f743cf3cc
8b3a44e415f460d774ea4eba84d8260d1c032d52420ff992ea8752b126b7b721
740e22f8df22333850c5cf943dc531f866d19dbabbc7c0791ea966c4ef93a337
da80b958699d45c7fb46ff7b2f0967d9d6e9ada7b97a3457ca134adb9aad0a45
40742d93c91305aac65a51e368b0c091b4e7f37ca13501119cc9c0f7c718686b
640c86afe4be68961a038f1b32e122955e5826c3c830b1a0c84dd29eaa88e6f6
11ab9398888d0045585dc2b5ff9c2a1022b7cc5ce25539fe4791fd5acec180bb
1307f9ae654b56d9004e3f03c316a6e205df3da0a8ac7b6878e7529c1daabdce
0e4462f7eeda1fc1671fc81d2ab0931709aeae5c0255b1129f7cfca1e8247f12
8149751008e13452bb1e0144e435f58c6fc45bf4e2d48372fbd840bcd5528f55
059c09fd2e0e3d90dce183f8ea66a3901bed7898f5e189b73040937a08a39feb
d6b0d50275cbd4bafad676fc3857df5c5f391ba19a9085219d420d7ff42706c5
d4a1c178b40cd7cb8d6d3faf66290fc780ad52670202a10eef1552f5cb07e814
0358787abc6fe03ba0c951b024d8b2b48cf626ca4b909bb7298bc05f2ef9916a
0271182b3624c5ca271c6428370bc66c37f9adb7deb6d3da89fa8f0951ba0d3d
52518018764b09ef08c98b9344351fee3f9635e64f3a2c5bb00fabd4c33a3967
fd242ba882873205860d35fb7d95f3ac23c9d8071afaf72eb5d443907e93aed2
dc09a3d04d887847e2a736cd64b3217c27c64ec92b3a321017c6d398c78cfb16
36da6d065365c2676e0530d0e54b00852b58831e29c9c669c03971639fe8fd19
f72583a55a61d00f3bf5ae143536f2d6697436dfba850fb91c0a705574320c5b
5d12c0a32ceb6e1f00d32dcc4041ca0d90147521469abe4534538038f96af670
418272d04f987ac87a95fc170842e44c295fb6f2265be207024e6ff039121f94
0af093470554dc7f319eea8cc7f2e1c6a18ec86c90b2d20bbfacf5ae30f7f66e
bacba58b4511507be97660221b3f29703d4dc03ac615fe4db96b2ee3777391f2
d37a6e0e94e49628041584939fa7b659c1391b59ab1f1332f1fc45af2323dc02
0b60ca2527adaf61b432947639fdb177118d9ace3c0ecd9c7881ad01522e4df4
fdf4d67321405ca67952dc78d2f9d48148e00048c4849305dc0072eb0d2d854b
7d97bcbb23636d1fd96f4400ce3ba06f838f4a3f31fbce3da04cf1789b99f6a6
f614135a85d3243a2c3600feb4226368c6c57c2e6ae1bff6c244963c1d7cfbf8
c21c40308e98c03cbbc8aa95960978fdd73c50fc7b77b8267f5e952691bb8b1e
94a358941a8706b6377e43dafd0656d0a78edc65a6aeff97c4c6e672a255a67d
dfca1c2983564b194c87ca542850d96b574ab1950d354e44482fb73cfa933fa2
fc3bec249203c6cd723d35471a49d940c2dead7baecb33d702e2348e95896010
bdb7fa21500072f7aab45de041511e7ed4e8a7306120efe5a9c21c96432cb8be
e2a48094fb3365e4518f2cbb186228c221c9ee10c8f7f771dac7f04181a89d41
b4d1daabc6db1846bc493215578cd50a97bb99163087fda379a0f47667c898da
fd5e07d2e692e4e9847c5f12c07a840c8eda9a4f6b6d6386192393c69569a3bd
c7d74fcb4f08e4a77c382ce1d950bcf3ca6905b023d4664e3978fd5980f2d7dd
43517cd493684fc6f207d3bef18b919025adbc9ca736f840589696065092d617
2741e864ea603ced165bbda09f273c332839359246a72288640bfb76352ee47b
4a13c6fb93624e2cdaf8ec1c9006c6d9273f1e635e2ca71cf49260b54ceb81f4
fad87d7dd893cdda5cc356b1f17bb4b29273b4e257bf763f19a9f60dcc30e003
a56185ad222894b58d42591dae1f0220991686af39f7095bb0446ade99ec4bd0
80b26936493b74c25b0ffdb8fe063df1ba932b5f0edc0f75a3a29091e0538bb3
7723b0158194f0658e748ad2feb97181af7fcc3f1c8f5162427a80abcffcb684
f7bf04f1fdec4b334a68f4d928a9e67b3feb1ae5a66ada3bff21048f34708c80
36b7e2f7a01b56ceaf592f5f42155330eb849a7a110f6884a23cb65e4da953c5
702aef908369e769bb978f8e21522d0ecb18925342e60c7b4d02332557f66335
b6b461ea700046b3f8382fafee7977150f9ef8ceb03d0acf33ad702bda6ccade
1333ea6ec14f972f1b72906ba13d0887fca8f71dbfbc2e8b7bc8fafc067d3e0a
1a0f924780c0e8d9618986fee8cea0164f1f84321d964a32500213117d1bd754
0b412bfa3c3e6236c9e8c78e5b32ae330cb716779b63e19eab501b1c5cfc9e95
fc6d0634a18da3f38d12450e256701a48273f57e68cae118eb3e9a455c840a9a
4f989d2580e26ea76a7e50a690631fcf61c471b913ec7bbd5c2cc57c5dfcfd26
b794c53a8624bef037286c20a3d6ce2dbff657047415817fa2cdfdb4ca1ac9b3
7aa7b641bf987896dd1d567c1e1b7111cbcc46619594b4be0f324d228e2b83c6
c9402a46811495206657036c8e2fb3730934138145bf46d8676687b90f46aae2
ef2b4741d66d97ca126d9b5c8a6e4960475c77109d2059634a2ccb29ed117acb
ca79a16b3bfca39a6172fdd259c0b785b8cd7ba68be54f8f64f7d17543dfaab6
18330084429d35e9634030b3200334c64ca6f9bd5c91e21fc03dba52561eaf9b
63413191443a0217c8a73a07ebbe752a39455b76651499dcd69dec1272583bf5
e23d9be1b403d24dba7bb772f5853b77a369fc1a41e018ee181f75b27e081716
089668f94360d97b7d068a2cf7a6d748c332cfc1dc3c793654c99e98d7a4d41a
1de9e56dc3304615d8f253c1ac2da2e4ccf6ef68c34470c859f1da002c5bdba6
02799c7310492ffab3f58c4125d651d2434659a79ee8d18d84260accfd4203f9
14fe3844a77f1a66980f339afb08aec5c6319c6e0673d393e946d7e34747fec5
27109ceb2c3091e5c4421e41d2ec18e060c2cf228a75560c1aa3d37644fc1d6b
66230a8dfc644a9a217cc5470549bf69710d3a27b22c34bcbf01e1c5e8e5e041
bf3f19c8226b6b809940b6bb574e208cf6832e51b63249eaadc76880cf3f9158
16cc98a9a6e62a4c5180e99b0a9fc3cdb3950d59daadd6c8bf29076b9cfd7ed8
3f7273502f6681d91bae7c6d46dedf15184aebbd6e2dc04126783edcb88e0800
5374719e45139c4fde99085b1b7834a75a4804754d7512b988772cc29d165cdd
5443436f0505b528778cdad6d8c0e9750f7af1efd886e82296c03a823bc05b67
2197d9221fb40fa880145e69f271dca81b1870516b1b0a93c8c17c4687431b23
c6bdc960219adefa3143fcfdbc8e44208fd37ed35d1644e813ac227ec87a2f65
f67ed0eac190f2dbeca6f7c805d4fd4a00df8a175e84eaed45a8e42920145a4a
cc3b2b1fdc1b5d02e01762a386d42e5cd483b65b22d62aaacd1d0f75720638f2
41e853574c8578351851558008f9a1f38884f5243523af2b0ea16b45d908f9a1
7fe50c6202a440fedf8899d726ed0abb246cbbed576220fa3a55c09414f36cdc
383dbd0a0d59e49726298403ac032c04372a372d4046a5d227213c33b71b8719
4f440e2fb44f4a174e99424fa1af9cdf1f33ee4f792c24bef934a22a02a696b1
1b13a898c0dce31ebbbdeb644cce5d686165466c5d908668dc8f131b47d82f6e
1087037add47efe0f24a9146c4bef27e7b9d66aac8cfa62072bbcdb408e7d1d9
cf33574f5166fe681c280f283f7ee01ce25acd01d4114540d3969b0ae9319c0c
278ed90aa1a32502818e131d47f544ffb117b52815eafc597866fcfdba79e857
b742a20f2df77b27d0a768e8b0eedef76aaf9503687f461ef774915528dfe51f
bd15a86bfa96c5b0dd2a24d2fa95d7a9ee02b44f1e784425ad06567b938f128a
82898ff8cde68eeb82f600ce27f7bf55669d2c04225903b5a6f1096e8a59e2cc
2c14798e119d5e32db357c62940c6a0b2ed16a0dfa9cbc7cefa3f73c9e16ef19
a30c073f090467e41b5a6d560f3aa550fe759643b49e0d7c0c417aadb70d8735
b91bb5c647c0fd2bd245723bdbbaffb94624a5aba5205b687b402b75d8d46c25
752f89b1d5028486ca4610040e13faca2e4db8e1894303a20a7e5e8be9aa355b
27a841a64781216979f462b487628f05410b5ea8b043f424823fbe90d3e8b1c1
bb07f5916ed431193629b0500fa32b52a942c4bb9d94a4ed8811f81bce2ade64
02e94c74575fb0a554e6d6e35f00065aab5c3186850cd7bf120f045a194755ec
d42a094bf29f8cc1d4ab60a9eb28e8c5de55b5228952051ff5e31ec0fc06dfc1
eccbe65740a12c4e162a635ec23d030b7f33c09292495f50bdafb78c1c4b3ff6
eab0c36d47c02f885dfbb7b49b46015e1fc224f6666e619f7536f6ef760e6f31
7a4bf73e690a4a705dc8cedb1b25b30a0a4d4b3b7961cd2a4dcee41f4c60d899
efe93663c8d707025bd9aa9a416d6f1275892176e815f700b1cd549ba932a2cb
366697eab5d423ab87bb3afceecc085748f80ba5679e97ae582b2b6c8bbd6bab
0aecd5edf9d1482f18daebbf0122b12182fe0323e2139f54e9d531c215d21cea
63d989094c6535412ae0573be3e13728ba9a4dfb50ed3f48ea9bad32eff06531
ff69b110a571f0ca5eb073537a8b2ef5b16942e724f7d726fe3344aa31afd59d
66d0578b035542efa968e040a0bc62bd4d7f917cd1e290f69fef284a78116b1a
88c1b3c5f773d49b38d91ed6b3394dd130754971680829c935ffd39d5e04e1da
f4c865e0f0c7fe77bb3c537c077cfe4121217bbf8dd8e98bc50b2547d1b558c0
156df955f750691155393e8635578b79205e260627e59107ad3a5ecc5686329d
6de9a642b1af59d3d4a252877830df326bdeebbcd792d50a059d3f15b2f825e9
8f226d2b59fcb3dd97b26e2311a33f668788b8d1b89df9d5c003744d3180ba51
806d511052fb9a3c7c70491aec97c4864131807b48684030c5946cc39e58132a
3bebee45faecbf976516766243eb348ec8f26e13dceb912464fdee32f48aeaf4
3385246788949d5588bb02d4d8a87659b2a58bb378f8c367f7ecd27f04ce0d13
5b68afddf5de79ea2ceb98c72a6ae009419f78582d31f0f347748e3a1b23ec1e
2acd0f43df6d4a304431d133cebf2adc82be9794be92bce37f4f08b2d9e40373
fb2eb085c331c8c9957f810bbf7a20f3a7902caa11ff47645634839368778bd2
f760fc3fddac2ecb4c0de360fcde6208fd07fb3bd26da3684f21622db406bce6
f1d20729532cdc2d316ce9f0c8d729e00da1958719a1e5a509b329168c4bd7b1
71934f05993fb81cd7a0a4e42c9b26d6eff26b09bb54db4009d2eb390838339f
cb20d2d263614d3a3cb2b9e1fdf59cdabb87e096784e32d9d97c41f8d4d246c3
2d6eaa124a8d30aee80372461cf8e36693684f022da6740c911e7fdd53c8662a
fb1ba15c8421310574700f3a4e71d60e5cfc3c4b3ed898b48b62c02d5fd22332
65400dbb38368cb2281c48de4db63c58fe091cfdc1e8895e20c3336b5b63d9a8
9ee1611c5e67ff1652e2478652e52dbf637353845cadebaf49062c4db09a872e
9e75b79a6e4751083e3c49d36fe6a97a2f69344159abf18835640bb8e3536207
02e7bdf3c4935fcc3d60c845627a5581fa3c5d34c90af7cb746845fcefcf9f58
644504662f90a5a5ebf39294c125db4c78a23662de5d4b3cf473b2549e4420bd
b17561e5740eb83a790de5148c86feb217abfe743ed77bd75e503efcd54e5283
37a05c14e349053f38a611d533b81b25f622fe2a5fa9ea98e5ed26082109e84b
04245162ea0cb386109b21671d1396ef93bf16e533e813f6331fd03cb4acc2d8
92840e0227b7fb5541f731d4d445b74abbc82dc562b758ba6c8ff0bdff3ffca7
4c4701c203060f7af5d96129807dc67a68fbc7ddcd1fccb7b13763e63bf416fc
e0b90a694e8c33edff59ac4b85a39e233274fab0a6d3c8f3c9a396a5d16b5d43
44f35115d81ca9c047bb7c2e507d8195408ac75d5bb6c2c142d17b4c5406687e
cc8f7e04d79a9060450d5a71122ae8eab7f4db7a11ed70dec6119d99a771e1ce
e023631b0df02712383b01093b54e34e638b83e2c774a1f5419c0eda34aec8d6
3df20dca283fdb30bc4a1e91be07079d2e0c39b46a8eb848f3c02e3c39b9a86b
08d8d53625c417f2c184debb1e82da691395cbc296413ecedba512b166ec44b8
0f8c50da1f565d5c0a5bfea26b60302783ac3b3b804cbd46565fb0d83097c1df
ae3bd64aeb7db347cca719b37125c36e69fc79c5e105fa73bb5246048f61887d
574306b5cec710d03820329e8bc8feb6df497fc696b624394e4acf07377a29ba
5c5a10c93e61bd3832bcf1c693b494280fa8ac3d88208809d82e1c32a6ed8f88
9d2aff1431ca82319532648a2a0d1291b22fd96cea71a4ae60aa63a23b2dff08
eab75dcd96d4c4b03c016f16e320218fbdf06ae4e0643ea7e98afbc3fa05f11a
77cfa038c394d24cce7c96500570943a5b40f27a4eb4fc7c6403addf1a60a850
1df3e271554e4e29430138cd7431a5cd87a47e5cacd6ddf71a793b219887320e
5e58b23623aa56a2852e325d5cfbf43bb8f502be5cc1b18685fd56ab5e856470
1dfd2be84cb2ba94836e3e685caeaddadbdd34757aa125a4bc9b07ea1b8a39ff
27a1a8991a4da7da6716373bc4ff01dfd581e9af36a7d24d725e6d5c44654646
eb361de309325f679387c4af79dcff9a3c243e3558f595eeaeffde0ddf8df815
8188c0d38f4c90942217e4304a56174fa0dbd8052276bd8b6d382a188d369789
3fd31505503f4cb05db4f3de5e8b6b1912a57d4488c0fc196958ecccf1c7d664
eb18d39d6fc9ebef612b9bdd04907a49040612837dce5dbcaeb93e213205c2b8
08878584bfc70403f8ddf96e9fafa5b740b44d739443b2a350c2ac92736c4df8
14da1468d8946f685d88e3790cf8bbc0f629b93b6339dadbddb25ccea9fa956e
f79d58c2f0aea80a43a0a1cafc9899784807bbb170f0c066b25820b54ce09626
0072fd957fa7f3ff404acd69322e53f0866a2fa0fe095b316213020cf8a70ada
6d925837b9ab7cab7fa7180256a3ee95adba1719cefd97f7d99ac76760f88bdf
b8e293e1bec28e365b68f6f5de0d49f2e136bfd678c56687c2203eec88e4793b
a4698895ce9c87633ad852eff4e8bcf9f876a8702f27532274ded9cb691f71cb
034fae4542256b85e2e9623fe03908afaf0716dd9ccaf0307a78015cdf54a466
3e3170b08d8baf390289040885dc7327edbb2d6ade4945c2a1e6f76b21cfa36c
e8be186666bd551514872da346eaa3cc35c8c50337454664245a93e585e65091
5e209cfa5c4adc2a1fbbae4000cbf517c2ec78490ca1c3feaf1682d9b5a67788
01936f9cad1bdfa8b5a48059b8cc8b8a20780fb4d0697d0e34795515668c3e36
c07346af174f1cdb17db0238a344ac53d611ac8efdb3c8869883766671ffdfeb
00c8c856d6fead3dc125aa7214ba96af1741c09e50dd6ae812a90f1ce1198a84
94a096064892a05681dda93b158cb01ae06f0d53adbfcacb113eefac113a003c
62dc417d93124280b485f4a328de4fbb9abb173d52650e0e92e19b9e076edc28
8e441be2b517bd4a708b272476c1db8f5b900539ba6de212369d3888b55e5200
5b4a94dfa8cc8758fbbd94c5050c1d3d49e37dabedc5a57231d74d54d15c854e
7e4bb499ce56621559d031e96633b27f9c1650d2c87a69090d7642b27b75950b
3d4d13159007c1844f58fd06dfe72e4c39dff4870c47af15fc51b8dada7fbde0
6ee37d17b3f1faa69cbdfd05c30403170aa9d70360312a10ca9835a55d6ad08c
3c7426c175ef6c9578b3d77eedbdc7c0a75e2780d10af0aaf022545007102ca0
38b96c242668697cd23b6fede03554362210968194d5244d8258e0619691dc6c
1017eb4f4182dfc165eb14a509c032835db55f1f19f84390b929e79864af0f73
29151e30319e3716e18a9e35019c1cf5582c6b6eef1834d199762019b7f55243
a5d3634de4290adc09f371f737b7eea1485a760ccfb249ecac70e7badc1a364f
fe27a2b48c7fbb04b31d4e57e92ef1f659bb3332c60983fcdf65e9b1ec8f5afd
ca93716b23579ef5c6a19514de83a51d5683f8935560d21a1198ddea5994e0c4
c639c7e3ed57215f116cde52dcb8af3d1bc4b0396c70d726ec284ffe53ef16e7
f53a187b2dccf23842a031cb851b7feed4f3b1faee9a33e31584ce9eeb2703e6
7d0864be288e2be57e87012264c9ba0d951182cc56fa42524ad0590c2da5d12b
3e35cfc13c9b79ad38301793206b0582cd2f58c70a50d1c6d215b9a181011eec
b61fadee6c7ee05a5da7d9c406c0a50038f1d3350f9a4bfa2f91b1628a80c2e8
237b8c775a7ef21c9d716841f710d4171da06ab01de9aec40596d86fbe508f3b
c718f3f58b8449276bd8d3e5a8b2a4e0ff0d36939fe56f2aaa2144464f480f4c
2e5f4db9e005acbda2bc708ec8c4886d8605400f904b5aa1fdbbdc2365a0a485
91aca91aaf54d184c3a10925e151b0f1717ea3a0108f2e818b7d4ea12de17a10
fcc9872b222f544eb3a5d3c9898c9755d2c390cdd16648364e358257c91931fa
8e31f2b5f4563150ff942da203aa04a9546bd812810543850b472a3970d99144
9baf3419b2cb23c6dd1b362aa2dd2b74fbe5a014828455c62d5b0f8cb668d81e
ea670b43b0cf64200e4b82f64ffc5cf662c21cae575e0bc8f4fbb73fb9f0ce66
4dba8ed6c2ee158f98e2f8a0ffc9db7cdd67ac30987c330870fddccf99d41790
9c3b35fab51c49950910704c789d7a1ffdaddf50acb657e76ea97a3a1dc976e3
02a0710cc36224344af113f27a88845ae00328687a47984b0b7f692898b72a14
35488783e32b9b52121abd7d37b08a9dc3e2f4d70e0f1656e8c60be9a4263eef
cb0104893f46cf139b34b312529862de4b42fc1d5d6835c40ccdc01147e416e5
229457e5052d838e6684bfcbff9d0e5b1475492c7b24689e24cc6c8a57cec934
faa71ee52af14f53d5a10355358e58cb1865e769c554283bf1d4f0c31a2b1f12
58e03622a84cf46679f4a99cf1030ba2786a6b30d888900bc5b28e6ee7778ded
197e998c5c3bf25a17b7e2f740afac2ceffcd8dcf9fd6a264390dc04dd9d5ce5
573f287836be622af004d4ae1be2032cf3014e4716de5b6682ff34a4f94fe9f8
751d750541d05a07b9e4d756fe8b226e7b917140613eb09a56d07c9c8e766203
88d253083b3ccc63effd6078b090a8862f4ca5264d45e94460518cd95a86eaf9
4995be4bb6432458f3d7075d09dd965d7a9d7748b57a0e1c85ee529a904aaec3
faa7115369b77521d4fa031fd6f80e98e3ca0b310e2323668038f29d595b0a09
0a55ecba3c9321e5f65aeb0799e572d39f11d8c31afe064e71e4f450acee1ae5
f1567aeaaa571176f8925180e0f0282d63c5a557f81f28ce695b445bafe38bbb
c23eb4ff9e2acc5cfa7bbd9ca0f6fab40deffef9e6f1b0447a15c562faddfa03
6685c8d8fe74fdbf1959cbf1b055dae862fbee7e0bf48017a7499ca742ff7c24
7f70862dde2968f052ca1c09e1ec083cb559ec4b5243fad6b79ab1c783f57bc3
d87943c6b187f1e89ca4a89488527db2bc97df31731974a9d456fa826ba2a2bb
7e3e62b77a364385cbf8fa3a55022736108fe576447f5cc9d0987370148d1b61
8aa41af28c82e1b90ddb20a21b5c1624cee29efcd97227c27dc4422ee55900c9
6502e803e2003a7d7be899fa8ecedb45af7f45038375032f0f7b05a0714320f8
f8cf70361f0bd041f5fd3e90154b21d4b2259d1b0b355f9c2a62577840e25af2
da627237597afd1cbcddcffec4a887614d4c9c01c75cbf6edba0a2d8a865a7f2
235ad01844be36e105df08b55e3e547225c1ed5475db9146aa7398e655e99661
746a718223652c696d1061f5d3a869fdcee27fa17dc4c1d5d077de52083970f0
190a36b4e3a01bb889eb14a28a0dddddbafa30df01e6709ea5c9bdbd8794d0de
ec89afc38e1879df93f7d5d3eac5724e1ca9ec05a007f34f2e5cb800459f473d
4c5c986bcb34c5760af9fed5ca4fde704ca51adffa323c3f5699340d4573019a
e1b90095465dbc8fc89c3e55ab35eb090b9da0630667055151c27b2842528dd7
0de0bdf9d98902c8a4c49c6dfc5aa80099a0f9a63585e685ab5f2754bd1deb3f
3278282ae8e7ea6d2e8790b28de040034ae5c9296c012fdf6972635472e9c4fc
f5a92a2a755f8c2d637e7d8dae03cb37554b841100c1a1580b711a80c3e177b9
c1819aa647653bdc4540d903d139e353935e2f7cab577b739883bdcbea27977a
1a62499abe41b2646d077d59650af1d1d7903dadd53e0891238469dcdec9f6bd
7124c08ef8568adbcde95529dbde0da9dbb3e28a3130bed644243d39c022173b
aca61fbb8fefad91fa9f18ca9d8131119d64cbdc06df5193dc11f199b5b71013
d657b6baa99a0fba3dc754f2e51d24f5cffe332cd0d8c44499f89ae9d804eb6d
6f7a9f553338c0cab7c83f4c8af514058e22fb3a404a676532e46da9a598bc78
6ee45a3d736a142fe7e13e562fe791eb7af7665e96507e4e496dc43bf54f791f
8f981a93c0359cf3fa487eceab9843fc0796360d837cd0cbc2a78bf19a45905c
b3117952935013eca119b15716fa256a9387768db2b8bba21410ea4931755c3d
5e3f90ed45d86d7eb9e38cd079530397a1acaee98bfe1d0e30c96ee519336136
045721d6bd27a2420147a3bf0fd024c3a13dbe51f1990440fd4364fc1b677351
0de2f2f2dfbcc38b484779a7ff41eeba5519c47eab6485b1231eab82887f6953
396e930ed56b785c7a157182ecaffc33b8966b531803d15bad0e47463a898786
f0051065fd0122da0ab8e22fb5baf9bb5b66294ee2a4870becd246a50648c768
3b707a738a688d752fbd270aefda6ef9e6fffa82e40d980078a41f5673a67da2
81d8a61a154f5b58e4405101c40f1bfc4e9d690df2f6694ed2e77c156222b911
7e995c3628f37898e7daf1ea042ef843fc5e98709294754df62dbb2cc433bf05
0f0366fd1f0cc2ed064fb7837839edd6e997f30a1c0dbeb4494a4f8082eeedf4
cc9422f514c743386180219a3a9703b97ad2b34ff7e321a3e27959966d984811
aa178f5c1ff519b1e15236350530f800912f025180ded5a594b1c8246f4fd6a2
745a957be5685f3277475a4256e8dd583ce59baab0ce1fe5bf64664a08eeb27f
2b1584f7554fa1e36d4c38d86c046bbed8ba6363d2c5f51fe37d39d34eff45aa
62987d102a48d6051e6f2c46403282602f11cb9b385f131c80c8e6f9bd6017f7
fc742cde8685e8ba5ed0aceb672b6f8966c86b623d3edfa7b9e1a8672a3b19e8
1ec24d1e15e38d739bd3acb45653459aefe205a84650ca55ac29ebc588025353
257f64c7ca66ea1557eeb372ce004418281de28cd04667660575583314f7b5cf
963b19e1c25cfe361314dbbaac370140758d089ec99e5204d93361be41d6a222
a7d81e9918be41d7f77b507476bc059fdd5fbd23f44396ef059c4b1ca727a215
9ba7a729a641034fe942e2e7bccd72aeddfe860fccf9343e6fa3b5d06808561a
f8c631408afb91308df463c8880e4a36afd826bdd50c313cb0f8c0cea6048ad7
2ac71a1ca86b9838947fd1315508e13778599f04dd1c9cb31af8386aeb5f930d
41d4369bfb8305950d88b03e32772e28e4b6dd470f86546fc66edd755bd028d0
2f78ee32c172fe170b63065e2619df6dafa556ed10df94d8ce565d9c74d0d70e
2b167658392ca8ba5ced2c6859cf21cd2f6ea37df70e20a5a8d231729cbbd6eb
db2e79e3027b40ffc23418ee5f00e0dbded3fabfbd014b1300142e7d2fca3de2
c74c082083dbe38296fe318e167df88918f7328f179848c92a73931b19d12e54
3b346406ceb2980ba8ad713698e1e7c8355d4ae8e66a9bf49f36657fc618fd9a
9190114672f0454dc52523e1fe767fd714397fbfa3488a60c4863c32a2b84d9b
b5200923efde6b93d8f7ee51fa2733d79e3d064ae56a3301e68359a804dbcc03
7a3b87158756381b8cb560ed819bbcee7b68834660e24721dc578ab5b5f0074f
e3db1afdedfaa8fb489313c360be56105cca746bb23d9b9c5ee39e582b313f15
a1f34ee637ced35124924fbb85d97e74984ded2ab320e69861a0b60720364ddd
b9d8b9fb5d101f40418ccc4c982dc6669196efad1067335b55938033f901d7e3
9bf1e58a5ebede71f74745c36e708a96f1295402f4845a1948e7aa64279f1e30
4efb9536c6862a4ccf8871d510a46979caea00577c1b00a3def25906db0e1a94
8340809a2c51e37476ea306597c86ed8196516ab4c0aed2e91d9946d8df6192f
421009142d5fe9615c071dd667cb500afe894bfadb7129b1e0899c34400c8035
3b77fc9278675992451871be34e040612722185a0419cd9ae6024cad54eef0ae
9533100fac72e7c0069e6bdae00f1303c6442af8f0192570b46dd692a400de22
3c9556e7147b40dee5e9ec5c160d25bc374008644c8451654a2be31a3f02ead5
19b5ccc2f432ce4e3315e8c148fd1c265609bdcd4355b8f7b7f4e32bd25c6341
1cafcbd630976e3e25c4792dc2c667dfa17b568853d0a113caad7048edb2cf19
47d1b575894a4149b25a2aefbc4f28fa327486191949071f954afb448cac64b0
6a5cd0d3b17fa0f6f72d1f0223d878bdd8bb3310423380ddc5b4e6ec5635ec43
87648002b40cd3e17f41f74f41085e28aaf9a9fbe2358c85c3e9050963f7f8e7
fe232ff970df2d8fde8f5fdb703348664f26b0027e94208e0aaa75d084f22489
937641dd38c433fad4d7323f3585245908891212cc3f261a9145c5961c9777ea
9efba3749adce903d0417c48ffa2eec2c23e76bbc7d93aae2ba1e9bdd0b3e419
4a7669be6624080c0276f035bea6bd1cdcde6577c35a9a470d0b66b9718ae5ab
cd91712fedecc359344e7292cf30ea45e3b1907710fa65c970beeafed7ebf183
a0652ae2557867a5c4c911cc916c7887d475b17e4614c7a22cc85355a2f4c7b4
bcd4abfb4adba29612805ba07cc277e5877ed224c8f02b9cc19de6bd850b480c
9e6b0b569fb74d012cb1a1981486e6cf711767d839ad03917e1b74b7cf96fcde
7e62324fe2973ec6f29fe7720ea8294efcbd85e72f49a7b7ec429c3405fe736c
ead1c1bdac04edaed2aa7859763b5f6ff72531baed3328b2ef73ee1ee39712fb
0d1e88a6fe906af4788491bd19568e784b2221b03edf1877d890813649f54675
b52dc09612f2f248aad62bd8bbeb3b5a8e2d20e05cc1ea6f1cef1b8a724dd23e
8fca0deaeb2156a49fb1d783e34639d3af855c83535e6d0ff482088e180fa737
3bad589035c5953b7331e1b72cd715f7e8d62fd4188cbabb65de47ca6b44883f
78527c25e3db628dcda0aa7103ccda3b01d5218fed87359d81b0a49fbf4c5c90
0aa9ccf289d137abcb053c05da7a78c07d74b02e0a90b517a3ffe5c943b3f9c7
082f585f152dda82487cce5f72c4f8b04e301f91dfc9015ba209507e7cb38402
43b756c07762c0d60cb8eb64da504ce0a85dc90eb695eb228d93854edd214c56
22acd37b303e1f5e08a12d53ffffdd1c21ae2e233797acb4f8c28813ab5a4d65
0d82730732722432b24ede7e89fd2a9361a2052e13492f54fb2e8564fd854156
8f503b8401a14cb57aece45f9e96cc8f14801adbe1b7d641f9e64231330f8983
916d58382420b7833c0c48e00267623e033defdd7b26f7f2239983266da36feb
ee6a0b99b86e1f508bf26aa4e29d78a47258045c7f06812fb69eb17d2ccc1bc9
6766903d9fed4e1ed19962fad8a3b5511fd1a8e071af52036115ccbe01311ad9
c3ddef8fbcb26dfe1a85e5082601a6f9bebadbf8d06ac48b7e44b7b24926772a
06e76615e4457467a6b13570be339d75764626c15ed13ff21639dc9044cb1e98
82bc47da8d7e7d66c3de191f7e4d427e294a8bfc36c6527d7ff26ccce097a804
be1fc7b87e881ca3cfd1c12c7800f340ba8aa3ce1f993732daa26a06909d5913
9a951f75e4c89938d9b0976294e79614cba3b25c2a9150780cac2e6d312e449d
244860b84c7648a2dc95a8ec1b49d47cdc434195fc2ebf6783cb9b18aa784470
f5d13c1a54aa45e6b57892ba041676192dc94fc8b42bb714c274b6b13c434ad0
732beeb2dcd808c189fc381724b37075f5c96fc1f2dc12d37ea48cc773ed1852
41fe0421c888e2eb44b96d34121c68f95c94911cc9fe1d3b49a6736d3b93d803
5f4227d9a6295e6bad262af5f3f5bc810de0daa2a7eeeb8f1c3e575d806576e8
8be791c65bba22558639b688b5000f8f9bb4a6472471a8a48a747183fda0284a
d52ed7cc3bba0d885cc340f47166de7a30c0df7f0a18c39a3613a842b1bb1648
070f5023ea7a64e29d02f4dc1acac9d37949473badeef59484340c9510a5a107
9201040d4667e62d3aa03bbe71ba17a6ac14c5ffeb7b2f26f929eac63110c09e
2bdbef7bc7d6e7e227c3a3f0a1524d6129a8feda3a5886d3285e6510900bd500
c4444c69f223aef39da17feed8d9ac16fabf06c5f285aedfda14c54c2ce69638
d8b255b567d9dc5a2d60a0fcaac827537de12caaf732919880940ec5f35cff33
719545af98ef4f3581a23c187164da75a126479cd1395faf2cadcacfc4fbf987
f82510d654cd116a35d12dc7f0cdc8a604d4dce79caae78c27ec0b039817a424
22b4ae751adaecba81fadef06f2e8f8fd7af022fd299fd74a8dad34e473520ac
80ecf1f5f3eb7c741e497c2b7474ddc7727584043aa92015bb45797a57698b8e
286d854973aec49fe2d60573129b4b9b1fe0450c50ac519e5a97fda56c8dbd61
422076fcef6cfaa7a466cf6efad1e5e453d668d36811cb44258c5422d24597e9
5dc1d40c15d83bc096f1267d90d6dedfcd7a30e4215d97c0d3d8616d88e35518
357b7f1df372a945e6373495a70096e36411f921dcc6a4cc15a148b6da6b2dec
9abeb74c6a7b6660d4c20825c60032189fba2e3ad8eda68133631364b3fbff9f
a3f33a185c5b8da871f05c7bde62b59000318114b5f3ac006029a51664562dac
0f969c2568ebe6b0110408ffe92063d09494ac06962594cb0bd5f97fdd627f38
17e01014dd7a88ba4a6613cb261789fc9c529a8740adf710f4ac4381389967ac
9a87849a248559555071f725cdf1cb0198507f94297cd468d1a0764eac19cf5f
2f1ebfcce84f57314a676e066533d9690f0deb72dd8e28f06acfbdfece94e614
7da9448a90d2f3834463327e9166736da6e67e07eb2493c52413c6948b1c2c21
4b9558d20f927d747b3916927209bf1297c226eb7bd47fd2a6748c4e00934aad
0fbacb121da34376943d95e30b1b6558d10242b8e2326d5757a619545e81157b
5630390d96550173056c205a01145b31e6405a7351ee2aff0d856e7ea3a680c8
3d5c694e61e4ce343fc7e63b52426e9e242fe7f9c3b3c599b4a328bfa4affca0
1405a7f8b1ccb465468caf1d12437bda6df704081de3667fdb596eb707019a9c
453021f83318b0aad218f5c95f4ef566218bcc7e1f63e8ae99b35cf8a4acbedc
00b5ad3bd60419a1d5451aa1a2de814d1ff9eaac474d81fb3a92ebd719484ca4
a3cbed15d0a31a837733a8e73fffbba7c5065797c250c5f9ecdc41dbd32ea49f
6ada82cdf9293760125f4b86f332cbeea7a45fd1c34d910ba11eb0571370993d
9dd4d6fd61ff1a48838b2c7b2895c035536d6a90ba2bb34d47c16e6b23409de9
70685bb36ad36ef6b54d5379900823dd9c6bdb4fdd21b6575a6930869150bf85
5fd114e331cfd5f3b5ca28fef4d6a0e27150268d5a56d2c6a755e006873dc49c
12803e30cb575c41cf52a1335d9b83df9a89813570b906f880e322f3866d25ef
acbd068122606741fb6436e0305d4e9e7ebb6c767576a3b9dfb5df0936eb7b54
36f858f9f513c8e59fed5f038855b8dd39decd7301d1f90455ce385b736cff8b
47abc31fc4c66300dd9dae15c8b02c059784567cbe094ffb555944e0547be9ac
a7cb6b609531fd8a6024b8e90a3a26905b7f10628f17ea42fef27476f7c85f31
776f56609ab3e8e23c3bdf956e9323f4f4cab6524df8ec038ad905c61078de2d
562b845752db002b02841006bf8b875f438b4f30cb5dc249779e85f691c3b808
31be0b95175faa8bfdf96f07a3065c98600e9185f5aa7e6aaf9ac76ae3e4abf1
f258fb30f4fe0d538c6b899b1d63d3322816b80eee1c9524b1bd49147255fb98
fded3c7096ba4e3066eb19797873542cd9774d68e388cf5438784ffb13649f77
f441c4144f67c8ed0de542dc745c9adbb82914cd59dd829bcd29bd298d8302dc
5ec529025e1a3db0960ebdf4fa05d3dbdb2834abadba57d336e4a3fbd58a91db
a41176c8f284075aff83d2ebe7681dd4aea633400e67a2b60106faab1713376d
7b35feb790505a316cad12e25176daa175ff81d82a9cce59266235ff37d33d07
afb72466838aa932c0ec3e5d80dd77bdfa503e71377add9a1368ed0f15eee6c8
89d20078fc59b4e5ea5e554078c98e3defe31c226fcee93f2abec4672308f13c
8549af96147fa7a39d99fe88408a0dd2a150af8e711e1a0cf967b76cd43f60bb
489226bf8a1c20eb728448754978ae6616f0da644b15563132e3a48347d3f6d6
e4311803be23fcf08aaaa3b621f546edac459fb61be50ece797c9945176299c6
b8b2191ed8b0569a1482a9fe6a85fe25d985398372aa08115ad8663a4a46e7c4
97478acab4965948569c0e4566bd045f96da2d7228e03ef7fef7231630314325
af9278a7d1974b2b7389bc0d8db5c5dad0c3a7004d0d19c75e9d5e2339ced704
f29e2c3d00d878c2b97534fbd7da67666a0ecc42bff7c9ab7240dcd5c57602d5
ad30ee5b51f55397298c2973b7ff21545efbe65bd4ce80d0f9b267208a5d87eb
0833b65437c3cc4e2837c3b81c4ab131000b9bec8d1ab3b25c252eff9fd9c78c
2aaf4094fa8642fb9fc8701d80e938578b5ad94354e7da1bf148fc672ba62dc2
0eaae8d67ff38613381c31a3691f6785becb66029dad426d923f350373d2f0b5
f6067f14f752f1b30f695244cd4c8ebe5288f5891e14385f0b0f78623337f5ab
91830b21a908df96e98f99a6c64f55ba7480ae6cef994163ab9d474245f3ad81
0cc8f86e1aa35b803a8cd395139eef46031d5fbd226e6ea196d1108e2f418111
81772e3dc497b09682b94985cf4ab71e570057a8773ba1e8746557f01da48408
942164ba0c48159c255ebb3863b63a6df01588796653f4ff64b654f6f83d4b1a
506efc1b92d298384278abf2f72c2d5f5f2270601778199755c2a286fede0ed2
5b3ef03dddd01baa4300e4057bb42b481377e340455e6b81a4dc76a136700139
eaff0337928ba69101929b32399b6124da408609132be8c82c24e1eb5a22db52
acb8cde10c11ed994d28af65e3ef0c4c5842ed9ee3fc85c9e4ec90b6e5cdbf3b
cf7a11260080dc628364abaad8075e104719a78bb11b53ada7f6c8249765a179
c29ba40fa9d4f5f0127846b659981632274ef376d8bb21353a53c3999160d79f
9365cb846cc5ec93c7ba352cdbadc1ac2124491d03386759fc4e7e7942cc84f0
3475f2a78e8916870305d73c78feedccf85fcbc90eafffddc267e2bf53c03153
4369299d2fe816bab9ca7ed26a265881f99896eb80cab23118f6cbf29625527c
b29b53d7b168d5487bf62d93ff443b6fb0d2650152f213e6299a119382f75df3
ac4b0089a85a24fa181d45b5e0a51b7554dacb4d151bd12530e1487793dd8fb2
034f28749a2c09e004e5b90216a2162e1b4615ca7a5e174141f775edc7dd25d1
b0c45140e01995f23fbfdb1b70e20549a171b8ebd02a6ff4a6d759966f3856ac
a68eac2316cd109a77e371cd4c512dcf6861cb083d707000b790d7c3c80e3a1f
85b6d65c549b7dc5777d9522bae11b53ea14a93d435fb1a70ed3eec61624d2a9
bf130d40c98b99f0077fa37b7bf71a79a5280e53acdd0643f220ac35b0e3c7f2
812acd3f70db2017f330fa3157d561e683fb1214e5dae7779174f746ce1a3a15
cf1682b4798cf33c4130dbe3fac96307089fc6322945a2c525f81c6ac4264ae8
864a357ab50390424d4c56808d0f09851d1f9525fab0f1e46aa491bc8677b2f5
d1cf316b918c0dba562a04ace09ce847c772208f45929cf55ad2256133a33808
25a66205dfeef92ba80e3d0258e228edcf8dffc98ff670b66938933300d73e3f
950fde9bd0fbd91e94a81f868ec5cda6e24148eb1903bf5b883a32e2419f5f65
9204957da833b8a547808c297d77a99047769d62b54b86ff9bb096b1b7159da3
2ceb411b5b86803a1753fae4825d4387e0aca6c38f75339464660afd32bd3a90
3156a3834e68a6fe33ff0a5c2f06754f7a4daf144ba2041af41652422aad9679
3767be4c2203e559abb8df3e8651ab6d8771da6b062765493d4192f8a420960a
aaa32b350461cad99e4e758d93ae88a5908a808ce67d54ee23077603d7695414
b9fd11b3b9a3528c03f6db50cd2e9d0dbc7e1378c19bba6cd16aad82ffa8db9d
d9caa5edf4c5494fba0080e578a0e8eb484c88bc031ba90696728e9f34a61edf
9cb3f0ee74d4fcf8f47a1ce55b6c8cff354b3d50cd2fc758cf0c8b6a052c4c9a
cc161034408240dcc11a86b1b19929f54acf399f8df17e3b1493ae6c06e16a42
3c971a04dfb1c2f148a6c791b64225e78e44fe8fc85bb86d1bae33e9120ac86d
c8dd37876d0170edfa8e98de5002d77f8c0453e40d9b60821db0668bb6ca6c82
58e87f9a7ac1623396ab3204702bbc0b35017f632e66827ef1d3bbdcb59963f7
9ec71209cd582581dd733e42ec3e863c9b87c2e410839e6ccd8391f5ffc45de6
9370f59692e167ee38359f1e74965d9887543269973fb9c08b8eab8d57d6a9e4
cccedcb47ea530db8f5a768406fcd84225a08ebb7a7241ab15582d9531670543
255b173b97d2f2b70338d6f95296b4e1bbd2aa23ccb79e32a52ef2de144d3a5a
c403c4473d5470522a6475dbad9c0faa4303f514d9ffe7caf2c7acca88ab5c16
44a7b818985c6db65674d1748913b0b1c0bab0e3a6e74976c2d3ce6a88f0cde9
bb824dcc4c65eff43086c6028344518e21b51a7e8cdbce54d1063f876a48d422
7f0267e3d37383973a2a151909c5af99e628ddba7b7982706fb12ac5b4eb4507
adb1be694386e391235c939033c857be3ff84123dce687b6978f0e03f6d89534
a8e34f21cf9c505c57eee55fcb4be98bb157f9d29682eb86f99a0e1a2c29d84d
95ab1cbeac57a420b639e7cf46dd033f8bee0834c122953fde9d89c2d1d83e57
748100ba48380a4c52ef482aed63504882c8eb076ab845574269e0c8ad92afc3
76914d631445fb7b688025c62dc930424945adbf893bc51ec86791605d3e7d9f
d8d854a17794699c502c699004e0c19494835cd04f6ec57c6ae4a495a2937f19
b639fe8f6bd54274ba5d4abcd456a3e6ad0b77c9df7c2b2aa5fc01fff4e2e076
e5d134e572584d50a92e89fc19a0e394d542325ed60eae441a2905923afa4be9
087536681d41a56323781f7cb03f206837ae7ad03f9e314b10c9faea88491c57
75664eff297b1c3d9f4e0ed8f3671fa203aef8f915e75fffbf88ad49bec044ea
aafa99cac77d158221d18d38b035a72575e3eb6be295ea3fd55e7bca8aa15b03
045ac706fbbaae9e2144891f2071d4f7e2a07c68bc8ade9f7253c4c226c0f5fe
50ff2e4ffd89dec34743146b35ccf14458da80076305c055800ed37ce2077d07
dde67019e74d5e5d1c3cda1d60faaf2b8a039d5a18343b558e680ede8ad50990
538febccb12df131c85e92e3711e7bc0f4526bac7b5a0fd4bed25f4f09ee068e
5a6527fbef4686310ba6cc2b08956bfab81ea8933af90d358b49f78278ada3a5
01675e833d58898e81b83a6c0bc4e94af4ffbf27f57cc46e7cf61ba2d0ba15c7
40ad1b4618b156efe2bbeaefaa23c50b46ed1232e58daf4e1523286f0f7a34bc
012e19309cbefb5cb2a83bcdfe3085725d019c975d0605f62a72e4d6a69a398a
70a62ba2267fc9d9ea3973521a01864521f21cafe293f64d5aab7c167b128ef5
decb747fd98b14911dd100cac6704dd18f6ef93a7c750541b5624f961d226028
467a76ddb790288da954f4237b31eba4436eb8cd1eb603b6313e97e1ef2b3d4a
9e7ef025ae785b146f22f8fc363f4da944c160848b814336c1a6a75b8ad0ccbc
2120e97947f4d3064705299cc027835fcb35cfc681fcc8ab18fc6b1e2327fbf9
eafc0787b6b6e36593cfe57f5bb034c6dcf67f24f6a57e43f7a120ae9889dad3
9974f99fa959f9ec3d2a0354f36818373b808126dade578e76cf36283f972d8c
17771ec59a3358aa573880f6226ebaff5c07c45c5addf082e3aa258a4a6982b4
8326d694294987c19f81331eb27bcc9ca0c093d6fe1e0a98d4514ba8cbe68ece
555aa3690b8e4231cc919bd3412730fb7b82f1c0712f87d76e42f386b396f776
0435942de39d51a5a83bc1b2d3eb2448e5a97fa1e17dcb88b1e795f77a3e0bbf
63561be91ddcba3dbe20751c0cb674b07e76c97c08db0addd02c308314814274
6a1a9f91281a278377095e3b45e9e0272d51013434b93cf11bbaf8ff00544fad
a08367a0b00079ce8d1c45352e54d16f4cae96238954b7238c489a71465a0818
39dfa18951e84a9024c9a1d6e9acbb7cf4449906f4a83a2407f33fa5174c93b0
e5640705bb7c8431a12866cca5a7e05281cb2fd3caa29293a24a48d7ff4b9b37
d26d97db09f448e07b9182da190304c27b6165215a3c86b60b3c6ec58b250636
76baeed6f8c49d91a428c86d955fbe75d19e7ef8c1c5a4bc33559eb3f6a05053
88e89e8f4e157800076b295ba03e1c2791ce3f94cb9692c12d82c37955a4f86b
c05b51a064bb185882cc765f9d152111e8ba3457e4f89027b89fd3b776b12ecf
7c17e30119610d0b94f657ace3cad58c6ccd00b52d219d7feeb640cc3e9906a3
98ca5166e63ae661ab4c90e0a0e1b2908c67811090b68e86913e44f971b41c8a
f681ee8d2bd0beb01bd3560001c1267ac7fb063a6afcb58bba57219d460f9937
b52a52ebf8dde848b4d2640ce67478643e1c4948b90e967183bc1db7c4c4f80c
9b710c44a7cce4dc2fe1b7d1eb50cabcde0f3ec6ba1dc6f386ddd76c73cb9953
c352d693d113e54feb2f37709ec3e0b36c47fd82c7f7fe91123138ffaaa384b3
3ae0e186d2fe156ee0c501ae4a7d998d56c7b5c2d4b89b122b6ea4914d20ab78
c04b202c7af34356ab5f1b72e907d11a3dd5f18dab3f09367b9f49db4042314e
e15e49ef8786c64f9c2fc84f4202e40ab3dce7f5ea19ff5fe73fd89f3af6c5c1
92a8d0c14e3b73d2654a7723f1f90b18c1a3fff0191b9244b9d4c397ae5e67df
7a982c1d4d48712fab63e5dafb8686328acafed144508c3618d174abf1d9c181
0837c73f155f302c9207e1c5d700d3ca739f6cfd32ad40b74235cd9e10c8f352
239ecf5dfb74911f6418d2f3fdafc7ca56d96643de5993b6b04a206b691e92af
417befbd4aa46bf5c96bb56643c692db2a0d3c7cad4a28747f618f0dd7bfc14a
a813fd264a80157eeb2c67465d67f1951f46c19f00e8190ee5ee0f09ef99febd
0e96e63136aeae83e87debcb57d61ff30c154f5e5439038946f228063a5d273b
38d4f6124d1c11e11c6521c4caea6928840457f106eec2317a88a267e29f5cc4
22324ab0c3e286cf1d55502f87eb34d9982d216a53258681fcbba528602b07a0
9b7dbcc81d2e294908974b74b19d20742b82c5ea3a32485adff25cd67b2aca53
8dafcc13b17b7d2810d8352e524eadc42a38156a56023bdcf81e39f8c1f879f1
8002042c35a212537bd719ae6c0cece8e06358645d8ded059472337f73ad79ef
f8d9c786a17387ffd0bfb829547cbe2c83cd1da87c1c081920ffbb7ad5240035
dde075bd5be805bb157f660a502ffa2e80a730603606bdf620e6f2cbc7278ea2
5095bccb96aa14d0df88ab63944d92d43e877fb013da47d3ef610f2da0b23ade
64f24c1b4f423a19bb7d93ba78938cb9f9f37840bfe6f110787b5c0b941bd935
1f2da3735fc5286d800630ffd27f948b49bf01011bad3f7bf09a07ea6147616f
ade95368ba9fc26af963e2a00ad6fb9a71aa3a7dfb65413ce188d9217829ff9d
93eb811e2c78cb84e3e2b7265a04ab28e3ed9a6e208051b3614ae378a18c37f9
11aaa244a391e53ce3bb7e085a206e6c0c6f01717cd7df7ad23f0b537c3c19ec
ac4429db7062d0cee1f8dac43d628fe16522b0695f05a844970aa4c7a342e205
15653619dc0b585dd5cfb29a50c6e114fb57cbc054fd5c06dcb743eb1185bd66
ef0ce81d5fca8bb4508e39d800ad05ed82be856d27f2b489691419f1f4331ee2
9fdb882b49d520e95b6b4852cf4f3ba3ebcdefdf6288828eb97d43a05931ade7
79fde2a06a83b1137db4f62fdeda23d63214d423779471c0fe9b0e01b009d576
6e62fe8b75ae08dc1e5abc1a02b5d8ffd65699cbae1acf69d13f4aaa57000903
bfc4a12b120fef6d7c95441897faabc58f59583ae57e36ba0da85f1823efb039
a134df46dc3ed280540f2914a183c520adb9cd7e7d610509624b6e5ce733d8f5
78478054928987eb8900bfc6dfd3b6fb07b764c19ee038816ae9e556f117a3dc
aea2406858ebbb4cd81004231b9556fe8a0c9846ae633e074072580136167c93
6dae47ce95031013d30382feadfd0d378fa0ccc893efff314b7f852e07d343c1
6238022db21cedd7af94f0903b64c78d5e86c1ef332e0342392232751c1b3498
60048ced86b2eadba4de94e2bf568b4dd732ccb62209a1331c3ec62d7041b79d
ab5b93965c749bf58ebbc53a46578d204db98b7380c2e3cf9f39ffed46dd2269
3d07c298935c503ddcd339a5e05f6bde8441ae8ad94b8c59b36a2cb73943bb0f
6c24a2ae3b1653e6e0e78709f7b49ff5022cf063530795a4c9401481f042d238
24dd21ed095c8d13d854008f26aaa55a7fba87cddf1485882241f1065a061e7a
c90806175dfeedcee40afebc38fe9b6aaf5159bbff08d21c60d6ad4ab795ce7d
26c8fb3aeaacc7c0310fb3fad3958a2a6f41981cca66dc86f62413b896ce8ad3
80f533914cf980e00d5e13bcaf7d9e9781ef40c5fa308ca868c7fdd026f04c7b
db92b9946725707ae91faeeb052b2cd333bcad85c70dbe520501705dc63d5f07
243752101eca349b6088f85a02602bf582201d1aa9db0c0becfc17b13f5b173f
c4c5d2b86b35e4e56216f632f3138d9eefad76b2b3c5888ba90d43b8996a35aa
ecbd98117e7ce75405fac0bbf95a013e57920090a0186248af80e9834345f8fb
c8e3796fd6d0948454495aa1c8d6d7f7fda971cfa86e1efc0e00862b66d45833
a8bb19ccb06b9d03fdb3e3549f4b4df6380e447fd4e37466b68f58ee65712dec
e7d535fdadc35d773d1f9d6c6c9fdb87c762b228827f124b2f948cef4fdbf32e
ef85b4bf3db5aac01f4817b3d82170da7267282b4f4e4f35b90818e4a0a3a0d5
af14452419c232b7873a2cb715d4bb350ecf27a1b21c1c103bf260eb794c5296
4c1ac75ada3f4e3ff14a122581e5a02bf30dd85a916885e7d1006fc0b01ba648
cadfd7dd4660a9934c55bc84ed695d1fd68ea178a37ea0a7e6b8c9b7c73b025f
1737665648cc14f73aad4487ccb8f7d23a8d1b8ef7265f7d2723173650dff5d1
b991a81c1f316d5beb69ff2b50643a5c4549dde639ca491b4eea5313b9686604
2309fda143524992fe474309c2b733f3591b31bf5627b3d99c33093099f34121
dae2a43e7bc3ca0528170da9a8f090a7d11fb8fc8bf4131251f32e9ea8172da8
1c3063f77af1376123cd47825e7431acbe0af652a0a42d56d3519b638b21dc3f
8a2a568cbda45a7b5690cf61fd982b532e6f2ee92b790bddc798332f39d95716
e6da61b19e776d6d944198f17e5e3a8128d47793520758e660b49566273edab2
6fd1978b654c977383c64f30ef76199e562e189e3b72248cecc92cd10fb8c979
61fb35165c7e10739a99fa4d50bc40110649ec2582bb00e723bd9184af5c3ca0
23c43fe86e95a20a03b9f7b69b0d065b43b19cacd7d2eadc0ed1f7d106286e55
d615bada7f42881322ccbe4a65ef9eb5d1274a5ff7e556072e831d8ff457410b
3d0b2d6ccc202ace20b08b08cb42fe9b8990a4b507c341a847b523852aa0a0e6
22c7e4530525d24736df1d0d7b208a129ab88d5c1330d959bd9761403bc9cd91
5575a828cbff221a036ba89e366f6534d6a06382b8295b6110679c7db0157210
3e2102011f764cac1372c04bfdeed79115b9ad23bcbadba0dcee034417e02ff9
e701ec4f5f6def0074b6f62865c8a4b74d4f4ff4937b02a981852a39d40ec8be
c54b13ccf109bd91ffe9a3964ecebd0b1212b8d6256ec09590bac016b4bf34aa
35fec546c33f05be6217e5e404d2e7d4cfaf5a88a83e837d499d50ac16f0e7df
cef2c1cf793be672586ac5045d8ef976be534214818868704a5f6f637c6b4403
d699fd2fff037d6d8450e3b0dac321a0dd07ce51cbbbabd2008d6ecf62675428
9844fbbc43cac1ad202abcdb2457be2728c5b5f9713e436029db981aa0c23fec
e729ab431a60a84eedabc97dd532fae56b193b3da2b257f656d2d1207b116079
829d56aeb8b1ecadaee33c159ea0c8cf0d5501724b45192819b91721e095d697
6aac6dd749637d52c11ee2f505c96370b72c9b15a166531a18603fea7b002292
57e5ef7eac6e6b7405783aec41a2efed28ae3194cb895a0ee47d6b44d3496e09
e25b1bee5963572dc8c8492b9bf57d46308e0af29d6b479196e161a3d44ae467
c6407d45f2637612e3b6d96daf8be48c32da5f1ddef4e210621ec71fbe7075ca
7fd278c6335fb3978ce2884ccb4da6663770fcac5960e71585a26f69d205e8fa
d0ee202e31e8c359f5e97e209b7f4531025f92039fbec7c5d72e9bb523988fe6
0af01c68609be1939e3883c779467cb7305212dbf10b78137864c04889388793
3efcfca0a7fb6320d439157ab3f1b84c9afe94f143b0e213cf9c5c00e9fecd11
a08f57594e24cb9e43c8f09fb911af874479197a06513944844a5bc0b9f69f28
8c7e27cded647153e91a4f35496c5a3f4aec07523fcfd0cfd0c3cf639cbc7f33
bab32891466c2f517c23fdbb1509d7199ca4e476e3f41e84ee384437a5527bc8
78c5e51c91caa24f275de0ab153be7b010d5aa886bfddc8b12634a25cd0410e9
e6c9f55ec5853f874c1b3c675ff90e3fa7c09e8cb57d0abe72196a50967d484a
b7519b38c0fd533eb5d8dea8ed8b179ab338a917e0d00f3ea69fe1c8106735c9
8c52b5dd6127931ba938694874f166d9c137b46148f41cb7c97d2380989f04a1
1a7033e75aecfdeb7457444796fe85dee437094ff6213c1af32e61dcceb81ddc
4247daa9aa704e9690131eda5e76905bf17a98ad8098c5a99341b2975e4a1265
3d56286fea57658d54cbd07dedd6ac20686dfdee5fc0ca05ad2d167f5ec11895
d4819619ab0600837b51cd75c1d01508778494151b8b3db0bb3e058f92117e26
432b4a4c61e0da1d13ba50b14dc09062a9f7eccfd9e9b64b91f426394ffb33eb
969ebd51f3a385ad4f4119d8f7ded8aa147f488163180003b6c15f12f4d2888c
dbd5d5ce8c4f994154918b39cfb212cfcf0477012bb2e1e0d5f8d6477bb106c3
ea6f80f695bfaa797fdcdabe7e34d3269f3bc7963cc9edf0f39d50d379a16ea7
f26e9b9513b50e12e3e9bf8359ebb376c43a71f3341b0897d138cb950a8f4e25
403f783345abba9819c0bc3a5ba842f33e8589742247c74422911d3069888a73
68cf4c887b1d4b331638c862700d167fe8e16e062fcea22bfef8015d7596e0cc
e95a5f9d9d4a24acc4546f2393b118e230bb4ed14c85b1d6522403f21a2964a3
73c9a0b322bd6f78b39bcc55ed9226ee8b4d0b57b964dbbd8b4d43f9528915a6
30430c052bdede05189fcd68c3e44e4f36a90e01b4a1488ab2a7a23e8eac0ab0
931aebdd1c67f0f54cf09322d70d73f7a6cde17853f666672ce3cc7ac1b87088
ea0180cc3bb1f0dd3a16534d86cf6b4a2bf06d9416f0d677d2c6280efca9b3ba
642275b499e5b735784e74ce3fb7bb67576785524721c412354986dbc72a35a3
453d63f26aa518da7bbc021e0f7c275f4ab5b3fa06f40c1a9770aabb996d6f95
3be0fd1804fae21f5780fbf1eda56c5b7d2f62dd1f0efc33db0b0a8fdef9c78a
6cc1925e29c2cfd6332df25bba60c3001770dcd7ff8b66463340c697a6ecafb6
c56b110ff150aaf2ffd920930a0048c9d76e5120534ee55e34f7056e043b3e31
60971af640c3e9faf56c804334d99319f24a78ea69e1ea3bbeb0590f2fc0d8cb
e1eae91bee829e10538e7207c45fa2f059beca5c4215d7bd23
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
cleartomark
{restore}if% End of font resource
%% Font Page 00
/NimbusSansL-Bold-ENC-00 [
/.notdef/R/e/c/i/v/S/t/r/a/m/P/o/s/T/n/A/d/p/I/F/b/u/l/f/M/g/C/H/X/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef] def
/NimbusSansL-Bold-Uni-00 NimbusSansL-Bold-ENC-00 /NimbusSansL-Bold MFEmb
%%BeginFont: NimbusSansL-Bold
%!PS-AdobeFont-1.0 Composite Font
%%FontName: NimbusSansL-Bold-Uni
%%Creator: Composite font created by Qt
25 dict begin
/FontName /NimbusSansL-Bold-Uni def
/PaintType 0 def
/FontMatrix[1 0 0 1 0 0]def
/FontType 0 def
/FMapType 2 def
/Encoding [
0]def
/FDepVector [
/NimbusSansL-Bold-Uni-00 findfont
]def
FontName currentdict end definefont pop
%%EndFont
/F1 13.3333/NimbusSansL-Bold-Uni DF
/F2 13.3333/NimbusSansL-Regu-Uni DF
%%EndSetup
%%Page: 1 1
%%BeginPageSetup
QI
%%EndPageSetup
[1 0 0 1 -168 -248]ST
0 0 B 0 0 PE
WB
W BC
168 248 1114 816 R
255 0 0 P1
NB
413 682 777 VL
454 682 503 778 DL
317 682 771 VL
282 826 941 VL
464 828 471 929 DL
325 905 284 941 DL
428 905 471 929 DL
714 666 454 HL
1055 299 388 VL
810 835 905 VL
908 835 897 VL
765 956 1013 VL
1012 948 1011 VL
971 439 917 784 DL
805 703 784 VL
1135 648 712 VL
1174 648 721 VL
832 604 784 VL
860 604 1098 HL
1165 597 534 VL
1142 483 439 VL
0 0 B 0 0 PE
WB
NP
413 682 MT
406 693 LT
420 693 LT
413 682 LT
CP BF QS
0 0 B 0 0 PE
NP
454 682 MT
453 695 LT
465 689 LT
454 682 LT
CP BF QS
0 0 B 0 0 PE
NP
317 682 MT
310 693 LT
324 693 LT
317 682 LT
CP BF QS
0 0 B 0 0 PE
NP
282 826 MT
275 837 LT
289 837 LT
282 826 LT
CP BF QS
0 0 B 0 0 PE
NP
464 828 MT
458 840 LT
471 839 LT
464 828 LT
CP BF QS
0 0 B 0 0 PE
NP
325 905 MT
312 908 LT
321 917 LT
325 905 LT
CP BF QS
0 0 B 0 0 PE
NP
428 905 MT
435 916 LT
441 905 LT
428 905 LT
CP BF QS
0 0 B 0 0 PE
NP
454 666 MT
464 670 LT
476 666 LT
464 662 LT
CP BF QS
0 0 B 0 0 PE
NP
1055 299 MT
1048 310 LT
1062 310 LT
1055 299 LT
CP BF QS
0 0 B 0 0 PE
NP
810 835 MT
803 846 LT
817 846 LT
810 835 LT
CP BF QS
0 0 B 0 0 PE
NP
908 835 MT
901 846 LT
915 846 LT
908 835 LT
CP BF QS
0 0 B 0 0 PE
NP
765 956 MT
758 967 LT
772 967 LT
765 956 LT
CP BF QS
0 0 B 0 0 PE
NP
1012 948 MT
1005 959 LT
1019 959 LT
1012 948 LT
CP BF QS
0 0 B 0 0 PE
NP
917 784 MT
923 775 LT
920 762 LT
914 773 LT
CP BF QS
0 0 B 0 0 PE
NP
805 703 MT
798 714 LT
812 714 LT
805 703 LT
CP BF QS
0 0 B 0 0 PE
NP
1135 648 MT
1128 659 LT
1142 659 LT
1135 648 LT
CP BF QS
0 0 B 0 0 PE
NP
1174 648 MT
1167 659 LT
1181 659 LT
1174 648 LT
CP BF QS
0 0 B 0 0 PE
NP
832 604 MT
825 615 LT
839 615 LT
832 604 LT
CP BF QS
0 0 B 0 0 PE
NP
1098 604 MT
1088 600 LT
1076 604 LT
1088 608 LT
CP BF QS
0 0 B 0 0 PE
NP
1165 534 MT
1161 544 LT
1165 556 LT
1169 544 LT
CP BF QS
0 0 B 0 0 PE
NP
1142 439 MT
1138 449 LT
1142 461 LT
1146 449 LT
CP BF QS
255 0 0 P1
NB
406 693 413 682 DL
420 693 406 HL
420 693 413 682 DL
453 695 454 682 DL
465 689 453 695 DL
465 689 454 682 DL
310 693 317 682 DL
324 693 310 HL
324 693 317 682 DL
275 837 282 826 DL
289 837 275 HL
289 837 282 826 DL
458 840 464 828 DL
471 839 458 840 DL
471 839 464 828 DL
312 908 325 905 DL
321 917 312 908 DL
321 917 325 905 DL
435 916 428 905 DL
441 905 435 916 DL
441 905 428 HL
464 670 454 666 DL
464 662 476 666 DL
476 666 464 670 DL
454 666 464 662 DL
1048 310 1055 299 DL
1062 310 1048 HL
1062 310 1055 299 DL
803 846 810 835 DL
817 846 803 HL
817 846 810 835 DL
901 846 908 835 DL
915 846 901 HL
915 846 908 835 DL
758 967 765 956 DL
772 967 758 HL
772 967 765 956 DL
1005 959 1012 948 DL
1019 959 1005 HL
1019 959 1012 948 DL
923 775 917 784 DL
914 773 920 762 DL
920 762 923 775 DL
917 784 914 773 DL
798 714 805 703 DL
812 714 798 HL
812 714 805 703 DL
1128 659 1135 648 DL
1142 659 1128 HL
1142 659 1135 648 DL
1167 659 1174 648 DL
1181 659 1167 HL
1181 659 1174 648 DL
825 615 832 604 DL
839 615 825 HL
839 615 832 604 DL
1088 600 1098 604 DL
1088 608 1076 604 DL
1076 604 1088 600 DL
1098 604 1088 608 DL
1161 544 1165 534 DL
1169 544 1165 556 DL
1165 556 1161 544 DL
1165 534 1169 544 DL
1138 449 1142 439 DL
1146 449 1142 461 DL
1142 461 1138 449 DL
1142 439 1146 449 DL
255 0 0 P1
1 255 255 192 BR
664 905 166 51 R
CLSTART
501 657 156 51 ACR
CLEND
B P1
F1 F
936 Y<000100020003000200040005000200060007000800020009000A000B0008000C00030002000D000D000C0008>155 669 AT
CLO
[1 0 0 1 -168 -248]ST
255 0 0 P1
1 255 255 192 BR
908 897 173 51 R
CLO
[1 0 0 1 -168 -248]ST
CLSTART
745 649 163 51 ACR
CLEND
B P1
1 255 255 192 BR
F1 F
928 Y<000E00080009000F000D000A0004000700060007000800020009000A000B0008000C00030002000D000D000C0008>162 913 AT
CLO
[1 0 0 1 -168 -248]ST
255 0 0 P1
1 255 255 192 BR
656 1013 207 51 R
CLO
[1 0 0 1 -168 -248]ST
CLSTART
493 765 197 51 ACR
CLEND
B P1
1 255 255 192 BR
F1 F
1044 Y<0010000A001100070012000100020003000200040005000200060007000800020009000A000B0008000C00030002000D000D000C0008>196 661 AT
CLO
[1 0 0 1 -168 -248]ST
255 0 0 P1
1 255 255 192 BR
893 1011 214 51 R
CLO
[1 0 0 1 -168 -248]ST
CLSTART
730 763 204 51 ACR
CLEND
B P1
1 255 255 192 BR
F1 F
1042 Y<0010000A001100070012000E00080009000F000D000A0004000700060007000800020009000A000B0008000C00030002000D000D000C0008>203 898 AT
CLO
[1 0 0 1 -168 -248]ST
255 0 0 P1
1 255 255 192 BR
786 553 74 51 R
CLO
[1 0 0 1 -168 -248]ST
CLSTART
623 305 64 51 ACR
CLEND
B P1
1 255 255 192 BR
F1 F
584 Y<0013000D000C00060007000800020009000A>63 791 AT
CLO
[1 0 0 1 -168 -248]ST
255 0 0 P1
1 255 255 192 BR
799 784 118 51 R
CLO
[1 0 0 1 -168 -248]ST
CLSTART
636 536 108 51 ACR
CLEND
B P1
1 255 255 192 BR
F1 F
815 Y<00060007000800020009000A000B0008000C00030002000D000D000C0008>107 804 AT
CLO
[1 0 0 1 -168 -248]ST
255 0 0 P1
1 255 255 192 BR
963 248 174 51 R
CLO
[1 0 0 1 -168 -248]ST
CLSTART
800 0 164 51 ACR
CLEND
B P1
1 255 255 192 BR
F1 F
279 Y<00140008000200020015000C001500010016000F000F00090015001700020013000F0007000200080018000900030002>163 968 AT
CLO
[1 0 0 1 -168 -248]ST
255 0 0 P1
1 255 255 192 BR
714 652 91 51 R
CLO
[1 0 0 1 -168 -248]ST
CLSTART
551 404 81 51 ACR
CLEND
B P1
1 255 255 192 BR
F1 F
683 Y<000B000C0008000700190009000F0009001A00020008>79 719 AT
CLO
[1 0 0 1 -168 -248]ST
255 0 0 P1
1 255 255 192 BR
971 388 171 51 R
CLO
[1 0 0 1 -168 -248]ST
CLSTART
808 140 161 51 ACR
CLEND
B P1
1 255 255 192 BR
F1 F
419 Y<00060007000800020009000A000B0008000C00030002000D000D000C000800190009000F0009001A00020008>160 976 AT
CLO
[1 0 0 1 -168 -248]ST
255 0 0 P1
1 255 255 192 BR
168 941 116 51 R
CLO
[1 0 0 1 -168 -248]ST
CLSTART
5 693 106 51 ACR
CLEND
B P1
1 255 255 192 BR
F1 F
972 Y<0010000A0011000700120010001600110004000C000B000C00080007>104 173 AT
CLO
[1 0 0 1 -168 -248]ST
255 0 0 P1
1 255 255 192 BR
399 777 65 51 R
CLO
[1 0 0 1 -168 -248]ST
CLSTART
236 529 55 51 ACR
CLEND
B P1
1 255 255 192 BR
F1 F
808 Y<0019000400110004000B000C00080007>53 404 AT
CLO
[1 0 0 1 -168 -248]ST
255 0 0 P1
1 255 255 192 BR
471 929 106 51 R
CLO
[1 0 0 1 -168 -248]ST
CLSTART
308 681 96 51 ACR
CLEND
B P1
1 255 255 192 BR
F1 F
960 Y<0010000A0011000700120019000400110004000B000C00080007>94 476 AT
CLO
[1 0 0 1 -168 -248]ST
255 0 0 P1
1 255 255 192 BR
282 775 75 51 R
CLO
[1 0 0 1 -168 -248]ST
CLSTART
119 527 65 51 ACR
CLEND
B P1
1 255 255 192 BR
F1 F
806 Y<0010001600110004000C000B000C00080007>63 287 AT
CLO
[1 0 0 1 -168 -248]ST
255 0 0 P1
1 255 255 192 BR
503 778 84 51 R
CLO
[1 0 0 1 -168 -248]ST
CLSTART
340 530 74 51 ACR
CLEND
B P1
1 255 255 192 BR
F1 F
809 Y<001B000C000F00070008000C0017000B000C00080007>72 508 AT
CLO
[1 0 0 1 -168 -248]ST
255 0 0 P1
1 255 255 192 BR
325 854 103 51 R
CLO
[1 0 0 1 -168 -248]ST
CLSTART
162 606 93 51 ACR
CLEND
B P1
1 255 255 192 BR
F1 F
885 Y<0010000A001100070012000B000C000800070013000F0018000C>91 330 AT
CLO
[1 0 0 1 -168 -248]ST
255 0 0 P1
1 255 255 192 BR
1098 597 78 51 R
CLO
[1 0 0 1 -168 -248]ST
CLSTART
935 349 68 51 ACR
CLEND
B P1
1 255 255 192 BR
F1 F
628 Y<0013000D000C001C0009000F0011001700020008>67 1103 AT
CLO
[1 0 0 1 -168 -248]ST
255 0 0 P1
1 255 255 192 BR
317 631 137 51 R
CLO
[1 0 0 1 -168 -248]ST
CLSTART
154 383 127 51 ACR
CLEND
B P1
1 255 255 192 BR
F1 F
662 Y<000B000C00080007>26 372 AT
CLO
[1 0 0 1 -168 -248]ST
255 0 0 P1
1 255 255 192 BR
1039 712 107 51 R
CLO
[1 0 0 1 -168 -248]ST
CLSTART
876 464 97 51 ACR
CLEND
B P1
1 255 255 192 BR
F1 F
743 Y<0013000D000C001D000A00040007001C0009000F0011001700020008>96 1044 AT
CLO
[1 0 0 1 -168 -248]ST
255 0 0 P1
1 255 255 192 BR
1174 721 108 51 R
CLO
[1 0 0 1 -168 -248]ST
CLSTART
1011 473 98 51 ACR
CLEND
B P1
1 255 255 192 BR
F1 F
752 Y<0013000D000C0001000200030005001C0009000F0011001700020008>97 1179 AT
CLO
[1 0 0 1 -168 -248]ST
255 0 0 P1
1 255 255 192 BR
1038 483 131 51 R
CLO
[1 0 0 1 -168 -248]ST
CLSTART
875 235 121 51 ACR
CLEND
B P1
1 255 255 192 BR
F1 F
514 Y<0013000D000C001C0009000F001100170002000800190009000F0009001A00020008>120 1043 AT
CLO
[1 0 0 1 -168 -248]ST
CLSTART
694 322 32 32 ACR
CLEND
50 d2 P1
NB
F2 F
592 Y<0001000200020003>22 866 AT
CLO
[1 0 0 1 -168 -248]ST
CLSTART
694 358 67 25 ACR
CLEND
50 d2 P1
NB
F2 F
624 Y<000400050006000700080009000A000B000C>59 865 AT
CLO
[1 0 0 1 -168 -248]ST
CLSTART
715 502 32 32 ACR
CLEND
50 d2 P1
NB
F2 F
772 Y<000D>5 896 AT
CLO
[1 0 0 1 -168 -248]ST
CLSTART
976 193 32 32 ACR
CLEND
50 d2 P1
NB
F2 F
463 Y<0003>7 1156 AT
CLO
[1 0 0 1 -168 -248]ST
CLSTART
976 201 32 32 ACR
CLEND
50 d2 P1
NB
F2 F
471 Y<0003>7 1156 AT
CLO
[1 0 0 1 -168 -248]ST
CLSTART
804 193 32 32 ACR
CLEND
50 d2 P1
NB
F2 F
463 Y<0003>7 984 AT
CLO
[1 0 0 1 -168 -248]ST
CLSTART
512 384 32 32 ACR
CLEND
50 d2 P1
NB
F2 F
654 Y<0003>7 692 AT
CLO
[1 0 0 1 -168 -248]ST
CLSTART
999 288 32 32 ACR
CLEND
50 d2 P1
NB
F2 F
558 Y<0003>7 1179 AT
CLO
[1 0 0 1 -168 -248]ST
CLSTART
999 315 32 32 ACR
CLEND
50 d2 P1
NB
F2 F
585 Y<000D>5 1180 AT
CLO
[1 0 0 1 -168 -248]ST
CLSTART
288 384 32 32 ACR
CLEND
50 d2 P1
NB
F2 F
654 Y<000D>5 469 AT
QP
%%Trailer
%%Pages: 1
%%DocumentFonts: NimbusSansL-Bold NimbusSansL-Regu
%%EOF
libffado-2.4.5/libffado/ 0000755 0001750 0000144 00000000000 14206145612 014427 5 ustar jwoithe users libffado-2.4.5/libffado/60-ffado.rules 0000644 0001750 0000144 00000005451 14206145246 017015 0 ustar jwoithe users SUBSYSTEM!="firewire", GOTO="ffado_end"
# TC GROUP A/S
ATTR{vendor}=="0x000166", GROUP="audio", ENV{ID_FFADO}="1"
# Mark of the Unicorn, Inc. (aka MOTU)
ATTR{vendor}=="0x0001f2", GROUP="audio", ENV{ID_FFADO}="1"
# Apogee Electronics Corp.
ATTR{vendor}=="0x0003db", GROUP="audio", ENV{ID_FFADO}="1"
# Alesis Corporation
ATTR{vendor}=="0x000595", GROUP="audio", ENV{ID_FFADO}="1"
# Bridgeco Co AG
ATTR{vendor}=="0x0007f5", GROUP="audio", ENV{ID_FFADO}="1"
# Presonus Corporation
ATTR{vendor}=="0x000a92", GROUP="audio", ENV{ID_FFADO}="1"
# TerraTec Electronic GmbH
ATTR{vendor}=="0x000aac", GROUP="audio", ENV{ID_FFADO}="1"
# M-Audio
ATTR{vendor}=="0x000d6c", GROUP="audio", ENV{ID_FFADO}="1"
# Ego Systems Inc.
ATTR{vendor}=="0x000f1b", GROUP="audio", ENV{ID_FFADO}="1"
# Loud Technologies Inc.
ATTR{vendor}=="0x000ff2", GROUP="audio", ENV{ID_FFADO}="1"
# Stanton Magnetics,inc.
ATTR{vendor}=="0x001260", GROUP="audio", ENV{ID_FFADO}="1"
# Focusrite Audio Engineering Limited
ATTR{vendor}=="0x00130e", GROUP="audio", ENV{ID_FFADO}="1"
# Echo Digital Audio Corporation
ATTR{vendor}=="0x001486", GROUP="audio", ENV{ID_FFADO}="1"
# Phonic Corporation
ATTR{vendor}=="0x001496", GROUP="audio", ENV{ID_FFADO}="1"
# BEHRINGER Spezielle Studiotechnik GmbH
ATTR{vendor}=="0x001564", GROUP="audio", ENV{ID_FFADO}="1"
# FlexRadio Systems
ATTR{vendor}=="0x001c2d", GROUP="audio", ENV{ID_FFADO}="1"
# Weiss Engineering Ltd.
ATTR{vendor}=="0x001c6a", GROUP="audio", ENV{ID_FFADO}="1"
# ROLAND DG CORPORATION
ATTR{vendor}=="0x0040ab", GROUP="audio", ENV{ID_FFADO}="1"
# DnR
ATTR{vendor}=="0x000f64", GROUP="audio", ENV{ID_FFADO}="1"
# Avid (for Mbox 3 Pro)
ATTR{vendor}=="0x00a07e", GROUP="audio", ENV{ID_FFAOD}="1"
# Yamaha (for GO4x devices)
ATTR{vendor}=="0x00a0de", GROUP="audio", ENV{ID_FFADO}="1"
# Lexicon (from Onix-FW810S)
ATTR{vendor}=="0x000fd7", GROUP="audio", ENV{ID_FFADO}="1"
# Allen and Heath
ATTR{vendor}=="0x0004c4", GROUP="audio", ENV{ID_FFADO}="1"
# Midas
ATTR{vendor}=="0x10c73f", GROUP="audio", ENV{ID_FFADO}="1"
# The devices below are by vendors who make other firewire devices in
# addition to their audio interfaces. They need more specific rules to
# ensure only audio interfaces are covered here.
# Tascam, a subsiduary of TEAC (the OUI is TEAC's)
ATTR{vendor}=="0x00022e", ATTR{model}=="0x010067", GROUP="audio", ENV{ID_FFADO}="1"
# The devices below abuse another Vendor's ID, and therefore we need more advanced rules for those.
# CME, Matrix K FW
ATTR{vendor}=="0x00000a", ATTR{model}=="0x030000", ATTR{units}=="*0x00a02d:0x010001*", GROUP="audio", ENV{ID_FFADO}="1"
# Mackie, Onyx FireWire
ATTR{vendor}=="0x00000f", ATTR{model}=="0x01006?", ATTR{units}=="*0x00a02d:0x010001*", GROUP="audio", ENV{ID_FFADO}="1"
# RME
ATTR{vendor}=="0x000a35", ATTR{units}=="0x000a35:0x00000[1234]", GROUP="audio", ENV{ID_FFADO}="1"
LABEL="ffado_end"
libffado-2.4.5/libffado/SConscript 0000644 0001750 0000144 00000002041 14206145246 016441 0 ustar jwoithe users #
# Copyright (C) 2007-2008 Arnold Krille
#
# This file is part of FFADO
# FFADO = Free FireWire (pro-)audio drivers for Linux
#
# FFADO is based upon FreeBoB.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
import os.path
Import( 'env' )
env = env.Clone()
env.ScanReplace( "ffado.h.in" )
env.Alias( 'install', env.Install( os.path.join(env['includedir'],"libffado"), "ffado.h" ) )
env.Alias( 'install', env.Install( env['udevdir'], "60-ffado.rules" ) )
libffado-2.4.5/libffado/ffado.h.in 0000644 0001750 0000144 00000041544 14206145246 016277 0 ustar jwoithe users /* ffado.h
*
* Copyright (C) 2005-2008 by Pieter Palmers
* Copyright (C) 2005-2008 by Daniel Wagner
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef FFADO_H
#define FFADO_H
#define FFADO_API_VERSION $FFADO_API_VERSION
#define FFADO_MAX_NAME_LEN 256
#include
#define FFADO_STREAMING_MAX_URL_LENGTH 2048
#define FFADO_IGNORE_CAPTURE (1<<0)
#define FFADO_IGNORE_PLAYBACK (1<<1)
enum ffado_direction {
FFADO_CAPTURE = 0,
FFADO_PLAYBACK = 1,
};
typedef struct ffado_handle* ffado_handle_t;
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __APPLE__
#define WEAK_ATTRIBUTE weak_import
#else
#define WEAK_ATTRIBUTE __weak__
#endif
#ifdef __GNUC__
#define FFADO_WEAK_EXPORT __attribute__((WEAK_ATTRIBUTE))
#else
/* Add support for non-gcc platforms here */
#endif
/* ABI stuff */
const char*
ffado_get_version();
int
ffado_get_api_version();
/* various function */
/* The basic operation of the API is as follows:
*
* ffado_streaming_init()
* ffado_streaming_start()
* while(running) {
* retval = ffado_streaming_wait();
* if (retval == -1) {
* ffado_streaming_reset();
* continue;
* }
*
* ffado_streaming_transfer_capture_buffers(dev);
*
* for(all channels) {
* // For both audio and MIDI channels, captured data is available
* // in the buffer previously set with a call to
* // ffado_streaming_set_capture_stream_buffer(dev, channel, buffer)
* switch (channel_type) {
* case audio:
* // Process incoming audio as needed
* case midi:
* // Process incoming MIDI data as needed
* }
* }
*
* for(all channels) {
* // For both audio and MIDI channels, data is written to buffers
* // previously associated with the playback channel streams using
* // ffado_streaming_set_playback_stream_buffer(dev, channel, buffer)
* switch (channel_type) {
* case audio:
* // Set audio playback buffer contents
* case midi:
* // Set MIDI playback buffer contents
* }
* }
* ffado_streaming_transfer_playback_buffers(dev);
*
* }
* ffado_streaming_stop();
* ffado_streaming_finish();
*
*/
typedef struct _ffado_device ffado_device_t;
/**
* The sample format used by the ffado streaming API
*/
typedef unsigned int ffado_sample_t; // FIXME
typedef unsigned int ffado_nframes_t;
#define FFADO_MAX_SPECSTRING_LENGTH 256
#define FFADO_MAX_SPECSTRINGS 64
/**
* This struct serves to define the devices that should be used by the library
* device_spec_strings is an array of pointers that should contain nb_device_spec_strings
* valid pointers to strings.
*
* The spec strings should be null terminated and can be no longer
* than FFADO_MAX_SPECSTRINGS.
*
* nb_device_spec_strings < FFADO_MAX_SPECSTRING_LENGTH
* nb_device_spec_strings >= 0
*
* If nb_device_spec_strings == 0, all busses are scanned for attached devices, and
* all found devices that are supported are combined into one large pseudo-device. The
* device order is defined by the GUID of the device. Devices with lower GUID's will
* be the first ones.
*
* If multiple device specifications are present, the device order is defined as follows:
* - device(s) that correspond to a spec string with a lower index will be added before
* devices from higher indexes.
* - if a spec string results in multiple devices, they are sorted by GUID unless the
* spec format dictates otherwise.
*
* The actual meaning of the device specification should be one of the following:
* - Format 1: "hw:x[,y[,z]]"
* x = the FireWire bus to use ('port' in raw1394 terminology)
* (mandatory)
* y = the node id the device currently has (bus resets might change that, but FFADO
* will track these changes and keep using the device specified on startup)
* (optional)
* z = the stream direction to use.
* 0 => capture (record) channels only
* 1 => playback channels only
* other/unspecified => both playback and capture
* (optional)
*
* - Format 2: the device alias as defined in the ffado config file (UNIMPLEMENTED)
*/
typedef struct ffado_device_info {
unsigned int nb_device_spec_strings;
char **device_spec_strings;
/* add some extra space to allow for future API extention
w/o breaking binary compatibility */
int32_t reserved[32];
} ffado_device_info_t;
/**
* Structure to pass the options to the ffado streaming code.
*/
typedef struct ffado_options {
/* driver related setup */
int32_t sample_rate; /*
* you can specify a value here or -1 to autodetect
*/
/* buffer setup */
int32_t period_size; /* one period is the amount of frames that
* has to be sent or received in order for
* a period boundary to be signalled.
* (unit: frames)
*/
int32_t nb_buffers; /* the size of the frame buffer (in periods) */
/* packetizer thread options */
int32_t realtime;
int32_t packetizer_priority;
/* verbosity */
int32_t verbose;
/* slave mode */
int32_t slave_mode;
/* snoop mode */
int32_t snoop_mode;
/* add some extra space to allow for future API extention
w/o breaking binary compatibility */
int32_t reserved[24];
} ffado_options_t;
/**
* The types of streams supported by the API
*
* A ffado_audio type stream is a stream that consists of successive samples.
* The format is a 24bit UINT in host byte order, aligned as the 24LSB's of the
* 32bit UINT of the read/write buffer.
* The wait operation looks at this type of streams only.
*
* A ffado_midi type stream is a stream of midi bytes. The bytes are 8bit UINT,
* aligned as the first 8LSB's of the 32bit UINT of the read/write buffer.
*
* A ffado_control type stream is a stream that provides control information. The
* format of this control information is undefined, and the stream should be ignored.
*
*/
typedef enum {
ffado_stream_type_invalid = -1,
ffado_stream_type_unknown = 0,
ffado_stream_type_audio = 1,
ffado_stream_type_midi = 2,
ffado_stream_type_control = 3,
} ffado_streaming_stream_type;
/**
*
* Audio data types known to the API
*
*/
typedef enum {
ffado_audio_datatype_error = -1,
ffado_audio_datatype_int24 = 0,
ffado_audio_datatype_float = 1,
} ffado_streaming_audio_datatype;
/**
*
* Wait responses
*
*/
typedef enum {
ffado_wait_shutdown = -3,
ffado_wait_error = -2,
ffado_wait_xrun = -1,
ffado_wait_ok = 0,
} ffado_wait_response;
/**
* Initializes the streaming from/to a FFADO device. A FFADO device
* is a virtual device composed of several BeBoB or compatible devices,
* linked together in one sync domain.
*
* This prepares all IEEE1394 related stuff and sets up all buffering.
* It elects a sync master if nescessary.
*
* @param device_info provides a way to specify the virtual device
* @param options options regarding buffers, ieee1394 setup, ...
*
* @return Opaque device handle if successful. If this is NULL, the
* init operation failed.
*
*/
ffado_device_t *ffado_streaming_init(
ffado_device_info_t device_info,
ffado_options_t options);
/**
* This permits the setting of the period size at some time after
* initialisation. The primary use of this function is to support the
* setbufsize functionality of JACK.
*
* @param dev the ffado device
* @param period the new period size
* @return 0 on success, non-zero if an error occurred
*/
int ffado_streaming_set_period_size(ffado_device_t *dev,
unsigned int period) FFADO_WEAK_EXPORT;
/**
* preparation should be done after setting all per-stream parameters
* the way you want them. being buffer data type etc...
*
* @param dev the ffado device
* @return
*/
int ffado_streaming_prepare(ffado_device_t *dev);
/**
* Finishes the FFADO streaming. Cleans up all internal data structures
* and terminates connections.
*
* @param dev the ffado device to be closed.
*/
void ffado_streaming_finish(ffado_device_t *dev);
/**
* Returns the amount of capture channels available
*
* @param dev the ffado device
*
* @return the number of capture streams present & active on the device.
* can be 0. returns -1 upon error.
*/
int ffado_streaming_get_nb_capture_streams(ffado_device_t *dev);
/**
* Returns the amount of playack channels available
*
* @param dev the ffado device
*
* @return the number of playback streams present & active on the device.
* can be 0. returns -1 upon error.
*/
int ffado_streaming_get_nb_playback_streams(ffado_device_t *dev);
/**
* Copies the capture channel name into the specified buffer
*
* @param dev the ffado device
* @param number the stream number
* @param buffer the buffer to copy the name into. has to be allocated.
* @param buffersize the size of the buffer
*
* @return the number of characters copied into the buffer
*/
int ffado_streaming_get_capture_stream_name(ffado_device_t *dev, int number, char* buffer, size_t buffersize);
/**
* Copies the playback channel name into the specified buffer
*
* @param dev the ffado device
* @param number the stream number
* @param buffer the buffer to copy the name into. has to be allocated.
* @param buffersize the size of the buffer
*
* @return the number of characters copied into the buffer
*/
int ffado_streaming_get_playback_stream_name(ffado_device_t *dev, int number, char* buffer, size_t buffersize);
/**
* Returns the type of a capture channel
*
* @param dev the ffado device
* @param number the stream number
*
* @return the channel type
*/
ffado_streaming_stream_type ffado_streaming_get_capture_stream_type(ffado_device_t *dev, int number);
/**
* Returns the type of a playback channel
*
* @param dev the ffado device
* @param number the stream number
*
* @return the channel type
*/
ffado_streaming_stream_type ffado_streaming_get_playback_stream_type(ffado_device_t *dev, int number);
/*
*
* Note: buffer handling will change in order to allow setting the sample type for *_read and *_write
* and separately indicate if you want to use a user buffer or a managed buffer.
*
*/
/**
* Sets the decode buffer for the stream. This allows for zero-copy decoding.
* The call to ffado_streaming_transfer_buffers will decode one period of the stream to
* this buffer. Make sure it is large enough.
*
* @param dev the ffado device
* @param number the stream number
* @param buff a pointer to the sample buffer, make sure it is large enough
* i.e. sizeof(your_sample_type)*period_size
* @param t the type of the buffer. this determines sample type and the decode function used.
*
* @return -1 on error, 0 on success
*/
int ffado_streaming_set_capture_stream_buffer(ffado_device_t *dev, int number, char *buff);
int ffado_streaming_capture_stream_onoff(ffado_device_t *dev, int number, int on);
/**
* Sets the encode buffer for the stream. This allows for zero-copy encoding (directly to the events).
* The call to ffado_streaming_transfer_buffers will encode one period of the stream from
* this buffer to the event buffer.
*
* @param dev the ffado device
* @param number the stream number
* @param buff a pointer to the sample buffer
* @param t the type of the buffer. this determines sample type and the decode function used.
*
* @return -1 on error, 0 on success
*/
int ffado_streaming_set_playback_stream_buffer(ffado_device_t *dev, int number, char *buff);
int ffado_streaming_playback_stream_onoff(ffado_device_t *dev, int number, int on);
ffado_streaming_audio_datatype ffado_streaming_get_audio_datatype(ffado_device_t *dev);
int ffado_streaming_set_audio_datatype(ffado_device_t *dev, ffado_streaming_audio_datatype t);
/**
* preparation should be done after setting all per-stream parameters
* the way you want them. being buffer data type etc...
*
* @param dev
* @return
*/
int ffado_streaming_prepare(ffado_device_t *dev);
/**
* Starts the streaming operation. This initiates the connections to the FFADO devices and
* starts the packet handling thread(s). This has to be called before any I/O can occur.
*
* @param dev the ffado device
*
* @return 0 on success, -1 on failure.
*/
int ffado_streaming_start(ffado_device_t *dev);
/**
* Stops the streaming operation. This closes the connections to the FFADO devices and
* stops the packet handling thread(s).
*
* @param dev the ffado device
*
* @return 0 on success, -1 on failure.
*/
int ffado_streaming_stop(ffado_device_t *dev);
/**
* Resets the streaming as if it was stopped and restarted. The difference is that the connections
* are not nescessarily broken and restored.
*
* All buffers are reset in the initial state and all data in them is lost.
*
* @param dev the ffado device
*
* @return 0 on success, -1 on failure.
*/
int ffado_streaming_reset(ffado_device_t *dev);
/**
* Waits until there is at least one period of data available on all capture connections and
* room for one period of data on all playback connections
*
* @param dev the ffado device
*
* @return The number of frames ready. -1 when a problem occurred.
*/
ffado_wait_response ffado_streaming_wait(ffado_device_t *dev);
/**
* Transfer & decode the events from the packet buffer to the sample buffers
*
* This should be called after the wait call returns, before reading/writing the sample buffers
* with ffado_streaming_[read|write].
*
* The purpose is to allow more precise timing information. ffado_streaming_wait returns as soon as the
* period boundary is crossed, and can therefore be used to determine the time instant of this crossing (e.g. jack DLL).
*
* The actual decoding work is done in this function and can therefore be omitted in this timing calculation.
* Note that you HAVE to call this function in order for the buffers not to overflow, and only call it when
* ffado_streaming_wait doesn't indicate a buffer xrun (xrun handler resets buffer).
*
* If user supplied playback buffers are specified with ffado_streaming_set_playback_buffers
* their contents should be valid before calling this function.
* If user supplied capture buffers are specified with ffado_streaming_set_capture_buffers
* their contents are updated in this function.
*
* Use either ffado_streaming_transfer_buffers to transfer all buffers at once, or use
* ffado_streaming_transfer_playback_buffers and ffado_streaming_transfer_capture_buffers
* to have more control. Don't use both.
*
* @param dev the ffado device
* @return -1 on error.
*/
int ffado_streaming_transfer_buffers(ffado_device_t *dev);
/**
* Transfer & encode the events from the sample buffers to the packet buffer
*
* This should be called after the wait call returns, after writing the sample buffers
* with ffado_streaming_write.
*
* If user supplied playback buffers are specified with ffado_streaming_set_playback_buffers
* their contents should be valid before calling this function.
*
* Use either ffado_streaming_transfer_buffers to transfer all buffers at once, or use
* ffado_streaming_transfer_playback_buffers and ffado_streaming_transfer_capture_buffers
* to have more control. Don't use both.
*
* @param dev the ffado device
* @return -1 on error.
*/
int ffado_streaming_transfer_playback_buffers(ffado_device_t *dev);
/**
* Transfer & decode the events from the packet buffer to the sample buffers
*
* This should be called after the wait call returns, before reading the sample buffers
* with ffado_streaming_read.
*
* If user supplied capture buffers are specified with ffado_streaming_set_capture_buffers
* their contents are updated in this function.
*
* Use either ffado_streaming_transfer_buffers to transfer all buffers at once, or use
* ffado_streaming_transfer_playback_buffers and ffado_streaming_transfer_capture_buffers
* to have more control. Don't use both.
*
* @param dev the ffado device
* @return -1 on error.
*/
int ffado_streaming_transfer_capture_buffers(ffado_device_t *dev);
#ifdef __cplusplus
}
#endif
#endif /* FFADO_STREAMING */
libffado-2.4.5/libffado/.gitignore 0000644 0001750 0000144 00000000010 12132617070 016404 0 ustar jwoithe users ffado.h
libffado-2.4.5/src/ 0000755 0001750 0000144 00000000000 14206145613 013451 5 ustar jwoithe users libffado-2.4.5/src/DeviceStringParser.cpp 0000644 0001750 0000144 00000025601 14206145246 017726 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Pieter Palmers
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "DeviceStringParser.h"
#include
#include
#include
#include
#include "libieee1394/configrom.h"
#include "libieee1394/ieee1394service.h"
IMPL_DEBUG_MODULE( DeviceStringParser, DeviceStringParser, DEBUG_LEVEL_NORMAL );
DeviceStringParser::DeviceString::DeviceString(DeviceStringParser& parent)
: m_Parent(parent)
, m_node( -1 )
, m_port( -1 )
, m_guid( 0 )
, m_String("")
, m_Type(eInvalid)
, m_debugModule( parent.m_debugModule )
{
}
DeviceStringParser::DeviceString::~DeviceString()
{
}
bool
DeviceStringParser::DeviceString::parse(std::string s)
{
m_String = s;
debugOutput(DEBUG_LEVEL_VERBOSE, "parse: %s\n", s.c_str());
std::string prefix = s.substr(0,3);
if(s.compare(0,3,"hw:")==0) {
m_Type = eBusNode;
std::string detail = s.substr(3);
std::string::size_type comma_pos = detail.find_first_of(",");
if(comma_pos == std::string::npos) {
// node is unspecified
m_node = -1;
std::string port = detail;
errno = 0;
m_port = strtol(port.c_str(), NULL, 0);
if(errno) {
m_Type = eInvalid;
m_port = -1;
m_node = -1;
debugOutput(DEBUG_LEVEL_VERBOSE, "failed to parse port\n");
return false;
}
} else {
std::string port = detail.substr(0, comma_pos);
std::string node = detail.substr(comma_pos+1);
errno = 0;
m_port = strtol(port.c_str(), NULL, 0);
if(errno) {
m_Type = eInvalid;
m_port = -1;
m_node = -1;
debugOutput(DEBUG_LEVEL_VERBOSE, "failed to parse port\n");
return false;
}
errno = 0;
m_node = strtol(node.c_str(), NULL, 0);
if(errno) {
m_Type = eInvalid;
m_port = -1;
m_node = -1;
debugOutput(DEBUG_LEVEL_VERBOSE, "failed to parse node\n");
return false;
}
}
} else if (s.compare(0,5,"guid:")==0) {
std::string detail = s.substr(5);
m_Type = eGUID;
errno = 0;
m_guid = strtoll(detail.c_str(), NULL, 0);
if(errno) {
m_Type = eInvalid;
m_guid = 0;
debugOutput(DEBUG_LEVEL_VERBOSE, "failed to parse guid\n");
return false;
}
} else {
m_Type = eInvalid;
debugOutput(DEBUG_LEVEL_VERBOSE, "invalid\n");
return false;
}
return true;
}
bool
DeviceStringParser::DeviceString::isValidString(std::string s)
{
std::string prefix = s.substr(0,3);
if(s.compare(0,3,"hw:")==0) {
std::string detail = s.substr(3);
std::string::size_type comma_pos = detail.find_first_of(",");
if(comma_pos == std::string::npos) {
std::string port = detail;
errno = 0;
strtol(port.c_str(), NULL, 0);
if(errno) {
return false;
}
} else {
std::string port = detail.substr(0, comma_pos);
std::string node = detail.substr(comma_pos+1);
errno = 0;
strtol(port.c_str(), NULL, 0);
if(errno) {
return false;
}
errno = 0;
strtol(node.c_str(), NULL, 0);
if(errno) {
return false;
}
}
} else if (s.compare(0,5,"guid:")==0) {
std::string detail = s.substr(5);
errno = 0;
strtoll(detail.c_str(), NULL, 0);
if(errno) {
return false;
}
} else {
return false;
}
return true;
}
bool
DeviceStringParser::DeviceString::match(ConfigRom& configRom)
{
debugOutput(DEBUG_LEVEL_VERBOSE, "match %p (%s)\n", &configRom, configRom.getGuidString().c_str());
bool match;
switch(m_Type) {
case eBusNode:
if(m_port < 0) {
debugWarning("Need at least a port spec\n");
return false;
}
match = configRom.get1394Service().getPort() == m_port;
if(m_node >= 0) {
match &= ((configRom.getNodeId() & 0x3F) == m_node);
}
if(match) {
debugOutput(DEBUG_LEVEL_VERBOSE, "(eBusNode) device matches device string %s\n", m_String.c_str());
}
return match;
case eGUID:
//GUID should not be 0
match = m_guid && (m_guid == configRom.getGuid());
if(match) {
debugOutput(DEBUG_LEVEL_VERBOSE, "(eGUID) device matches device string %s\n", m_String.c_str());
}
return match;
case eInvalid:
default:
debugError("invalid DeviceString type (%d)\n", m_Type);
return false;
}
return false;
}
bool
DeviceStringParser::DeviceString::operator==(const DeviceString& x)
{
bool retval;
switch(m_Type) {
case eBusNode:
retval = (m_port == x.m_port) && (m_node == x.m_node);
debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "eBusNode %d,%d == %d,%d? %d\n",
m_port, m_node, x.m_port, x.m_node, retval);
return retval;
case eGUID:
retval = m_guid && (m_guid == x.m_guid);
debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "eGUID 0x%016" PRIX64 " == 0x%016" PRIX64 "? %d\n",
m_guid, x.m_guid, retval);
return retval;
case eInvalid:
debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "eInvalid \n");
default:
return false;
}
}
void
DeviceStringParser::DeviceString::show()
{
debugOutput(DEBUG_LEVEL_INFO, "string: %s\n", m_String.c_str());
switch(m_Type) {
case eBusNode:
debugOutput(DEBUG_LEVEL_INFO, "type: eBusNode\n");
debugOutput(DEBUG_LEVEL_INFO, " Port: %d, Node: %d\n",
m_port, m_node);
break;
case eGUID:
debugOutput(DEBUG_LEVEL_INFO, "type: eGUID\n");
debugOutput(DEBUG_LEVEL_INFO, " GUID: %016" PRIX64 "\n", m_guid);
break;
case eInvalid:
default:
debugOutput(DEBUG_LEVEL_INFO, "type: eInvalid\n");
break;
}
}
// ------------------------
DeviceStringParser::DeviceStringParser()
{}
DeviceStringParser::~DeviceStringParser()
{
while(m_DeviceStrings.size()) {
DeviceString *tmp = m_DeviceStrings.at(0);
debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "removing device string: %p\n", tmp);
m_DeviceStrings.erase(m_DeviceStrings.begin());
delete tmp;
}
}
bool
DeviceStringParser::parseString(std::string s)
{
debugOutput(DEBUG_LEVEL_VERBOSE, "parse: %s\n", s.c_str());
std::string::size_type next_sep;
std::string tmp = s;
do {
debugOutput(DEBUG_LEVEL_VERBOSE, " left: %s\n", tmp.c_str());
next_sep = tmp.find_first_of(";");
std::string to_parse = tmp.substr(0, next_sep);
DeviceString *d = new DeviceString(*this);
if(d == NULL) {
debugError("failed to allocate memory for device string\n");
continue;
}
if(d->parse(to_parse)) {
addDeviceString(d);
} else {
debugWarning("Failed to parse device substring: \"%s\"\n",
to_parse.c_str());
delete d;
}
tmp = tmp.substr(next_sep+1);
} while(tmp.size() && next_sep != std::string::npos);
pruneDuplicates();
return true;
}
bool
DeviceStringParser::isValidString(std::string s)
{
debugOutput(DEBUG_LEVEL_VERBOSE, "isvalid? %s\n", s.c_str());
return DeviceString::isValidString(s);
}
bool
DeviceStringParser::match(ConfigRom& c)
{
return matchPosition(c) != -1;
}
int
DeviceStringParser::matchPosition(ConfigRom& c)
{
int pos = 0;
for ( DeviceStringVectorIterator it = m_DeviceStrings.begin();
it != m_DeviceStrings.end();
++it )
{
if((*it)->match(c)) {
return pos;
}
pos++;
}
return -1;
}
bool
DeviceStringParser::addDeviceString(DeviceString *o)
{
debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "adding device string: %p\n", o);
if (hasDeviceString(o)){
return false;
}
m_DeviceStrings.push_back(o);
return true;
}
bool
DeviceStringParser::removeDeviceString(DeviceString *o)
{
debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "removing device string: %p\n", o);
int i=findDeviceString(o);
if (i<0) {
debugOutput(DEBUG_LEVEL_VERBOSE, "not found\n");
return false;
} else {
DeviceString *tmp = m_DeviceStrings.at(i);
m_DeviceStrings.erase(m_DeviceStrings.begin()+i);
delete tmp;
return true;
}
}
bool
DeviceStringParser::hasDeviceString(DeviceString *o)
{
return (findDeviceString(o) >= 0);
}
int
DeviceStringParser::findDeviceString(DeviceString *o)
{
int i=0;
for ( DeviceStringVectorIterator it = m_DeviceStrings.begin();
it != m_DeviceStrings.end();
++it )
{
if(*it == o) {
return i;
}
i++;
}
return -1;
}
void
DeviceStringParser::pruneDuplicates()
{
DeviceStringVector duplicates;
// find duplicates
for ( DeviceStringVectorIterator it = m_DeviceStrings.begin();
it != m_DeviceStrings.end();
++it )
{
for ( DeviceStringVectorIterator it2 = it+1;
it2 != m_DeviceStrings.end();
++it2 )
{
if(**it == **it2) {
duplicates.push_back(*it2);
}
}
}
// remove duplicates
for ( DeviceStringVectorIterator it = duplicates.begin();
it != duplicates.end();
++it )
{
removeDeviceString(*it);
}
}
void
DeviceStringParser::show()
{
debugOutput(DEBUG_LEVEL_INFO, "DeviceStringParser: %p\n", this);
for ( DeviceStringVectorIterator it = m_DeviceStrings.begin();
it != m_DeviceStrings.end();
++it )
{
(*it)->show();
}
}
void
DeviceStringParser::setVerboseLevel(int i)
{
setDebugLevel(i);
}
libffado-2.4.5/src/DeviceStringParser.h 0000644 0001750 0000144 00000005062 14206145246 017372 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Pieter Palmers
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef __FFADO_DEVICESTRINGPARSER__
#define __FFADO_DEVICESTRINGPARSER__
#include "debugmodule/debugmodule.h"
#include
#include
#include
class ConfigRom;
class DeviceStringParser {
protected:
class DeviceString {
public:
enum eType {
eInvalid = 0,
eBusNode = 1, // old-style hw:bus,node
eGUID = 2, // GUID match
};
DeviceString(DeviceStringParser&);
~DeviceString();
bool parse(std::string s);
bool match(ConfigRom &);
std::string getString() {return m_String;};
void show();
bool operator==(const DeviceString& x);
static bool isValidString(std::string s);
private:
DeviceStringParser & m_Parent;
int m_node;
int m_port;
uint64_t m_guid;
std::string m_String;
enum eType m_Type;
DECLARE_DEBUG_MODULE_REFERENCE;
};
public:
DeviceStringParser();
virtual ~DeviceStringParser();
int countDeviceStrings() {return m_DeviceStrings.size();};
bool match(ConfigRom &);
int matchPosition(ConfigRom& c);
bool parseString(std::string s);
void show();
void setVerboseLevel(int i);
static bool isValidString(std::string s);
protected:
bool removeDeviceString(DeviceString *);
bool addDeviceString(DeviceString *);
bool hasDeviceString(DeviceString *);
private:
int findDeviceString(DeviceString *);
void pruneDuplicates();
typedef std::vector< DeviceString* > DeviceStringVector;
typedef std::vector< DeviceString* >::iterator DeviceStringVectorIterator;
DeviceStringVector m_DeviceStrings;
protected:
DECLARE_DEBUG_MODULE;
};
#endif /* __FFADO_DEVICESTRINGPARSER__ */
libffado-2.4.5/src/SConscript 0000644 0001750 0000144 00000026062 14206145246 015473 0 ustar jwoithe users #
# Copyright (C) 2007-2008 Arnold Krille
# Copyright (C) 2007-2008 Pieter Palmers
#
# This file is part of FFADO
# FFADO = Free FireWire (pro-)audio drivers for Linux
#
# FFADO is based upon FreeBoB.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
import os
Import( 'env' )
libenv = env.Clone()
libenv.MergeFlags( "-I#/ -I#/src" )
ffado_source = env.Split( '\
devicemanager.cpp \
ffado.cpp \
ffadodevice.cpp \
debugmodule/debugmodule.cpp \
DeviceStringParser.cpp \
libieee1394/ARMHandler.cpp \
libieee1394/configrom.cpp \
libieee1394/csr1212.c \
libieee1394/CycleTimerHelper.cpp \
libieee1394/ieee1394service.cpp \
libieee1394/IEC61883.cpp \
libieee1394/IsoHandlerManager.cpp \
libstreaming/StreamProcessorManager.cpp \
libstreaming/util/cip.c \
libstreaming/generic/StreamProcessor.cpp \
libstreaming/generic/Port.cpp \
libstreaming/generic/PortManager.cpp \
libutil/cmd_serialize.cpp \
libutil/DelayLockedLoop.cpp \
libutil/IpcRingBuffer.cpp \
libutil/PacketBuffer.cpp \
libutil/Configuration.cpp \
libutil/OptionContainer.cpp \
libutil/PosixMessageQueue.cpp \
libutil/PosixSharedMemory.cpp \
libutil/PosixMutex.cpp \
libutil/PosixThread.cpp \
libutil/ringbuffer.c \
libutil/StreamStatistics.cpp \
libutil/SystemTimeSource.cpp \
libutil/TimestampedBuffer.cpp \
libutil/Watchdog.cpp \
libcontrol/Element.cpp \
libcontrol/BasicElements.cpp \
libcontrol/MatrixMixer.cpp \
libcontrol/CrossbarRouter.cpp \
libcontrol/ClockSelect.cpp \
libcontrol/Nickname.cpp \
')
if env['SERIALIZE_USE_EXPAT']:
ffado_source.append('libutil/serialize_expat.cpp')
ffado_source.append('libutil/serialize_expat_xml.cpp')
else:
ffado_source.append('libutil/serialize_libxml.cpp')
bebob_source = env.Split( '\
bebob/bebob_avdevice.cpp \
bebob/bebob_avdevice_subunit.cpp \
bebob/bebob_avplug.cpp \
bebob/bebob_dl_bcd.cpp \
bebob/bebob_dl_codes.cpp \
bebob/bebob_dl_mgr.cpp \
bebob/bebob_functionblock.cpp \
bebob/bebob_mixer.cpp \
bebob/focusrite/focusrite_generic.cpp \
bebob/focusrite/focusrite_saffire.cpp \
bebob/focusrite/focusrite_saffirepro.cpp \
bebob/focusrite/focusrite_cmd.cpp \
bebob/terratec/terratec_device.cpp \
bebob/terratec/terratec_cmd.cpp \
bebob/edirol/edirol_fa101.cpp \
bebob/edirol/edirol_fa66.cpp \
bebob/esi/quatafire610.cpp \
bebob/mackie/onyxmixer.cpp \
bebob/yamaha/yamaha_cmd.cpp \
bebob/yamaha/yamaha_avdevice.cpp \
bebob/maudio/normal_avdevice.cpp \
bebob/maudio/special_avdevice.cpp \
bebob/maudio/special_mixer.cpp \
bebob/presonus/firebox_avdevice.cpp \
bebob/presonus/inspire1394_avdevice.cpp \
' )
bebob_pkgdata = env.Split( '\
bebob/maudio/refdesign.xml \
bebob/maudio/fw410.xml \
bebob/maudio/fwap.xml \
' )
genericavc_source = env.Split( '\
genericavc/avc_avdevice.cpp \
genericavc/stanton/scs.cpp \
' )
genericavc_pkgdata = env.Split( '\
' )
fireworks_source = env.Split( '\
fireworks/fireworks_device.cpp \
fireworks/fireworks_control.cpp \
fireworks/fireworks_firmware.cpp \
fireworks/efc/efc_avc_cmd.cpp \
fireworks/efc/efc_cmd.cpp \
fireworks/efc/efc_cmds_hardware.cpp \
fireworks/efc/efc_cmds_hardware_ctrl.cpp \
fireworks/efc/efc_cmds_flash.cpp \
fireworks/efc/efc_cmds_mixer.cpp \
fireworks/efc/efc_cmds_monitor.cpp \
fireworks/efc/efc_cmds_ioconfig.cpp \
fireworks/fireworks_session_block.cpp \
fireworks/audiofire/audiofire_device.cpp \
' )
fireworks_pkgdata = env.Split( '\
' )
oxford_source = env.Split( '\
oxford/oxford_device.cpp \
libstreaming/amdtp-oxford/AmdtpOxfordReceiveStreamProcessor.cpp \
' )
oxford_pkgdata = env.Split( '\
' )
motu_source = env.Split( '\
motu/motu_avdevice.cpp \
motu/motu_controls.cpp \
motu/motu_mark3_controls.cpp \
motu/motu_mixerdefs.cpp \
motu/motu_mark3_mixerdefs.cpp \
motu/motu_mixer.cpp \
libstreaming/motu/MotuPort.cpp \
libstreaming/motu/MotuPortInfo.cpp \
libstreaming/motu/MotuReceiveStreamProcessor.cpp \
libstreaming/motu/MotuTransmitStreamProcessor.cpp \
' )
dice_source = env.Split( '\
dice/dice_avdevice.cpp \
dice/dice_firmware_loader.cpp \
dice/dice_eap.cpp \
dice/focusrite/focusrite_eap.cpp \
dice/focusrite/saffire_pro40.cpp \
dice/focusrite/saffire_pro26.cpp \
dice/focusrite/saffire_pro24.cpp \
dice/focusrite/saffire_pro14.cpp \
dice/focusrite/saffire_56.cpp \
dice/maudio/profire_2626.cpp \
dice/presonus/firestudio_tube.cpp \
dice/presonus/firestudio_project.cpp \
dice/presonus/firestudio_mobile.cpp \
' )
bounce_source = env.Split( '\
bounce/bounce_avdevice.cpp \
bounce/bounce_slave_avdevice.cpp \
' )
metric_halo_source = env.Split( '\
metrichalo/mh_avdevice.cpp \
' )
rme_source = env.Split( '\
rme/rme_shm.cpp \
rme/rme_avdevice.cpp \
rme/rme_avdevice_settings.cpp \
rme/fireface_flash.cpp \
rme/fireface_hw.cpp \
rme/fireface_settings_ctrls.cpp \
libstreaming/rme/RmePort.cpp \
libstreaming/rme/RmePortInfo.cpp \
libstreaming/rme/RmeReceiveStreamProcessor.cpp \
libstreaming/rme/RmeTransmitStreamProcessor.cpp \
' )
digidesign_source = env.Split( '\
digidesign/digidesign_avdevice.cpp \
libstreaming/digidesign/DigidesignPort.cpp \
libstreaming/digidesign/DigidesignPortInfo.cpp \
libstreaming/digidesign/DigidesignReceiveStreamProcessor.cpp \
libstreaming/digidesign/DigidesignTransmitStreamProcessor.cpp \
' )
amdtp_source = env.Split( '\
libstreaming/amdtp/AmdtpPort.cpp \
libstreaming/amdtp/AmdtpPortInfo.cpp \
libstreaming/amdtp/AmdtpReceiveStreamProcessor.cpp \
libstreaming/amdtp/AmdtpTransmitStreamProcessor.cpp \
' )
libavc_source = env.Split( '\
libavc/streamformat/avc_extended_stream_format.cpp \
libavc/musicsubunit/avc_descriptor_music.cpp \
libavc/musicsubunit/avc_musicsubunit.cpp \
libavc/audiosubunit/avc_audiosubunit.cpp \
libavc/audiosubunit/avc_descriptor_audio.cpp \
libavc/audiosubunit/avc_function_block.cpp \
libavc/descriptors/avc_descriptor_cmd.cpp \
libavc/descriptors/avc_descriptor.cpp \
libavc/general/avc_extended_subunit_info.cpp \
libavc/general/avc_unit_info.cpp \
libavc/general/avc_generic.cpp \
libavc/general/avc_subunit_info.cpp \
libavc/general/avc_connect.cpp \
libavc/general/avc_signal_format.cpp \
libavc/general/avc_extended_cmd_generic.cpp \
libavc/general/avc_extended_plug_info.cpp \
libavc/general/avc_plug_info.cpp \
libavc/general/avc_unit.cpp \
libavc/general/avc_subunit.cpp \
libavc/general/avc_plug.cpp \
libavc/general/avc_vendor_dependent_cmd.cpp \
libavc/avc_definitions.cpp \
libavc/ccm/avc_signal_source.cpp \
' )
source = ffado_source
pkgdata = []
if env['ENABLE_BEBOB']:
env['ENABLE_GENERICAVC'] = True
libenv.MergeFlags( "-DENABLE_BEBOB" )
source += bebob_source
pkgdata += bebob_pkgdata
if env['ENABLE_FIREWORKS']:
env['ENABLE_GENERICAVC'] = True
libenv.MergeFlags( "-DENABLE_FIREWORKS" )
source += fireworks_source
pkgdata += fireworks_pkgdata
if env['ENABLE_OXFORD']:
env['ENABLE_GENERICAVC'] = True
libenv.MergeFlags( "-DENABLE_OXFORD" )
source += oxford_source
pkgdata += oxford_pkgdata
if env['ENABLE_MOTU']:
libenv.MergeFlags( "-DENABLE_MOTU" )
source += motu_source
if env['ENABLE_DICE']:
env['ENABLE_GENERICAVC'] = True
libenv.MergeFlags( "-DENABLE_DICE" )
source += dice_source
if env['ENABLE_METRIC_HALO']:
libenv.MergeFlags( "-DENABLE_METRIC_HALO" )
source += metric_halo_source
if env['ENABLE_RME']:
libenv.MergeFlags( "-DENABLE_RME" )
source += rme_source
if env['ENABLE_DIGIDESIGN']:
libenv.MergeFlags( "-DENABLE_DIGIDESIGN" )
source += digidesign_source
if env['ENABLE_BOUNCE']:
env['ENABLE_GENERICAVC'] = True
libenv.MergeFlags( "-DENABLE_BOUNCE" )
source += bounce_source
if env['ENABLE_GENERICAVC']:
libenv.MergeFlags( "-DENABLE_GENERICAVC" )
source += libavc_source
source += amdtp_source
source += genericavc_source
pkgdata += genericavc_pkgdata
if not env.GetOption( "clean" ):
libenv.MergeFlags( "-lrt -lpthread" )
libenv.MergeFlags( env['LIBRAW1394_FLAGS'].decode() )
libenv.MergeFlags( env['LIBIEC61883_FLAGS'].decode() )
libenv.MergeFlags( env['LIBCONFIG_FLAGS'].decode() )
if not env['SERIALIZE_USE_EXPAT']:
if 'LIBXML30_FLAGS' in env :
libenv.MergeFlags( env['LIBXML30_FLAGS'].decode() )
if not('LIBXML30_FLAGS' in env) :
libenv.MergeFlags( env['LIBXML26_FLAGS'].decode() )
else:
libenv.PrependUnique( LIBS=["expat"] )
libenv.MergeFlags( "-DSERIALIZE_USE_EXPAT" )
if env['REQUIRE_LIBAVC']:
libenv.MergeFlags( env['LIBAVC1394_FLAGS'].decode() )
libname_versioned = "libffado.so.%s" % libenv['VERSION']
libname_versioned_short = "libffado.so.%s" % libenv['VERSION'].split('.')[0]
libenv.MergeFlags( "-Wl,-soname=%s" % libname_versioned_short )
ffadolib = libenv.SharedLibrary( "ffado", source )
#libenv.Install( "$libdir", ffadolib )
installer = libenv.InstallAs ( "$libdir/%s" % libname_versioned , ffadolib )
# if stripping would be something for us
#libenv.AddPostAction(installer, [['strip', env['STRIPFLAGS'], t[0].path]])
# make the required links
libenv.NoCache( '$libdir/%s' % libname_versioned )
libenv.AddPostAction(installer, [['rm', '-f', '$libdir/libffado.so', '$libdir/%s' % libname_versioned_short],
['cd', '$libdir',
'&&','ln', '-s', libname_versioned_short, 'libffado.so',
'&&','ln', '-s', installer[0].name, libname_versioned_short,
]
])
if libenv['BUILD_STATIC_LIB']:
ffadolib_static = libenv.StaticLibrary( "ffado", source )
#
# Install the pkgdata to $sharedir
#
for data in pkgdata:
libenv.Install( "$sharedir", data )
#
# For the debugging apps
#
env2 = libenv.Clone()
env2.PrependUnique( LIBPATH=env['build_base']+"src" )
env2.PrependUnique( LIBS="ffado" )
apps = { \
"test-debugmodule" : "debugmodule/test_debugmodule.cpp", \
"test-dll" : "libutil/test-dll.cpp", \
"test-unittests-util" : "libutil/unittests.cpp", \
"test-cyclecalc" : "libieee1394/test-cyclecalc.cpp", \
}
installapps = []
for app in apps.keys():
env2.Program( target=app, source = env.Split( apps[app] ) )
if app.find( "test" ) == -1:
env2.Install( "$bindir", app )
libffado-2.4.5/src/bebob/ 0000755 0001750 0000144 00000000000 14206145612 014521 5 ustar jwoithe users libffado-2.4.5/src/bebob/bebob_avdevice.cpp 0000644 0001750 0000144 00000072535 14206145246 020163 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Daniel Wagner
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "config.h"
#include "devicemanager.h"
#include "bebob/bebob_avdevice.h"
#include "bebob/bebob_avdevice_subunit.h"
#include "bebob/bebob_mixer.h"
#include "bebob/focusrite/focusrite_saffire.h"
#include "bebob/focusrite/focusrite_saffirepro.h"
#include "bebob/terratec/terratec_device.h"
#include "bebob/mackie/onyxmixer.h"
#include "bebob/edirol/edirol_fa101.h"
#include "bebob/edirol/edirol_fa66.h"
#include "bebob/esi/quatafire610.h"
#include "bebob/yamaha/yamaha_avdevice.h"
#include "bebob/maudio/normal_avdevice.h"
#include "bebob/maudio/special_avdevice.h"
#include "bebob/presonus/firebox_avdevice.h"
#include "bebob/presonus/inspire1394_avdevice.h"
#include "libieee1394/configrom.h"
#include "libieee1394/ieee1394service.h"
#include "libavc/general/avc_plug_info.h"
#include "libavc/general/avc_extended_plug_info.h"
#include "libavc/general/avc_subunit_info.h"
#include "libavc/streamformat/avc_extended_stream_format.h"
#include "libutil/cmd_serialize.h"
#include "libavc/avc_definitions.h"
#include "debugmodule/debugmodule.h"
#include
#include
#include
#include
#include
#include
using namespace AVC;
namespace BeBoB {
Device::Device( DeviceManager& d, ffado_smartptr< ConfigRom >( configRom ) )
: GenericAVC::Device( d, configRom )
, m_last_discovery_config_id ( 0xFFFFFFFFFFFFFFFFLLU )
, m_Mixer ( 0 )
{
debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::Device (NodeID %d)\n",
getConfigRom().getNodeId() );
}
Device::~Device()
{
destroyMixer();
}
bool
Device::probe( Util::Configuration& c, ConfigRom& configRom, bool generic )
{
unsigned int vendorId = configRom.getNodeVendorId();
unsigned int modelId = configRom.getModelId();
if(generic) {
/* M-Audio Special Devices don't support followed commands */
if ((vendorId == FW_VENDORID_MAUDIO) &&
((modelId == 0x00010071) || (modelId == 0x00010091)))
return true;
// try a bebob-specific command to check for the firmware
ExtendedPlugInfoCmd extPlugInfoCmd( configRom.get1394Service() );
UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
configRom.getNodeId() );
extPlugInfoCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input,
PlugAddress::ePAM_Unit,
unitPlugAddress ) );
extPlugInfoCmd.setNodeId( configRom.getNodeId() );
extPlugInfoCmd.setCommandType( AVCCommand::eCT_Status );
extPlugInfoCmd.setVerbose( configRom.getVerboseLevel() );
ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
ExtendedPlugInfoInfoType::eIT_NoOfChannels );
extendedPlugInfoInfoType.initialize();
extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
if ( !extPlugInfoCmd.fire() ) {
debugError( "Number of channels command failed\n" );
return false;
}
if((extPlugInfoCmd.getResponse() != AVCCommand::eR_Implemented)) {
// command not supported
return false;
}
ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
if ( infoType
&& infoType->m_plugNrOfChns )
{
return true;
}
return false;
} else {
// check if device is in supported devices list
Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
return c.isValid(vme) && vme.driver == Util::Configuration::eD_BeBoB;
}
}
FFADODevice *
Device::createDevice(DeviceManager& d, ffado_smartptr( configRom ))
{
unsigned int vendorId = configRom->getNodeVendorId();
unsigned int modelId = configRom->getModelId();
switch (vendorId) {
case FW_VENDORID_MACKIE:
if (modelId == 0x00010065 ) {
return new Mackie::OnyxMixerDevice(d, configRom);
}
case FW_VENDORID_EDIROL:
switch (modelId) {
case 0x00010048:
return new Edirol::EdirolFa101Device(d, configRom);
case 0x00010049:
return new Edirol::EdirolFa66Device(d, configRom);
default:
return new Device(d, configRom);
}
case FW_VENDORID_ESI:
if (modelId == 0x00010064 || modelId == 0x00000210) {
return new ESI::QuataFireDevice(d, configRom);
}
break;
case FW_VENDORID_TERRATEC:
switch(modelId) {
case 0x00000003:
return new Terratec::Phase88Device(d, configRom);
default: // return a plain BeBoB device
return new Device(d, configRom);
}
case FW_VENDORID_FOCUSRITE:
switch(modelId) {
case 0x00000003:
case 0x00000006:
return new Focusrite::SaffireProDevice(d, configRom);
case 0x00000000:
return new Focusrite::SaffireDevice(d, configRom);
default: // return a plain BeBoB device
return new Device(d, configRom);
}
case FW_VENDORID_YAMAHA:
switch (modelId) {
case 0x0010000b:
case 0x0010000c:
return new Yamaha::GoDevice(d, configRom);
default: // return a plain BeBoB device
return new Device(d, configRom);
}
case FW_VENDORID_MAUDIO:
switch (modelId) {
case 0x0000000a: // Ozonic
case 0x00010046: // fw410
case 0x00010060: // Audiophile
case 0x00010062: // Solo
return new MAudio::Normal::Device(d, configRom, modelId);
case 0x00010071: // FireWire 1814
case 0x00010091: // ProjectMix I/O
return new MAudio::Special::Device(d, configRom);
default:
return new Device(d, configRom);
}
case FW_VENDORID_PRESONUS:
switch (modelId) {
case 0x00010000:
return new Presonus::Firebox::Device(d, configRom);
case 0x00010001:
return new Presonus::Inspire1394::Device(d, configRom);
default:
return new Device(d, configRom);
}
default:
return new Device(d, configRom);
}
return NULL;
}
#define BEBOB_CHECK_AND_ADD_SR(v, x) \
{ if(supportsSamplingFrequency(x)) \
v.push_back(x); }
bool
Device::discover()
{
unsigned int vendorId = getConfigRom().getNodeVendorId();
unsigned int modelId = getConfigRom().getModelId();
Util::Configuration &c = getDeviceManager().getConfiguration();
Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
if (c.isValid(vme) && vme.driver == Util::Configuration::eD_BeBoB) {
debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
vme.vendor_name.c_str(),
vme.model_name.c_str());
} else {
debugWarning("Using generic BeBoB support for unsupported device '%s %s'\n",
getConfigRom().getVendorName().c_str(), getConfigRom().getModelName().c_str());
}
if ( !Unit::discover() ) {
debugError( "Could not discover unit\n" );
return false;
}
if((getAudioSubunit( 0 ) == NULL)) {
debugError( "Unit doesn't have an Audio subunit.\n");
return false;
}
if((getMusicSubunit( 0 ) == NULL)) {
debugError( "Unit doesn't have a Music subunit.\n");
return false;
}
if(!buildMixer()) {
debugWarning("Could not build mixer\n");
}
// keep track of the config id of this discovery
m_last_discovery_config_id = getConfigurationId();
return true;
}
bool
Device::buildMixer()
{
debugOutput(DEBUG_LEVEL_VERBOSE, "Building a generic BeBoB mixer...\n");
// create a Mixer
// this removes the mixer if it already exists
// note: a mixer self-registers to it's parent
delete m_Mixer;
// create the mixer & register it
if(getAudioSubunit(0) == NULL) {
debugWarning("Could not find audio subunit, mixer not available.\n");
m_Mixer = NULL;
} else {
m_Mixer = new Mixer(*this);
}
if (m_Mixer) m_Mixer->setVerboseLevel(getDebugLevel());
return m_Mixer != NULL;
}
bool
Device::destroyMixer()
{
delete m_Mixer;
return true;
}
bool
Device::setSelectorFBValue(int id, int value) {
FunctionBlockCmd fbCmd( get1394Service(),
FunctionBlockCmd::eFBT_Selector,
id,
FunctionBlockCmd::eCA_Current );
fbCmd.setNodeId( getNodeId() );
fbCmd.setSubunitId( 0x00 );
fbCmd.setCommandType( AVCCommand::eCT_Control );
fbCmd.m_pFBSelector->m_inputFbPlugNumber = (value & 0xFF);
fbCmd.setVerboseLevel( getDebugLevel() );
if ( !fbCmd.fire() ) {
debugError( "cmd failed\n" );
return false;
}
// if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
// Util::Cmd::CoutSerializer se;
// fbCmd.serialize( se );
// }
//
if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
}
return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
}
int
Device::getSelectorFBValue(int id) {
FunctionBlockCmd fbCmd( get1394Service(),
FunctionBlockCmd::eFBT_Selector,
id,
FunctionBlockCmd::eCA_Current );
fbCmd.setNodeId( getNodeId() );
fbCmd.setSubunitId( 0x00 );
fbCmd.setCommandType( AVCCommand::eCT_Status );
fbCmd.m_pFBSelector->m_inputFbPlugNumber = 0xFF;
fbCmd.setVerboseLevel( getDebugLevel() );
if ( !fbCmd.fire() ) {
debugError( "cmd failed\n" );
return -1;
}
// if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
// Util::Cmd::CoutSerializer se;
// fbCmd.serialize( se );
// }
if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
}
return fbCmd.m_pFBSelector->m_inputFbPlugNumber;
}
bool
Device::setFeatureFBVolumeCurrent(int id, int channel, int v) {
FunctionBlockCmd fbCmd( get1394Service(),
FunctionBlockCmd::eFBT_Feature,
id,
FunctionBlockCmd::eCA_Current );
fbCmd.setNodeId( getNodeId() );
fbCmd.setSubunitId( 0x00 );
fbCmd.setCommandType( AVCCommand::eCT_Control );
fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_Volume;
AVC::FunctionBlockFeatureVolume vl;
fbCmd.m_pFBFeature->m_pVolume = vl.clone();
fbCmd.m_pFBFeature->m_pVolume->m_volume = v;
fbCmd.setVerboseLevel( getDebugLevel() );
if ( !fbCmd.fire() ) {
debugError( "cmd failed\n" );
return false;
}
// if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
// Util::Cmd::CoutSerializer se;
// fbCmd.serialize( se );
// }
if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
}
return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
}
int
Device::getFeatureFBVolumeValue(int id, int channel, FunctionBlockCmd::EControlAttribute controlAttribute)
{
FunctionBlockCmd fbCmd( get1394Service(),
FunctionBlockCmd::eFBT_Feature,
id,
controlAttribute);
fbCmd.setNodeId( getNodeId() );
fbCmd.setSubunitId( 0x00 );
fbCmd.setCommandType( AVCCommand::eCT_Status );
fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_Volume;
AVC::FunctionBlockFeatureVolume vl;
fbCmd.m_pFBFeature->m_pVolume = vl.clone();
fbCmd.m_pFBFeature->m_pVolume->m_volume = 0;
fbCmd.setVerboseLevel( getDebugLevel() );
if ( !fbCmd.fire() ) {
debugError( "cmd failed\n" );
return 0;
}
// if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
// Util::Cmd::CoutSerializer se;
// fbCmd.serialize( se );
// }
if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
}
int16_t volume=(int16_t)(fbCmd.m_pFBFeature->m_pVolume->m_volume);
return volume;
}
int
Device::getFeatureFBVolumeMinimum(int id, int channel)
{
return getFeatureFBVolumeValue(id, channel, AVC::FunctionBlockCmd::eCA_Minimum);
}
int
Device::getFeatureFBVolumeMaximum(int id, int channel)
{
return getFeatureFBVolumeValue(id, channel, AVC::FunctionBlockCmd::eCA_Maximum);
}
int
Device::getFeatureFBVolumeCurrent(int id, int channel)
{
return getFeatureFBVolumeValue(id, channel, AVC::FunctionBlockCmd::eCA_Current);
}
bool
Device::setFeatureFBLRBalanceCurrent(int id, int channel, int v) {
FunctionBlockCmd fbCmd( get1394Service(),
FunctionBlockCmd::eFBT_Feature,
id,
FunctionBlockCmd::eCA_Current );
fbCmd.setNodeId( getNodeId() );
fbCmd.setSubunitId( 0x00 );
fbCmd.setCommandType( AVCCommand::eCT_Control );
fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_LRBalance;
AVC::FunctionBlockFeatureLRBalance bl;
fbCmd.m_pFBFeature->m_pLRBalance = bl.clone();
fbCmd.m_pFBFeature->m_pLRBalance->m_lrBalance = v;
fbCmd.setVerboseLevel( getDebugLevel() );
if ( !fbCmd.fire() ) {
debugError( "cmd failed\n" );
return false;
}
// if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
// Util::Cmd::CoutSerializer se;
// fbCmd.serialize( se );
// }
if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
}
return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
}
int
Device::getFeatureFBLRBalanceValue(int id, int channel, FunctionBlockCmd::EControlAttribute controlAttribute)
{
FunctionBlockCmd fbCmd( get1394Service(),
FunctionBlockCmd::eFBT_Feature,
id,
controlAttribute);
fbCmd.setNodeId( getNodeId() );
fbCmd.setSubunitId( 0x00 );
fbCmd.setCommandType( AVCCommand::eCT_Status );
fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_LRBalance;
AVC::FunctionBlockFeatureLRBalance bl;
fbCmd.m_pFBFeature->m_pLRBalance = bl.clone();
fbCmd.m_pFBFeature->m_pLRBalance->m_lrBalance = 0;
fbCmd.setVerboseLevel( getDebugLevel() );
if ( !fbCmd.fire() ) {
debugError( "cmd failed\n" );
return 0;
}
// if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
// Util::Cmd::CoutSerializer se;
// fbCmd.serialize( se );
// }
if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
}
int16_t balance=(int16_t)(fbCmd.m_pFBFeature->m_pLRBalance->m_lrBalance);
return balance;
}
int
Device::getFeatureFBLRBalanceMinimum(int id, int channel)
{
return getFeatureFBLRBalanceValue(id, channel, AVC::FunctionBlockCmd::eCA_Minimum);
}
int
Device::getFeatureFBLRBalanceMaximum(int id, int channel)
{
return getFeatureFBLRBalanceValue(id, channel, AVC::FunctionBlockCmd::eCA_Maximum);
}
int
Device::getFeatureFBLRBalanceCurrent(int id, int channel)
{
return getFeatureFBLRBalanceValue(id, channel, AVC::FunctionBlockCmd::eCA_Current);
}
bool
Device::setProcessingFBMixerSingleCurrent(int id, int iPlugNum,
int iAChNum, int oAChNum,
int setting)
{
AVC::FunctionBlockCmd fbCmd(get1394Service(),
AVC::FunctionBlockCmd::eFBT_Processing,
id,
AVC::FunctionBlockCmd::eCA_Current);
fbCmd.setNodeId(getNodeId());
fbCmd.setSubunitId(0x00);
fbCmd.setCommandType(AVCCommand::eCT_Control);
fbCmd.setVerboseLevel( getDebugLevel() );
AVC::FunctionBlockProcessing *fbp = fbCmd.m_pFBProcessing;
fbp->m_selectorLength = 0x04;
fbp->m_fbInputPlugNumber = iPlugNum;
fbp->m_inputAudioChannelNumber = iAChNum;
fbp->m_outputAudioChannelNumber = oAChNum;
// mixer object is not generated automatically
fbp->m_pMixer = new AVC::FunctionBlockProcessingMixer;
fbp->m_pMixer->m_mixerSetting = setting;
if ( !fbCmd.fire() ) {
debugError( "cmd failed\n" );
return false;
}
if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
}
return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
}
int
Device::getProcessingFBMixerSingleCurrent(int id, int iPlugNum,
int iAChNum, int oAChNum)
{
AVC::FunctionBlockCmd fbCmd(get1394Service(),
AVC::FunctionBlockCmd::eFBT_Processing,
id,
AVC::FunctionBlockCmd::eCA_Current);
fbCmd.setNodeId(getNodeId());
fbCmd.setSubunitId(0x00);
fbCmd.setCommandType(AVCCommand::eCT_Status);
fbCmd.setVerboseLevel( getDebugLevel() );
AVC::FunctionBlockProcessing *fbp = fbCmd.m_pFBProcessing;
fbp->m_selectorLength = 0x04;
fbp->m_fbInputPlugNumber = iPlugNum;
fbp->m_inputAudioChannelNumber = iAChNum;
fbp->m_outputAudioChannelNumber = oAChNum;
// mixer object is not generated automatically
fbp->m_pMixer = new AVC::FunctionBlockProcessingMixer;
if ( !fbCmd.fire() ) {
debugError( "cmd failed\n" );
return 0;
}
if( (fbCmd.getResponse() != AVCCommand::eR_Implemented) ) {
debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
}
int16_t setting = (int16_t)(fbp->m_pMixer->m_mixerSetting);
return setting;
}
void
Device::showDevice()
{
debugOutput(DEBUG_LEVEL_NORMAL, "Device is a BeBoB device\n");
GenericAVC::Device::showDevice();
flushDebugOutput();
}
void
Device::setVerboseLevel(int l)
{
if (m_Mixer) m_Mixer->setVerboseLevel( l );
GenericAVC::Device::setVerboseLevel( l );
debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
}
AVC::Subunit*
Device::createSubunit(AVC::Unit& unit,
AVC::ESubunitType type,
AVC::subunit_t id )
{
AVC::Subunit* s=NULL;
switch (type) {
case eST_Audio:
s=new BeBoB::SubunitAudio(unit, id );
break;
case eST_Music:
s=new BeBoB::SubunitMusic(unit, id );
break;
default:
s=NULL;
break;
}
if(s) s->setVerboseLevel(getDebugLevel());
return s;
}
AVC::Plug *
Device::createPlug( AVC::Unit* unit,
AVC::Subunit* subunit,
AVC::function_block_type_t functionBlockType,
AVC::function_block_type_t functionBlockId,
AVC::Plug::EPlugAddressType plugAddressType,
AVC::Plug::EPlugDirection plugDirection,
AVC::plug_id_t plugId,
int globalId )
{
Plug *p= new BeBoB::Plug( unit,
subunit,
functionBlockType,
functionBlockId,
plugAddressType,
plugDirection,
plugId,
globalId );
if (p) p->setVerboseLevel(getDebugLevel());
return p;
}
bool
Device::propagatePlugInfo() {
// we don't have to propagate since we discover things
// another way
debugOutput(DEBUG_LEVEL_VERBOSE, "Skip plug info propagation\n");
return true;
}
uint8_t
Device::getConfigurationIdSampleRate()
{
ExtendedStreamFormatCmd extStreamFormatCmd( get1394Service() );
UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR, 0 );
extStreamFormatCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input,
PlugAddress::ePAM_Unit,
unitPlugAddress ) );
extStreamFormatCmd.setNodeId( getNodeId() );
extStreamFormatCmd.setCommandType( AVCCommand::eCT_Status );
extStreamFormatCmd.setVerbose( getDebugLevel() );
if ( !extStreamFormatCmd.fire() ) {
debugError( "Stream format command failed\n" );
return 0;
}
FormatInformation* formatInfo =
extStreamFormatCmd.getFormatInformation();
FormatInformationStreamsCompound* compoundStream
= dynamic_cast< FormatInformationStreamsCompound* > (
formatInfo->m_streams );
if ( compoundStream ) {
debugOutput(DEBUG_LEVEL_VERBOSE, "Sample rate 0x%02x\n",
compoundStream->m_samplingFrequency );
return compoundStream->m_samplingFrequency;
}
debugError( "Could not retrieve sample rate\n" );
return 0;
}
uint8_t
Device::getConfigurationIdNumberOfChannel( PlugAddress::EPlugDirection ePlugDirection )
{
ExtendedPlugInfoCmd extPlugInfoCmd( get1394Service() );
UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
0 );
extPlugInfoCmd.setPlugAddress( PlugAddress( ePlugDirection,
PlugAddress::ePAM_Unit,
unitPlugAddress ) );
extPlugInfoCmd.setNodeId( getNodeId() );
extPlugInfoCmd.setCommandType( AVCCommand::eCT_Status );
extPlugInfoCmd.setVerbose( getDebugLevel() );
ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
ExtendedPlugInfoInfoType::eIT_NoOfChannels );
extendedPlugInfoInfoType.initialize();
extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
if ( !extPlugInfoCmd.fire() ) {
debugError( "Number of channels command failed\n" );
return 0;
}
ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
if ( infoType
&& infoType->m_plugNrOfChns )
{
debugOutput(DEBUG_LEVEL_VERBOSE, "Number of channels 0x%02x\n",
infoType->m_plugNrOfChns->m_nrOfChannels );
return infoType->m_plugNrOfChns->m_nrOfChannels;
}
debugError( "Could not retrieve number of channels\n" );
return 0;
}
uint16_t
Device::getConfigurationIdSyncMode()
{
SignalSourceCmd signalSourceCmd( get1394Service() );
SignalUnitAddress signalUnitAddr;
signalUnitAddr.m_plugId = 0x01;
signalSourceCmd.setSignalDestination( signalUnitAddr );
signalSourceCmd.setNodeId( getNodeId() );
signalSourceCmd.setSubunitType( eST_Unit );
signalSourceCmd.setSubunitId( 0xff );
signalSourceCmd.setVerbose( getDebugLevel() );
signalSourceCmd.setCommandType( AVCCommand::eCT_Status );
if ( !signalSourceCmd.fire() ) {
debugError( "Signal source command failed\n" );
return 0;
}
SignalAddress* pSyncPlugSignalAddress = signalSourceCmd.getSignalSource();
SignalSubunitAddress* pSyncPlugSubunitAddress
= dynamic_cast( pSyncPlugSignalAddress );
if ( pSyncPlugSubunitAddress ) {
debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
( pSyncPlugSubunitAddress->m_subunitType << 3
| pSyncPlugSubunitAddress->m_subunitId ) << 8
| pSyncPlugSubunitAddress->m_plugId );
return ( pSyncPlugSubunitAddress->m_subunitType << 3
| pSyncPlugSubunitAddress->m_subunitId ) << 8
| pSyncPlugSubunitAddress->m_plugId;
}
SignalUnitAddress* pSyncPlugUnitAddress
= dynamic_cast( pSyncPlugSignalAddress );
if ( pSyncPlugUnitAddress ) {
debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
0xff << 8 | pSyncPlugUnitAddress->m_plugId );
return ( 0xff << 8 | pSyncPlugUnitAddress->m_plugId );
}
debugError( "Could not retrieve sync mode\n" );
return 0;
}
bool
Device::needsRediscovery()
{
// require rediscovery if the config id differs from the one saved
// in the previous discovery
return getConfigurationId() != m_last_discovery_config_id;
}
uint64_t
Device::getConfigurationId()
{
// create a unique configuration id.
uint64_t id = 0;
id = getConfigurationIdSampleRate();
id |= getConfigurationIdNumberOfChannel( PlugAddress::ePD_Input ) << 8;
id |= getConfigurationIdNumberOfChannel( PlugAddress::ePD_Output ) << 16;
id |= ((uint64_t)getConfigurationIdSyncMode()) << 24;
return id;
}
bool
Device::serialize( std::string basePath,
Util::IOSerialize& ser ) const
{
bool result;
result = GenericAVC::Device::serialize( basePath, ser );
return result;
}
bool
Device::deserialize( std::string basePath,
Util::IODeserialize& deser )
{
bool result;
result = GenericAVC::Device::deserialize( basePath, deser );
return result;
}
std::string
Device::getCachePath()
{
std::string cachePath;
char* pCachePath;
string path = CACHEDIR;
if ( path.size() && path[0] == '~' ) {
path.erase( 0, 1 ); // remove ~
path.insert( 0, getenv( "HOME" ) ); // prepend the home path
}
if ( asprintf( &pCachePath, "%s/cache/", path.c_str() ) < 0 ) {
debugError( "Could not create path string for cache pool (trying '/var/cache/libffado' instead)\n" );
cachePath = "/var/cache/libffado/";
} else {
cachePath = pCachePath;
free( pCachePath );
}
return cachePath;
}
bool
Device::loadFromCache()
{
std::string sDevicePath = getCachePath() + getConfigRom().getGuidString();
char* configId;
asprintf(&configId, "%016" PRIx64 "", getConfigurationId() );
if ( !configId ) {
debugError( "could not create id string\n" );
return false;
}
std::string sFileName = sDevicePath + "/" + configId + ".xml";
free( configId );
debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", sFileName.c_str() );
struct stat buf;
if ( stat( sFileName.c_str(), &buf ) != 0 ) {
debugOutput( DEBUG_LEVEL_NORMAL, "\"%s\" does not exist\n", sFileName.c_str() );
return false;
} else {
if ( !S_ISREG( buf.st_mode ) ) {
debugOutput( DEBUG_LEVEL_NORMAL, "\"%s\" is not a regular file\n", sFileName.c_str() );
return false;
}
}
Util::XMLDeserialize deser( sFileName, getDebugLevel() );
if (!deser.isValid()) {
debugOutput( DEBUG_LEVEL_NORMAL, "cache not valid: %s\n",
sFileName.c_str() );
return false;
}
bool result = deserialize( "", deser );
if ( result ) {
debugOutput( DEBUG_LEVEL_NORMAL, "could create valid bebob driver from %s\n",
sFileName.c_str() );
}
if(result) {
buildMixer();
}
return result;
}
bool
Device::saveCache()
{
// the path looks like this:
// PATH_TO_CACHE + GUID + CONFIGURATION_ID
string tmp_path = getCachePath() + getConfigRom().getGuidString();
// the following piece should do something like
// 'mkdir -p some/path/with/some/dirs/which/do/not/exist'
vector tokens;
tokenize( tmp_path, tokens, "/" );
string path;
for ( vector::const_iterator it = tokens.begin();
it != tokens.end();
++it )
{
path += "/" + *it;
struct stat buf;
if ( stat( path.c_str(), &buf ) == 0 ) {
if ( !S_ISDIR( buf.st_mode ) ) {
debugError( "\"%s\" is not a directory\n", path.c_str() );
return false;
}
} else {
if ( mkdir( path.c_str(), S_IRWXU | S_IRWXG ) != 0 ) {
debugError( "Could not create \"%s\" directory\n", path.c_str() );
return false;
}
}
}
// come up with an unique file name for the current settings
char* configId;
asprintf(&configId, "%016" PRIx64 "", BeBoB::Device::getConfigurationId() );
if ( !configId ) {
debugError( "Could not create id string\n" );
return false;
}
string filename = path + "/" + configId + ".xml";
free( configId );
debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", filename.c_str() );
Util::XMLSerialize ser( filename );
return serialize( "", ser );
}
} // end of namespace
libffado-2.4.5/src/bebob/bebob_avdevice.h 0000644 0001750 0000144 00000011603 14206145246 017615 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Daniel Wagner
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef BEBOB_DEVICE_H
#define BEBOB_DEVICE_H
#include
#include "debugmodule/debugmodule.h"
#include "libieee1394/configrom.h"
#include "libieee1394/ieee1394service.h"
#include "libavc/avc_definitions.h"
#include "libavc/general/avc_extended_cmd_generic.h"
#include "libavc/general/avc_unit.h"
#include "libavc/general/avc_subunit.h"
#include "libavc/general/avc_plug.h"
#include "libavc/audiosubunit/avc_function_block.h"
#include "bebob/bebob_avplug.h"
#include "bebob/bebob_avdevice_subunit.h"
#include "bebob/bebob_mixer.h"
#include "libstreaming/amdtp/AmdtpReceiveStreamProcessor.h"
#include "libstreaming/amdtp/AmdtpTransmitStreamProcessor.h"
#include "libstreaming/amdtp/AmdtpPort.h"
#include "libstreaming/amdtp/AmdtpPortInfo.h"
#include "libutil/serialize.h"
#include "genericavc/avc_avdevice.h"
#include "ffadodevice.h"
#include
#include
namespace BeBoB {
class Device : public GenericAVC::Device {
public:
Device( DeviceManager& d, ffado_smartptr( configRom ));
virtual ~Device();
static bool probe( Util::Configuration&, ConfigRom& configRom, bool generic = false );
virtual bool loadFromCache();
virtual bool saveCache();
virtual bool discover();
static FFADODevice * createDevice( DeviceManager& d, ffado_smartptr( configRom ));
virtual AVC::Subunit* createSubunit(AVC::Unit& unit,
AVC::ESubunitType type,
AVC::subunit_t id );
virtual AVC::Plug *createPlug( AVC::Unit* unit,
AVC::Subunit* subunit,
AVC::function_block_type_t functionBlockType,
AVC::function_block_type_t functionBlockId,
AVC::Plug::EPlugAddressType plugAddressType,
AVC::Plug::EPlugDirection plugDirection,
AVC::plug_id_t plugId,
int globalId = -1 );
virtual int getSelectorFBValue(int id);
virtual bool setSelectorFBValue(int id, int v);
virtual int getFeatureFBVolumeMinimum(int id, int channel);
virtual int getFeatureFBVolumeMaximum(int id, int channel);
virtual int getFeatureFBVolumeCurrent(int id, int channel);
virtual bool setFeatureFBVolumeCurrent(int id, int channel, int v);
virtual int getFeatureFBLRBalanceMinimum(int id, int channel);
virtual int getFeatureFBLRBalanceMaximum(int id, int channel);
virtual int getFeatureFBLRBalanceCurrent(int id, int channel);
virtual bool setFeatureFBLRBalanceCurrent(int id, int channel, int v);
virtual bool setProcessingFBMixerSingleCurrent(int id, int iPlugNum,
int iAChNum, int oAChNum,
int setting);
virtual int getProcessingFBMixerSingleCurrent(int id, int iPlugNum,
int iAChNum, int oAChNum);
virtual void showDevice();
virtual void setVerboseLevel(int l);
protected:
virtual bool propagatePlugInfo();
virtual bool buildMixer();
virtual bool destroyMixer();
virtual int getFeatureFBVolumeValue(int id, int channel, AVC::FunctionBlockCmd::EControlAttribute controlAttribute);
virtual int getFeatureFBLRBalanceValue(int id, int channel, AVC::FunctionBlockCmd::EControlAttribute controlAttribute);
public:
virtual bool serialize( std::string basePath, Util::IOSerialize& ser ) const;
virtual bool deserialize( std::string basePath, Util::IODeserialize& deser );
virtual uint64_t getConfigurationId();
virtual bool needsRediscovery();
std::string getCachePath();
protected:
virtual uint8_t getConfigurationIdSampleRate();
virtual uint8_t getConfigurationIdNumberOfChannel( AVC::PlugAddress::EPlugDirection ePlugDirection );
virtual uint16_t getConfigurationIdSyncMode();
std::vector m_supported_frequencies;
uint64_t m_last_discovery_config_id;
protected:
Mixer* m_Mixer;
};
}
#endif
libffado-2.4.5/src/bebob/bebob_avdevice_subunit.cpp 0000644 0001750 0000144 00000034361 14206145246 021727 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Daniel Wagner
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "bebob/bebob_functionblock.h"
#include "bebob/bebob_avdevice_subunit.h"
#include "bebob/bebob_avdevice.h"
#include "bebob/bebob_avplug.h"
#include "libieee1394/configrom.h"
#include "libavc/general/avc_plug_info.h"
#include "libavc/streamformat/avc_extended_stream_format.h"
#include "libutil/cmd_serialize.h"
#include
using namespace AVC;
//////////////////////////
BeBoB::SubunitAudio::SubunitAudio( AVC::Unit& avDevice,
subunit_t id )
: AVC::SubunitAudio( avDevice, id )
{
}
BeBoB::SubunitAudio::SubunitAudio()
: AVC::SubunitAudio()
{
}
BeBoB::SubunitAudio::~SubunitAudio()
{
for ( FunctionBlockVector::iterator it = m_functions.begin();
it != m_functions.end();
++it )
{
delete *it;
}
}
AVC::Plug *
BeBoB::SubunitAudio::createPlug( AVC::Unit* unit,
AVC::Subunit* subunit,
AVC::function_block_type_t functionBlockType,
AVC::function_block_type_t functionBlockId,
AVC::Plug::EPlugAddressType plugAddressType,
AVC::Plug::EPlugDirection plugDirection,
AVC::plug_id_t plugId )
{
return new BeBoB::Plug( unit,
subunit,
functionBlockType,
functionBlockId,
plugAddressType,
plugDirection,
plugId );
}
bool
BeBoB::SubunitAudio::discover()
{
debugOutput(DEBUG_LEVEL_NORMAL, "Discovering %s...\n", getName());
// discover the AV/C generic part
if ( !AVC::SubunitAudio::discover() ) {
return false;
}
// do the remaining BeBoB audio subunit discovery
if ( !discoverFunctionBlocks() ) {
debugError( "function block discovering failed\n" );
return false;
}
return true;
}
bool
BeBoB::SubunitAudio::discoverConnections()
{
debugOutput(DEBUG_LEVEL_NORMAL, "Discovering connections...\n");
if ( !Subunit::discoverConnections() ) {
return false;
}
for ( FunctionBlockVector::iterator it = m_functions.begin();
it != m_functions.end();
++it )
{
FunctionBlock* function = *it;
if ( !function->discoverConnections() ) {
debugError( "functionblock connection discovering failed ('%s')\n",
function->getName() );
return false;
}
}
return true;
}
const char*
BeBoB::SubunitAudio::getName()
{
return "BeBoB::AudioSubunit";
}
bool
BeBoB::SubunitAudio::discoverFunctionBlocks()
{
debugOutput( DEBUG_LEVEL_NORMAL,
"Discovering function blocks...\n");
if ( !discoverFunctionBlocksDo(
ExtendedSubunitInfoCmd::eFBT_AudioSubunitSelector) )
{
debugError( "Could not discover function block selector\n" );
return false;
}
if ( !discoverFunctionBlocksDo(
ExtendedSubunitInfoCmd::eFBT_AudioSubunitFeature) )
{
debugError( "Could not discover function block feature\n" );
return false;
}
if ( !discoverFunctionBlocksDo(
ExtendedSubunitInfoCmd::eFBT_AudioSubunitProcessing) )
{
debugError( "Could not discover function block processing\n" );
return false;
}
if ( !discoverFunctionBlocksDo(
ExtendedSubunitInfoCmd::eFBT_AudioSubunitCodec) )
{
debugError( "Could not discover function block codec\n" );
return false;
}
// print a function block list
#ifdef DEBUG
if ((int)getDebugLevel() >= DEBUG_LEVEL_NORMAL) {
for ( FunctionBlockVector::iterator it = m_functions.begin();
it != m_functions.end();
++it )
{
debugOutput(DEBUG_LEVEL_NORMAL, "%20s FB, type 0x%X, id=%d\n",
(*it)->getName(),
(*it)->getType(),
(*it)->getId());
}
}
#endif
return true;
}
bool
BeBoB::SubunitAudio::discoverFunctionBlocksDo(
ExtendedSubunitInfoCmd::EFunctionBlockType fbType )
{
int page = 0;
bool cmdSuccess = false;
bool finished = false;
do {
ExtendedSubunitInfoCmd
extSubunitInfoCmd( m_unit->get1394Service() );
extSubunitInfoCmd.setNodeId( m_unit->getConfigRom().getNodeId() );
extSubunitInfoCmd.setCommandType( AVCCommand::eCT_Status );
extSubunitInfoCmd.setSubunitId( getSubunitId() );
extSubunitInfoCmd.setSubunitType( getSubunitType() );
extSubunitInfoCmd.setVerbose( (int)getDebugLevel() );
extSubunitInfoCmd.m_fbType = fbType;
extSubunitInfoCmd.m_page = page;
cmdSuccess = extSubunitInfoCmd.fire();
if ( cmdSuccess
&& ( extSubunitInfoCmd.getResponse()
== AVCCommand::eR_Implemented ) )
{
for ( ExtendedSubunitInfoPageDataVector::iterator it =
extSubunitInfoCmd.m_infoPageDatas.begin();
cmdSuccess
&& ( it != extSubunitInfoCmd.m_infoPageDatas.end() );
++it )
{
cmdSuccess = createFunctionBlock( fbType, **it );
}
if ( ( extSubunitInfoCmd.m_infoPageDatas.size() != 0 )
&& ( extSubunitInfoCmd.m_infoPageDatas.size() == 5 ) )
{
page++;
} else {
finished = true;
}
} else {
finished = true;
}
} while ( cmdSuccess && !finished );
return cmdSuccess;
}
bool
BeBoB::SubunitAudio::createFunctionBlock(
ExtendedSubunitInfoCmd::EFunctionBlockType fbType,
ExtendedSubunitInfoPageData& data )
{
FunctionBlock::ESpecialPurpose purpose
= convertSpecialPurpose( data.m_functionBlockSpecialPupose );
FunctionBlock* fb = 0;
switch ( fbType ) {
case ExtendedSubunitInfoCmd::eFBT_AudioSubunitSelector:
{
fb = new FunctionBlockSelector( *this,
data.m_functionBlockId,
purpose,
data.m_noOfInputPlugs,
data.m_noOfOutputPlugs,
(int)getDebugLevel() );
}
break;
case ExtendedSubunitInfoCmd::eFBT_AudioSubunitFeature:
{
fb = new FunctionBlockFeature( *this,
data.m_functionBlockId,
purpose,
data.m_noOfInputPlugs,
data.m_noOfOutputPlugs,
(int)getDebugLevel() );
}
break;
case ExtendedSubunitInfoCmd::eFBT_AudioSubunitProcessing:
{
switch ( data.m_functionBlockType ) {
case ExtendedSubunitInfoCmd::ePT_EnhancedMixer:
{
fb = new FunctionBlockEnhancedMixer( *this,
data.m_functionBlockId,
purpose,
data.m_noOfInputPlugs,
data.m_noOfOutputPlugs,
(int)getDebugLevel() );
}
break;
case ExtendedSubunitInfoCmd::ePT_Mixer:
case ExtendedSubunitInfoCmd::ePT_Generic:
case ExtendedSubunitInfoCmd::ePT_UpDown:
case ExtendedSubunitInfoCmd::ePT_DolbyProLogic:
case ExtendedSubunitInfoCmd::ePT_3DStereoExtender:
case ExtendedSubunitInfoCmd::ePT_Reverberation:
case ExtendedSubunitInfoCmd::ePT_Chorus:
case ExtendedSubunitInfoCmd::ePT_DynamicRangeCompression:
default:
/* It is no use to add a dummy FunctionBlockProcessing because
then the function type is not set in FunctionBlockProcessing.
When we try to discover the plugs attached to this function block
it will fail. It's better just to skip them. */
debugOutput( DEBUG_LEVEL_NORMAL, "Found a processing subfunction (type %d) which is not supported. "
"It will be ignored.\n",
data.m_functionBlockType);
return true;
}
}
break;
case ExtendedSubunitInfoCmd::eFBT_AudioSubunitCodec:
{
/* It is no use to add a dummy FunctionBlockProcessing because
then the function type is not set in FunctionBlockProcessing.
When we try to discover the plugs attached to this function block
it will fail. It's better just to skip them. */
debugOutput( DEBUG_LEVEL_NORMAL, "Found a codec subfunction (type %d) which is not supported. "
"It will be ignored.\n",
data.m_functionBlockType);
return true;
}
break;
default:
debugError( "Unhandled function block type found\n" );
return false;
}
if ( !fb ) {
debugError( "Could create function block\n" );
return false;
}
if ( !fb->discover() ) {
debugError( "Could not discover function block %s\n",
fb->getName() );
delete fb;
return false;
}
m_functions.push_back( fb );
return true;
}
BeBoB::FunctionBlock::ESpecialPurpose
BeBoB::SubunitAudio::convertSpecialPurpose(
function_block_special_purpose_t specialPurpose )
{
FunctionBlock::ESpecialPurpose p;
switch ( specialPurpose ) {
case ExtendedSubunitInfoPageData::eSP_InputGain:
p = FunctionBlock::eSP_InputGain;
break;
case ExtendedSubunitInfoPageData::eSP_OutputVolume:
p = FunctionBlock::eSP_OutputVolume;
break;
default:
p = FunctionBlock::eSP_NoSpecialPurpose;
}
return p;
}
bool
BeBoB::SubunitAudio::serializeChild( std::string basePath,
Util::IOSerialize& ser ) const
{
bool result = true;
int i = 0;
for ( FunctionBlockVector::const_iterator it = m_functions.begin();
it != m_functions.end();
++it )
{
FunctionBlock* pFB = *it;
std::ostringstream strstrm;
strstrm << basePath << "FunctionBlock" << i << "/";
result &= pFB->serialize( strstrm.str() , ser );
i++;
}
return result;
}
bool
BeBoB::SubunitAudio::deserializeChild( std::string basePath,
Util::IODeserialize& deser,
AVC::Unit& avDevice )
{
int i = 0;
bool bFinished = false;
do {
std::ostringstream strstrm;
strstrm << basePath << "FunctionBlock" << i << "/";
FunctionBlock* pFB = FunctionBlock::deserialize( strstrm.str(),
deser,
avDevice,
*this );
if ( pFB ) {
m_functions.push_back( pFB );
i++;
} else {
bFinished = true;
}
} while ( !bFinished );
return true;
}
bool
BeBoB::SubunitAudio::deserializeUpdateChild( std::string basePath,
Util::IODeserialize& deser )
{
bool result = true;
int i = 0;
for ( FunctionBlockVector::iterator it = m_functions.begin();
it != m_functions.end();
++it )
{
std::ostringstream strstrm;
strstrm << basePath << "FunctionBlock" << i << "/";
result &= (*it)->deserializeUpdate( basePath, deser );
i++;
}
return result;
}
////////////////////////////////////////////
BeBoB::SubunitMusic::SubunitMusic( AVC::Unit& avDevice,
subunit_t id )
: AVC::SubunitMusic( avDevice, id )
{
}
BeBoB::SubunitMusic::SubunitMusic()
: AVC::SubunitMusic()
{
}
BeBoB::SubunitMusic::~SubunitMusic()
{
}
AVC::Plug *
BeBoB::SubunitMusic::createPlug( AVC::Unit* unit,
AVC::Subunit* subunit,
AVC::function_block_type_t functionBlockType,
AVC::function_block_type_t functionBlockId,
AVC::Plug::EPlugAddressType plugAddressType,
AVC::Plug::EPlugDirection plugDirection,
AVC::plug_id_t plugId )
{
return new BeBoB::Plug( unit,
subunit,
functionBlockType,
functionBlockId,
plugAddressType,
plugDirection,
plugId );
}
bool
BeBoB::SubunitMusic::discover()
{
debugOutput(DEBUG_LEVEL_NORMAL, "Discovering %s...\n", getName());
// discover the AV/C generic part
if ( !AVC::SubunitMusic::discover() ) {
return false;
}
// do the remaining BeBoB music subunit discovery
// which is nothing
return true;
}
const char*
BeBoB::SubunitMusic::getName()
{
return "BeBoB::MusicSubunit";
}
bool
BeBoB::SubunitMusic::serializeChild( std::string basePath,
Util::IOSerialize& ser ) const
{
return true;
}
bool
BeBoB::SubunitMusic::deserializeChild( std::string basePath,
Util::IODeserialize& deser,
AVC::Unit& avDevice )
{
return true;
}
bool
BeBoB::SubunitMusic::deserializeUpdateChild( std::string basePath,
Util::IODeserialize& deser )
{
return true;
}
libffado-2.4.5/src/bebob/bebob_avdevice_subunit.h 0000644 0001750 0000144 00000010407 14206145246 021367 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Daniel Wagner
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef BEBOB_AVDEVICESUBUNIT_H
#define BEBOB_AVDEVICESUBUNIT_H
#include "bebob/bebob_avplug.h"
#include "bebob/bebob_functionblock.h"
#include "debugmodule/debugmodule.h"
#include "libavc/general/avc_extended_subunit_info.h"
#include "libavc/avc_definitions.h"
#include "libavc/general/avc_generic.h"
#include
#include "libavc/general/avc_subunit.h"
#include "libavc/musicsubunit/avc_musicsubunit.h"
#include "libavc/audiosubunit/avc_audiosubunit.h"
#include "libavc/general/avc_plug.h"
namespace BeBoB {
/////////////////////////////
class SubunitAudio : public AVC::SubunitAudio
{
public:
SubunitAudio( AVC::Unit& avDevice,
AVC::subunit_t id );
SubunitAudio();
virtual ~SubunitAudio();
virtual bool discover();
virtual bool discoverConnections();
virtual AVC::Plug *createPlug( AVC::Unit* unit,
AVC::Subunit* subunit,
AVC::function_block_type_t functionBlockType,
AVC::function_block_type_t functionBlockId,
AVC::Plug::EPlugAddressType plugAddressType,
AVC::Plug::EPlugDirection plugDirection,
AVC::plug_id_t plugId );
virtual const char* getName();
virtual FunctionBlockVector getFunctionBlocks() { return m_functions; };
protected:
bool discoverFunctionBlocks();
bool discoverFunctionBlocksDo(
AVC::ExtendedSubunitInfoCmd::EFunctionBlockType fbType );
bool createFunctionBlock(
AVC::ExtendedSubunitInfoCmd::EFunctionBlockType fbType,
AVC::ExtendedSubunitInfoPageData& data );
FunctionBlock::ESpecialPurpose convertSpecialPurpose(
AVC::function_block_special_purpose_t specialPurpose );
virtual bool serializeChild( std::string basePath,
Util::IOSerialize& ser ) const;
virtual bool deserializeChild( std::string basePath,
Util::IODeserialize& deser,
AVC::Unit& unit );
virtual bool deserializeUpdateChild( std::string basePath,
Util::IODeserialize& deser );
protected:
FunctionBlockVector m_functions;
};
/////////////////////////////
class SubunitMusic : public AVC::SubunitMusic
{
public:
SubunitMusic( AVC::Unit& avDevice,
AVC::subunit_t id );
SubunitMusic();
virtual ~SubunitMusic();
virtual bool discover();
virtual AVC::Plug *createPlug( AVC::Unit* unit,
AVC::Subunit* subunit,
AVC::function_block_type_t functionBlockType,
AVC::function_block_type_t functionBlockId,
AVC::Plug::EPlugAddressType plugAddressType,
AVC::Plug::EPlugDirection plugDirection,
AVC::plug_id_t plugId );
virtual const char* getName();
protected:
virtual bool serializeChild( std::string basePath,
Util::IOSerialize& ser ) const;
virtual bool deserializeChild( std::string basePath,
Util::IODeserialize& deser,
AVC::Unit& unit );
virtual bool deserializeUpdateChild( std::string basePath,
Util::IODeserialize& deser );
};
}
#endif
libffado-2.4.5/src/bebob/bebob_avplug.cpp 0000644 0001750 0000144 00000055507 14206145246 017673 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Daniel Wagner
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "bebob/bebob_avplug.h"
#include "bebob/bebob_avdevice.h"
#include "libieee1394/configrom.h"
#include "libieee1394/ieee1394service.h"
#include "libutil/cmd_serialize.h"
#include
using namespace AVC;
namespace BeBoB {
Plug::Plug( AVC::Unit* unit,
AVC::Subunit* subunit,
AVC::function_block_type_t functionBlockType,
AVC::function_block_type_t functionBlockId,
AVC::Plug::EPlugAddressType plugAddressType,
AVC::Plug::EPlugDirection plugDirection,
AVC::plug_id_t plugId )
: AVC::Plug( unit,
subunit,
functionBlockType,
functionBlockId,
plugAddressType,
plugDirection,
plugId )
{
debugOutput( DEBUG_LEVEL_VERBOSE,
"nodeId = %d, subunitType = %d, "
"subunitId = %d, functionBlockType = %d, "
"functionBlockId = %d, addressType = %d, "
"direction = %d, id = %d\n",
unit->getConfigRom().getNodeId(),
getSubunitType(),
getSubunitId(),
functionBlockType,
functionBlockId,
plugAddressType,
plugDirection,
plugId );
}
Plug::Plug( AVC::Unit* unit,
AVC::Subunit* subunit,
AVC::function_block_type_t functionBlockType,
AVC::function_block_type_t functionBlockId,
AVC::Plug::EPlugAddressType plugAddressType,
AVC::Plug::EPlugDirection plugDirection,
AVC::plug_id_t plugId,
int globalId )
: AVC::Plug( unit,
subunit,
functionBlockType,
functionBlockId,
plugAddressType,
plugDirection,
plugId,
globalId )
{
debugOutput( DEBUG_LEVEL_VERBOSE,
"nodeId = %d, subunitType = %d, "
"subunitId = %d, functionBlockType = %d, "
"functionBlockId = %d, addressType = %d, "
"direction = %d, id = %d\n",
unit->getConfigRom().getNodeId(),
getSubunitType(),
getSubunitId(),
functionBlockType,
functionBlockId,
plugAddressType,
plugDirection,
plugId );
}
Plug::Plug( const Plug& rhs )
: AVC::Plug( rhs )
{
}
Plug::Plug()
: AVC::Plug()
{
}
Plug::~Plug()
{
}
bool
Plug::discover()
{
if ( !discoverPlugType() ) {
debugError( "discover: Could not discover plug type (%d,%d,%d,%d,%d)\n",
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
return false;
}
if ( !discoverName() ) {
debugError( "Could not discover name (%d,%d,%d,%d,%d)\n",
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
return false;
}
if ( !discoverNoOfChannels() ) {
debugError( "Could not discover number of channels "
"(%d,%d,%d,%d,%d)\n",
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
return false;
}
if ( !discoverChannelPosition() ) {
debugError( "Could not discover channel positions "
"(%d,%d,%d,%d,%d)\n",
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
return false;
}
if ( !discoverChannelName() ) {
debugError( "Could not discover channel name "
"(%d,%d,%d,%d,%d)\n",
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
return false;
}
if ( !discoverClusterInfo() ) {
debugError( "Could not discover channel name "
"(%d,%d,%d,%d,%d)\n",
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
return false;
}
if ( !discoverStreamFormat() ) {
debugError( "Could not discover stream format "
"(%d,%d,%d,%d,%d)\n",
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
return false;
}
if ( !discoverSupportedStreamFormats() ) {
debugError( "Could not discover supported stream formats "
"(%d,%d,%d,%d,%d)\n",
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
return false;
}
return m_unit->getPlugManager().addPlug( *this );
}
bool
Plug::discoverConnections()
{
return discoverConnectionsInput() && discoverConnectionsOutput();
}
bool
Plug::discoverPlugType()
{
ExtendedPlugInfoCmd extPlugInfoCmd = setPlugAddrToPlugInfoCmd();
ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
ExtendedPlugInfoInfoType::eIT_PlugType );
extendedPlugInfoInfoType.initialize();
extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
extPlugInfoCmd.setVerbose( getDebugLevel() );
if ( !extPlugInfoCmd.fire() ) {
debugError( "plug type command failed\n" );
return false;
}
m_infoPlugType = eAPT_Unknown;
if ( extPlugInfoCmd.getResponse() == AVCCommand::eR_Implemented ) {
ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
if ( infoType
&& infoType->m_plugType )
{
plug_type_t plugType = infoType->m_plugType->m_plugType;
debugOutput( DEBUG_LEVEL_VERBOSE,
"plug %d is of type %d (%s)\n",
m_id,
plugType,
extendedPlugInfoPlugTypeToString( plugType ) );
switch ( plugType ) {
case ExtendedPlugInfoPlugTypeSpecificData::eEPIPT_IsoStream:
m_infoPlugType = eAPT_IsoStream;
break;
case ExtendedPlugInfoPlugTypeSpecificData::eEPIPT_AsyncStream:
m_infoPlugType = eAPT_AsyncStream;
break;
case ExtendedPlugInfoPlugTypeSpecificData::eEPIPT_Midi:
m_infoPlugType = eAPT_Midi;
break;
case ExtendedPlugInfoPlugTypeSpecificData::eEPIPT_Sync:
m_infoPlugType = eAPT_Sync;
break;
case ExtendedPlugInfoPlugTypeSpecificData::eEPIPT_Analog:
m_infoPlugType = eAPT_Analog;
break;
case ExtendedPlugInfoPlugTypeSpecificData::eEPIPT_Digital:
m_infoPlugType = eAPT_Digital;
break;
default:
m_infoPlugType = eAPT_Unknown;
}
}
} else {
debugError( "Plug does not implement extended plug info plug "
"type info command\n" );
return false;
}
return true;
}
bool
Plug::discoverName()
{
ExtendedPlugInfoCmd extPlugInfoCmd = setPlugAddrToPlugInfoCmd();
ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
ExtendedPlugInfoInfoType::eIT_PlugName );
extendedPlugInfoInfoType.initialize();
extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
extPlugInfoCmd.setVerbose( getDebugLevel() );
if ( !extPlugInfoCmd.fire() ) {
debugError( "name command failed\n" );
return false;
}
ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
if ( infoType
&& infoType->m_plugName )
{
std::string name =
infoType->m_plugName->m_name;
debugOutput( DEBUG_LEVEL_VERBOSE,
"plug %d has name '%s'\n",
m_id,
name.c_str() );
m_name = name;
}
return true;
}
bool
Plug::discoverNoOfChannels()
{
ExtendedPlugInfoCmd extPlugInfoCmd = setPlugAddrToPlugInfoCmd();
//extPlugInfoCmd.setVerbose( true );
ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
ExtendedPlugInfoInfoType::eIT_NoOfChannels );
extendedPlugInfoInfoType.initialize();
extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
extPlugInfoCmd.setVerbose( getDebugLevel() );
if ( !extPlugInfoCmd.fire() ) {
debugError( "number of channels command failed\n" );
return false;
}
ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
if ( infoType
&& infoType->m_plugNrOfChns )
{
nr_of_channels_t nrOfChannels
= infoType->m_plugNrOfChns->m_nrOfChannels;
debugOutput( DEBUG_LEVEL_VERBOSE,
"plug %d has %d channels\n",
m_id,
nrOfChannels );
m_nrOfChannels = nrOfChannels;
}
return true;
}
bool
Plug::discoverChannelPosition()
{
ExtendedPlugInfoCmd extPlugInfoCmd = setPlugAddrToPlugInfoCmd();
ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
ExtendedPlugInfoInfoType::eIT_ChannelPosition );
extendedPlugInfoInfoType.initialize();
extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
extPlugInfoCmd.setVerbose( getDebugLevel() );
if ( !extPlugInfoCmd.fire() ) {
debugError( "channel position command failed\n" );
return false;
}
ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
if ( infoType
&& infoType->m_plugChannelPosition )
{
if ( !copyClusterInfo( *( infoType->m_plugChannelPosition ) ) ) {
debugError( "Could not copy channel position "
"information\n" );
return false;
}
debugOutput( DEBUG_LEVEL_VERBOSE,
"plug %d: channel position information "
"retrieved\n",
m_id );
debugOutputClusterInfos( DEBUG_LEVEL_VERBOSE );
}
return true;
}
bool
Plug::copyClusterInfo(ExtendedPlugInfoPlugChannelPositionSpecificData&
channelPositionData )
{
int index = 1;
for ( ExtendedPlugInfoPlugChannelPositionSpecificData::ClusterInfoVector::const_iterator it
= channelPositionData.m_clusterInfos.begin();
it != channelPositionData.m_clusterInfos.end();
++it )
{
const ExtendedPlugInfoPlugChannelPositionSpecificData::ClusterInfo*
extPlugSpClusterInfo = &( *it );
ClusterInfo clusterInfo;
clusterInfo.m_nrOfChannels = extPlugSpClusterInfo->m_nrOfChannels;
clusterInfo.m_index = index;
index++;
for ( ExtendedPlugInfoPlugChannelPositionSpecificData::ChannelInfoVector::const_iterator cit
= extPlugSpClusterInfo->m_channelInfos.begin();
cit != extPlugSpClusterInfo->m_channelInfos.end();
++cit )
{
const ExtendedPlugInfoPlugChannelPositionSpecificData::ChannelInfo*
extPlugSpChannelInfo = &( *cit );
ChannelInfo channelInfo;
channelInfo.m_streamPosition =
extPlugSpChannelInfo->m_streamPosition-1;
// FIXME: this can only become a mess with the two meanings
// of the location parameter. the audio style meaning
// starts from 1, the midi style meaning from 0
// lucky for us we recalculate this for the midi channels
// and don't use this value.
channelInfo.m_location =
extPlugSpChannelInfo->m_location;
clusterInfo.m_channelInfos.push_back( channelInfo );
}
m_clusterInfos.push_back( clusterInfo );
}
return true;
}
bool
Plug::discoverChannelName()
{
for ( ClusterInfoVector::iterator clit = m_clusterInfos.begin();
clit != m_clusterInfos.end();
++clit )
{
ClusterInfo* clitInfo = &*clit;
for ( ChannelInfoVector::iterator pit = clitInfo->m_channelInfos.begin();
pit != clitInfo->m_channelInfos.end();
++pit )
{
ChannelInfo* channelInfo = &*pit;
ExtendedPlugInfoCmd extPlugInfoCmd = setPlugAddrToPlugInfoCmd();
ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
ExtendedPlugInfoInfoType::eIT_ChannelName );
extendedPlugInfoInfoType.initialize();
extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
extPlugInfoCmd.setVerbose( getDebugLevel() );
ExtendedPlugInfoInfoType* infoType =
extPlugInfoCmd.getInfoType();
if ( infoType ) {
infoType->m_plugChannelName->m_streamPosition =
channelInfo->m_streamPosition + 1;
}
if ( !extPlugInfoCmd.fire() ) {
debugError( "channel name command failed\n" );
return false;
}
infoType = extPlugInfoCmd.getInfoType();
if ( infoType
&& infoType->m_plugChannelName )
{
debugOutput( DEBUG_LEVEL_VERBOSE,
"plug %d stream "
"position %d: channel name = %s\n",
m_id,
channelInfo->m_streamPosition,
infoType->m_plugChannelName->m_plugChannelName.c_str() );
channelInfo->m_name =
infoType->m_plugChannelName->m_plugChannelName;
}
}
}
return true;
}
bool
Plug::discoverClusterInfo()
{
if ( m_infoPlugType == eAPT_Sync )
{
// If the plug is of type sync it is either a normal 2 channel
// stream (not compound stream) or it is a compound stream
// with exactly one cluster. This depends on the
// extended stream format command version which is used.
// We are not interested in this plug so we skip it.
debugOutput( DEBUG_LEVEL_VERBOSE,
"%s plug %d is of type sync -> skip\n",
getName(),
m_id );
return true;
}
for ( ClusterInfoVector::iterator clit = m_clusterInfos.begin();
clit != m_clusterInfos.end();
++clit )
{
ClusterInfo* clusterInfo = &*clit;
ExtendedPlugInfoCmd extPlugInfoCmd = setPlugAddrToPlugInfoCmd();
ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
ExtendedPlugInfoInfoType::eIT_ClusterInfo );
extendedPlugInfoInfoType.initialize();
extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
extPlugInfoCmd.setVerbose( getDebugLevel() );
extPlugInfoCmd.getInfoType()->m_plugClusterInfo->m_clusterIndex =
clusterInfo->m_index;
if ( !extPlugInfoCmd.fire() ) {
debugError( "cluster info command failed\n" );
return false;
}
ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
if ( infoType
&& infoType->m_plugClusterInfo )
{
debugOutput( DEBUG_LEVEL_VERBOSE,
"%s plug %d: cluster index = %d, "
"portType %s, cluster name = %s\n",
getName(),
m_id,
infoType->m_plugClusterInfo->m_clusterIndex,
extendedPlugInfoClusterInfoPortTypeToString(
infoType->m_plugClusterInfo->m_portType ),
infoType->m_plugClusterInfo->m_clusterName.c_str() );
clusterInfo->m_portType = infoType->m_plugClusterInfo->m_portType;
clusterInfo->m_name = infoType->m_plugClusterInfo->m_clusterName;
}
}
return true;
}
bool
Plug::discoverConnectionsInput()
{
ExtendedPlugInfoCmd extPlugInfoCmd = setPlugAddrToPlugInfoCmd();
ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
ExtendedPlugInfoInfoType::eIT_PlugInput );
extendedPlugInfoInfoType.initialize();
extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
extPlugInfoCmd.setVerbose( getDebugLevel() );
if ( !extPlugInfoCmd.fire() ) {
debugError( "plug type command failed\n" );
return false;
}
if ( extPlugInfoCmd.getResponse() == AVCCommand::eR_Rejected ) {
// Plugs does not like to be asked about connections
debugOutput( DEBUG_LEVEL_VERBOSE, "Plug '%s' rejects "
"connections command\n",
getName() );
return true;
}
ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
if ( infoType
&& infoType->m_plugInput )
{
PlugAddressSpecificData* plugAddress
= infoType->m_plugInput->m_plugAddress;
if ( plugAddress->m_addressMode ==
PlugAddressSpecificData::ePAM_Undefined )
{
// This plug has no input connection
return true;
}
if ( !discoverConnectionsFromSpecificData( eAPD_Input,
plugAddress,
m_inputConnections ) )
{
debugWarning( "Could not discover connections for plug '%s'\n",
getName() );
}
} else {
debugError( "no valid info type for plug '%s'\n", getName() );
return false;
}
return true;
}
bool
Plug::discoverConnectionsOutput()
{
ExtendedPlugInfoCmd extPlugInfoCmd = setPlugAddrToPlugInfoCmd();
ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
ExtendedPlugInfoInfoType::eIT_PlugOutput );
extendedPlugInfoInfoType.initialize();
extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
extPlugInfoCmd.setVerbose( getDebugLevel() );
if ( !extPlugInfoCmd.fire() ) {
debugError( "plug type command failed\n" );
return false;
}
if ( extPlugInfoCmd.getResponse() == AVCCommand::eR_Rejected ) {
// Plugs does not like to be asked about connections
debugOutput( DEBUG_LEVEL_VERBOSE, "Plug '%s' rejects "
"connections command\n",
getName() );
return true;
}
ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
if ( infoType
&& infoType->m_plugOutput )
{
if ( infoType->m_plugOutput->m_nrOfOutputPlugs
!= infoType->m_plugOutput->m_outputPlugAddresses.size() )
{
debugError( "number of output plugs (%d) disagree with "
"number of elements in plug address vector (%zd)\n",
infoType->m_plugOutput->m_nrOfOutputPlugs,
infoType->m_plugOutput->m_outputPlugAddresses.size());
}
if ( infoType->m_plugOutput->m_nrOfOutputPlugs == 0 ) {
// This plug has no output connections
return true;
}
for ( unsigned int i = 0;
i < infoType->m_plugOutput->m_outputPlugAddresses.size();
++i )
{
PlugAddressSpecificData* plugAddress
= infoType->m_plugOutput->m_outputPlugAddresses[i];
if ( !discoverConnectionsFromSpecificData( eAPD_Output,
plugAddress,
m_outputConnections ) )
{
debugWarning( "Could not discover connections for "
"plug '%s'\n", getName() );
}
}
} else {
debugError( "no valid info type for plug '%s'\n", getName() );
return false;
}
return true;
}
ExtendedPlugInfoCmd
Plug::setPlugAddrToPlugInfoCmd()
{
ExtendedPlugInfoCmd extPlugInfoCmd( m_unit->get1394Service() );
switch( getSubunitType() ) {
case eST_Unit:
{
UnitPlugAddress::EPlugType ePlugType =
UnitPlugAddress::ePT_Unknown;
switch ( m_addressType ) {
case eAPA_PCR:
ePlugType = UnitPlugAddress::ePT_PCR;
break;
case eAPA_ExternalPlug:
ePlugType = UnitPlugAddress::ePT_ExternalPlug;
break;
case eAPA_AsynchronousPlug:
ePlugType = UnitPlugAddress::ePT_AsynchronousPlug;
break;
default:
ePlugType = UnitPlugAddress::ePT_Unknown;
}
UnitPlugAddress unitPlugAddress( ePlugType,
m_id );
extPlugInfoCmd.setPlugAddress(
PlugAddress( convertPlugDirection( getPlugDirection() ),
PlugAddress::ePAM_Unit,
unitPlugAddress ) );
}
break;
case eST_Music:
case eST_Audio:
{
switch( m_addressType ) {
case eAPA_SubunitPlug:
{
SubunitPlugAddress subunitPlugAddress( m_id );
extPlugInfoCmd.setPlugAddress(
PlugAddress(
convertPlugDirection( getPlugDirection() ),
PlugAddress::ePAM_Subunit,
subunitPlugAddress ) );
}
break;
case eAPA_FunctionBlockPlug:
{
FunctionBlockPlugAddress functionBlockPlugAddress(
m_functionBlockType,
m_functionBlockId,
m_id );
extPlugInfoCmd.setPlugAddress(
PlugAddress(
convertPlugDirection( getPlugDirection() ),
PlugAddress::ePAM_FunctionBlock,
functionBlockPlugAddress ) );
}
break;
default:
extPlugInfoCmd.setPlugAddress(PlugAddress());
}
}
break;
default:
debugError( "Unknown subunit type\n" );
}
extPlugInfoCmd.setNodeId( m_unit->getConfigRom().getNodeId() );
extPlugInfoCmd.setCommandType( AVCCommand::eCT_Status );
extPlugInfoCmd.setSubunitId( getSubunitId() );
extPlugInfoCmd.setSubunitType( getSubunitType() );
return extPlugInfoCmd;
}
}
libffado-2.4.5/src/bebob/bebob_avplug.h 0000644 0001750 0000144 00000005252 14206145246 017330 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Daniel Wagner
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef BEBOB_AVPLUG_H
#define BEBOB_AVPLUG_H
#include "libavc/ccm/avc_signal_source.h"
#include "libavc/streamformat/avc_extended_stream_format.h"
#include "libavc/general/avc_extended_plug_info.h"
#include "libavc/general/avc_extended_cmd_generic.h"
#include "libavc/avc_definitions.h"
#include "libavc/general/avc_generic.h"
#include "libavc/general/avc_plug.h"
#include "libutil/serialize.h"
#include "debugmodule/debugmodule.h"
class Ieee1394Service;
class ConfigRom;
namespace BeBoB {
class AvDevice;
class Plug : public AVC::Plug {
public:
// \todo This constructors sucks. too many parameters. fix it.
Plug( AVC::Unit* unit,
AVC::Subunit* subunit,
AVC::function_block_type_t functionBlockType,
AVC::function_block_type_t functionBlockId,
AVC::Plug::EPlugAddressType plugAddressType,
AVC::Plug::EPlugDirection plugDirection,
AVC::plug_id_t plugId );
Plug( AVC::Unit* unit,
AVC::Subunit* subunit,
AVC::function_block_type_t functionBlockType,
AVC::function_block_type_t functionBlockId,
AVC::Plug::EPlugAddressType plugAddressType,
AVC::Plug::EPlugDirection plugDirection,
AVC::plug_id_t plugId,
int globalId );
Plug( const Plug& rhs );
virtual ~Plug();
bool discover();
bool discoverConnections();
public:
protected:
Plug();
bool discoverPlugType();
bool discoverName();
bool discoverNoOfChannels();
bool discoverChannelPosition();
bool discoverChannelName();
bool discoverClusterInfo();
bool discoverConnectionsInput();
bool discoverConnectionsOutput();
private:
bool copyClusterInfo(AVC::ExtendedPlugInfoPlugChannelPositionSpecificData&
channelPositionData );
AVC::ExtendedPlugInfoCmd setPlugAddrToPlugInfoCmd();
};
}
#endif // BEBOB_AVPLUG_H
libffado-2.4.5/src/bebob/bebob_dl_bcd.cpp 0000644 0001750 0000144 00000023021 14206145246 017566 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Daniel Wagner
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "bebob_dl_bcd.h"
#include
namespace BeBoB {
enum {
BCDMagic = 0x446f4362,
};
// XXX not very nice tool box function?
std::string makeString( fb_octlet_t v )
{
std::string s;
for ( unsigned int i=0; i ( &v )[i];
}
return s;
}
std::string makeDate( fb_octlet_t v )
{
std::string s;
char* vc = reinterpret_cast ( &v );
s += vc[6];
s += vc[7];
s += '.';
s += vc[4];
s += vc[5];
s += '.';
s += vc[0];
s += vc[1];
s += vc[2];
s += vc[3];
return s;
}
std::string makeTime( fb_octlet_t v )
{
std::string s;
char* vc = reinterpret_cast( &v );
s += vc[0];
s += vc[1];
s += ':';
s += vc[2];
s += vc[3];
s += ':';
s += vc[4];
s += vc[5];
s += vc[6];
s += vc[7];
return s;
}
enum {
BCDFileVersionOffset = 0x28,
V0HeaderCRCOffset = 0x2c,
V0HeaderSize = 0x60,
V1HeaderCRC0ffset = 0x2c,
V1HeaderSize = 0x70,
};
IMPL_DEBUG_MODULE( BCD, BCD, DEBUG_LEVEL_NORMAL );
};
BeBoB::BCD::BCD( std::string filename )
: m_file( 0 )
, m_filename( filename )
, m_bcd_version( -1 )
, m_softwareDate( 0 )
, m_softwareTime( 0 )
, m_softwareId( 0 )
, m_softwareVersion( 0 )
, m_hardwareId( 0 )
, m_vendorOUI( 0 )
, m_imageBaseAddress( 0 )
, m_imageLength( 0 )
, m_imageOffset( 0 )
, m_imageCRC( 0 )
, m_cneLength( 0 )
, m_cneOffset( 0 )
, m_cneCRC( 0 )
{
initCRC32Table();
}
BeBoB::BCD::~BCD()
{
if ( m_file ) {
fclose( m_file );
}
}
bool
BeBoB::BCD::parse()
{
using namespace std;
m_file = fopen( m_filename.c_str(), "r" );
if ( !m_file ) {
debugError( "parse: Could not open file '%s'\n",
m_filename.c_str() );
return false;
}
fb_quadlet_t identifier;
size_t bytes_read = fread( &identifier, 1, sizeof( identifier ), m_file );
if ( bytes_read != sizeof( identifier ) ) {
debugError( "parse: 4 bytes read failed at position 0\n" );
return false;
}
if ( identifier != BCDMagic ) {
debugError( "parse: File has not BCD header magic, 0x%08x expected, "
"0x%08x found\n", BCDMagic, identifier );
return false;
}
if ( fseek( m_file, BCDFileVersionOffset, SEEK_SET ) == -1 ) {
debugError( "parse: fseek failed\n" );
return false;
}
bytes_read = fread( &m_bcd_version, 1, sizeof( fb_quadlet_t ), m_file );
if ( bytes_read != sizeof( fb_quadlet_t ) ) {
debugError( "parse: %zd bytes read at position %d failed\n",
sizeof( fb_quadlet_t ),
BCDFileVersionOffset );
return false;
}
unsigned int headerSize = 0;
unsigned int crcOffset = 0;
switch( m_bcd_version ) {
case 0:
headerSize = V0HeaderSize;
crcOffset = V0HeaderCRCOffset;
break;
case 1:
headerSize = V1HeaderSize;
crcOffset = V1HeaderCRC0ffset;
break;
default:
debugError( "parse: Unknown BCD file version %d found\n",
m_bcd_version );
return false;
}
if ( !checkHeaderCRC( crcOffset, headerSize ) ) {
debugError( "parse: Header CRC check failed\n" );
return false;
}
if ( !readHeaderInfo() ) {
debugError( "parse: Could not read all header info\n" );
return false;
}
return true;
}
bool
BeBoB::BCD::readHeaderInfo()
{
if ( !read( 0x08, &m_softwareDate ) ) {
return false;
}
if ( !read( 0x10, &m_softwareTime ) ) {
return false;
}
if ( !read( 0x18, &m_softwareId ) ) {
return false;
}
if ( !read( 0x1c, &m_softwareVersion ) ) {
return false;
}
if ( !read( 0x20, &m_hardwareId ) ) {
return false;
}
if ( !read( 0x24, &m_vendorOUI ) ) {
return false;
}
if ( !read( 0x30, &m_imageOffset ) ) {
return false;
}
if ( !read( 0x34, &m_imageBaseAddress ) ) {
return false;
}
if ( !read( 0x38, &m_imageLength ) ) {
return false;
}
if ( !read( 0x3c, &m_imageCRC ) ) {
return false;
}
if ( !read( 0x50, &m_cneOffset ) ) {
return false;
}
if ( !read( 0x58, &m_cneLength ) ) {
return false;
}
if ( !read( 0x5c, &m_cneCRC ) ) {
return false;
}
return true;
}
bool
BeBoB::BCD::read( int addr, fb_quadlet_t* q )
{
if ( std::fseek( m_file, addr, SEEK_SET ) == -1 ) {
debugError( "read: seek to position 0x%08x failed\n", addr );
return false;
}
size_t bytes_read = std::fread( q, 1, sizeof( *q ), m_file );
if ( bytes_read != sizeof( *q ) ) {
debugError( "read: %zd byte read failed at position 0x%08x\n",
sizeof( *q ), addr );
return false;
}
return true;
}
bool
BeBoB::BCD::read( int addr, fb_octlet_t* o )
{
if ( std::fseek( m_file, addr, SEEK_SET ) == -1 ) {
debugError( "read: seek to position 0x%08x failed\n", addr );
return false;
}
size_t bytes_read = std::fread( o, 1, sizeof( *o ), m_file );
if ( bytes_read != sizeof( *o ) ) {
debugError( "read: %zd byte read failed at position 0x%08x\n",
sizeof( *o ), addr );
return false;
}
return true;
}
bool
BeBoB::BCD::read( int addr, unsigned char* b, size_t len )
{
if ( std::fseek( m_file, addr, SEEK_SET ) == -1 ) {
debugError( "read: seek to position 0x%08x failed\n", addr );
return false;
}
size_t bytes_read = std::fread( b, 1, len, m_file );
if ( bytes_read != len ) {
debugError( "read: %zd byte read failed at position 0x%08x\n",
len, addr );
return false;
}
return true;
}
void
BeBoB::BCD::initCRC32Table()
{
unsigned long polynomial = 0x04c11db7;
for ( int i = 0; i <= 0xff; ++i ) {
crc32_table[i] = reflect( i, 8 ) << 24;
for ( int j = 0; j < 8; ++j ) {
crc32_table[i] =
(crc32_table[i] << 1)
^ (crc32_table[i] & (1 << 31) ? polynomial : 0);
}
crc32_table[i] = reflect( crc32_table[i], 32 );
}
}
unsigned long
BeBoB::BCD::reflect( unsigned long ref, char ch )
{
unsigned long value = 0;
for ( int i = 1; i < (ch + 1); ++i ) {
if(ref & 1) {
value |= 1 << (ch - i);
}
ref >>= 1;
}
return value;
}
unsigned int
BeBoB::BCD::getCRC( unsigned char* text, size_t len )
{
unsigned long crc = 0xffffffff;
unsigned char* buffer;
buffer = text;
while ( len-- ) {
crc = (crc >> 8) ^ crc32_table[(crc & 0xff) ^ *buffer++];
}
return crc ^ 0xffffffff;
}
bool
BeBoB::BCD::checkHeaderCRC( unsigned int crcOffset, unsigned int headerSize )
{
fb_quadlet_t headerCRC;
if ( !read( crcOffset, &headerCRC ) ) {
debugError( "checkHeaderCRC: Could not read header CRC\n" );
return false;
}
const int headerLength = headerSize;
unsigned char buf[headerLength];
if ( !read( 0x00, buf, headerLength ) ) {
debugError( "checkHeaderCRC: Could not read complete header from file\n" );
return false;
}
buf[crcOffset+0] = 0x00;
buf[crcOffset+1] = 0x00;
buf[crcOffset+2] = 0x00;
buf[crcOffset+3] = 0x00;
fb_quadlet_t calcCRC = getCRC( buf, headerLength );
if ( headerCRC != calcCRC ) {
debugError( "checkHeaderCRC: CRC check failed, 0x%08x expected, "
"0x%08x calculated\n", headerCRC, calcCRC );
return false;
}
return true;
}
void
BeBoB::BCD::displayInfo()
{
using namespace std;
printf( "BCD Info\n" );
printf( "\tBCD File Version\t%d\n", m_bcd_version );
printf( "\tSoftware Date:\t\t%s, %s\n",
makeDate( m_softwareDate ).c_str(),
makeTime( m_softwareTime ).c_str() );
printf( "\tSoftware Version:\t0x%08x\n", m_softwareVersion );
printf( "\tSoftware Id:\t\t0x%08x\n", m_softwareId );
printf( "\tHardware ID:\t\t0x%08x\n", m_hardwareId );
printf( "\tVendor OUI:\t\t0x%08x\n", m_vendorOUI );
printf( "\tImage Offset:\t\t0x%08x\n", m_imageOffset );
printf( "\tImage Base Address:\t0x%08x\n", m_imageBaseAddress );
printf( "\tImage Length:\t\t0x%08x\n", m_imageLength );
printf( "\tImage CRC:\t\t0x%08x\n", m_imageCRC );
printf( "\tCNE Length:\t\t0x%08x\n", m_cneLength );
printf( "\tCNE Offset:\t\t0x%08x\n", m_cneOffset );
printf( "\tCNE CRC:\t\t0x%08x\n", m_cneCRC );
}
libffado-2.4.5/src/bebob/bebob_dl_bcd.h 0000644 0001750 0000144 00000006463 14206145246 017246 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Daniel Wagner
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef BEBOB_DL_BCD_H
#define BEBOB_DL_BCD_H
#include "fbtypes.h"
#include "debugmodule/debugmodule.h"
#include
#include
namespace BeBoB {
class BCD {
public:
BCD( std::string filename );
~BCD();
bool parse();
fb_octlet_t getSoftwareDate() const
{ return m_softwareDate; }
fb_octlet_t getSoftwareTime() const
{ return m_softwareTime; }
fb_quadlet_t getSoftwareId() const
{ return m_softwareId; }
fb_quadlet_t getSoftwareVersion() const
{ return m_softwareVersion; }
fb_quadlet_t getHardwareId() const
{ return m_hardwareId; }
fb_quadlet_t getVendorOUI() const
{ return m_vendorOUI; }
fb_quadlet_t getImageBaseAddress() const
{ return m_imageBaseAddress; }
fb_quadlet_t getImageOffset() const
{ return m_imageOffset; }
fb_quadlet_t getImageLength() const
{ return m_imageLength; }
fb_quadlet_t getImageCRC() const
{ return m_imageCRC; }
fb_quadlet_t getCnEOffset() const
{ return m_cneOffset; }
fb_quadlet_t getCnELength() const
{ return m_cneLength; }
fb_quadlet_t getCnECRC() const
{ return m_cneCRC; }
bool read( int addr, fb_quadlet_t* q );
bool read( int addr, fb_octlet_t* o );
bool read( int addr, unsigned char* b, size_t len );
void displayInfo();
protected:
unsigned long crc32_table[256];
void initCRC32Table();
unsigned long reflect(unsigned long ref, char ch);
unsigned int getCRC(unsigned char* text, size_t len);
bool checkHeaderCRC( unsigned int crcOffset,
unsigned int headerSize );
bool readHeaderInfo();
protected:
std::FILE* m_file;
std::string m_filename;
fb_quadlet_t m_bcd_version;
fb_octlet_t m_softwareDate;
fb_octlet_t m_softwareTime;
fb_quadlet_t m_softwareId;
fb_quadlet_t m_softwareVersion;
fb_quadlet_t m_hardwareId;
fb_quadlet_t m_vendorOUI;
fb_quadlet_t m_imageBaseAddress;
fb_quadlet_t m_imageLength;
fb_quadlet_t m_imageOffset;
fb_quadlet_t m_imageCRC;
fb_quadlet_t m_cneLength;
fb_quadlet_t m_cneOffset;
fb_quadlet_t m_cneCRC;
DECLARE_DEBUG_MODULE;
};
std::string makeString( fb_octlet_t v );
std::string makeDate( fb_octlet_t v );
std::string makeTime( fb_octlet_t v );
};
#endif
libffado-2.4.5/src/bebob/bebob_dl_codes.cpp 0000644 0001750 0000144 00000022507 14206145246 020143 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Daniel Wagner
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "bebob/bebob_dl_codes.h"
#include "bebob/bebob_dl_bcd.h"
unsigned short BeBoB::CommandCodes::m_gCommandId = 0;
BeBoB::CommandCodes::CommandCodes( fb_quadlet_t protocolVersion,
fb_byte_t commandCode,
size_t msgSize,
fb_byte_t operandSizeRequest,
fb_byte_t operandSizeRespone )
: m_commandId( m_gCommandId++ )
, m_protocolVersion( protocolVersion )
, m_commandCode( commandCode )
, m_msgSize( msgSize )
, m_operandSizeRequest( operandSizeRequest )
, m_operandSizeResponse( operandSizeRespone )
, m_resp_protocolVersion( 0 )
, m_resp_commandId( 0 )
, m_resp_commandCode( 0 )
, m_resp_operandSize( 0 )
{
}
BeBoB::CommandCodes::~CommandCodes()
{
}
bool
BeBoB::CommandCodes::serialize( Util::Cmd::IOSSerialize& se )
{
byte_t tmp;
bool result = se.write( m_protocolVersion, "CommandCodes: protocol version" );
tmp = m_commandId & 0xff;
result &= se.write( tmp, "CommandCodes: command id low" );
tmp = m_commandId >> 8;
result &= se.write( tmp, "CommandCodes: command id high" );
result &= se.write( m_commandCode, "CommandCodes: command code" );
result &= se.write( m_operandSizeRequest, "CommandCodes: request operand size" );
return result;
}
bool
BeBoB::CommandCodes::deserialize( Util::Cmd::IISDeserialize& de )
{
bool result = de.read( &m_resp_protocolVersion );
fb_byte_t tmp;
result &= de.read( &tmp );
m_resp_commandId = tmp;
result &= de.read( &tmp );
m_resp_commandId |= tmp << 8;
result &= de.read( &m_resp_commandCode );
result &= de.read( &m_resp_operandSize );
return result;
}
size_t
BeBoB::CommandCodes::getMaxSize()
{
return 2 * sizeof( fb_quadlet_t ) + m_msgSize;
}
////////////////////////////////
BeBoB::CommandCodesReset::CommandCodesReset( fb_quadlet_t protocolVersion,
EStartMode startMode )
: CommandCodes( protocolVersion, eCmdC_Reset, sizeof( m_startMode ), 1, 0 )
, m_startMode( startMode )
{
}
BeBoB::CommandCodesReset::~CommandCodesReset()
{
}
bool
BeBoB::CommandCodesReset::serialize( Util::Cmd::IOSSerialize& se )
{
bool result = CommandCodes::serialize( se );
result &= se.write( m_startMode, "CommandCodesReset: boot mode" );
return result;
}
bool
BeBoB::CommandCodesReset::deserialize( Util::Cmd::IISDeserialize& de )
{
return CommandCodes::deserialize( de );
}
////////////////////////////////
BeBoB::CommandCodesProgramGUID::CommandCodesProgramGUID(
fb_quadlet_t protocolVersion,
fb_octlet_t guid )
: CommandCodes( protocolVersion, eCmdC_ProgramGUID, sizeof( m_guid ), 2, 0 )
, m_guid( guid )
{
}
BeBoB::CommandCodesProgramGUID::~CommandCodesProgramGUID()
{
}
bool
BeBoB::CommandCodesProgramGUID::serialize( Util::Cmd::IOSSerialize& se )
{
bool result = CommandCodes::serialize( se );
fb_quadlet_t tmp = m_guid >> 32;
result &= se.write( tmp, "CommandCodesProgramGUID: GUID (high)" );
tmp = m_guid & 0xffffffff;
result &= se.write( tmp, "CommandCodesProgramGUID: GUID (low)" );
return result;
}
bool
BeBoB::CommandCodesProgramGUID::deserialize( Util::Cmd::IISDeserialize& de )
{
return CommandCodes::deserialize( de );
}
////////////////////////////////
BeBoB::CommandCodesDownloadStart::CommandCodesDownloadStart(
fb_quadlet_t protocolVersion,
EObject object )
: CommandCodes( protocolVersion, eCmdC_DownloadStart, 10*4, 10, 1 )
, m_object( object )
, m_date( 0 )
, m_time( 0 )
, m_id( 0 )
, m_version( 0 )
, m_address( 0 )
, m_length( 0 )
, m_crc( 0 )
{
}
BeBoB::CommandCodesDownloadStart::~CommandCodesDownloadStart()
{
}
bool
BeBoB::CommandCodesDownloadStart::serialize( Util::Cmd::IOSSerialize& se )
{
bool result = CommandCodes::serialize( se );
result &= se.write( m_object, "CommandCodesDownloadStart: object" );
for ( unsigned int i = 0; i < sizeof( m_date ); ++i ) {
fb_byte_t* tmp = ( fb_byte_t* )( &m_date );
result &= se.write( tmp[i], "CommandCodesDownloadStart: date" );
}
for ( unsigned int i = 0; i < sizeof( m_date ); ++i ) {
fb_byte_t* tmp = ( fb_byte_t* )( &m_time );
result &= se.write( tmp[i], "CommandCodesDownloadStart: time" );
}
result &= se.write( m_id, "CommandCodesDownloadStart: id" );
result &= se.write( m_version, "CommandCodesDownloadStart: version" );
result &= se.write( m_address, "CommandCodesDownloadStart: address" );
result &= se.write( m_length, "CommandCodesDownloadStart: length" );
result &= se.write( m_crc, "CommandCodesDownloadStart: crc" );
return result;
}
bool
BeBoB::CommandCodesDownloadStart::deserialize( Util::Cmd::IISDeserialize& de )
{
bool result = CommandCodes::deserialize( de );
result &= de.read( reinterpret_cast( &m_resp_max_block_size ) );
return result;
}
////////////////////////////////
BeBoB::CommandCodesDownloadBlock::CommandCodesDownloadBlock(
fb_quadlet_t protocolVersion )
: CommandCodes( protocolVersion,
eCmdC_DownloadBlock,
12,
3,
2 )
, m_seqNumber( 0 )
, m_address ( 0 )
, m_resp_seqNumber( 0 )
, m_resp_errorCode( 0 )
{
}
BeBoB::CommandCodesDownloadBlock::~CommandCodesDownloadBlock()
{
}
bool
BeBoB::CommandCodesDownloadBlock::serialize( Util::Cmd::IOSSerialize& se )
{
bool result = CommandCodes::serialize( se );
result &= se.write( m_seqNumber, "CommandCodesDownloadBlock: sequence number" );
result &= se.write( m_address, "CommandCodesDownloadBlock: address" );
result &= se.write( m_numBytes, "CommandCodesDownloadBlock: number of bytes" );
return result;
}
bool
BeBoB::CommandCodesDownloadBlock::deserialize( Util::Cmd::IISDeserialize& de )
{
bool result = CommandCodes::deserialize( de );
result &= de.read( &m_resp_seqNumber );
result &= de.read( &m_resp_errorCode );
return result;
}
////////////////////////////////
BeBoB::CommandCodesDownloadEnd::CommandCodesDownloadEnd(
fb_quadlet_t protocolVersion )
: CommandCodes( protocolVersion, eCmdC_DownloadEnd, 2, 0, 2 )
{
}
BeBoB::CommandCodesDownloadEnd::~CommandCodesDownloadEnd()
{
}
bool
BeBoB::CommandCodesDownloadEnd::serialize( Util::Cmd::IOSSerialize& se )
{
return CommandCodes::serialize( se );
}
bool
BeBoB::CommandCodesDownloadEnd::deserialize( Util::Cmd::IISDeserialize& de )
{
bool result = CommandCodes::deserialize( de );
result &= de.read( &m_resp_crc32 );
result &= de.read( &m_resp_valid );
return result;
}
////////////////////////////////
BeBoB::CommandCodesInitializePersParam::CommandCodesInitializePersParam(
fb_quadlet_t protocolVersion )
: CommandCodes( protocolVersion, eCmdC_InitPersParams, 0, 0, 0 )
{
}
BeBoB::CommandCodesInitializePersParam::~CommandCodesInitializePersParam()
{
}
bool
BeBoB::CommandCodesInitializePersParam::serialize( Util::Cmd::IOSSerialize& se )
{
return CommandCodes::serialize( se );
}
bool
BeBoB::CommandCodesInitializePersParam::deserialize( Util::Cmd::IISDeserialize& de )
{
return CommandCodes::deserialize( de );
}
////////////////////////////////
BeBoB::CommandCodesInitializeConfigToFactorySetting::CommandCodesInitializeConfigToFactorySetting(
fb_quadlet_t protocolVersion )
: CommandCodes( protocolVersion, eCmdC_InitConfigToFactorySetting, 0, 0, 0 )
{
}
BeBoB::CommandCodesInitializeConfigToFactorySetting::~CommandCodesInitializeConfigToFactorySetting()
{
}
bool
BeBoB::CommandCodesInitializeConfigToFactorySetting::serialize( Util::Cmd::IOSSerialize& se )
{
return CommandCodes::serialize( se );
}
bool
BeBoB::CommandCodesInitializeConfigToFactorySetting::deserialize( Util::Cmd::IISDeserialize& de )
{
return CommandCodes::deserialize( de );
}
////////////////////////////////
BeBoB::CommandCodesGo::CommandCodesGo( fb_quadlet_t protocolVersion,
EStartMode startMode )
: CommandCodes( protocolVersion, eCmdC_Go, sizeof( m_startMode ), 1, 1 )
, m_startMode( startMode )
{
}
BeBoB::CommandCodesGo::~CommandCodesGo()
{
}
bool
BeBoB::CommandCodesGo::serialize( Util::Cmd::IOSSerialize& se )
{
bool result = CommandCodes::serialize( se );
result &= se.write( m_startMode, "CommandCodesGo: start mode" );
return result;
}
bool
BeBoB::CommandCodesGo::deserialize( Util::Cmd::IISDeserialize& de )
{
bool result = CommandCodes::deserialize( de );
result &= de.read( &m_resp_validCRC );
return result;
}
libffado-2.4.5/src/bebob/bebob_dl_codes.h 0000644 0001750 0000144 00000023624 14206145246 017611 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Daniel Wagner
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef BEBOB_DL_CODES_H
#define BEBOB_DL_CODES_H
#include "fbtypes.h"
#include "libutil/cmd_serialize.h"
namespace BeBoB {
enum EBootloaderProtocolVersion {
eBPV_Unknown = 0,
eBPV_V1 = 1,
eBPV_V2 = 2,
eBPV_V3 = 3,
};
enum EBootloaderCommandCodes {
eCmdC_Halt = 0x01,
eCmdC_Reset = 0x02,
eCmdC_ReadImageCRC = 0x03,
eCmdC_DownloadStart = 0x04,
eCmdC_DownloadBlock = 0x05,
eCmdC_DownloadEnd = 0x06,
eCmdC_SwitchTo1394Shell = 0x07,
eCmdC_ReadShellChars = 0x08,
eCmdC_WriteShellChars = 0x09,
eCmdC_ProgramGUID = 0x0a,
eCmdC_ProgramMAC = 0x0b,
eCmdC_InitPersParams = 0x0c,
eCmdC_InitConfigToFactorySetting = 0x0d,
eCmdC_SetDebugGUID = 0x0f,
eCmdC_ProgramHWIdVersion = 0x10,
eCmdC_Go = 0x11,
};
/////////////////////////
class CommandCodes {
public:
CommandCodes( fb_quadlet_t protocolVersion,
fb_byte_t commandCode,
size_t msgSize,
fb_byte_t operandSizeRequestField,
fb_byte_t operandSizeResponseField );
virtual ~CommandCodes();
virtual bool serialize( Util::Cmd::IOSSerialize& se );
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
virtual size_t getMaxSize();
EBootloaderCommandCodes getCommandCode() const
{ return static_cast( m_commandCode ); }
fb_byte_t getProtocolVersion() const
{ return m_protocolVersion; }
size_t getMsgSize() const
{ return m_msgSize; }
fb_byte_t getOperandSizeRequest() const
{ return m_operandSizeRequest; }
fb_byte_t getOperandSizeResponse() const
{ return m_operandSizeResponse; }
unsigned short getCommandId() const
{ return m_commandId; }
fb_quadlet_t getRespProtocolVersion() const
{ return m_resp_protocolVersion; }
unsigned short getRespCommandId() const
{ return m_resp_commandId; }
fb_byte_t getRespCommandCode() const
{ return m_resp_commandCode; }
fb_byte_t getRespOperandSize() const
{ return m_resp_operandSize; }
fb_byte_t getRespSizeInQuadlets() const
{ return 2 + m_operandSizeResponse; }
protected:
static unsigned short m_gCommandId;
unsigned short m_commandId;
fb_quadlet_t m_protocolVersion;
fb_byte_t m_commandCode;
size_t m_msgSize;
fb_byte_t m_operandSizeRequest;
fb_byte_t m_operandSizeResponse;
fb_quadlet_t m_resp_protocolVersion;
unsigned short m_resp_commandId;
fb_byte_t m_resp_commandCode;
fb_byte_t m_resp_operandSize;
};
/////////////////////////
class CommandCodesReset : public CommandCodes {
public:
enum EStartMode {
eSM_Application = 0,
eSM_Bootloader,
eSM_Debugger,
};
CommandCodesReset( fb_quadlet_t protocolVersion, EStartMode startMode );
virtual ~CommandCodesReset();
virtual bool serialize( Util::Cmd::IOSSerialize& se );
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
EStartMode getStartMode() const
{ return static_cast( m_startMode ); }
bool setStartMode( EStartMode startMode )
{ m_startMode = startMode; return true; }
private:
fb_byte_t m_startMode;
};
/////////////////////////
class CommandCodesProgramGUID : public CommandCodes {
public:
CommandCodesProgramGUID( fb_quadlet_t protocolVersion,
fb_octlet_t guid );
virtual ~CommandCodesProgramGUID();
virtual bool serialize( Util::Cmd::IOSSerialize& se );
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
fb_octlet_t getGUID() const
{ return m_guid; }
bool setGUID( fb_octlet_t guid )
{ m_guid = guid; return true; }
private:
fb_octlet_t m_guid;
};
/////////////////////////
class CommandCodesDownloadStart : public CommandCodes {
public:
enum EObject {
eO_Application = 0,
eO_Config = 1,
eO_Debugger = 2,
eO_Bootloader = 3,
eO_WarpImage = 4,
eO_SerialBootCode = 5,
};
CommandCodesDownloadStart( fb_quadlet_t protocolVersion,
EObject object );
virtual ~CommandCodesDownloadStart();
virtual bool serialize( Util::Cmd::IOSSerialize& se );
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
bool setDate( fb_octlet_t date )
{ m_date = date; return true; }
bool setTime( fb_octlet_t time )
{ m_time = time; return true; }
bool setId( fb_quadlet_t id )
{ m_id = id; return true; }
bool setVersion( fb_quadlet_t version )
{ m_version = version; return true; }
bool setBaseAddress( fb_quadlet_t address )
{ m_address = address; return true; }
bool setLength( fb_quadlet_t length )
{ m_length = length; return true; }
bool setCRC( fb_quadlet_t crc )
{ m_crc = crc; return true; }
int getMaxBlockSize() const
{ return m_resp_max_block_size; }
private:
fb_quadlet_t m_object;
fb_octlet_t m_date;
fb_octlet_t m_time;
fb_quadlet_t m_id;
fb_quadlet_t m_version;
fb_quadlet_t m_address;
fb_quadlet_t m_length;
fb_quadlet_t m_crc;
int m_resp_max_block_size;
};
/////////////////////////
class CommandCodesDownloadBlock : public CommandCodes {
public:
CommandCodesDownloadBlock( fb_quadlet_t protocolVersion );
virtual ~CommandCodesDownloadBlock();
virtual bool serialize( Util::Cmd::IOSSerialize& se );
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
bool setSeqNumber( fb_quadlet_t seqNumber )
{ m_seqNumber = seqNumber; return true; }
bool setAddress( fb_quadlet_t address )
{ m_address = address; return true; }
bool setNumberBytes( fb_quadlet_t numByte )
{ m_numBytes = numByte; return true; }
fb_quadlet_t getRespSeqNumber() const
{ return m_resp_seqNumber; }
fb_quadlet_t getRespErrorCode() const
{ return m_resp_errorCode; }
private:
fb_quadlet_t m_seqNumber;
fb_quadlet_t m_address;
fb_quadlet_t m_numBytes;
fb_quadlet_t m_resp_seqNumber;
fb_quadlet_t m_resp_errorCode;
};
/////////////////////////
class CommandCodesDownloadEnd : public CommandCodes {
public:
CommandCodesDownloadEnd( fb_quadlet_t protocolVersion );
virtual ~CommandCodesDownloadEnd();
virtual bool serialize( Util::Cmd::IOSSerialize& se );
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
fb_quadlet_t getRespCrc32() const
{ return m_resp_crc32; }
bool getRespIsValid() const
{ return m_resp_valid == 0; }
private:
quadlet_t m_resp_crc32;
quadlet_t m_resp_valid;
};
/////////////////////////
class CommandCodesInitializePersParam : public CommandCodes {
public:
CommandCodesInitializePersParam( fb_quadlet_t protocolVersion );
virtual ~CommandCodesInitializePersParam();
virtual bool serialize( Util::Cmd::IOSSerialize& se );
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
};
/////////////////////////
class CommandCodesInitializeConfigToFactorySetting : public CommandCodes {
public:
CommandCodesInitializeConfigToFactorySetting(
fb_quadlet_t protocolVersion );
virtual ~CommandCodesInitializeConfigToFactorySetting();
virtual bool serialize( Util::Cmd::IOSSerialize& se );
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
};
/////////////////////////
class CommandCodesGo : public CommandCodes {
public:
enum EStartMode {
eSM_Application = 0,
eSM_Debugger = 2,
};
CommandCodesGo( fb_quadlet_t protocolVersion, EStartMode startMode );
virtual ~CommandCodesGo();
virtual bool serialize( Util::Cmd::IOSSerialize& se );
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
EStartMode getStartMode() const
{ return static_cast( m_startMode ); }
bool setStartMode( EStartMode startMode )
{ m_startMode = startMode; return true; }
fb_quadlet_t getRespIsValidCRC() const
{ return m_resp_validCRC; }
private:
fb_quadlet_t m_startMode;
fb_quadlet_t m_resp_validCRC;
};
};
#endif
libffado-2.4.5/src/bebob/bebob_dl_mgr.cpp 0000644 0001750 0000144 00000054527 14206145246 017642 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Daniel Wagner
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "bebob_dl_mgr.h"
#include "bebob_dl_codes.h"
#include "bebob_dl_bcd.h"
#include "libieee1394/configrom.h"
#include "libieee1394/ieee1394service.h"
#include "libutil/cmd_serialize.h"
#include "libutil/Time.h"
#include "libutil/ByteSwap.h"
#include "ffadodevice.h"
#include
#include
#include
#include
namespace BeBoB {
enum {
AddrRegInfo = 0xffffc8020000ULL,
AddrRegReq = 0xffffc8021000ULL,
AddrRegReqBuf = 0xffffc8021040ULL,
AddrRegResp = 0xffffc8029000ULL,
AddrRegRespBuf = 0xffffc8029040ULL,
};
enum {
RegInfoManufactorIdOffset = 0x00,
RegInfoProtocolVersionOffset = 0x08,
RegInfoBootloaderVersionOffset = 0x0c,
RegInfoGUID = 0x10,
RegInfoHardwareModelId = 0x18,
RegInfoHardwareRevision = 0x1c,
RegInfoSoftwareDate = 0x20,
RegInfoSoftwareTime = 0x28,
RegInfoSoftwareId = 0x30,
RegInfoSoftwareVersion = 0x34,
RegInfoBaseAddress = 0x38,
RegInfoMaxImageLen = 0x3c,
RegInfoBootloaderDate = 0x40,
RegInfoBootloaderTime = 0x48,
RegInfoDebuggerDate = 0x50,
RegInfoDebuggerTime = 0x58,
RegInfoDebuggerId = 0x60,
RegInfoDebuggerVersion = 0x64
};
enum {
MaxRetries = 10,
};
IMPL_DEBUG_MODULE( BootloaderManager, BootloaderManager, DEBUG_LEVEL_NORMAL );
}
BeBoB::BootloaderManager::BootloaderManager(Ieee1394Service& ieee1349service,
fb_nodeid_t nodeId )
: m_ieee1394service( &ieee1349service )
, m_protocolVersion( eBPV_Unknown )
, m_isAppRunning( false )
, m_forceEnabled( false )
, m_bStartBootloader( true )
{
memset( &m_cachedInfoRegs, 0, sizeof( m_cachedInfoRegs ) );
m_configRom = new ConfigRom( *m_ieee1394service, nodeId );
// XXX throw exception if initialize fails!
m_configRom->initialize();
if ( !cacheInfoRegisters() ) {
debugError( "BootloaderManager: could not cache info registers\n" );
}
switch( m_cachedInfoRegs.m_protocolVersion ) {
case 1:
m_protocolVersion = eBPV_V1;
break;
case 3:
m_protocolVersion = eBPV_V3;
break;
default:
// exception?
break;
}
pthread_mutex_init( &m_mutex, 0 );
pthread_cond_init( &m_cond, 0 );
m_functor = new MemberFunctor0< BeBoB::BootloaderManager*,
void (BeBoB::BootloaderManager::*)() >
( this, &BeBoB::BootloaderManager::busresetHandler, false );
m_ieee1394service->addBusResetHandler( m_functor );
}
BeBoB::BootloaderManager::~BootloaderManager()
{
m_ieee1394service->remBusResetHandler( m_functor );
delete( m_functor );
delete m_configRom;
pthread_cond_destroy( &m_cond );
pthread_mutex_destroy( &m_mutex );
}
bool
BeBoB::BootloaderManager::cacheInfoRegisters()
{
if ( !m_configRom->updatedNodeId() ) {
debugError( "cacheInfoRegisters: did not find device anymore\n" );
return false;
}
if ( !m_ieee1394service->read(
0xffc0 | m_configRom->getNodeId(),
AddrRegInfo,
sizeof( m_cachedInfoRegs )/4,
reinterpret_cast( &m_cachedInfoRegs ) ) )
{
return false;
}
if ( m_cachedInfoRegs.m_bootloaderVersion != 0x0 ) {
m_isAppRunning = false;
} else {
m_isAppRunning = true;
}
m_cachedInfoRegs.m_guid = ( m_cachedInfoRegs.m_guid >> 32 )
| ( m_cachedInfoRegs.m_guid << 32 );
return true;
}
bool
BeBoB::BootloaderManager::cacheInfoRegisters( int retries )
{
for ( int i = 0; i < retries; ++i ) {
if ( cacheInfoRegisters() ) {
return true;
}
sleep( 1 );
printf(".");
fflush(stdout);
}
return false;
}
std::string
BeBoB::BootloaderManager::getSoftwareDate()
{
return makeDate( m_cachedInfoRegs.m_softwareDate );
}
std::string
BeBoB::BootloaderManager::getSoftwareTime()
{
return makeDate( m_cachedInfoRegs.m_softwareTime );
}
void
BeBoB::BootloaderManager::printInfoRegisters()
{
using namespace std;
if ( !cacheInfoRegisters() ) {
debugError( "Could not read info registers\n" );
return;
}
printf( "Info Registers\n" );
printf( "\tManufactors Id:\t\t%s\n",
makeString( m_cachedInfoRegs.m_manId ).c_str() );
printf( "\tProtocol Version:\t0x%08x\n",
m_cachedInfoRegs.m_protocolVersion );
printf( "\tBootloader Version:\t0x%08x\n",
m_cachedInfoRegs.m_bootloaderVersion );
printf( "\tGUID:\t\t\t0x%08x%08x\n",
( unsigned int )( m_cachedInfoRegs.m_guid >> 32 ),
( unsigned int )( m_cachedInfoRegs.m_guid & 0xffffffff ) );
printf( "\tHardware Model ID:\t0x%08x\n",
m_cachedInfoRegs.m_hardwareModelId );
printf( "\tHardware Revision:\t0x%08x\n",
m_cachedInfoRegs.m_hardwareRevision );
if ( m_cachedInfoRegs.m_softwareDate
&& m_cachedInfoRegs.m_softwareTime )
{
printf( "\tSoftware Date:\t\t%s, %s\n",
makeDate( m_cachedInfoRegs.m_softwareDate ).c_str(),
makeTime( m_cachedInfoRegs.m_softwareTime ).c_str() );
}
printf( "\tSoftware Id:\t\t0x%08x\n", m_cachedInfoRegs.m_softwareId );
printf( "\tSoftware Version:\t0x%08x\n",
m_cachedInfoRegs.m_softwareVersion );
printf( "\tBase Address:\t\t0x%08x\n", m_cachedInfoRegs.m_baseAddress );
printf( "\tMax. Image Len:\t\t0x%08x\n", m_cachedInfoRegs.m_maxImageLen );
if ( m_cachedInfoRegs.m_bootloaderDate
&& m_cachedInfoRegs.m_bootloaderTime )
{
printf( "\tBootloader Date:\t%s, %s\n",
makeDate( m_cachedInfoRegs.m_bootloaderDate ).c_str(),
makeTime( m_cachedInfoRegs.m_bootloaderTime ).c_str() );
}
if ( m_cachedInfoRegs.m_debuggerDate
&& m_cachedInfoRegs.m_debuggerTime )
{
printf( "\tDebugger Date:\t\t%s, %s\n",
makeDate( m_cachedInfoRegs.m_debuggerDate ).c_str(),
makeTime( m_cachedInfoRegs.m_debuggerTime ).c_str() );
}
printf( "\tDebugger Id:\t\t0x%08x\n", m_cachedInfoRegs.m_debuggerId );
printf( "\tDebugger Version:\t0x%08x\n",
m_cachedInfoRegs.m_debuggerVersion );
}
bool
BeBoB::BootloaderManager::downloadFirmware( std::string filename )
{
using namespace std;
printf( "parse BCD file\n" );
ffado_smartptr bcd = ffado_smartptr( new BCD( filename ) );
if ( !bcd.get() ) {
debugError( "downloadFirmware: Could not open or parse BCD '%s'\n",
filename.c_str() );
return false;
}
if ( !bcd->parse() ) {
debugError( "downloadFirmware: BCD parsing failed\n" );
return false;
}
printf( "check firmware device compatibility... " );
if ( !m_forceEnabled ) {
if ( !checkDeviceCompatibility( *bcd ) ) {
printf( "failed.\n" );
return false;
}
printf( "ok\n" );
} else {
printf( "forced\n" );
}
if ( m_bStartBootloader ) {
printf( "prepare for download (start bootloader)\n" );
if ( !startBootloaderCmd() ) {
debugError( "downloadFirmware: Could not start bootloader\n" );
return false;
}
}
printf( "start downloading protocol for application image\n" );
if ( !downloadObject( *bcd, eOT_Application ) ) {
debugError( "downloadFirmware: Firmware download failed\n" );
return false;
}
printf( "start downloading protocol for CnE\n" );
if ( !downloadObject( *bcd, eOT_CnE ) ) {
debugError( "downloadFirmware: CnE download failed\n" );
return false;
}
printf( "setting CnE to factory default settings\n" );
if ( !initializeConfigToFactorySettingCmd() ) {
debugError( "downloadFirmware: Could not reinitalize CnE\n" );
return false;
}
printf( "start application\n" );
if ( !startApplicationCmd() ) {
debugError( "downloadFirmware: Could not restart application\n" );
return false;
}
return true;
}
bool
BeBoB::BootloaderManager::downloadCnE( std::string filename )
{
using namespace std;
printf( "parse BCD file\n" );
ffado_smartptr bcd = ffado_smartptr( new BCD( filename ) );
if ( !bcd.get() ) {
debugError( "downloadCnE: Could not open or parse BCD '%s'\n",
filename.c_str() );
return false;
}
if ( !bcd->parse() ) {
debugError( "downloadCnE: BCD parsing failed\n" );
return false;
}
printf( "check firmware device compatibility... " );
if ( !m_forceEnabled ) {
if ( !checkDeviceCompatibility( *bcd ) ) {
printf( "failed.\n" );
return false;
}
printf( "ok\n" );
} else {
printf( "forced\n" );
}
if ( m_bStartBootloader ) {
printf( "prepare for download (start bootloader)\n" );
if ( !startBootloaderCmd() ) {
debugError( "downloadCnE: Could not start bootloader\n" );
return false;
}
}
printf( "start downloading protocol for CnE\n" );
if ( !downloadObject( *bcd, eOT_CnE ) ) {
debugError( "downloadCnE: CnE download failed\n" );
return false;
}
printf( "setting CnE to factory default settings\n" );
if ( !initializeConfigToFactorySettingCmd() ) {
debugError( "downloadFirmware: Could not reinitalize CnE\n" );
return false;
}
printf( "start application\n" );
if ( !startApplicationCmd() ) {
debugError( "downloadCnE: Could not restart application\n" );
return false;
}
return true;
}
bool
BeBoB::BootloaderManager::downloadObject( BCD& bcd, EObjectType eObject )
{
using namespace std;
CommandCodesDownloadStart::EObject eCCDSObject;
fb_quadlet_t baseAddress;
fb_quadlet_t imageLength;
fb_quadlet_t crc;
fb_quadlet_t offset;
switch ( eObject ) {
case eOT_Application:
eCCDSObject = CommandCodesDownloadStart::eO_Application;
baseAddress = bcd.getImageBaseAddress();
imageLength = bcd.getImageLength();
crc = bcd.getImageCRC();
offset = bcd.getImageOffset();
break;
case eOT_CnE:
eCCDSObject = CommandCodesDownloadStart::eO_Config;
baseAddress = 0;
imageLength = bcd.getCnELength();
crc = bcd.getCnECRC();
offset = bcd.getCnEOffset();
break;
default:
return false;
}
CommandCodesDownloadStart ccDStart ( m_protocolVersion, eCCDSObject );
ccDStart.setDate( bcd.getSoftwareDate() );
ccDStart.setTime( bcd.getSoftwareTime() );
ccDStart.setId( bcd.getSoftwareId() );
ccDStart.setVersion( bcd.getSoftwareVersion() );
ccDStart.setBaseAddress( baseAddress );
ccDStart.setLength( imageLength );
ccDStart.setCRC( crc );
if ( !writeRequest( ccDStart ) ) {
debugError( "downloadObject: start command write request failed\n" );
return false;
}
// bootloader erases the flash, have to wait until is ready
// to answer our next request
printf( "wait until flash erasing has terminated\n" );
int cnt = 30;
while(cnt--) {
sleep( 1 );
printf(".");
fflush(stdout);
}
printf("\n");
if ( !readResponse( ccDStart ) ) {
debugError( "downloadObject: (start) command read request failed\n" );
return false;
}
if ( ccDStart.getMaxBlockSize() < 0 ) {
debugError( "downloadObject: (start) command reported error %d\n",
ccDStart.getMaxBlockSize() );
return false;
}
unsigned int maxBlockSize = m_configRom->getAsyMaxPayload();
unsigned int i = 0;
fb_quadlet_t address = 0;
bool result = true;
int totalBytes = imageLength;
int downloadedBytes = 0;
while ( imageLength > 0 ) {
unsigned int blockSize = imageLength > maxBlockSize ?
maxBlockSize : imageLength;
fb_byte_t block[blockSize];
if ( !bcd.read( offset, block, blockSize ) ) {
result = false;
break;
}
if ( !get1394Serivce()->write(
0xffc0 | getConfigRom()->getNodeId(),
AddrRegReqBuf,
( blockSize + 3 ) / 4,
reinterpret_cast( block ) ) )
{
debugError( "downloadObject: Could not write to node %d\n",
getConfigRom()->getNodeId() );
return false;
}
CommandCodesDownloadBlock ccBlock( m_protocolVersion );
ccBlock.setSeqNumber( i );
ccBlock.setAddress( baseAddress + address );
ccBlock.setNumberBytes( blockSize );
if ( !writeRequest( ccBlock ) ) {
debugError( "downloadObject: (block) write request failed\n" );
result = false;
break;
}
SleepRelativeUsec( 100 );
if ( !readResponse( ccBlock ) ) {
debugError( "downloadObject: (block) read request failed\n" );
result = false;
break;
}
if ( i != ccBlock.getRespSeqNumber() ) {
debugError( "downloadObject: (block) wrong sequence number "
"reported. %d expected, %d reported\n",
i, ccBlock.getRespSeqNumber() );
result = false;
break;
}
if ( ccBlock.getRespErrorCode() != 0 ) {
debugError( "downloadObject: (block) failed download with "
"error code 0x%08x\n", ccBlock.getRespErrorCode() );
result = false;
break;
}
downloadedBytes += blockSize;
if ( ( i % 100 ) == 0 ) {
printf( "%10d/%d bytes downloaded\r",
downloadedBytes, totalBytes );
fflush(stdout);
}
imageLength -= blockSize;
address += blockSize;
offset += blockSize;
i++;
}
printf( "%10d/%d bytes downloaded\n",
downloadedBytes, totalBytes );
if ( !result ) {
debugError( "downloadObject: seqNumber = %d, "
"address = 0%08x, offset = 0x%08x, "
"restImageLength = 0x%08x\n",
i, address, offset, imageLength );
}
CommandCodesDownloadEnd ccEnd( m_protocolVersion );
if ( !writeRequest( ccEnd ) ) {
debugError( "downloadObject: (end) command write failed\n" );
}
printf( "wait for transaction completion\n" );
cnt = 10;
while(cnt--) {
sleep( 1 );
printf(".");
fflush(stdout);
}
printf("\n");
if ( !readResponse( ccEnd ) ) {
debugError( "downloadObject: (end) command read failed\n" );
}
if ( result ) {
if ( ccEnd.getRespIsValid() ) {
if ( ccEnd.getRespCrc32() == crc ) {
debugOutput( DebugModule::eDL_Normal,
"downloadObject: CRC match\n" );
} else {
debugError( "downloadObject: CRC mismatch. 0x%08x expected, "
"0x%08x reported",
crc, ccEnd.getRespCrc32() );
result = false;
}
} else {
debugError( "downloadObject: (end) object is not valid\n" );
result = false;
}
}
printf( "download protocol successfully completed\n" );
return result;
}
bool
BeBoB::BootloaderManager::programGUID( fb_octlet_t guid )
{
if ( m_bStartBootloader ) {
if ( !startBootloaderCmd() ) {
debugError( "programGUID: Could not start bootloader\n" );
return false;
}
}
if ( !programGUIDCmd( guid ) ) {
debugError( "programGUID: Could not program guid\n" );
return false;
}
if ( !startApplicationCmd() ) {
debugError( "Could not restart application\n");
return false;
}
return true;
}
void
BeBoB::BootloaderManager::busresetHandler()
{
pthread_cond_signal( &m_cond );
}
void
BeBoB::BootloaderManager::waitForBusReset()
{
struct timespec timeout;
int retcode;
// pthread_cond_timedwait() uses CLOCK_REALTIME to evaluate its
// timeout argument.
clock_gettime(CLOCK_REALTIME, &timeout);
do {
printf(".");
fflush(stdout);
timeout.tv_sec = timeout.tv_sec + 1;
retcode = pthread_cond_timedwait( &m_cond, &m_mutex, &timeout );
} while (retcode == ETIMEDOUT);
}
bool
BeBoB::BootloaderManager::writeRequest( CommandCodes& cmd )
{
unsigned char buf[ ( ( cmd.getMaxSize()+3 )/4 ) * 4 ];
memset( buf, 0, sizeof( buf ) );
Util::Cmd::BufferSerialize se( buf, sizeof( buf ) );
if ( !cmd.serialize( se ) ) {
debugError( "writeRequest: Could not serialize command code %d\n",
cmd.getCommandCode() );
return false;
}
if ( !get1394Serivce()->write(
0xffc0 | getConfigRom()->getNodeId(),
AddrRegReq,
sizeof( buf )/4,
reinterpret_cast( buf ) ) )
{
debugError( "writeRequest: Could not ARM write to node %d\n",
getConfigRom()->getNodeId() );
return false;
}
return true;
}
bool
BeBoB::BootloaderManager::readResponse( CommandCodes& writeRequestCmd )
{
const size_t buf_length = 0x40;
unsigned char raw[buf_length];
if ( !get1394Serivce()->read(
0xffc0 | getConfigRom()->getNodeId(),
AddrRegResp,
writeRequestCmd.getRespSizeInQuadlets(),
reinterpret_cast( raw ) ) )
{
return false;
}
Util::Cmd::BufferDeserialize de( raw, buf_length );
if ( !writeRequestCmd.deserialize( de ) ) {
debugError( "readResponse: deserialize failed\n" );
return false;
}
bool result =
writeRequestCmd.getProtocolVersion()
== writeRequestCmd.getRespProtocolVersion();
result &=
writeRequestCmd.getCommandId()
== writeRequestCmd.getRespCommandId();
result &=
writeRequestCmd.getCommandCode()
== writeRequestCmd.getRespCommandCode();
#ifdef DEBUG
if ( !result ) {
debugError( "readResponse: protocol version: %d expected, "
" %d reported\n",
writeRequestCmd.getProtocolVersion(),
writeRequestCmd.getRespProtocolVersion() );
debugError( "readResponse: command id: %d expected, "
" %d reported\n",
writeRequestCmd.getCommandId(),
writeRequestCmd.getRespCommandId() );
debugError( "readResponse: command code: %d expected, "
" %d reported\n",
writeRequestCmd.getCommandCode(),
writeRequestCmd.getRespCommandCode() );
}
#endif
return result;
}
bool
BeBoB::BootloaderManager::startBootloaderCmd()
{
CommandCodesReset cmd( m_protocolVersion,
CommandCodesReset::eSM_Bootloader ) ;
if ( !writeRequest( cmd ) ) {
debugError( "startBootloaderCmd: writeRequest failed\n" );
return false;
}
waitForBusReset();
if ( !cacheInfoRegisters( MaxRetries ) ) {
debugError( "startBootloaderCmd: Could not read info registers\n" );
return false;
}
// wait for bootloader finish startup sequence
// there is no way to find out when it has finished
sleep( 10 );
int cnt = 10;
while(cnt--) {
sleep( 1 );
printf(".");
fflush(stdout);
}
printf("\n");
return true;
}
bool
BeBoB::BootloaderManager::startApplicationCmd()
{
CommandCodesGo cmd( m_protocolVersion,
CommandCodesGo::eSM_Application ) ;
if ( !writeRequest( cmd ) ) {
debugError( "startApplicationCmd: writeRequest failed\n" );
return false;
}
return true;
}
bool
BeBoB::BootloaderManager::programGUIDCmd( fb_octlet_t guid )
{
CommandCodesProgramGUID cmd( m_protocolVersion, guid );
if ( !writeRequest( cmd ) ) {
debugError( "programGUIDCmd: writeRequest failed\n" );
return false;
}
sleep( 1 );
return true;
}
bool
BeBoB::BootloaderManager::initializePersParamCmd()
{
CommandCodesInitializePersParam cmd( m_protocolVersion );
if ( !writeRequest( cmd ) ) {
debugError( "initializePersParamCmd: writeRequest failed\n" );
return false;
}
sleep( 1 );
return true;
}
bool
BeBoB::BootloaderManager::initializeConfigToFactorySettingCmd()
{
CommandCodesInitializeConfigToFactorySetting cmd( m_protocolVersion );
if ( !writeRequest( cmd ) ) {
debugError( "initializeConfigToFactorySettingCmd: writeRequest failed\n" );
return false;
}
sleep( 5 );
int cnt = 5;
while(cnt--) {
sleep( 1 );
printf(".");
fflush(stdout);
}
printf("\n");
return true;
}
bool
BeBoB::BootloaderManager::checkDeviceCompatibility( BCD& bcd )
{
fb_quadlet_t vendorOUI = ( m_cachedInfoRegs.m_guid >> 40 );
if ( ( vendorOUI == bcd.getVendorOUI() )
&& ( m_cachedInfoRegs.m_softwareId == bcd.getSoftwareId() ) )
{
return true;
}
printf( "vendorOUI = 0x%08x\n", vendorOUI );
printf( "BCD vendorOUI = 0x%08x\n", bcd.getVendorOUI() );
printf( "software ID = 0x%08x\n", m_cachedInfoRegs.m_softwareId );
printf( "BCD software ID = 0x%08x\n", bcd.getSoftwareId() );
return false;
}
libffado-2.4.5/src/bebob/bebob_dl_mgr.h 0000644 0001750 0000144 00000007661 14206145246 017304 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Daniel Wagner
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef BEBOB_DL_MGR_H
#define BEBOB_DL_MGR_H
#include "bebob_dl_codes.h"
#include "fbtypes.h"
#include "libutil/Functors.h"
#include "debugmodule/debugmodule.h"
#include
class Ieee1394Service;
class ConfigRom;
using namespace Util;
namespace BeBoB {
class BCD;
class BootloaderManager {
public:
BootloaderManager( Ieee1394Service& ieee1349service,
fb_nodeid_t nodeId );
~BootloaderManager();
const ConfigRom* const getConfigRom() const
{ return m_configRom; }
void printInfoRegisters();
bool downloadFirmware( std::string filename );
bool downloadCnE( std::string filename );
bool programGUID( octlet_t guid );
void busresetHandler();
Ieee1394Service* get1394Serivce() const
{ return m_ieee1394service; }
bool setForceOperations( bool enabled )
{ m_forceEnabled = enabled; return true; }
bool setStartBootloader( bool bStartBootloader )
{ m_bStartBootloader = bStartBootloader; return true; }
int getSoftwareVersion() {return m_cachedInfoRegs.m_softwareVersion;};
std::string getSoftwareDate();
std::string getSoftwareTime();
protected:
enum EObjectType {
eOT_Application,
eOT_CnE
};
void waitForBusReset();
bool writeRequest( CommandCodes& cmd );
bool readResponse( CommandCodes& writeRequestCmd );
bool downloadObject( BCD& bcd, EObjectType eObject );
bool programGUIDCmd( octlet_t guid );
bool startBootloaderCmd();
bool startApplicationCmd();
bool initializePersParamCmd();
bool initializeConfigToFactorySettingCmd();
bool checkDeviceCompatibility( BCD& bcd );
private:
bool cacheInfoRegisters();
bool cacheInfoRegisters( int retries );
struct info_register_t {
fb_octlet_t m_manId;
fb_quadlet_t m_protocolVersion;
fb_quadlet_t m_bootloaderVersion;
fb_octlet_t m_guid;
fb_quadlet_t m_hardwareModelId;
fb_quadlet_t m_hardwareRevision;
fb_octlet_t m_softwareDate;
fb_octlet_t m_softwareTime;
fb_quadlet_t m_softwareId;
fb_quadlet_t m_softwareVersion;
fb_quadlet_t m_baseAddress;
fb_quadlet_t m_maxImageLen;
fb_octlet_t m_bootloaderDate;
fb_octlet_t m_bootloaderTime;
fb_octlet_t m_debuggerDate;
fb_octlet_t m_debuggerTime;
fb_quadlet_t m_debuggerId;
fb_quadlet_t m_debuggerVersion;
};
Ieee1394Service* m_ieee1394service;
ConfigRom* m_configRom;
EBootloaderProtocolVersion m_protocolVersion;
bool m_isAppRunning;
info_register_t m_cachedInfoRegs;
pthread_mutex_t m_mutex;
pthread_cond_t m_cond;
Functor* m_functor;
bool m_forceEnabled;
bool m_bStartBootloader;
DECLARE_DEBUG_MODULE;
};
}
#endif
libffado-2.4.5/src/bebob/bebob_functionblock.cpp 0000644 0001750 0000144 00000035045 14206145246 021230 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Daniel Wagner
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "bebob/bebob_functionblock.h"
#include "bebob/bebob_avdevice_subunit.h"
#include "bebob/bebob_avdevice.h"
#include "libieee1394/configrom.h"
#include "libutil/cmd_serialize.h"
using namespace AVC;
namespace BeBoB {
IMPL_DEBUG_MODULE( FunctionBlock, FunctionBlock, DEBUG_LEVEL_NORMAL );
FunctionBlock::FunctionBlock(
AVC::Subunit& subunit,
function_block_type_t type,
function_block_type_t subtype,
function_block_id_t id,
ESpecialPurpose purpose,
no_of_input_plugs_t nrOfInputPlugs,
no_of_output_plugs_t nrOfOutputPlugs,
int verbose )
: m_subunit( &subunit )
, m_type( type )
, m_subtype( subtype )
, m_id( id )
, m_purpose( purpose )
, m_nrOfInputPlugs( nrOfInputPlugs )
, m_nrOfOutputPlugs( nrOfOutputPlugs )
, m_verbose( verbose )
{
setDebugLevel( verbose );
}
FunctionBlock::FunctionBlock( const FunctionBlock& rhs )
: m_subunit( rhs.m_subunit )
, m_type( rhs.m_type )
, m_subtype( rhs.m_subtype )
, m_id( rhs.m_id )
, m_purpose( rhs.m_purpose )
, m_nrOfInputPlugs( rhs.m_nrOfInputPlugs )
, m_nrOfOutputPlugs( rhs.m_nrOfOutputPlugs )
, m_verbose( rhs.m_verbose )
{
}
FunctionBlock::FunctionBlock()
{
}
FunctionBlock::~FunctionBlock()
{
for ( PlugVector::iterator it = m_plugs.begin();
it != m_plugs.end();
++it )
{
delete *it;
}
}
bool
FunctionBlock::discover()
{
debugOutput( DEBUG_LEVEL_NORMAL,
"discover function block %s (nr of input plugs = %d, "
"nr of output plugs = %d)\n",
getName(),
m_nrOfInputPlugs,
m_nrOfOutputPlugs );
if ( !discoverPlugs( AVC::Plug::eAPD_Input, m_nrOfInputPlugs ) ) {
debugError( "Could not discover input plug for '%s'\n",
getName() );
return false;
}
if ( !discoverPlugs( AVC::Plug::eAPD_Output, m_nrOfOutputPlugs ) ) {
debugError( "Could not discover output plugs for '%s'\n",
getName() );
return false;
}
return true;
}
bool
FunctionBlock::discoverPlugs( AVC::Plug::EPlugDirection plugDirection,
plug_id_t plugMaxId )
{
for ( int plugId = 0; plugId < plugMaxId; ++plugId ) {
AVC::Plug* plug = new BeBoB::Plug(
&m_subunit->getUnit(),
m_subunit,
m_type,
m_id,
AVC::Plug::eAPA_FunctionBlockPlug,
plugDirection,
plugId);
if ( !plug || !plug->discover() ) {
debugError( "plug discovering failed for plug %d\n",
plugId );
delete plug;
return false;
}
debugOutput( DEBUG_LEVEL_NORMAL, "plug '%s' found\n",
plug->getName() );
m_plugs.push_back( plug );
}
return true;
}
bool
FunctionBlock::discoverConnections()
{
debugOutput( DEBUG_LEVEL_VERBOSE,
"discover connections function block %s\n",
getName() );
for ( PlugVector::iterator it = m_plugs.begin();
it != m_plugs.end();
++it )
{
BeBoB::Plug* plug = dynamic_cast(*it);
if(!plug) {
debugError("BUG: not a bebob plug\n");
return false;
}
if ( !plug->discoverConnections() ) {
debugError( "Could not discover plug connections\n" );
return false;
}
}
return true;
}
bool
FunctionBlock::serialize( std::string basePath, Util::IOSerialize& ser ) const
{
bool result;
result = ser.write( basePath + "m_type", m_type );
result &= ser.write( basePath + "m_subtype", m_subtype );
result &= ser.write( basePath + "m_id", m_id );
result &= ser.write( basePath + "m_purpose", m_purpose );
result &= ser.write( basePath + "m_nrOfInputPlugs", m_nrOfInputPlugs );
result &= ser.write( basePath + "m_nrOfOutputPlugs", m_nrOfOutputPlugs );
result &= serializePlugVector( basePath + "m_plugs", ser, m_plugs );
return result;
}
FunctionBlock*
FunctionBlock::deserialize( std::string basePath,
Util::IODeserialize& deser,
AVC::Unit& unit,
AVC::Subunit& subunit )
{
bool result;
function_block_type_t type;
function_block_type_t subtype;
FunctionBlock* pFB = 0;
if ( !deser.isExisting( basePath + "m_type" ) ) {
return 0;
}
result = deser.read( basePath + "m_type", type );
result &= deser.read( basePath + "m_subtype", subtype );
if ( !result ) {
return 0;
}
switch ( type ) {
case ExtendedSubunitInfoCmd::eFBT_AudioSubunitSelector:
pFB = new FunctionBlockSelector;
break;
case ExtendedSubunitInfoCmd::eFBT_AudioSubunitFeature:
pFB = new FunctionBlockFeature;
break;
case ExtendedSubunitInfoCmd::eFBT_AudioSubunitProcessing:
if ( subtype == ExtendedSubunitInfoCmd::ePT_EnhancedMixer ) {
pFB = new FunctionBlockEnhancedMixer;
} else {
pFB = new FunctionBlockProcessing;
}
break;
case ExtendedSubunitInfoCmd::eFBT_AudioSubunitCodec:
pFB = new FunctionBlockCodec;
break;
default:
pFB = 0;
}
if ( !pFB ) {
return 0;
}
pFB->m_subunit = &subunit;
pFB->m_type = type;
pFB->m_subtype = subtype;
result &= deser.read( basePath + "m_id", pFB->m_id );
result &= deser.read( basePath + "m_purpose", pFB->m_purpose );
result &= deser.read( basePath + "m_nrOfInputPlugs", pFB->m_nrOfInputPlugs );
result &= deser.read( basePath + "m_nrOfOutputPlugs", pFB->m_nrOfOutputPlugs );
if ( !result ) {
delete pFB;
return 0;
}
return pFB;
}
bool
FunctionBlock::deserializeUpdate( std::string basePath,
Util::IODeserialize& deser )
{
bool result;
result = deserializePlugVector( basePath + "m_plugs", deser,
m_subunit->getUnit().getPlugManager(), m_plugs );
return result;
}
///////////////////////
FunctionBlockSelector::FunctionBlockSelector(
AVC::Subunit& subunit,
function_block_id_t id,
ESpecialPurpose purpose,
no_of_input_plugs_t nrOfInputPlugs,
no_of_output_plugs_t nrOfOutputPlugs,
int verbose )
: FunctionBlock( subunit,
eFBT_AudioSubunitSelector,
0,
id,
purpose,
nrOfInputPlugs,
nrOfOutputPlugs,
verbose )
{
}
FunctionBlockSelector::FunctionBlockSelector(
const FunctionBlockSelector& rhs )
: FunctionBlock( rhs )
{
}
FunctionBlockSelector::FunctionBlockSelector()
: FunctionBlock()
{
}
FunctionBlockSelector::~FunctionBlockSelector()
{
}
const char*
FunctionBlockSelector::getName()
{
return "Selector";
}
bool
FunctionBlockSelector::serializeChild( std::string basePath,
Util::IOSerialize& ser ) const
{
return true;
}
bool
FunctionBlockSelector::deserializeChild( std::string basePath,
Util::IODeserialize& deser,
AvDevice& unit )
{
return true;
}
///////////////////////
FunctionBlockFeature::FunctionBlockFeature(
AVC::Subunit& subunit,
function_block_id_t id,
ESpecialPurpose purpose,
no_of_input_plugs_t nrOfInputPlugs,
no_of_output_plugs_t nrOfOutputPlugs,
int verbose )
: FunctionBlock( subunit,
eFBT_AudioSubunitFeature,
0,
id,
purpose,
nrOfInputPlugs,
nrOfOutputPlugs,
verbose )
{
}
FunctionBlockFeature::FunctionBlockFeature(
const FunctionBlockFeature& rhs )
: FunctionBlock( rhs )
{
}
FunctionBlockFeature::FunctionBlockFeature()
: FunctionBlock()
{
}
FunctionBlockFeature::~FunctionBlockFeature()
{
}
const char*
FunctionBlockFeature::getName()
{
return "Feature";
}
bool
FunctionBlockFeature::serializeChild( std::string basePath,
Util::IOSerialize& ser ) const
{
return true;
}
bool
FunctionBlockFeature::deserializeChild( std::string basePath,
Util::IODeserialize& deser,
AvDevice& unit )
{
return true;
}
///////////////////////
FunctionBlockEnhancedMixer::FunctionBlockEnhancedMixer(
AVC::Subunit& subunit,
function_block_id_t id,
ESpecialPurpose purpose,
no_of_input_plugs_t nrOfInputPlugs,
no_of_output_plugs_t nrOfOutputPlugs,
int verbose )
: FunctionBlock( subunit,
eFBT_AudioSubunitProcessing,
ExtendedSubunitInfoCmd::ePT_EnhancedMixer,
id,
purpose,
nrOfInputPlugs,
nrOfOutputPlugs,
verbose )
{
}
FunctionBlockEnhancedMixer::FunctionBlockEnhancedMixer(
const FunctionBlockEnhancedMixer& rhs )
: FunctionBlock( rhs )
{
}
FunctionBlockEnhancedMixer::FunctionBlockEnhancedMixer()
: FunctionBlock()
{
}
FunctionBlockEnhancedMixer::~FunctionBlockEnhancedMixer()
{
}
bool
FunctionBlockEnhancedMixer::discover()
{
if (!FunctionBlock::discover())
return false;
/*
* Disable discovering of enhanced mixer because all
* device out there do not use, and all implementations
* are buggy. So there is no point to use it.
* All 'mixer' functions are implemented with selector function blocks
*/
AVC::FunctionBlockCmd fbCmd( m_subunit->getUnit().get1394Service(),
FunctionBlockCmd::eFBT_Processing,
m_id,
FunctionBlockCmd::eCA_Current);
fbCmd.setNodeId( m_subunit->getUnit().getConfigRom().getNodeId() );
fbCmd.setSubunitId( 0x00 );
fbCmd.setCommandType( AVCCommand::eCT_Status );
// fbCmd.setVerboseLevel( DEBUG_LEVEL_VERY_VERBOSE );
// Ok, this enhanced mixer setting here is just a hack, we need
// a sane way to set processing features (read pointer management)
AVC::FunctionBlockProcessingEnhancedMixer em;
delete fbCmd.m_pFBProcessing->m_pMixer;
fbCmd.m_pFBProcessing->m_pMixer = 0;
fbCmd.m_pFBProcessing->m_pEnhancedMixer = em.clone();
fbCmd.m_pFBProcessing->m_inputAudioChannelNumber = 0xff;
fbCmd.m_pFBProcessing->m_outputAudioChannelNumber = 0xff;
if ( !fbCmd.fire() ) {
debugError( "cmd failed\n" );
return false;
}
// if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
// Util::Cmd::CoutSerializer se;
// fbCmd.serialize( se );
// }
if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
}
return true;
}
const char*
FunctionBlockEnhancedMixer::getName()
{
return "EnhancedMixer";
}
bool
FunctionBlockEnhancedMixer::serializeChild( std::string basePath,
Util::IOSerialize& ser ) const
{
return true;
}
bool
FunctionBlockEnhancedMixer::deserializeChild( std::string basePath,
Util::IODeserialize& deser,
AvDevice& unit )
{
return true;
}
///////////////////////
FunctionBlockProcessing::FunctionBlockProcessing(
AVC::Subunit& subunit,
function_block_id_t id,
ESpecialPurpose purpose,
no_of_input_plugs_t nrOfInputPlugs,
no_of_output_plugs_t nrOfOutputPlugs,
int verbose )
: FunctionBlock( subunit,
eFBT_AudioSubunitProcessing,
0,
id,
purpose,
nrOfInputPlugs,
nrOfOutputPlugs,
verbose )
{
}
FunctionBlockProcessing::FunctionBlockProcessing(
const FunctionBlockProcessing& rhs )
: FunctionBlock( rhs )
{
}
FunctionBlockProcessing::FunctionBlockProcessing()
: FunctionBlock()
{
}
FunctionBlockProcessing::~FunctionBlockProcessing()
{
}
const char*
FunctionBlockProcessing::getName()
{
return "Dummy Processing";
}
bool
FunctionBlockProcessing::serializeChild( std::string basePath,
Util::IOSerialize& ser ) const
{
return true;
}
bool
FunctionBlockProcessing::deserializeChild( std::string basePath,
Util::IODeserialize& deser,
AvDevice& unit )
{
return true;
}
///////////////////////
FunctionBlockCodec::FunctionBlockCodec(
AVC::Subunit& subunit,
function_block_id_t id,
ESpecialPurpose purpose,
no_of_input_plugs_t nrOfInputPlugs,
no_of_output_plugs_t nrOfOutputPlugs,
int verbose )
: FunctionBlock( subunit,
eFBT_AudioSubunitCodec,
0,
id,
purpose,
nrOfInputPlugs,
nrOfOutputPlugs,
verbose )
{
}
FunctionBlockCodec::FunctionBlockCodec( const FunctionBlockCodec& rhs )
: FunctionBlock( rhs )
{
}
FunctionBlockCodec::FunctionBlockCodec()
: FunctionBlock()
{
}
FunctionBlockCodec::~FunctionBlockCodec()
{
}
const char*
FunctionBlockCodec::getName()
{
return "Dummy Codec";
}
bool
FunctionBlockCodec::serializeChild( std::string basePath,
Util::IOSerialize& ser ) const
{
return true;
}
bool
FunctionBlockCodec::deserializeChild( std::string basePath,
Util::IODeserialize& deser,
AvDevice& unit )
{
return true;
}
}
libffado-2.4.5/src/bebob/bebob_functionblock.h 0000644 0001750 0000144 00000021162 14206145246 020670 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Daniel Wagner
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef BEBOB_FUNCTION_BLOCK_H
#define BEBOB_FUNCTION_BLOCK_H
#include "bebob/bebob_avplug.h"
#include "libavc/avc_definitions.h"
#include "debugmodule/debugmodule.h"
#include
namespace AVC {
class Subunit;
}
namespace BeBoB {
class FunctionBlock {
public:
enum EFunctionBlockType {
eFBT_AllFunctionBlockType = 0xff,
eFBT_AudioSubunitSelector = 0x80,
eFBT_AudioSubunitFeature = 0x81,
eFBT_AudioSubunitProcessing = 0x82,
eFBT_AudioSubunitCodec = 0x83,
};
enum ESpecialPurpose {
eSP_InputGain,
eSP_OutputVolume,
eSP_NoSpecialPurpose
};
FunctionBlock( AVC::Subunit& subunit,
AVC::function_block_type_t type,
AVC::function_block_type_t subtype,
AVC::function_block_id_t id,
ESpecialPurpose purpose,
AVC::no_of_input_plugs_t nrOfInputPlugs,
AVC::no_of_output_plugs_t nrOfOutputPlugs,
int verbose );
FunctionBlock( const FunctionBlock& rhs );
FunctionBlock();
virtual ~FunctionBlock();
virtual bool discover();
virtual bool discoverConnections();
virtual const char* getName() = 0;
AVC::function_block_type_t getType() {return m_type;};
AVC::function_block_type_t getSubtype() {return m_subtype;};
AVC::function_block_id_t getId() {return m_id;};
AVC::no_of_input_plugs_t getNrOfInputPlugs() {return m_nrOfInputPlugs;};
AVC::no_of_output_plugs_t getNrOfOutputPlugs() {return m_nrOfOutputPlugs;};
bool serialize( std::string basePath, Util::IOSerialize& ser ) const;
static FunctionBlock* deserialize( std::string basePath,
Util::IODeserialize& deser,
AVC::Unit& unit,
AVC::Subunit& subunit );
bool deserializeUpdate( std::string basePath,
Util::IODeserialize& deser );
protected:
bool discoverPlugs( AVC::Plug::EPlugDirection plugDirection,
AVC::plug_id_t plugMaxId );
protected:
AVC::Subunit* m_subunit;
AVC::function_block_type_t m_type;
AVC::function_block_type_t m_subtype;
AVC::function_block_id_t m_id;
ESpecialPurpose m_purpose;
AVC::no_of_input_plugs_t m_nrOfInputPlugs;
AVC::no_of_output_plugs_t m_nrOfOutputPlugs;
int m_verbose;
AVC::PlugVector m_plugs;
DECLARE_DEBUG_MODULE;
};
typedef std::vector FunctionBlockVector;
/////////////////////////////////////
/////////////////////////////////////
class FunctionBlockSelector: public FunctionBlock
{
public:
FunctionBlockSelector(AVC::Subunit& subunit,
AVC::function_block_id_t id,
ESpecialPurpose purpose,
AVC::no_of_input_plugs_t nrOfInputPlugs,
AVC::no_of_output_plugs_t nrOfOutputPlugs,
int verbose);
FunctionBlockSelector( const FunctionBlockSelector& rhs );
FunctionBlockSelector();
virtual ~FunctionBlockSelector();
virtual const char* getName();
protected:
virtual bool serializeChild( std::string basePath,
Util::IOSerialize& ser ) const;
virtual bool deserializeChild( std::string basePath,
Util::IODeserialize& deser,
AvDevice& avDevice );
};
/////////////////////////////////////
class FunctionBlockFeature: public FunctionBlock
{
public:
FunctionBlockFeature(AVC::Subunit& subunit,
AVC::function_block_id_t id,
ESpecialPurpose purpose,
AVC::no_of_input_plugs_t nrOfInputPlugs,
AVC::no_of_output_plugs_t nrOfOutputPlugs,
int verbose);
FunctionBlockFeature( const FunctionBlockFeature& rhs );
FunctionBlockFeature();
virtual ~FunctionBlockFeature();
virtual const char* getName();
// FIXME: this is not pretty!
enum EControlSelectorEncoding {
eCSE_Feature_Unknown = 0x00,
eCSE_Feature_Mute = 0x01,
eCSE_Feature_Volume = 0x02,
eCSE_Feature_LRBalance = 0x03,
eCSE_Feature_FRBalance = 0x04,
eCSE_Feature_Bass = 0x05,
eCSE_Feature_Mid = 0x06,
eCSE_Feature_Treble = 0x07,
eCSE_Feature_GEQ = 0x08,
eCSE_Feature_AGC = 0x09,
eCSE_Feature_Delay = 0x0a,
eCSE_Feature_BassBoost = 0x0b,
eCSE_Feature_Loudness = 0x0c,
};
protected:
virtual bool serializeChild( std::string basePath,
Util::IOSerialize& ser ) const;
virtual bool deserializeChild( std::string basePath,
Util::IODeserialize& deser,
AvDevice& avDevice );
};
/////////////////////////////////////
class FunctionBlockEnhancedMixer: public FunctionBlock
{
public:
FunctionBlockEnhancedMixer( AVC::Subunit& subunit,
AVC::function_block_id_t id,
ESpecialPurpose purpose,
AVC::no_of_input_plugs_t nrOfInputPlugs,
AVC::no_of_output_plugs_t nrOfOutputPlugs,
int verbose );
FunctionBlockEnhancedMixer();
FunctionBlockEnhancedMixer( const FunctionBlockEnhancedMixer& rhs );
virtual ~FunctionBlockEnhancedMixer();
virtual bool discover();
virtual const char* getName();
protected:
virtual bool serializeChild( std::string basePath,
Util::IOSerialize& ser ) const;
virtual bool deserializeChild( std::string basePath,
Util::IODeserialize& deser,
AvDevice& avDevice );
};
/////////////////////////////////////
class FunctionBlockProcessing: public FunctionBlock
{
public:
FunctionBlockProcessing( AVC::Subunit& subunit,
AVC::function_block_id_t id,
ESpecialPurpose purpose,
AVC::no_of_input_plugs_t nrOfInputPlugs,
AVC::no_of_output_plugs_t nrOfOutputPlugs,
int verbose );
FunctionBlockProcessing( const FunctionBlockProcessing& rhs );
FunctionBlockProcessing();
virtual ~FunctionBlockProcessing();
virtual const char* getName();
protected:
virtual bool serializeChild( std::string basePath,
Util::IOSerialize& ser ) const;
virtual bool deserializeChild( std::string basePath,
Util::IODeserialize& deser,
AvDevice& avDevice );
};
/////////////////////////////////////
class FunctionBlockCodec: public FunctionBlock
{
public:
FunctionBlockCodec(AVC::Subunit& subunit,
AVC::function_block_id_t id,
ESpecialPurpose purpose,
AVC::no_of_input_plugs_t nrOfInputPlugs,
AVC::no_of_output_plugs_t nrOfOutputPlugs,
int verbose);
FunctionBlockCodec( const FunctionBlockCodec& rhs );
FunctionBlockCodec();
virtual ~FunctionBlockCodec();
virtual const char* getName();
protected:
virtual bool serializeChild( std::string basePath,
Util::IOSerialize& ser ) const;
virtual bool deserializeChild( std::string basePath,
Util::IODeserialize& deser,
AvDevice& avDevice );
};
}
#endif
libffado-2.4.5/src/bebob/bebob_mixer.cpp 0000644 0001750 0000144 00000030410 14206145246 017503 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Pieter Palmers
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "bebob/bebob_mixer.h"
#include "bebob/bebob_avdevice.h"
#include "bebob/bebob_avdevice_subunit.h"
#include "libavc/audiosubunit/avc_function_block.h"
#include "libutil/cmd_serialize.h"
#include "libcontrol/BasicElements.h"
#include "libieee1394/ieee1394service.h"
#include "libieee1394/configrom.h"
#include
#include
#include
#include
using namespace AVC;
namespace BeBoB {
template
bool from_string(T& t,
const std::string& s,
std::ios_base& (*f)(std::ios_base&))
{
std::istringstream iss(s);
return !(iss >> f >> t).fail();
}
IMPL_DEBUG_MODULE( Mixer, Mixer, DEBUG_LEVEL_NORMAL );
Mixer::Mixer(Device &d)
: Control::Container(&d)
, m_device(d)
{
addElementForAllFunctionBlocks();
if (!d.addElement(this)) {
debugWarning("Could not add myself to Control::Container\n");
}
}
Mixer::~Mixer() {
debugOutput(DEBUG_LEVEL_VERBOSE,"Unregistering from Control::Container...\n");
if (!m_device.deleteElement(this)) {
debugWarning("Could not delete myself from Control::Container\n");
}
// delete all our elements since we should have created
// them ourselves.
for ( Control::ElementVectorIterator it = m_Children.begin();
it != m_Children.end();
++it )
{
debugOutput(DEBUG_LEVEL_VERBOSE,"deleting %s...\n", (*it)->getName().c_str());
delete *it;
}
}
bool
Mixer::deleteElement(Element *e)
{
if (Control::Container::deleteElement(e)) {
delete e;
return true;
} else return false;
}
bool
Mixer::clearElements() {
// delete all our elements since we should have created
// them ourselves.
for ( Control::ElementVectorIterator it = m_Children.begin();
it != m_Children.end();
++it )
{
delete *it;
}
m_Children.clear();
return true;
}
template
bool
Mixer::addElementForFunctionBlock(FBType& b)
{
Control::Element *e = new MixerType(*this, b);
if (!e) {
debugError("Control element creation failed\n");
return false;
}
e->setVerboseLevel(getDebugLevel());
return Control::Container::addElement(e);
}
bool
Mixer::addElementForAllFunctionBlocks() {
debugOutput(DEBUG_LEVEL_VERBOSE,"Adding elements for functionblocks...\n");
bool retval = true;
BeBoB::SubunitAudio *asu =
dynamic_cast(m_device.getAudioSubunit(0));
if(asu == NULL) {
debugWarning("No BeBoB audio subunit found\n");
return false;
}
FunctionBlockVector functions=asu->getFunctionBlocks();
for ( FunctionBlockVector::iterator it = functions.begin();
it != functions.end();
++it )
{
FunctionBlock *pfb = *it;
FunctionBlockSelector *ps;
FunctionBlockFeature *pf;
FunctionBlockEnhancedMixer *pm;
if ((ps = dynamic_cast(pfb))) {
debugOutput( DEBUG_LEVEL_VERBOSE, "FB is a SelectorFunctionBlock\n");
retval = addElementForFunctionBlock(*ps);
} else if ((pf = dynamic_cast(pfb))) {
// We might should check if really both feature function
// blocks exists and only then announce them. The FA-101,
// FA-66 and the Ref BCO Audio5 do have both.
debugOutput( DEBUG_LEVEL_VERBOSE, "FB is a FeatureFunctionBlock\n");
retval = addElementForFunctionBlock(*pf);
retval &= addElementForFunctionBlock(*pf);
} else if ((pm = dynamic_cast(pfb))) {
// All BeBoB devices lock the mixer feature function
// block. The AV/C model for this mixer is just to
// complex and the BridgeCo guys decided to use the above
// function feature blocks (level and balance) to achive
// the same.
debugOutput( DEBUG_LEVEL_VERBOSE, "FB is a FunctionBlockEnhancedMixer\n");
retval = addElementForFunctionBlock(*pm);
}
if (!retval) {
std::ostringstream ostrm;
ostrm << (*it)->getName() << " " << (int)((*it)->getId());
debugWarning("Failed to add element for function block %s\n",
ostrm.str().c_str());
};
}
return retval;
}
// --- element implementation classes
MixerFBFeatureVolume::MixerFBFeatureVolume(Mixer& parent, FunctionBlockFeature& s)
: Control::Continuous(&parent)
, m_Parent(parent)
, m_Slave(s)
{
std::ostringstream ostrm;
ostrm << s.getName() << "_Volume_" << (int)(s.getId());
Control::Continuous::setName(ostrm.str());
ostrm.str("");
ostrm << "Label for " << s.getName() << "_Volume " << (int)(s.getId());
setLabel(ostrm.str());
ostrm.str("");
ostrm << "Description for " << s.getName() << "_Volume " << (int)(s.getId());
setDescription(ostrm.str());
}
MixerFBFeatureVolume::~MixerFBFeatureVolume()
{
}
bool
MixerFBFeatureVolume::setValue(double v)
{
return setValue(0, v);
}
bool
MixerFBFeatureVolume::setValue(int idx, double v)
{
int volume=(int)v;
debugOutput(DEBUG_LEVEL_NORMAL,"Set feature volume %d to %d...\n",
m_Slave.getId(), volume);
return m_Parent.getParent().setFeatureFBVolumeCurrent(m_Slave.getId(), idx, volume);
}
double
MixerFBFeatureVolume::getValue()
{
return getValue(0);
}
double
MixerFBFeatureVolume::getValue(int idx)
{
debugOutput(DEBUG_LEVEL_NORMAL,"Get feature volume %d...\n",
m_Slave.getId());
return m_Parent.getParent().getFeatureFBVolumeCurrent(m_Slave.getId(), idx);
}
double
MixerFBFeatureVolume::getMinimum()
{
debugOutput(DEBUG_LEVEL_NORMAL,"Get feature minimum volume %d...\n",
m_Slave.getId());
return m_Parent.getParent().getFeatureFBVolumeMinimum(m_Slave.getId(), 0);
}
double
MixerFBFeatureVolume::getMaximum()
{
debugOutput(DEBUG_LEVEL_NORMAL,"Get feature maximum volume %d...\n",
m_Slave.getId());
return m_Parent.getParent().getFeatureFBVolumeMaximum(m_Slave.getId(), 0);
}
// --- element implementation classes
MixerFBFeatureLRBalance::MixerFBFeatureLRBalance(Mixer& parent, FunctionBlockFeature& s)
: Control::Continuous(&parent)
, m_Parent(parent)
, m_Slave(s)
{
std::ostringstream ostrm;
ostrm << s.getName() << "_LRBalance_" << (int)(s.getId());
Control::Continuous::setName(ostrm.str());
ostrm.str("");
ostrm << "Label for " << s.getName() << "_LRBalance " << (int)(s.getId());
setLabel(ostrm.str());
ostrm.str("");
ostrm << "Description for " << s.getName() << "_LRBalance " << (int)(s.getId());
setDescription(ostrm.str());
}
MixerFBFeatureLRBalance::~MixerFBFeatureLRBalance()
{
}
bool
MixerFBFeatureLRBalance::setValue(double v)
{
return setValue(0, v);
}
bool
MixerFBFeatureLRBalance::setValue(int idx, double v)
{
int volume=(int)v;
debugOutput(DEBUG_LEVEL_NORMAL,"Set feature balance %d to %d...\n",
m_Slave.getId(), volume);
return m_Parent.getParent().setFeatureFBLRBalanceCurrent(m_Slave.getId(), idx, volume);
}
double
MixerFBFeatureLRBalance::getValue()
{
return getValue(0);
}
double
MixerFBFeatureLRBalance::getValue(int idx)
{
debugOutput(DEBUG_LEVEL_NORMAL,"Get feature balance %d...\n",
m_Slave.getId());
return m_Parent.getParent().getFeatureFBLRBalanceCurrent(m_Slave.getId(), idx);
}
double
MixerFBFeatureLRBalance::getMinimum()
{
debugOutput(DEBUG_LEVEL_NORMAL,"Get feature balance volume %d...\n",
m_Slave.getId());
return m_Parent.getParent().getFeatureFBLRBalanceMinimum(m_Slave.getId(), 0);
}
double
MixerFBFeatureLRBalance::getMaximum()
{
debugOutput(DEBUG_LEVEL_NORMAL,"Get feature maximum balance %d...\n",
m_Slave.getId());
return m_Parent.getParent().getFeatureFBLRBalanceMaximum(m_Slave.getId(), 0);
}
// --- element implementation classes
/*
* This function is named with 'EnhancedMixer' but current implementation is
* for 'Processing'. There is several reasons.
* There is no way to distinguish 'EnhancedMixer' from 'Processing', the
* former is an extension of 'Processing' in AV/C audio subunit command.
* The limitation of parameter of Continuous dbus interface. The ffado
* developer considered to change the type of interface but it's not
* reasonable in a point of cost/effect.
* As of Oct 2013, the FFADO developers confirm only M-Audio BeBoB devices uses
* this command to control mixer. No other devices use it. M-Audio BeBoB
* devices can be controlled by single type 'Processing' command even if
* they can be controlled by both single and multi type.
*/
EnhancedMixerFBFeature::EnhancedMixerFBFeature(Mixer& parent, FunctionBlockEnhancedMixer& s)
: Control::Continuous(&parent)
, m_Parent(parent)
, m_Slave(s)
{
std::ostringstream ostrm;
ostrm << s.getName() << "_" << (int)(s.getId());
Control::Continuous::setName(ostrm.str());
ostrm.str("");
ostrm << "Label for " << s.getName() << " " << (int)(s.getId());
setLabel(ostrm.str());
ostrm.str("");
ostrm << "Description for " << s.getName() << " " << (int)(s.getId());
setDescription(ostrm.str());
}
EnhancedMixerFBFeature::~EnhancedMixerFBFeature()
{
}
bool
EnhancedMixerFBFeature::setValue(int idx, double v)
{
int iPlugNum = (idx >> 8) & 0xF;
int iAChNum = (idx >> 4) & 0xF;
int oAChNum = (idx >> 0) & 0xF;
debugOutput(DEBUG_LEVEL_NORMAL,"Set: FBID: 0x%02X, FBPN: 0x%02X, "
"ICN: 0x%02X, OCN: 0x%02X, DATA: 0x%04X\n",
m_Slave.getId(), iPlugNum, iAChNum, oAChNum, (int)v);
return m_Parent.getParent().setProcessingFBMixerSingleCurrent(m_Slave.getId(),
iPlugNum, iAChNum, oAChNum,
(int)v);
}
double
EnhancedMixerFBFeature::getValue(int idx)
{
int iPlugNum = (idx >> 8) & 0xF;
int iAChNum = (idx >> 4) & 0xF;
int oAChNum = (idx >> 0) & 0xF;
debugOutput(DEBUG_LEVEL_NORMAL,"Set: FBID: 0x%02X, FBPN: 0x%02X, "
"ICN: 0x%02X, OCN: 0x%02X\n",
m_Slave.getId(), iPlugNum, iAChNum, oAChNum);
return m_Parent.getParent().getProcessingFBMixerSingleCurrent(m_Slave.getId(),
iPlugNum, iAChNum, oAChNum);
}
// --- element implementation classes
MixerFBSelector::MixerFBSelector(Mixer& parent, FunctionBlockSelector& s)
: Control::Discrete(&parent)
, m_Parent(parent)
, m_Slave(s)
{
std::ostringstream ostrm;
ostrm << s.getName() << "_" << (int)(s.getId());
Control::Discrete::setName(ostrm.str());
ostrm.str("");
ostrm << "Label for " << s.getName() << " " << (int)(s.getId());
setLabel(ostrm.str());
ostrm.str("");
ostrm << "Description for " << s.getName() << " " << (int)(s.getId());
setDescription(ostrm.str());
}
MixerFBSelector::~MixerFBSelector()
{
}
bool
MixerFBSelector::setValue(int v)
{
debugOutput(DEBUG_LEVEL_NORMAL,"Set selector %d to %d...\n",
m_Slave.getId(), v);
return m_Parent.getParent().setSelectorFBValue(m_Slave.getId(), v);
}
int
MixerFBSelector::getValue()
{
debugOutput(DEBUG_LEVEL_NORMAL,"Get selector %d...\n",
m_Slave.getId());
return m_Parent.getParent().getSelectorFBValue(m_Slave.getId());
}
} // end of namespace BeBoB
libffado-2.4.5/src/bebob/bebob_mixer.h 0000644 0001750 0000144 00000007660 14206145246 017163 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Pieter Palmers
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef __FFAD0_BEBOB_MIXER__
#define __FFAD0_BEBOB_MIXER__
#include "src/debugmodule/debugmodule.h"
#include "libcontrol/BasicElements.h"
#include
namespace BeBoB {
class Device;
class FunctionBlock;
class FunctionBlockFeature;
class FunctionBlockSelector;
class FunctionBlockEnhancedMixer;
class Mixer
: public Control::Container
{
public:
Mixer(Device &d);
virtual ~Mixer();
virtual std::string getName()
{ return "Mixer"; };
virtual bool setName( std::string n )
{ return false; };
template bool addElementForFunctionBlock(FBType& b);
bool addElementForAllFunctionBlocks();
// manipulation of the contained elements
bool addElement(Control::Element *)
{debugWarning("not allowed"); return false;};
bool deleteElement(Control::Element *);
bool clearElements();
Device& getParent()
{return m_device;};
protected:
Device& m_device;
protected:
DECLARE_DEBUG_MODULE;
};
class MixerFBFeatureVolume
: public Control::Continuous
{
public:
MixerFBFeatureVolume(Mixer& parent, FunctionBlockFeature&);
virtual ~MixerFBFeatureVolume();
virtual bool setValue(double v);
virtual double getValue();
virtual bool setValue(int idx, double v);
virtual double getValue(int idx);
virtual double getMinimum();
virtual double getMaximum();
private:
Mixer& m_Parent;
FunctionBlockFeature& m_Slave;
};
class MixerFBFeatureLRBalance
: public Control::Continuous
{
public:
MixerFBFeatureLRBalance(Mixer& parent, FunctionBlockFeature&);
virtual ~MixerFBFeatureLRBalance();
virtual bool setValue(double v);
virtual double getValue();
virtual bool setValue(int idx, double v);
virtual double getValue(int idx);
virtual double getMinimum();
virtual double getMaximum();
private:
Mixer& m_Parent;
FunctionBlockFeature& m_Slave;
};
class EnhancedMixerFBFeature
: public Control::Continuous
{
public:
EnhancedMixerFBFeature(Mixer& parent, FunctionBlockEnhancedMixer&);
virtual ~EnhancedMixerFBFeature();
virtual bool setValue(int idx, double v);
virtual double getValue(int idx);
virtual bool setValue(double v)
{return setValue(1, v);};
virtual double getValue()
{return getValue(1);};
virtual double getMinimum() {return -32768;};
virtual double getMaximum() {return 0;};
private:
Mixer& m_Parent;
FunctionBlockEnhancedMixer& m_Slave;
};
class MixerFBSelector
: public Control::Discrete
{
public:
MixerFBSelector(Mixer& parent, FunctionBlockSelector&);
virtual ~MixerFBSelector();
virtual bool setValue(int v);
virtual int getValue();
virtual bool setValue(int idx, int v)
{return setValue(v);};
virtual int getValue(int idx)
{return getValue();};
virtual int getMinimum() {return 0;};
virtual int getMaximum() {return 0;};
private:
Mixer& m_Parent;
FunctionBlockSelector& m_Slave;
};
} // end of namespace BeBoB
#endif /* __FFAD0_BEBOB_MIXER__ */
libffado-2.4.5/src/bebob/edirol/ 0000755 0001750 0000144 00000000000 14206145612 015777 5 ustar jwoithe users libffado-2.4.5/src/bebob/edirol/edirol_fa101.cpp 0000644 0001750 0000144 00000004210 14206145246 020651 0 ustar jwoithe users /*
* Copyright (C) 2008 by Daniel Wagner
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "edirol_fa101.h"
namespace BeBoB {
namespace Edirol {
EdirolFa101Device::EdirolFa101Device( DeviceManager& d,
ffado_smartptr( configRom ))
: BeBoB::Device( d , configRom)
{
debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::Edirol::EdirolFa101Device (NodeID %d)\n",
getConfigRom().getNodeId() );
m_fixed_clocksource.type = FFADODevice::eCT_Auto;
m_fixed_clocksource.valid = true;
m_fixed_clocksource.locked = true;
m_fixed_clocksource.id = 0;
m_fixed_clocksource.slipping = false;
m_fixed_clocksource.description = "Device Controlled";
get1394Service().setFCPResponseFiltering(true);
}
EdirolFa101Device::~EdirolFa101Device()
{
}
FFADODevice::ClockSource
EdirolFa101Device::getActiveClockSource() {
return m_fixed_clocksource;
}
bool
EdirolFa101Device::setActiveClockSource(ClockSource s) {
// can't change, hence only succeed when identical
return s.id == m_fixed_clocksource.id;
}
FFADODevice::ClockSourceVector
EdirolFa101Device::getSupportedClockSources() {
FFADODevice::ClockSourceVector r;
r.push_back(m_fixed_clocksource);
return r;
}
void
EdirolFa101Device::showDevice()
{
debugOutput(DEBUG_LEVEL_VERBOSE, "This is a BeBoB::EdirolFa101::EdirolFa101Device\n");
BeBoB::Device::showDevice();
}
}
}
libffado-2.4.5/src/bebob/edirol/edirol_fa101.h 0000644 0001750 0000144 00000002603 14206145246 020322 0 ustar jwoithe users /*
* Copyright (C) 2008 by Daniel Wagner
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef BEBOB_EDIROL_FA101_H
#define BEBOB_EDIROL_FA101_H
#include "bebob/bebob_avdevice.h"
namespace BeBoB {
namespace Edirol {
class EdirolFa101Device : public BeBoB::Device {
public:
EdirolFa101Device( DeviceManager& d,
ffado_smartptr( configRom ));
virtual ~EdirolFa101Device();
virtual ClockSourceVector getSupportedClockSources();
virtual bool setActiveClockSource(ClockSource);
virtual ClockSource getActiveClockSource();
virtual void showDevice();
private:
ClockSource m_fixed_clocksource;
};
}
}
#endif
libffado-2.4.5/src/bebob/edirol/edirol_fa66.cpp 0000644 0001750 0000144 00000004107 14206145246 020610 0 ustar jwoithe users /*
* Copyright (C) 2008 by Daniel Wagner
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "edirol_fa66.h"
namespace BeBoB {
namespace Edirol {
EdirolFa66Device::EdirolFa66Device( DeviceManager& d,
ffado_smartptr( configRom ))
: BeBoB::Device( d , configRom)
{
debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::Edirol::EdirolFa66Device (NodeID %d)\n",
getConfigRom().getNodeId() );
m_fixed_clocksource.type = FFADODevice::eCT_Auto;
m_fixed_clocksource.valid = true;
m_fixed_clocksource.locked = true;
m_fixed_clocksource.id = 0;
m_fixed_clocksource.slipping = false;
m_fixed_clocksource.description = "Device Controlled";
}
EdirolFa66Device::~EdirolFa66Device()
{
}
FFADODevice::ClockSource
EdirolFa66Device::getActiveClockSource() {
return m_fixed_clocksource;
}
bool
EdirolFa66Device::setActiveClockSource(ClockSource s) {
// can't change, hence only succeed when identical
return s.id == m_fixed_clocksource.id;
}
FFADODevice::ClockSourceVector
EdirolFa66Device::getSupportedClockSources() {
FFADODevice::ClockSourceVector r;
r.push_back(m_fixed_clocksource);
return r;
}
void
EdirolFa66Device::showDevice()
{
debugOutput(DEBUG_LEVEL_VERBOSE, "This is a BeBoB::EdirolFa66::EdirolFa66Device\n");
BeBoB::Device::showDevice();
}
}
}
libffado-2.4.5/src/bebob/edirol/edirol_fa66.h 0000644 0001750 0000144 00000002576 14206145246 020265 0 ustar jwoithe users /*
* Copyright (C) 2008 by Daniel Wagner
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef BEBOB_EDIROL_FA66_H
#define BEBOB_EDIROL_FA66_H
#include "bebob/bebob_avdevice.h"
namespace BeBoB {
namespace Edirol {
class EdirolFa66Device : public BeBoB::Device {
public:
EdirolFa66Device( DeviceManager& d,
ffado_smartptr( configRom ));
virtual ~EdirolFa66Device();
virtual ClockSourceVector getSupportedClockSources();
virtual bool setActiveClockSource(ClockSource);
virtual ClockSource getActiveClockSource();
virtual void showDevice();
private:
ClockSource m_fixed_clocksource;
};
}
}
#endif
libffado-2.4.5/src/bebob/esi/ 0000755 0001750 0000144 00000000000 14206145612 015301 5 ustar jwoithe users libffado-2.4.5/src/bebob/esi/quatafire610.cpp 0000644 0001750 0000144 00000004077 14206145246 020230 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Pieter Palmers
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "quatafire610.h"
#include "debugmodule/debugmodule.h"
namespace BeBoB {
namespace ESI {
QuataFireDevice::QuataFireDevice( DeviceManager& d, ffado_smartptr( configRom ))
: BeBoB::Device( d, configRom)
{
m_fixed_clocksource.type = FFADODevice::eCT_Auto;
m_fixed_clocksource.valid = true;
m_fixed_clocksource.locked = true;
m_fixed_clocksource.id = 0;
m_fixed_clocksource.slipping = false;
m_fixed_clocksource.description = "Autoselect";
debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::ESI::QuataFireDevice (NodeID %d)\n",
getConfigRom().getNodeId() );
}
QuataFireDevice::~QuataFireDevice()
{
}
void
QuataFireDevice::showDevice()
{
debugOutput(DEBUG_LEVEL_VERBOSE, "This is a BeBoB::ESI::QuataFireDevice\n");
BeBoB::Device::showDevice();
}
FFADODevice::ClockSource
QuataFireDevice::getActiveClockSource() {
return m_fixed_clocksource;
}
bool
QuataFireDevice::setActiveClockSource(ClockSource s) {
// can't change, hence only succeed when identical
return s.id == m_fixed_clocksource.id;
}
FFADODevice::ClockSourceVector
QuataFireDevice::getSupportedClockSources() {
FFADODevice::ClockSourceVector r;
r.push_back(m_fixed_clocksource);
return r;
}
} // ESI
} // BeBoB
libffado-2.4.5/src/bebob/esi/quatafire610.h 0000644 0001750 0000144 00000003106 14206145246 017665 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Daniel Wagner
* Copyright (C) 2005-2008 by Pieter Palmers
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef BEBOB_ESI_QUATAFIRE_DEVICE_H
#define BEBOB_ESI_QUATAFIRE_DEVICE_H
#include "bebob/bebob_avdevice.h"
namespace BeBoB {
namespace ESI {
class QuataFireDevice : public BeBoB::Device {
public:
QuataFireDevice( DeviceManager& d, ffado_smartptr( configRom ));
virtual ~QuataFireDevice();
// override these since the quatafire does not support
// setting the clock source (it automatically syncs to SPDIF)
virtual ClockSourceVector getSupportedClockSources();
virtual bool setActiveClockSource(ClockSource);
virtual ClockSource getActiveClockSource();
virtual void showDevice();
private:
ClockSource m_fixed_clocksource;
};
} // namespace BeBoB
} // namespace ESI
#endif
libffado-2.4.5/src/bebob/focusrite/ 0000755 0001750 0000144 00000000000 14206145612 016524 5 ustar jwoithe users libffado-2.4.5/src/bebob/focusrite/focusrite_cmd.cpp 0000644 0001750 0000144 00000004353 14206145246 022066 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Pieter Palmers
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "focusrite_cmd.h"
#include "libutil/ByteSwap.h"
#include
using namespace std;
using namespace AVC;
namespace BeBoB {
namespace Focusrite {
FocusriteVendorDependentCmd::FocusriteVendorDependentCmd(Ieee1394Service& ieee1394service)
: VendorDependentCmd( ieee1394service )
, m_arg1 ( 0x03 )
, m_arg2 ( 0x01 )
, m_id ( 0x00000000 )
, m_value ( 0x00000000 )
{
m_companyId=0x00130e;
}
FocusriteVendorDependentCmd::~FocusriteVendorDependentCmd()
{
}
bool
FocusriteVendorDependentCmd::serialize( Util::Cmd::IOSSerialize& se )
{
bool result=true;
result &= VendorDependentCmd::serialize( se );
result &= se.write(m_arg1,"FocusriteVendorDependentCmd arg1");
result &= se.write(m_arg2,"FocusriteVendorDependentCmd arg2");
// FIXME: this is not consistent, we should not have to care about CondSwapFromBus32 here
result &= se.write(CondSwapToBus32(m_id),"FocusriteVendorDependentCmd ID");
result &= se.write(CondSwapToBus32(m_value),"FocusriteVendorDependentCmd value");
return result;
}
bool
FocusriteVendorDependentCmd::deserialize( Util::Cmd::IISDeserialize& de )
{
bool result=true;
result &= VendorDependentCmd::deserialize( de );
result &= de.read(&m_arg1);
result &= de.read(&m_arg2);
result &= de.read(&m_id);
m_id=CondSwapFromBus32(m_id);
result &= de.read(&m_value);
m_value=CondSwapFromBus32(m_value);
return result;
}
}
}
libffado-2.4.5/src/bebob/focusrite/focusrite_cmd.h 0000644 0001750 0000144 00000003121 14206145246 021523 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Pieter Palmers
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef FOCUSRITEVENDORDEPENDENT_H
#define FOCUSRITEVENDORDEPENDENT_H
#include "libavc/general/avc_generic.h"
#include "libutil/cmd_serialize.h"
#include "libavc/general/avc_vendor_dependent_cmd.h"
namespace BeBoB {
namespace Focusrite {
class FocusriteVendorDependentCmd: public AVC::VendorDependentCmd
{
public:
FocusriteVendorDependentCmd(Ieee1394Service& ieee1394service);
virtual ~FocusriteVendorDependentCmd();
virtual bool serialize( Util::Cmd::IOSSerialize& se );
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
virtual const char* getCmdName() const
{ return "FocusriteVendorDependentCmd"; }
byte_t m_arg1;
byte_t m_arg2;
quadlet_t m_id;
quadlet_t m_value;
};
}
}
#endif // FOCUSRITEVENDORDEPENDENT_H
libffado-2.4.5/src/bebob/focusrite/focusrite_generic.cpp 0000644 0001750 0000144 00000041407 14206145246 022740 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Pieter Palmers
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "focusrite_saffirepro.h"
#include "focusrite_cmd.h"
#include "libutil/ByteSwap.h"
namespace BeBoB {
namespace Focusrite {
FocusriteDevice::FocusriteDevice( DeviceManager& d, ffado_smartptr( configRom ))
: BeBoB::Device( d, configRom)
, m_cmd_time_interval( 0 )
, m_earliest_next_cmd_time( 0 )
{
debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::Focusrite::FocusriteDevice (NodeID %d)\n",
getConfigRom().getNodeId() );
addOption(Util::OptionContainer::Option("useAvcForParameters", false));
}
void
FocusriteDevice::showDevice()
{
debugOutput(DEBUG_LEVEL_NORMAL, "This is a BeBoB::Focusrite::FocusriteDevice\n");
BeBoB::Device::showDevice();
}
void
FocusriteDevice::setVerboseLevel(int l)
{
debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
BeBoB::Device::setVerboseLevel(l);
}
bool
FocusriteDevice::setSpecificValue(uint32_t id, uint32_t v)
{
debugOutput(DEBUG_LEVEL_VERBOSE, "Writing parameter address space id 0x%08X (%u), data: 0x%08X\n",
id, id, v);
bool use_avc = false;
if(!getOption("useAvcForParameters", use_avc)) {
debugWarning("Could not retrieve useAvcForParameters parameter, defaulting to false\n");
}
// rate control
ffado_microsecs_t now = Util::SystemTimeSource::getCurrentTimeAsUsecs();
if(m_cmd_time_interval && (m_earliest_next_cmd_time > now)) {
ffado_microsecs_t wait = m_earliest_next_cmd_time - now;
debugOutput( DEBUG_LEVEL_VERBOSE, "Rate control... %" PRIu64 "\n", wait );
Util::SystemTimeSource::SleepUsecRelative(wait);
}
m_earliest_next_cmd_time = now + m_cmd_time_interval;
if (use_avc) {
return setSpecificValueAvc(id, v);
} else {
return setSpecificValueARM(id, v);
}
}
bool
FocusriteDevice::getSpecificValue(uint32_t id, uint32_t *v)
{
bool retval;
bool use_avc = false;
if(!getOption("useAvcForParameters", use_avc)) {
debugWarning("Could not retrieve useAvcForParameters parameter, defaulting to false\n");
}
// rate control
ffado_microsecs_t now = Util::SystemTimeSource::getCurrentTimeAsUsecs();
if(m_cmd_time_interval && (m_earliest_next_cmd_time > now)) {
ffado_microsecs_t wait = m_earliest_next_cmd_time - now;
debugOutput( DEBUG_LEVEL_VERBOSE, "Rate control... %" PRIu64 "\n", wait );
Util::SystemTimeSource::SleepUsecRelative(wait);
}
m_earliest_next_cmd_time = now + m_cmd_time_interval;
// execute
if (use_avc) {
retval = getSpecificValueAvc(id, v);
} else {
retval = getSpecificValueARM(id, v);
}
debugOutput(DEBUG_LEVEL_VERBOSE,"Read parameter address space id 0x%08X (%u): %08X\n", id, id, *v);
return retval;
}
// The AV/C methods to set parameters
bool
FocusriteDevice::setSpecificValueAvc(uint32_t id, uint32_t v)
{
FocusriteVendorDependentCmd cmd( get1394Service() );
cmd.setCommandType( AVC::AVCCommand::eCT_Control );
cmd.setNodeId( getConfigRom().getNodeId() );
cmd.setSubunitType( AVC::eST_Unit );
cmd.setSubunitId( 0xff );
cmd.setVerbose( getDebugLevel() );
// cmd.setVerbose( DEBUG_LEVEL_VERY_VERBOSE );
cmd.m_id=id;
cmd.m_value=v;
if ( !cmd.fire() ) {
debugError( "FocusriteVendorDependentCmd info command failed\n" );
return false;
}
return true;
}
bool
FocusriteDevice::getSpecificValueAvc(uint32_t id, uint32_t *v)
{
FocusriteVendorDependentCmd cmd( get1394Service() );
cmd.setCommandType( AVC::AVCCommand::eCT_Status );
cmd.setNodeId( getConfigRom().getNodeId() );
cmd.setSubunitType( AVC::eST_Unit );
cmd.setSubunitId( 0xff );
cmd.setVerbose( getDebugLevel() );
// cmd.setVerbose( DEBUG_LEVEL_VERY_VERBOSE );
cmd.m_id=id;
if ( !cmd.fire() ) {
debugError( "FocusriteVendorDependentCmd info command failed\n" );
return false;
}
*v=cmd.m_value;
return true;
}
// The ARM methods to set parameters
bool
FocusriteDevice::setSpecificValueARM(uint32_t id, uint32_t v)
{
fb_quadlet_t data = v;
debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing parameter address space id 0x%08X (%u), data: 0x%08X\n",
id, id, data);
fb_nodeaddr_t addr = FR_PARAM_SPACE_START + (id * 4);
fb_nodeid_t nodeId = getNodeId() | 0xFFC0;
if(!get1394Service().write_quadlet( nodeId, addr, CondSwapToBus32(data) ) ) {
debugError("Could not write to node 0x%04X addr 0x%012" PRIX64 "\n", nodeId, addr);
return false;
}
return true;
}
bool
FocusriteDevice::getSpecificValueARM(uint32_t id, uint32_t *v)
{
fb_quadlet_t result;
debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading parameter address space id 0x%08X\n", id);
fb_nodeaddr_t addr = FR_PARAM_SPACE_START + (id * 4);
fb_nodeid_t nodeId = getNodeId() | 0xFFC0;
if(!get1394Service().read_quadlet( nodeId, addr, &result ) ) {
debugError("Could not read from node 0x%04X addr 0x%012" PRIX64 "\n", nodeId, addr);
return false;
}
result = CondSwapFromBus32(result);
debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Read result: 0x%08X\n", result);
*v = result;
return true;
}
int
FocusriteDevice::convertDefToSr( uint32_t def ) {
switch(def) {
case FOCUSRITE_CMD_SAMPLERATE_44K1: return 44100;
case FOCUSRITE_CMD_SAMPLERATE_48K: return 48000;
case FOCUSRITE_CMD_SAMPLERATE_88K2: return 88200;
case FOCUSRITE_CMD_SAMPLERATE_96K: return 96000;
case FOCUSRITE_CMD_SAMPLERATE_176K4: return 176400;
case FOCUSRITE_CMD_SAMPLERATE_192K: return 192000;
default:
debugWarning("Unsupported samplerate def: %08X\n", def);
return 0;
}
}
uint32_t
FocusriteDevice::convertSrToDef( int sr ) {
switch(sr) {
case 44100: return FOCUSRITE_CMD_SAMPLERATE_44K1;
case 48000: return FOCUSRITE_CMD_SAMPLERATE_48K;
case 88200: return FOCUSRITE_CMD_SAMPLERATE_88K2;
case 96000: return FOCUSRITE_CMD_SAMPLERATE_96K;
case 176400: return FOCUSRITE_CMD_SAMPLERATE_176K4;
case 192000: return FOCUSRITE_CMD_SAMPLERATE_192K;
default:
debugWarning("Unsupported samplerate: %d\n", sr);
return 0;
}
}
// --- element implementation classes
BinaryControl::BinaryControl(FocusriteDevice& parent, int id, int bit)
: Control::Discrete(&parent)
, m_Parent(parent)
, m_cmd_id ( id )
, m_cmd_bit ( bit )
{}
BinaryControl::BinaryControl(FocusriteDevice& parent, int id, int bit,
std::string name, std::string label, std::string descr)
: Control::Discrete(&parent)
, m_Parent(parent)
, m_cmd_id ( id )
, m_cmd_bit ( bit )
{
setName(name);
setLabel(label);
setDescription(descr);
}
bool
BinaryControl::setValue(int v)
{
uint32_t reg;
uint32_t old_reg;
if ( !m_Parent.getSpecificValue(m_cmd_id, ®) ) {
debugError( "getSpecificValue failed\n" );
return 0;
}
old_reg=reg;
if (v) {
reg |= (1< 0x%08X)\n",
m_cmd_id, v, old_reg, reg);
if ( !m_Parent.setSpecificValue(m_cmd_id, reg) ) {
debugError( "setSpecificValue failed\n" );
return false;
} else return true;
}
int
BinaryControl::getValue()
{
uint32_t reg;
if ( !m_Parent.getSpecificValue(m_cmd_id, ®) ) {
debugError( "getSpecificValue failed\n" );
return 0;
} else {
bool val= (reg & (1<0x07FFF) v=0x07FFF;
else if (v<0) v=0;
debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for id %d to %d\n",
m_cmd_id, v);
if ( !m_Parent.setSpecificValue(m_cmd_id, v) ) {
debugError( "setSpecificValue failed\n" );
return false;
} else return true;
}
int
VolumeControl::getValue()
{
uint32_t val=0;
if ( !m_Parent.getSpecificValue(m_cmd_id, &val) ) {
debugError( "getSpecificValue failed\n" );
return 0;
} else {
debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for %d = %d\n",
m_cmd_id, val);
return val;
}
}
MeteringControl::MeteringControl(FocusriteDevice& parent, int id)
: Control::Discrete(&parent)
, m_Parent(parent)
, m_cmd_id ( id )
{}
MeteringControl::MeteringControl(FocusriteDevice& parent, int id,
std::string name, std::string label, std::string descr)
: Control::Discrete(&parent)
, m_Parent(parent)
, m_cmd_id ( id )
{
setName(name);
setLabel(label);
setDescription(descr);
}
int
MeteringControl::getValue()
{
uint32_t val=0;
if ( !m_Parent.getSpecificValue(m_cmd_id, &val) ) {
debugError( "getSpecificValue failed\n" );
return 0;
} else {
debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for %d = %d\n",
m_cmd_id, val);
return val;
}
}
// reg control
RegisterControl::RegisterControl(FocusriteDevice& parent)
: Control::Register(&parent)
, m_Parent(parent)
{}
RegisterControl::RegisterControl(FocusriteDevice& parent,
std::string name, std::string label, std::string descr)
: Control::Register(&parent)
, m_Parent(parent)
{
setName(name);
setLabel(label);
setDescription(descr);
}
bool
RegisterControl::setValue(uint64_t addr, uint64_t v)
{
debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for addr %" PRIu64 " to %" PRIu64 "\n",
addr, v);
if ( !m_Parent.setSpecificValue(addr, v) ) {
debugError( "setSpecificValue failed\n" );
return false;
} else return true;
}
uint64_t
RegisterControl::getValue(uint64_t addr)
{
uint32_t val=0;
if ( !m_Parent.getSpecificValue(addr, &val) ) {
debugError( "getSpecificValue failed\n" );
return 0;
} else {
debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for %" PRIu64 " = %u\n",
addr, val);
return val;
}
}
// low resolution volume control
VolumeControlLowRes::VolumeControlLowRes(FocusriteDevice& parent, int id, int shift)
: Control::Discrete(&parent)
, m_Parent(parent)
, m_cmd_id ( id )
, m_bit_shift( shift )
{}
VolumeControlLowRes::VolumeControlLowRes(FocusriteDevice& parent, int id, int shift,
std::string name, std::string label, std::string descr)
: Control::Discrete(&parent)
, m_Parent(parent)
, m_cmd_id ( id )
, m_bit_shift( shift )
{
setName(name);
setLabel(label);
setDescription(descr);
}
bool
VolumeControlLowRes::setValue(int v)
{
uint32_t reg;
uint32_t old_reg;
if (v>0xFF) v=0xFF;
else if (v<0) v=0;
if ( !m_Parent.getSpecificValue(m_cmd_id, ®) ) {
debugError( "getSpecificValue failed\n" );
return 0;
}
old_reg=reg;
reg &= ~(0xFF< 0x%08X)\n",
m_cmd_id, v, m_bit_shift, old_reg, reg);
if ( !m_Parent.setSpecificValue(m_cmd_id, reg) ) {
debugError( "setSpecificValue failed\n" );
return false;
} else return true;
}
int
VolumeControlLowRes::getValue()
{
uint32_t val, reg;
if ( !m_Parent.getSpecificValue(m_cmd_id, ®) ) {
debugError( "getSpecificValue failed\n" );
return 0;
} else {
val = (reg & 0xFF)>>m_bit_shift;
debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for %d: reg: 0x%08X, result=%d\n",
m_cmd_id, reg, val);
return val;
}
}
// hardware dial control
DialPositionControl::DialPositionControl(FocusriteDevice& parent, int id, int shift)
: Control::Discrete(&parent)
, m_Parent(parent)
, m_cmd_id ( id )
, m_shift ( shift )
{}
DialPositionControl::DialPositionControl(FocusriteDevice& parent, int id, int shift,
std::string name, std::string label, std::string descr)
: Control::Discrete(&parent)
, m_Parent(parent)
, m_cmd_id ( id )
, m_shift ( shift )
{
setName(name);
setLabel(label);
setDescription(descr);
}
int
DialPositionControl::getValue()
{
uint32_t val=0;
if ( !m_Parent.getSpecificValue(m_cmd_id, &val) ) {
debugError( "getSpecificValue failed\n" );
return 0;
} else {
if (m_shift > 0) {
val = val >> m_shift;
} else if (m_shift < 0) {
val = val << -m_shift;
}
debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for %d = %d\n",
m_cmd_id, val);
return val;
}
}
// Saffire pro matrix mixer element
FocusriteMatrixMixer::FocusriteMatrixMixer(FocusriteDevice& p)
: Control::MatrixMixer(&p, "MatrixMixer")
, m_Parent(p)
{
}
FocusriteMatrixMixer::FocusriteMatrixMixer(FocusriteDevice& p,std::string n)
: Control::MatrixMixer(&p, n)
, m_Parent(p)
{
}
void FocusriteMatrixMixer::addSignalInfo(std::vector &target,
std::string name, std::string label, std::string descr)
{
struct sSignalInfo s;
s.name=name;
s.label=label;
s.description=descr;
target.push_back(s);
}
void FocusriteMatrixMixer::setCellInfo(int row, int col, int addr, bool valid)
{
struct sCellInfo c;
c.row=row;
c.col=col;
c.valid=valid;
c.address=addr;
m_CellInfo.at(row).at(col) = c;
}
void FocusriteMatrixMixer::show()
{
debugOutput(DEBUG_LEVEL_NORMAL, "Focusrite Matrix mixer\n");
}
std::string FocusriteMatrixMixer::getRowName( const int row )
{
debugOutput(DEBUG_LEVEL_VERBOSE, "name for row %d is %s\n",
row, m_RowInfo.at(row).name.c_str());
return m_RowInfo.at(row).name;
}
std::string FocusriteMatrixMixer::getColName( const int col )
{
debugOutput(DEBUG_LEVEL_VERBOSE, "name for col %d is %s\n",
col, m_ColInfo.at(col).name.c_str());
return m_ColInfo.at(col).name;
}
int FocusriteMatrixMixer::canWrite( const int row, const int col )
{
debugOutput(DEBUG_LEVEL_VERBOSE, "canWrite for row %d col %d is %d\n",
row, col, m_CellInfo.at(row).at(col).valid);
return m_CellInfo.at(row).at(col).valid;
}
double FocusriteMatrixMixer::setValue( const int row, const int col, const double val )
{
int32_t v = (int32_t)val;
struct sCellInfo c = m_CellInfo.at(row).at(col);
debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for id %d row %d col %d to %lf (%d)\n",
c.address, row, col, val, v);
if (v>0x07FFF) v=0x07FFF;
else if (v<0) v=0;
if ( !m_Parent.setSpecificValue(c.address, v) ) {
debugError( "setSpecificValue failed\n" );
return false;
} else return true;
}
double FocusriteMatrixMixer::getValue( const int row, const int col )
{
struct sCellInfo c=m_CellInfo.at(row).at(col);
uint32_t val=0;
if ( !m_Parent.getSpecificValue(c.address, &val) ) {
debugError( "getSpecificValue failed\n" );
return 0;
} else {
debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for id %d row %d col %d = %u\n",
c.address, row, col, val);
return val;
}
}
int FocusriteMatrixMixer::getRowCount( )
{
return m_RowInfo.size();
}
int FocusriteMatrixMixer::getColCount( )
{
return m_ColInfo.size();
}
} // Focusrite
} // BeBoB
libffado-2.4.5/src/bebob/focusrite/focusrite_generic.h 0000644 0001750 0000144 00000016606 14206145246 022410 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Daniel Wagner
* Copyright (C) 2005-2008 by Pieter Palmers
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef BEBOB_FOCUSRITE_GENERIC_DEVICE_H
#define BEBOB_FOCUSRITE_GENERIC_DEVICE_H
#include "debugmodule/debugmodule.h"
#include "bebob/bebob_avdevice.h"
#include "libcontrol/BasicElements.h"
#include "libcontrol/MatrixMixer.h"
#include "libutil/SystemTimeSource.h"
#define FR_PARAM_SPACE_START 0x000100000000LL
namespace BeBoB {
namespace Focusrite {
class FocusriteDevice;
class BinaryControl
: public Control::Discrete
{
public:
BinaryControl(FocusriteDevice& parent, int id, int bit);
BinaryControl(FocusriteDevice& parent, int id, int bit,
std::string name, std::string label, std::string descr);
virtual bool setValue(int v);
virtual int getValue();
virtual bool setValue(int idx, int v)
{return setValue(v);};
virtual int getValue(int idx)
{return getValue();};
virtual int getMinimum() {return 0;};
virtual int getMaximum() {return 1;};
private:
FocusriteDevice& m_Parent;
unsigned int m_cmd_id;
unsigned int m_cmd_bit;
};
class VolumeControl
: public Control::Discrete
{
public:
VolumeControl(FocusriteDevice& parent, int id);
VolumeControl(FocusriteDevice& parent, int id,
std::string name, std::string label, std::string descr);
virtual bool setValue(int v);
virtual int getValue();
virtual bool setValue(int idx, int v)
{return setValue(v);};
virtual int getValue(int idx)
{return getValue();};
virtual int getMinimum() {return 0;};
virtual int getMaximum() {return 0x07FFF;};
private:
FocusriteDevice& m_Parent;
unsigned int m_cmd_id;
};
class MeteringControl
: public Control::Discrete
{
public:
MeteringControl(FocusriteDevice& parent, int id);
MeteringControl(FocusriteDevice& parent, int id,
std::string name, std::string label, std::string descr);
virtual bool setValue(int v) {return false;};
virtual int getValue();
virtual bool setValue(int idx, int v)
{return setValue(v);};
virtual int getValue(int idx)
{return getValue();};
virtual int getMinimum() {return 0;};
virtual int getMaximum() {return 0x07FFF;};
private:
FocusriteDevice& m_Parent;
unsigned int m_cmd_id;
};
class RegisterControl
: public Control::Register
{
public:
RegisterControl(FocusriteDevice& parent);
RegisterControl(FocusriteDevice& parent,
std::string name, std::string label, std::string descr);
virtual bool setValue(uint64_t addr, uint64_t value);
virtual uint64_t getValue(uint64_t addr);
private:
FocusriteDevice& m_Parent;
};
class VolumeControlLowRes
: public Control::Discrete
{
public:
VolumeControlLowRes(FocusriteDevice& parent, int id, int shift);
VolumeControlLowRes(FocusriteDevice& parent, int id, int shift,
std::string name, std::string label, std::string descr);
virtual bool setValue(int v);
virtual int getValue();
virtual bool setValue(int idx, int v)
{return setValue(v);};
virtual int getValue(int idx)
{return getValue();};
virtual int getMinimum() {return 0;};
virtual int getMaximum() {return 0x0FF;};
private:
FocusriteDevice& m_Parent;
unsigned int m_cmd_id;
unsigned int m_bit_shift;
};
class DialPositionControl
: public Control::Discrete
{
public:
DialPositionControl(FocusriteDevice& parent, int id, int shift);
DialPositionControl(FocusriteDevice& parent, int id, int shift,
std::string name, std::string label, std::string descr);
virtual bool setValue(int v) {return false;};
virtual int getValue();
virtual bool setValue(int idx, int v)
{return setValue(v);};
virtual int getValue(int idx)
{return getValue();};
virtual int getMinimum() {return 0;};
virtual int getMaximum() {return 0x07FFF;};
private:
FocusriteDevice& m_Parent;
unsigned int m_cmd_id;
int m_shift;
};
class FocusriteMatrixMixer : public Control::MatrixMixer
{
public:
FocusriteMatrixMixer(FocusriteDevice& parent);
FocusriteMatrixMixer(FocusriteDevice& parent, std::string n);
virtual ~FocusriteMatrixMixer() {};
virtual void show();
virtual int getRowCount( );
virtual int getColCount( );
virtual int canWrite( const int, const int );
virtual double setValue( const int, const int, const double );
virtual double getValue( const int, const int );
// full map updates are unsupported
virtual bool getCoefficientMap(int &) {return false;};
virtual bool storeCoefficientMap(int &) {return false;};
bool hasNames() const { return true; }
virtual std::string getRowName( const int );
virtual std::string getColName( const int );
bool canConnect() const { return false; }
protected:
struct sSignalInfo {
std::string name;
std::string label;
std::string description;
};
struct sCellInfo {
int row;
int col;
// indicates whether a cell can be valid, this
// doesn't mean that it is writable. Just that it can be.
bool valid;
// the address to use when manipulating this cell
int address;
};
virtual void init() = 0;
virtual void addSignalInfo(std::vector &target,
std::string name, std::string label, std::string descr);
virtual void setCellInfo(int row, int col, int addr, bool valid);
std::vector m_RowInfo;
std::vector m_ColInfo;
std::vector< std::vector > m_CellInfo;
FocusriteDevice& m_Parent;
};
class FocusriteDevice : public BeBoB::Device {
public:
FocusriteDevice(DeviceManager& d, ffado_smartptr( configRom ));
virtual ~FocusriteDevice() {};
virtual void showDevice();
virtual void setVerboseLevel(int l);
public:
bool setSpecificValue(uint32_t id, uint32_t v);
bool getSpecificValue(uint32_t id, uint32_t *v);
protected:
int convertDefToSr( uint32_t def );
uint32_t convertSrToDef( int sr );
private:
bool setSpecificValueAvc(uint32_t id, uint32_t v);
bool getSpecificValueAvc(uint32_t id, uint32_t *v);
bool setSpecificValueARM(uint32_t id, uint32_t v);
bool getSpecificValueARM(uint32_t id, uint32_t *v);
protected:
ffado_microsecs_t m_cmd_time_interval;
ffado_microsecs_t m_earliest_next_cmd_time;
};
} // namespace Focusrite
} // namespace BeBoB
#endif
libffado-2.4.5/src/bebob/focusrite/focusrite_saffire.cpp 0000644 0001750 0000144 00000102001 14206145246 022727 0 ustar jwoithe users /*
* Copyright (C) 2005-2008 by Pieter Palmers
*
* This file is part of FFADO
* FFADO = Free FireWire (pro-)audio drivers for Linux
*
* FFADO is based upon FreeBoB.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "focusrite_saffire.h"
#include "focusrite_cmd.h"
#include "devicemanager.h"
namespace BeBoB {
namespace Focusrite {
SaffireDevice::SaffireDevice( DeviceManager& d, ffado_smartptr( configRom ))
: FocusriteDevice( d, configRom)
, m_MixerContainer( NULL )
{
debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::Focusrite::SaffireDevice (NodeID %d)\n",
getConfigRom().getNodeId() );
if(getConfigRom().getGuid() < 0x130e0100040000LL) {
m_isSaffireLE = false;
} else {
m_isSaffireLE = true;
}
// find the configured delay time for this device
Util::Configuration &config = d.getConfiguration();
int delaytime = 0;
if(config.getValueForDeviceSetting(getConfigRom().getNodeVendorId(), getConfigRom().getModelId(), "cmd_interval_time", delaytime)) {
m_cmd_time_interval = delaytime;
debugOutput( DEBUG_LEVEL_VERBOSE, "Setting command interval time to %" PRIu64 "\n",
m_cmd_time_interval );
} else {
m_cmd_time_interval = 10000;
debugOutput( DEBUG_LEVEL_VERBOSE, "No command interval time setting found, defaulting to %" PRIu64 "\n",
m_cmd_time_interval );
}
}
bool
SaffireDevice::buildMixer()
{
bool result=true;
debugOutput(DEBUG_LEVEL_VERBOSE, "Building a Focusrite Saffire mixer...\n");
destroyMixer();
// create the mixer object container
m_MixerContainer = new Control::Container(this, "Mixer");
if (!m_MixerContainer) {
debugError("Could not create mixer container...\n");
return false;
}
if(m_isSaffireLE) {
// create control objects for the saffire LE
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRELE_CMD_ID_SPDIF_TRANSPARENT, 0,
"SpdifTransparent", "S/PDIF Transparent", "S/PDIF Transparent"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRELE_CMD_ID_MIDITHRU, 0,
"MidiThru", "MIDI Thru", "MIDI Thru"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRELE_CMD_ID_SAVE_SETTINGS, 0,
"SaveSettings", "Save Settings", "Save Settings"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRELE_CMD_ID_HIGH_GAIN_LINE3, 0,
"HighGainLine3", "High Gain Line-in 3", "High Gain Line-in 3"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRELE_CMD_ID_HIGH_GAIN_LINE4, 0,
"HighGainLine4", "High Gain Line-in 4", "High Gain Line-in 4"));
// output mute controls
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRELE_CMD_ID_BITFIELD_OUT12, FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_MUTE,
"Out12Mute", "Out1/2 Mute", "Output 1/2 Mute"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRELE_CMD_ID_BITFIELD_OUT34, FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_MUTE,
"Out34Mute", "Out3/4 Mute", "Output 3/4 Mute"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRELE_CMD_ID_BITFIELD_OUT56, FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_MUTE,
"Out56Mute", "Out5/6 Mute", "Output 5/6 Mute"));
// output front panel hw volume control
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRELE_CMD_ID_BITFIELD_OUT12, FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_HWCTRL,
"Out12HwCtrl", "Out1/2 HwCtrl", "Output 1/2 Front Panel Hardware volume control"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRELE_CMD_ID_BITFIELD_OUT34, FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_HWCTRL,
"Out34HwCtrl", "Out3/4 HwCtrl", "Output 3/4 Front Panel Hardware volume control"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRELE_CMD_ID_BITFIELD_OUT56, FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_HWCTRL,
"Out56HwCtrl", "Out5/6 HwCtrl", "Output 5/6 Front Panel Hardware volume control"));
// dac ignore
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRELE_CMD_ID_BITFIELD_OUT12, FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_DACIGNORE,
"Out12DacIgnore", "Out1/2 Dac Ignore", "Output 1/2 Dac Ignore"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRELE_CMD_ID_BITFIELD_OUT34, FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_DACIGNORE,
"Out34DacIgnore", "Out3/4 Dac Ignore", "Output 3/4 Dac Ignore"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRELE_CMD_ID_BITFIELD_OUT56, FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_DACIGNORE,
"Out56DacIgnore", "Out5/6 Dac Ignore", "Output 5/6 Dac Ignore"));
// output level controls
result &= m_MixerContainer->addElement(
new VolumeControlLowRes(*this,
FR_SAFFIRELE_CMD_ID_BITFIELD_OUT12, FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_DAC,
"Out12Level", "Out1/2 Level", "Output 1/2 Level"));
result &= m_MixerContainer->addElement(
new VolumeControlLowRes(*this,
FR_SAFFIRELE_CMD_ID_BITFIELD_OUT34, FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_DAC,
"Out34Level", "Out3/4 Level", "Output 3/4 Level"));
result &= m_MixerContainer->addElement(
new VolumeControlLowRes(*this,
FR_SAFFIRELE_CMD_ID_BITFIELD_OUT56, FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_DAC,
"Out56Level", "Out5/6 Level", "Output 5/6 Level"));
} else {
// create control objects for the saffire
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRE_CMD_ID_INPUT_SOURCE, 0,
"SpdifSwitch", "S/PDIF Switch", "S/PDIF Switch"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRE_CMD_ID_MONO_MODE, 0,
"MonoMode", "Mono Mode", "Toggle Mono Mode"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRE_CMD_ID_DEVICE_MODE, 0,
"DeviceMode", "Device Mode", "Toggle Device Mode"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRE_CMD_ID_EXTERNAL_LOCK, 0,
"ExternalLock", "External Lock", "Has external lock?"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRE_CMD_ID_AUDIO_ON_STATUS, 0,
"AudioOnStatus", "Audio On Status", "Audio On Status"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRE_CMD_ID_SAVE_SETTINGS, 0,
"SaveSettings", "Save Settings", "Save Settings"));
// output mute controls
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRE_CMD_ID_BITFIELD_OUT12, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_MUTE,
"Out12Mute", "Out1/2 Mute", "Output 1/2 Mute"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRE_CMD_ID_BITFIELD_OUT34, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_MUTE,
"Out34Mute", "Out3/4 Mute", "Output 3/4 Mute"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRE_CMD_ID_BITFIELD_OUT56, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_MUTE,
"Out56Mute", "Out5/6 Mute", "Output 5/6 Mute"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRE_CMD_ID_BITFIELD_OUT78, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_MUTE,
"Out78Mute", "Out7/8 Mute", "Output 7/8 Mute"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRE_CMD_ID_BITFIELD_OUT910, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_MUTE,
"Out910Mute", "Out9/10 Mute", "Output 9/10 Mute"));
// output front panel hw volume control
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRE_CMD_ID_BITFIELD_OUT12, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_HWCTRL,
"Out12HwCtrl", "Out1/2 HwCtrl", "Output 1/2 Front Panel Hardware volume control"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRE_CMD_ID_BITFIELD_OUT34, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_HWCTRL,
"Out34HwCtrl", "Out3/4 HwCtrl", "Output 3/4 Front Panel Hardware volume control"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRE_CMD_ID_BITFIELD_OUT56, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_HWCTRL,
"Out56HwCtrl", "Out5/6 HwCtrl", "Output 5/6 Front Panel Hardware volume control"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRE_CMD_ID_BITFIELD_OUT78, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_HWCTRL,
"Out78HwCtrl", "Out7/8 HwCtrl", "Output 7/8 Front Panel Hardware volume control"));
// output level dim
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRE_CMD_ID_BITFIELD_OUT12, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_DIM,
"Out12Dim", "Out1/2 Dim", "Output 1/2 Level Dim"));
// dac ignore
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRE_CMD_ID_BITFIELD_OUT12, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_DACIGNORE,
"Out12DacIgnore", "Out1/2 Dac Ignore", "Output 1/2 Dac Ignore"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRE_CMD_ID_BITFIELD_OUT34, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_DACIGNORE,
"Out34DacIgnore", "Out3/4 Dac Ignore", "Output 3/4 Dac Ignore"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRE_CMD_ID_BITFIELD_OUT56, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_DACIGNORE,
"Out56DacIgnore", "Out5/6 Dac Ignore", "Output 5/6 Dac Ignore"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRE_CMD_ID_BITFIELD_OUT78, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_DACIGNORE,
"Out78DacIgnore", "Out7/8 Dac Ignore", "Output 7/8 Dac Ignore"));
// output level controls
result &= m_MixerContainer->addElement(
new VolumeControlLowRes(*this,
FR_SAFFIRE_CMD_ID_BITFIELD_OUT12, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_DAC,
"Out12Level", "Out1/2 Level", "Output 1/2 Level"));
result &= m_MixerContainer->addElement(
new VolumeControlLowRes(*this,
FR_SAFFIRE_CMD_ID_BITFIELD_OUT34, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_DAC,
"Out34Level", "Out3/4 Level", "Output 3/4 Level"));
result &= m_MixerContainer->addElement(
new VolumeControlLowRes(*this,
FR_SAFFIRE_CMD_ID_BITFIELD_OUT56, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_DAC,
"Out56Level", "Out5/6 Level", "Output 5/6 Level"));
result &= m_MixerContainer->addElement(
new VolumeControlLowRes(*this,
FR_SAFFIRE_CMD_ID_BITFIELD_OUT78, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_DAC,
"Out78Level", "Out7/8 Level", "Output 7/8 Level"));
result &= m_MixerContainer->addElement(
new DialPositionControl(*this,
FR_SAFFIRE_CMD_ID_MONITOR_DIAL, 0,
"MonitorDial", "Monitor Dial", "Monitor Dial Value"));
// metering
result &= m_MixerContainer->addElement(
new MeteringControl(*this,
FR_SAFFIRE_CMD_ID_METERING_IN1,
"MeteringIn1", "Metering Input 1", "Metering on Input 1"));
result &= m_MixerContainer->addElement(
new MeteringControl(*this,
FR_SAFFIRE_CMD_ID_METERING_IN2,
"MeteringIn2", "Metering Input 2", "Metering on Input 2"));
result &= m_MixerContainer->addElement(
new MeteringControl(*this,
FR_SAFFIRE_CMD_ID_METERING_IN3,
"MeteringIn3", "Metering Input 3", "Metering on Input 3"));
result &= m_MixerContainer->addElement(
new MeteringControl(*this,
FR_SAFFIRE_CMD_ID_METERING_IN4,
"MeteringIn4", "Metering Input 4", "Metering on Input 4"));
result &= m_MixerContainer->addElement(
new MeteringControl(*this,
FR_SAFFIRE_CMD_ID_METERING_PC1,
"MeteringPc1", "Metering PC 1", "Metering on PC Channel 1"));
result &= m_MixerContainer->addElement(
new MeteringControl(*this,
FR_SAFFIRE_CMD_ID_METERING_PC2,
"MeteringPc2", "Metering PC 2", "Metering on PC Channel 2"));
result &= m_MixerContainer->addElement(
new MeteringControl(*this,
FR_SAFFIRE_CMD_ID_METERING_PC3,
"MeteringPc3", "Metering PC 3", "Metering on PC Channel 3"));
result &= m_MixerContainer->addElement(
new MeteringControl(*this,
FR_SAFFIRE_CMD_ID_METERING_PC4,
"MeteringPc4", "Metering PC 4", "Metering on PC Channel 4"));
result &= m_MixerContainer->addElement(
new MeteringControl(*this,
FR_SAFFIRE_CMD_ID_METERING_PC5,
"MeteringPc5", "Metering PC 5", "Metering on PC Channel 5"));
result &= m_MixerContainer->addElement(
new MeteringControl(*this,
FR_SAFFIRE_CMD_ID_METERING_PC6,
"MeteringPc6", "Metering PC 6", "Metering on PC Channel 6"));
result &= m_MixerContainer->addElement(
new MeteringControl(*this,
FR_SAFFIRE_CMD_ID_METERING_PC7,
"MeteringPc7", "Metering PC 7", "Metering on PC Channel 7"));
result &= m_MixerContainer->addElement(
new MeteringControl(*this,
FR_SAFFIRE_CMD_ID_METERING_PC8,
"MeteringPc8", "Metering PC 8", "Metering on PC Channel 8"));
result &= m_MixerContainer->addElement(
new MeteringControl(*this,
FR_SAFFIRE_CMD_ID_METERING_PC9,
"MeteringPc9", "Metering PC 9", "Metering on PC Channel 9"));
result &= m_MixerContainer->addElement(
new MeteringControl(*this,
FR_SAFFIRE_CMD_ID_METERING_PC10,
"MeteringPc10", "Metering PC 10", "Metering on PC Channel 10"));
}
// matrix mix controls
if(m_isSaffireLE) {
result &= m_MixerContainer->addElement(
new SaffireMatrixMixer(*this, SaffireMatrixMixer::eMMT_LEMix48, "LEMix48"));
result &= m_MixerContainer->addElement(
new SaffireMatrixMixer(*this, SaffireMatrixMixer::eMMT_LEMix96, "LEMix96"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRELE_CMD_ID_SWAP_OUT4_OUT1_48K, 0,
"Swap41_48", "Swap41_48", "Swap41_48"));
result &= m_MixerContainer->addElement(
new BinaryControl(*this,
FR_SAFFIRELE_CMD_ID_SWAP_OUT4_OUT1_96K, 0,
"Swap41_96", "Swap41_96", "Swap41_96"));
} else {
result &= m_MixerContainer->addElement(
new SaffireMatrixMixer(*this, SaffireMatrixMixer::eMMT_SaffireStereoMatrixMix, "MatrixMixerStereo"));
result &= m_MixerContainer->addElement(
new SaffireMatrixMixer(*this, SaffireMatrixMixer::eMMT_SaffireMonoMatrixMix, "MatrixMixerMono"));
}
if (!result) {
debugWarning("One or more control elements could not be created.");
// clean up those that were created
destroyMixer();
return false;
}
if (!addElement(m_MixerContainer)) {
debugWarning("Could not register mixer to device\n");
// clean up
destroyMixer();
return false;
}
// add a direct register access element
if (!addElement(new RegisterControl(*this, "Register", "Register Access", "Direct register access"))) {
debugWarning("Could not create register control element.");
// clean up those that were created
destroyMixer();
return false;
}
return true;
}
bool
SaffireDevice::destroyMixer()
{
debugOutput(DEBUG_LEVEL_VERBOSE, "destroy mixer...\n");
if (m_MixerContainer == NULL) {
debugOutput(DEBUG_LEVEL_VERBOSE, "no mixer to destroy...\n");
return true;
}
if (!deleteElement(m_MixerContainer)) {
debugError("Mixer present but not registered to the avdevice\n");
return false;
}
// remove and delete (as in free) child control elements
m_MixerContainer->clearElements(true);
delete m_MixerContainer;
return true;
}
std::vector
SaffireDevice::getSupportedSamplingFrequencies()
{
std::vector frequencies;
frequencies.push_back(44100);
frequencies.push_back(48000);
frequencies.push_back(88200);
frequencies.push_back(96000);
return frequencies;
}
void
SaffireDevice::showDevice()
{
if(m_isSaffireLE) {
debugOutput(DEBUG_LEVEL_NORMAL, "This is a BeBoB::Focusrite::SaffireDevice (Saffire LE)\n");
} else {
debugOutput(DEBUG_LEVEL_NORMAL, "This is a BeBoB::Focusrite::SaffireDevice (Saffire)\n");
}
FocusriteDevice::showDevice();
}
void
SaffireDevice::setVerboseLevel(int l)
{
debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
FocusriteDevice::setVerboseLevel(l);
}
// Saffire pro matrix mixer element
SaffireMatrixMixer::SaffireMatrixMixer(SaffireDevice& p,
enum eMatrixMixerType type)
: FocusriteMatrixMixer(p, "MatrixMixer")
, m_type(type)
{
init();
}
SaffireMatrixMixer::SaffireMatrixMixer(SaffireDevice& p,
enum eMatrixMixerType type, std::string n)
: FocusriteMatrixMixer(p, n)
, m_type(type)
{
init();
}
void SaffireMatrixMixer::init()
{
if (m_type==eMMT_SaffireStereoMatrixMix) {
m_RowInfo.clear();
addSignalInfo(m_RowInfo, "PC910", "PC 9/10", "PC Channel 9/10");
addSignalInfo(m_RowInfo, "PC12", "PC 1/2", "PC Channel 1/2");
addSignalInfo(m_RowInfo, "PC34", "PC 3/4", "PC Channel 3/4");
addSignalInfo(m_RowInfo, "PC56", "PC 5/6", "PC Channel 5/6");
addSignalInfo(m_RowInfo, "PC78", "PC 7/8", "PC Channel 7/8");
addSignalInfo(m_RowInfo, "IN12", "Input 1/2", "Hardware Inputs 1/2");
addSignalInfo(m_RowInfo, "IN34", "Input 3/4", "Hardware Inputs 3/4 (dry / S/PDIF)");
addSignalInfo(m_RowInfo, "FX", "Effect return", "Effect return");
m_ColInfo.clear();
addSignalInfo(m_ColInfo, "OUT910", "OUT 9/10", "Output 9/10");
addSignalInfo(m_ColInfo, "OUT12", "OUT 1/2", "Output 1/2");
addSignalInfo(m_ColInfo, "OUT34", "OUT 3/4", "Output 3/4");
addSignalInfo(m_ColInfo, "OUT56", "OUT 5/6", "Output 5/6 (HP1)");
addSignalInfo(m_ColInfo, "OUT78", "OUT 7/8", "Output 7/8 (HP2)");
// init the cell matrix
#define FOCUSRITE_SAFFIRE_STEREO_MATRIXMIX_NB_COLS 5
#define FOCUSRITE_SAFFIRE_STEREO_MATRIXMIX_NB_ROWS 8
#define FOCUSRITE_SAFFIRE_STEREO_MATRIXMIX_OFFSET 0
std::vector tmp_cols( FOCUSRITE_SAFFIRE_STEREO_MATRIXMIX_NB_COLS );
std::vector< std::vector > tmp_all(FOCUSRITE_SAFFIRE_STEREO_MATRIXMIX_NB_ROWS, tmp_cols);
m_CellInfo = tmp_all;
struct sCellInfo c;
c.row=-1;
c.col=-1;
c.valid=false;
c.address=0;
// all cells are valid
for (int i=0; i < FOCUSRITE_SAFFIRE_STEREO_MATRIXMIX_NB_ROWS; i++) {
for (int j=0; j < FOCUSRITE_SAFFIRE_STEREO_MATRIXMIX_NB_COLS; j++) {
c.row = i;
c.col = j;
c.valid = true;
c.address = FOCUSRITE_SAFFIRE_STEREO_MATRIXMIX_OFFSET + c.row * FOCUSRITE_SAFFIRE_STEREO_MATRIXMIX_NB_COLS + c.col;
m_CellInfo.at(i).at(j) = c;
}
}
} else if (m_type==eMMT_SaffireMonoMatrixMix) {
m_RowInfo.clear();
addSignalInfo(m_RowInfo, "IN1", "Input 1", "Hardware Inputs 1");
addSignalInfo(m_RowInfo, "IN3", "Input 3", "Hardware Inputs 3");
addSignalInfo(m_RowInfo, "FX1", "Effect return 1", "Effect return 1");
addSignalInfo(m_RowInfo, "IN2", "Input 2", "Hardware Inputs 2");
addSignalInfo(m_RowInfo, "IN4", "Input 4", "Hardware Inputs 4");
addSignalInfo(m_RowInfo, "FX2", "Effect return 2", "Effect return 2");
addSignalInfo(m_RowInfo, "PC910", "PC 9/10", "PC Channel 9/10");
addSignalInfo(m_RowInfo, "PC12", "PC 1/2", "PC Channel 1/2");
addSignalInfo(m_RowInfo, "PC34", "PC 3/4", "PC Channel 3/4");
addSignalInfo(m_RowInfo, "PC56", "PC 5/6", "PC Channel 5/6");
addSignalInfo(m_RowInfo, "PC78", "PC 7/8", "PC Channel 7/8");
m_ColInfo.clear();
addSignalInfo(m_ColInfo, "OUT910", "OUT 9/10", "Output 9/10");
addSignalInfo(m_ColInfo, "OUT12", "OUT 1/2", "Output 1/2");
addSignalInfo(m_ColInfo, "OUT34", "OUT 3/4", "Output 3/4");
addSignalInfo(m_ColInfo, "OUT56", "OUT 5/6", "Output 5/6 (HP1)");
addSignalInfo(m_ColInfo, "OUT78", "OUT 7/8", "Output 7/8 (HP2)");
// init the cell matrix
#define FOCUSRITE_SAFFIRE_MONO_MATRIXMIX_NB_COLS 5
#define FOCUSRITE_SAFFIRE_MONO_MATRIXMIX_NB_ROWS 11
#define FOCUSRITE_SAFFIRE_MONO_MATRIXMIX_OFFSET 0
std::vector tmp_cols( FOCUSRITE_SAFFIRE_MONO_MATRIXMIX_NB_COLS );
std::vector< std::vector > tmp_all(FOCUSRITE_SAFFIRE_MONO_MATRIXMIX_NB_ROWS, tmp_cols);
m_CellInfo = tmp_all;
struct sCellInfo c;
c.row=-1;
c.col=-1;
c.valid=false;
c.address=0;
// all cells are valid
for (int i=0; i < FOCUSRITE_SAFFIRE_MONO_MATRIXMIX_NB_ROWS; i++) {
for (int j=0; j < FOCUSRITE_SAFFIRE_MONO_MATRIXMIX_NB_COLS; j++) {
c.row = i;
c.col = j;
c.valid = true;
c.address = FOCUSRITE_SAFFIRE_MONO_MATRIXMIX_OFFSET + c.row * FOCUSRITE_SAFFIRE_MONO_MATRIXMIX_NB_COLS + c.col;
m_CellInfo.at(i).at(j) = c;
}
}
} else if (m_type == eMMT_LEMix48) {
addSignalInfo(m_RowInfo, "IN1", "Input 1", "Analog Input 1");
addSignalInfo(m_RowInfo, "IN2", "Input 2", "Analog Input 2");
addSignalInfo(m_RowInfo, "IN3", "Input 3", "Analog Input 3");
addSignalInfo(m_RowInfo, "IN4", "Input 4", "Analog Input 4");
addSignalInfo(m_RowInfo, "SPDIFL", "SPDIF L", "S/PDIF Left Input");
addSignalInfo(m_RowInfo, "SPDIFR", "SPDIF R", "S/PDIF Right Input");
addSignalInfo(m_RowInfo, "PC1", "PC 1", "PC Channel 1");
addSignalInfo(m_RowInfo, "PC2", "PC 2", "PC Channel 2");
addSignalInfo(m_RowInfo, "PC3", "PC 3", "PC Channel 3");
addSignalInfo(m_RowInfo, "PC4", "PC 4", "PC Channel 4");
addSignalInfo(m_RowInfo, "PC5", "PC 5", "PC Channel 5");
addSignalInfo(m_RowInfo, "PC6", "PC 6", "PC Channel 6");
addSignalInfo(m_RowInfo, "PC7", "PC 7", "PC Channel 7");
addSignalInfo(m_RowInfo, "PC8", "PC 8", "PC Channel 8");
addSignalInfo(m_ColInfo, "OUT1", "OUT 1", "Output 1");
addSignalInfo(m_ColInfo, "OUT2", "OUT 2", "Output 2");
addSignalInfo(m_ColInfo, "OUT3", "OUT 3", "Output 3");
addSignalInfo(m_ColInfo, "OUT4", "OUT 4", "Output 4");
// init the cell matrix
#define FOCUSRITE_SAFFIRELE_48KMIX_NB_COLS 4
#define FOCUSRITE_SAFFIRELE_48KMIX_NB_ROWS 14
std::vector tmp_cols( FOCUSRITE_SAFFIRELE_48KMIX_NB_COLS );
std::vector< std::vector > tmp_all(FOCUSRITE_SAFFIRELE_48KMIX_NB_ROWS,tmp_cols);
m_CellInfo = tmp_all;
struct sCellInfo c;
c.row=-1;
c.col=-1;
c.valid=false;
c.address=0;
for (int i=0;i tmp_cols( FOCUSRITE_SAFFIRELE_96KMIX_NB_COLS );
std::vector< std::vector > tmp_all(FOCUSRITE_SAFFIRELE_96KMIX_NB_ROWS,tmp_cols);
m_CellInfo = tmp_all;
struct sCellInfo c;
c.row=-1;
c.col=-1;
c.valid=false;
c.address=0;
for (int i=0;i