diff options
Diffstat (limited to 'meta-agl-profile-core')
130 files changed, 17696 insertions, 0 deletions
diff --git a/meta-agl-profile-core/classes/cloc.bbclass b/meta-agl-profile-core/classes/cloc.bbclass new file mode 100644 index 000000000..53713bfc3 --- /dev/null +++ b/meta-agl-profile-core/classes/cloc.bbclass @@ -0,0 +1,29 @@ +# (C) 2017 Jan-Simon Möller <dl9pf@gmx.de> +# +# License: GPLv2 +# +# summary with +# cloc --sum-reports `find . -name "*clocreport" | grep -v "\-native" ` --out summary.report + +CLOC_DIRECTORY ??= "${DEPLOY_DIR}/cloc/" +CLOCSTATEDIR = "${WORKDIR}/cloc-destdir/" + +python do_cloc() { + + import subprocess + + source_dir = d.getVar('S', True) + pn = d.getVar('PN', True) + + destdir = d.expand('${CLOCSTATEDIR}') + bb.utils.mkdirhier(destdir) + + cloc_cmd = 'cloc %s -q --out=%s/%s.clocreport' % (source_dir, destdir, pn ) + subprocess.call(cloc_cmd, shell=True) + +} + + +addtask cloc before do_configure after do_unpack + +EXPORT_FUNCTIONS do_cloc diff --git a/meta-agl-profile-core/conf/include/agl-devel.inc b/meta-agl-profile-core/conf/include/agl-devel.inc new file mode 100644 index 000000000..705b1739a --- /dev/null +++ b/meta-agl-profile-core/conf/include/agl-devel.inc @@ -0,0 +1,15 @@ +IMAGE_FEATURES =+ "debug-tweaks eclipse-debug tools-debug tools-profile" + +#IMAGE_INSTALL_append = " \ +# packagegroup-agl-core-devel \ +#" + +IMAGE_INSTALL_append = "${@bb.utils.contains('IMAGE_FSTYPES', 'wic.vmdk', ' open-vm-tools vboxguestdrivers', '', d)}" + +# disable install of debug files in SDK +# initial value: SDKIMAGE_FEATURES="dev-pkgs dbg-pkgs staticdev-pkgs" +SDKIMAGE_FEATURES="dev-pkgs" + +# allows insertion of code or items specific to developement +OVERRIDES .= ":agl-devel" +DISTRO_FEATURES_append = " agl-devel" diff --git a/meta-agl-profile-core/conf/include/agl-gplv2.inc b/meta-agl-profile-core/conf/include/agl-gplv2.inc new file mode 100644 index 000000000..fc9a4072b --- /dev/null +++ b/meta-agl-profile-core/conf/include/agl-gplv2.inc @@ -0,0 +1,8 @@ +# GPLv3 Compliance +PREFERRED_VERSION_bash = "3.2.%" +PREFERRED_VERSION_gawk = "3.1.%" +PREFERRED_VERSION_gdbm = "1.8.%" +PREFERRED_VERSION_gnupg = "1.4.7" +PREFERRED_VERSION_gnutls = "3.3.%" +PREFERRED_VERSION_mc = "4.7.5.%" +PREFERRED_VERSION_readline = "5.2" diff --git a/meta-agl-profile-core/conf/include/base-agl.inc b/meta-agl-profile-core/conf/include/base-agl.inc new file mode 100644 index 000000000..a332c08a4 --- /dev/null +++ b/meta-agl-profile-core/conf/include/base-agl.inc @@ -0,0 +1,19 @@ +# AGL includes all kernel modules here for ease-of-use during development. +# Comment this out to be able to select the kernel modules yourself. +IMAGE_INSTALL_append = " kernel-modules" + +# Likewise as we included all kernel modules by default in the filesystem, +# we do not need a separate tarball stored. +# Comment this out to receive the separate modules tarball again. +MODULE_TARBALL_DEPLOY ?= "0" + +# Comment out below if want to use QtWebkit +PACKAGECONFIG_remove_pn-qtquick1 = "webkit" + + +ASSUME_PROVIDED_remove = "tar-native" + +# Use static IDs to enable full-filesystem updates +USERADDEXTENSION = "useradd-staticids" +USERADD_ERROR_DYNAMIC = "error" + diff --git a/meta-agl-profile-core/conf/layer.conf b/meta-agl-profile-core/conf/layer.conf new file mode 100644 index 000000000..83c5555bc --- /dev/null +++ b/meta-agl-profile-core/conf/layer.conf @@ -0,0 +1,10 @@ +# We have a conf and classes directory, add to BBPATH +BBPATH =. "${LAYERDIR}:" + +# We have recipes-* directories, add to BBFILES +BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \ + ${LAYERDIR}/recipes-*/*/*.bbappend" + +BBFILE_COLLECTIONS += "aglprofilecore" +BBFILE_PATTERN_aglprofilecore = "^${LAYERDIR}/" +BBFILE_PRIORITY_aglprofilecore = "80" diff --git a/meta-agl-profile-core/files/group b/meta-agl-profile-core/files/group new file mode 100644 index 000000000..f8a3843bd --- /dev/null +++ b/meta-agl-profile-core/files/group @@ -0,0 +1,90 @@ +root::0: +daemon::1: +bin::2: +sys::3: +adm::4: +tty::5: +disk::6: +lp::7: +mail::8: +news::9: +uucp::10: +man::12: +proxy::13: +kmem::15: +input::19: +dialout::20: +fax::21: +voice::22: +cdrom::24: +floppy::25: +tape::26: +sudo::27: +audio::29: +dip::30: +www-data::33: +backup::34: +operator::37: +list::38: +irc::39: +src::40: +gnats::41: +shadow::42: +utmp::43: +video::44: +sasl::45: +plugdev::46: +staff::50: +games::60: +shutdown::70: +users::100: +nogroup::65534: +cynara::999: +dhcp::998: +avahi::997: +tracing::1000: +sshd::996: +systemd-bus-proxy::995: +netdev::993: +messagebus::994: +afm::992: +weston-launch::986: +lock::990: +systemd-journal::989: +systemd-timesync::988: +pulse::991: +bind::987: +trinity::985: +mpd::984: +mysql::983: +polkitd::982: +datetime::981: +network::980: +zabbix::979: +nm-openvpn::978: +xuser::1002: +builder::977: +rpc::976: +crontab::975: +lpadmin::974: +_apt::972: +rpcuser::970: +avahi-autoipd::969: +ntp::968: +dovecot::967: +dovenull::966: +quagga::965: +quaggavty::964: +rwhod::963: +ftp::962: +squid::960: +postfix::959: +vmail::958: +opensaf::957: +lldpd::956: +postdrop::954: +display::200: +agl-driver::1001: +agl-passenger::1002: +systemd-network::1005: +systemd-resolve::1006: diff --git a/meta-agl-profile-core/files/passwd b/meta-agl-profile-core/files/passwd new file mode 100644 index 000000000..754cb819a --- /dev/null +++ b/meta-agl-profile-core/files/passwd @@ -0,0 +1,60 @@ +root::0:0::: +daemon::1:1::: +bin::2:2::: +sys::3:3::: +sync::4:65534::: +games::5:60::: +man::6:12::: +lp::7:7::: +mail::8:8::: +news::9:9::: +uucp::10:10::: +proxy::13:13::: +www-data::33:33::: +backup::34:34::: +list::38:38::: +irc::39:39::: +gnats::41:41::: +nobody::65534:65534::: +cynara::999:999::: +dhcp::998:998::: +avahi::997:997::: +sshd::996:996::: +systemd-bus-proxy::995:995::: +agl-driver::1001:1001::: +agl-passenger::1002:1002::: +messagebus::994:994::: +afm::992:992::: +systemd-timesync::988:988::: +pulse::991:991::: +bind::987:987::: +trinity::985:985::: +mpd::984:984::: +mysql::983:983::: +polkitd::982:982::: +zabbix::979:979::: +nm-openvpn::978:978::: +xuser::1002:1002::: +builder::977:977::: +rpc::976:976::: +distcc::973:65534::: +_apt::972:972::: +ppp::971:65534::: +rpcuser::970:970::: +avahi-autoipd::969:969::: +ntp::968:968::: +dovecot::967:967::: +dovenull::966:966::: +quagga::965:965::: +rwhod::963:963::: +ftp::962:962::: +radvd::961:65534::: +squid::960:960::: +postfix::959:959::: +vmail::958:958::: +opensaf::957:957::: +lldpd::956:956::: +cyrus::955:8::: +display::200:200::: +systemd-network::1005:1005::: +systemd-resolve::1006:1006::: diff --git a/meta-agl-profile-core/recipes-core/dbus/.appends.core b/meta-agl-profile-core/recipes-core/dbus/.appends.core new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/meta-agl-profile-core/recipes-core/dbus/.appends.core diff --git a/meta-agl-profile-core/recipes-core/dbus/dbus-cynara_%.bbappend b/meta-agl-profile-core/recipes-core/dbus/dbus-cynara_%.bbappend new file mode 120000 index 000000000..fcdfb1783 --- /dev/null +++ b/meta-agl-profile-core/recipes-core/dbus/dbus-cynara_%.bbappend @@ -0,0 +1 @@ +dbus_%.bbappend
\ No newline at end of file diff --git a/meta-agl-profile-core/recipes-core/dbus/dbus/dbus.service b/meta-agl-profile-core/recipes-core/dbus/dbus/dbus.service new file mode 100644 index 000000000..dee6ad741 --- /dev/null +++ b/meta-agl-profile-core/recipes-core/dbus/dbus/dbus.service @@ -0,0 +1,10 @@ +[Unit] +Description=D-Bus User Message Bus +Documentation=man:dbus-daemon(1) +Requires=dbus.socket + +[Service] +ExecStart=/usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation +ExecReload=/usr/bin/dbus-send --print-reply --session --type=method_call --dest=org.freedesktop.DBus / org.freedesktop.DBus.ReloadConfig +Restart=always +RestartSec=1 diff --git a/meta-agl-profile-core/recipes-core/dbus/dbus/dbus.socket b/meta-agl-profile-core/recipes-core/dbus/dbus/dbus.socket new file mode 100644 index 000000000..af76b2f12 --- /dev/null +++ b/meta-agl-profile-core/recipes-core/dbus/dbus/dbus.socket @@ -0,0 +1,9 @@ +[Unit] +Description=D-Bus User Message Bus Socket +Before=sockets.target + +[Socket] +ListenStream=%t/bus + +[Install] +WantedBy=default.target diff --git a/meta-agl-profile-core/recipes-core/dbus/dbus/dbus_env.conf b/meta-agl-profile-core/recipes-core/dbus/dbus/dbus_env.conf new file mode 100644 index 000000000..f8f02669b --- /dev/null +++ b/meta-agl-profile-core/recipes-core/dbus/dbus/dbus_env.conf @@ -0,0 +1,5 @@ +[Unit] +Wants=dbus.service + +[Service] +Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/%I/bus diff --git a/meta-agl-profile-core/recipes-core/dbus/dbus_%.bbappend b/meta-agl-profile-core/recipes-core/dbus/dbus_%.bbappend new file mode 100644 index 000000000..e63ea0f28 --- /dev/null +++ b/meta-agl-profile-core/recipes-core/dbus/dbus_%.bbappend @@ -0,0 +1,28 @@ +FILESEXTRAPATHS_append := ":${THISDIR}/dbus" + +SRC_URI_append = "file://dbus.service \ + file://dbus.socket \ + file://dbus_env.conf \ + " + +inherit systemd + +do_install_append() { + if [ "${PN}" != "nativesdk-dbus" ]; then + if ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'true', 'false', d)}; then + install -m 644 -p -D ${WORKDIR}/dbus.service ${D}${systemd_user_unitdir}/dbus.service + install -m 644 -p -D ${WORKDIR}/dbus.socket ${D}${systemd_user_unitdir}/dbus.socket + install -m 644 -p -D ${WORKDIR}/dbus_env.conf ${D}${systemd_system_unitdir}/user@.service.d/dbus_env.conf + + # Execute these manually on behalf of systemctl script (from systemd-systemctl-native.bb) + # because it does not support systemd's user mode. + mkdir -p ${D}/etc/systemd/user/default.target.wants/ + ln -sf ${systemd_user_unitdir}/dbus.socket ${D}/etc/systemd/user/default.target.wants/dbus.socket + fi + fi +} + +FILES_${PN} += " \ + ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', '${systemd_user_unitdir}/dbus.*', '', d)} \ + ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', '${systemd_system_unitdir}/user@.service.d/dbus_env.conf', '', d)} \ + " diff --git a/meta-agl-profile-core/recipes-core/glibc/.appends.core b/meta-agl-profile-core/recipes-core/glibc/.appends.core new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/meta-agl-profile-core/recipes-core/glibc/.appends.core diff --git a/meta-agl-profile-core/recipes-core/glibc/glibc/arm/local-arm-futex.diff b/meta-agl-profile-core/recipes-core/glibc/glibc/arm/local-arm-futex.diff new file mode 100644 index 000000000..27d1144d0 --- /dev/null +++ b/meta-agl-profile-core/recipes-core/glibc/glibc/arm/local-arm-futex.diff @@ -0,0 +1,22 @@ +Description: Lie about futex_atomic_cmpxchg_inatomic kernel support. + In past versions of glibc, we incorrectly assumed all ARM kernels + in all configurations supported futex_atomic_cmpxchg_inatomic. This + was clearly a lie, however it was a lie that we relied on, because + the fallback implementation appears to not play nicely with certain + applications like pulseaudio. Restore the lie for kernels > 2.6.32 + and plug our ears and scream "LA LA LA" about how wrong this is. +Author: Adam Conrad <adconrad@ubuntu.com> +Bug-Ubuntu: https://launchpad.net/bugs/1436162 +Bug-Debian: https://bugs.debian.org/788799 +Last-Update: 2015-03-25 + +--- a/sysdeps/unix/sysv/linux/arm/kernel-features.h ++++ b/sysdeps/unix/sysv/linux/arm/kernel-features.h +@@ -22,7 +22,7 @@ + /* The ARM kernel before 3.14.3 may or may not support + futex_atomic_cmpxchg_inatomic, depending on kernel + configuration. */ +-#if __LINUX_KERNEL_VERSION < 0x030E03 ++#if __LINUX_KERNEL_VERSION < 0x020620 + # undef __ASSUME_SET_ROBUST_LIST + #endif diff --git a/meta-agl-profile-core/recipes-core/glibc/glibc_2.2%.bbappend b/meta-agl-profile-core/recipes-core/glibc/glibc_2.2%.bbappend new file mode 100644 index 000000000..0868a2c7d --- /dev/null +++ b/meta-agl-profile-core/recipes-core/glibc/glibc_2.2%.bbappend @@ -0,0 +1,3 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI_append_arm = " file://arm/local-arm-futex.diff " diff --git a/meta-agl-profile-core/recipes-core/images/agl-image-boot.bb b/meta-agl-profile-core/recipes-core/images/agl-image-boot.bb new file mode 100644 index 000000000..84cdbcf31 --- /dev/null +++ b/meta-agl-profile-core/recipes-core/images/agl-image-boot.bb @@ -0,0 +1,9 @@ +SUMMARY = "An AGL small image just capable of allowing a device to boot." + +require agl-image-boot.inc + +LICENSE = "MIT" + +IMAGE_INSTALL_append = "\ + packagegroup-agl-image-boot \ + " diff --git a/meta-agl-profile-core/recipes-core/images/agl-image-boot.inc b/meta-agl-profile-core/recipes-core/images/agl-image-boot.inc new file mode 100644 index 000000000..825393978 --- /dev/null +++ b/meta-agl-profile-core/recipes-core/images/agl-image-boot.inc @@ -0,0 +1,10 @@ +IMAGE_LINGUAS = " " + +inherit core-image + +IMAGE_INSTALL = "${CORE_IMAGE_EXTRA_INSTALL}" + +IMAGE_ROOTFS_SIZE ?= "8192" + +# Allow extra IMAGE_FSTYPES to be added by boards configs +IMAGE_FSTYPES += "${AGL_EXTRA_IMAGE_FSTYPES}" diff --git a/meta-agl-profile-core/recipes-core/images/agl-image-minimal-qa.bb b/meta-agl-profile-core/recipes-core/images/agl-image-minimal-qa.bb new file mode 100644 index 000000000..b162f2904 --- /dev/null +++ b/meta-agl-profile-core/recipes-core/images/agl-image-minimal-qa.bb @@ -0,0 +1,12 @@ +SUMMARY = "An AGL small image just capable of allowing a device to boot and run tests." + +DESCRIPTION = "A minimal set of AGL Distribution. This image also has additional \ +packages (e.g. commandline tools) for Quality Assurance(QA)." + +require agl-image-minimal.bb + +LICENSE = "MIT" + +IMAGE_INSTALL_append = " \ + packagegroup-ivi-common-test \ + " diff --git a/meta-agl-profile-core/recipes-core/images/agl-image-minimal.bb b/meta-agl-profile-core/recipes-core/images/agl-image-minimal.bb new file mode 100644 index 000000000..1fd213d0f --- /dev/null +++ b/meta-agl-profile-core/recipes-core/images/agl-image-minimal.bb @@ -0,0 +1,9 @@ +SUMMARY = "An AGL small image just capable of allowing a device to boot." + +require agl-image-minimal.inc + +LICENSE = "MIT" + +IMAGE_INSTALL_append = "\ + packagegroup-agl-image-minimal \ + " diff --git a/meta-agl-profile-core/recipes-core/images/agl-image-minimal.inc b/meta-agl-profile-core/recipes-core/images/agl-image-minimal.inc new file mode 100644 index 000000000..825393978 --- /dev/null +++ b/meta-agl-profile-core/recipes-core/images/agl-image-minimal.inc @@ -0,0 +1,10 @@ +IMAGE_LINGUAS = " " + +inherit core-image + +IMAGE_INSTALL = "${CORE_IMAGE_EXTRA_INSTALL}" + +IMAGE_ROOTFS_SIZE ?= "8192" + +# Allow extra IMAGE_FSTYPES to be added by boards configs +IMAGE_FSTYPES += "${AGL_EXTRA_IMAGE_FSTYPES}" diff --git a/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-automotive.bb b/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-automotive.bb new file mode 100644 index 000000000..d9f2279e1 --- /dev/null +++ b/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-automotive.bb @@ -0,0 +1,13 @@ +DESCRIPTION = "The minimal set of packages for Automotive Subsystem" +LICENSE = "MIT" + +inherit packagegroup + +PACKAGES = "\ + packagegroup-agl-core-automotive \ + " + +ALLOW_EMPTY_${PN} = "1" + +RDEPENDS_${PN} += "\ + " diff --git a/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-connectivity.bb b/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-connectivity.bb new file mode 100644 index 000000000..e909d5e5f --- /dev/null +++ b/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-connectivity.bb @@ -0,0 +1,15 @@ +DESCRIPTION = "The minimal set of packages for Connectivity Subsystem" +LICENSE = "MIT" + +inherit packagegroup + +PACKAGES = "\ + packagegroup-agl-core-connectivity \ + " + +ALLOW_EMPTY_${PN} = "1" + +RDEPENDS_${PN} += "\ + dhcp-server \ + ${@bb.utils.contains('VIRTUAL-RUNTIME_net_manager','connman','connman connman-client connman-tests connman-tools connman-ncurses','',d)} \ + " diff --git a/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-graphics.bb b/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-graphics.bb new file mode 100644 index 000000000..1cc6f457b --- /dev/null +++ b/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-graphics.bb @@ -0,0 +1,10 @@ +DESCRIPTION = "The minimal set of packages for Graphics Subsystem" +LICENSE = "MIT" + +inherit packagegroup + +PACKAGES = "\ + packagegroup-agl-core-graphics \ + " + +ALLOW_EMPTY_${PN} = "1" diff --git a/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-kernel.bb b/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-kernel.bb new file mode 100644 index 000000000..3d5556fd5 --- /dev/null +++ b/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-kernel.bb @@ -0,0 +1,13 @@ +DESCRIPTION = "The minimal set of packages for Kernel Subsystem" +LICENSE = "MIT" + +inherit packagegroup + +PACKAGES = "\ + packagegroup-agl-core-kernel \ + " + +ALLOW_EMPTY_${PN} = "1" + +RDEPENDS_${PN} += "\ + " diff --git a/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-multimedia.bb b/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-multimedia.bb new file mode 100644 index 000000000..01ca4cb85 --- /dev/null +++ b/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-multimedia.bb @@ -0,0 +1,13 @@ +DESCRIPTION = "The minimal set of packages for Multimedia Subsystem" +LICENSE = "MIT" + +inherit packagegroup + +PACKAGES = "\ + packagegroup-agl-core-multimedia \ + " + +ALLOW_EMPTY_${PN} = "1" + +RDEPENDS_${PN} += "\ + " diff --git a/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-navi-lbs.bb b/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-navi-lbs.bb new file mode 100644 index 000000000..2b04d5387 --- /dev/null +++ b/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-navi-lbs.bb @@ -0,0 +1,13 @@ +DESCRIPTION = "The minimal set of packages for Navigation and Location Based Services Subsystem" +LICENSE = "MIT" + +inherit packagegroup + +PACKAGES = "\ + packagegroup-agl-core-navi-lbs \ + " + +ALLOW_EMPTY_${PN} = "1" + +RDEPENDS_${PN} += "\ + " diff --git a/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-os-commonlibs.bb b/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-os-commonlibs.bb new file mode 100644 index 000000000..c44166e12 --- /dev/null +++ b/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-os-commonlibs.bb @@ -0,0 +1,13 @@ +DESCRIPTION = "The minimal set of packages for Operating System and Common libraries Subsystem" +LICENSE = "MIT" + +inherit packagegroup + +PACKAGES = "\ + packagegroup-agl-core-os-commonlibs \ + " + +ALLOW_EMPTY_${PN} = "1" + +RDEPENDS_${PN} += "\ + " diff --git a/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-security.bb b/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-security.bb new file mode 100644 index 000000000..eb5a68f0a --- /dev/null +++ b/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-security.bb @@ -0,0 +1,13 @@ +DESCRIPTION = "The minimal set of packages for Security Subsystem" +LICENSE = "MIT" + +inherit packagegroup + +PACKAGES = "\ + packagegroup-agl-core-security \ + " + +ALLOW_EMPTY_${PN} = "1" + +RDEPENDS_${PN} += "\ + " diff --git a/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-speech-services.bb b/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-speech-services.bb new file mode 100644 index 000000000..a494e5889 --- /dev/null +++ b/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-core-speech-services.bb @@ -0,0 +1,13 @@ +DESCRIPTION = "The minimal set of packages for Speech Services Subsystem" +LICENSE = "MIT" + +inherit packagegroup + +PACKAGES = "\ + packagegroup-agl-core-speech-services \ + " + +ALLOW_EMPTY_${PN} = "1" + +RDEPENDS_${PN} += "\ + " diff --git a/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-image-boot.bb b/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-image-boot.bb new file mode 100644 index 000000000..29f859c49 --- /dev/null +++ b/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-image-boot.bb @@ -0,0 +1,18 @@ +DESCRIPTION = "The minimal set of packages required by AGL" +LICENSE = "MIT" + +inherit packagegroup + +PACKAGES = "\ + packagegroup-agl-image-boot \ + " + +ALLOW_EMPTY_${PN} = "1" + +RDEPENDS_${PN} += "\ + packagegroup-core-boot-agl \ + " + + +RDEPENDS_${PN} += "\ + " diff --git a/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-image-minimal.bb b/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-image-minimal.bb new file mode 100644 index 000000000..630c11d43 --- /dev/null +++ b/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-agl-image-minimal.bb @@ -0,0 +1,27 @@ +DESCRIPTION = "The minimal set of packages required by AGL" +LICENSE = "MIT" + +inherit packagegroup + +PACKAGES = "\ + packagegroup-agl-image-minimal \ + " + +ALLOW_EMPTY_${PN} = "1" + +RDEPENDS_${PN} += "\ + packagegroup-core-boot-agl \ + " + + +RDEPENDS_${PN} += "\ + packagegroup-agl-core-automotive \ + packagegroup-agl-core-connectivity \ + packagegroup-agl-core-graphics \ + packagegroup-agl-core-multimedia \ + packagegroup-agl-core-navi-lbs \ + packagegroup-agl-core-os-commonlibs \ + packagegroup-agl-core-speech-services \ + packagegroup-agl-core-security \ + packagegroup-agl-core-kernel \ + " diff --git a/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-core-boot-agl.bb b/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-core-boot-agl.bb new file mode 100644 index 000000000..c9d679879 --- /dev/null +++ b/meta-agl-profile-core/recipes-core/packagegroups/packagegroup-core-boot-agl.bb @@ -0,0 +1,50 @@ +# +# Copyright (C) 2007 OpenedHand Ltd. +# +# derived from oe-core: meta/recipes-core/packagegroups/packagegroup-core-boot.bb + +SUMMARY = "Minimal boot requirements" +DESCRIPTION = "The minimal set of packages required to boot the system" +LICENSE = "MIT" + +PACKAGE_ARCH = "${MACHINE_ARCH}" + +inherit packagegroup + +# +# Set by the machine configuration with packages essential for device bootup +# +MACHINE_ESSENTIAL_EXTRA_RDEPENDS ?= "" +MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS ?= "" + +# Distro can override the following VIRTUAL-RUNTIME providers: +VIRTUAL-RUNTIME_dev_manager ?= "udev" +VIRTUAL-RUNTIME_login_manager ?= "busybox" +VIRTUAL-RUNTIME_init_manager ?= "sysvinit" +VIRTUAL-RUNTIME_initscripts ?= "initscripts" +VIRTUAL-RUNTIME_keymaps ?= "keymaps" + +SYSVINIT_SCRIPTS = "${@bb.utils.contains('MACHINE_FEATURES', 'rtc', 'busybox-hwclock', '', d)} \ + modutils-initscripts \ + init-ifupdown \ + ${VIRTUAL-RUNTIME_initscripts} \ + " + +RDEPENDS_${PN} = "\ + base-files \ + base-passwd \ + busybox \ + run-agl-postinsts \ + ${@bb.utils.contains("DISTRO_FEATURES", "sysvinit", "${SYSVINIT_SCRIPTS}", "", d)} \ + ${@bb.utils.contains("MACHINE_FEATURES", "keyboard", "${VIRTUAL-RUNTIME_keymaps}", "", d)} \ + netbase \ + ${VIRTUAL-RUNTIME_login_manager} \ + ${VIRTUAL-RUNTIME_init_manager} \ + ${VIRTUAL-RUNTIME_dev_manager} \ + ${VIRTUAL-RUNTIME_update-alternatives} \ + ${MACHINE_ESSENTIAL_EXTRA_RDEPENDS}" + +RRECOMMENDS_${PN} = "\ + tzdata \ + ${MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS}" + diff --git a/meta-agl-profile-core/recipes-core/psplash/.appends.core b/meta-agl-profile-core/recipes-core/psplash/.appends.core new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/meta-agl-profile-core/recipes-core/psplash/.appends.core diff --git a/meta-agl-profile-core/recipes-core/psplash/files/psplash-anim b/meta-agl-profile-core/recipes-core/psplash/files/psplash-anim new file mode 100755 index 000000000..ac9bf674a --- /dev/null +++ b/meta-agl-profile-core/recipes-core/psplash/files/psplash-anim @@ -0,0 +1,11 @@ +#/bin/bash + +psplash-default "$@" & +sleep .2 +while :; do + for x in 0 1 2 3 4 5 6 7 8 9 10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 -1 -2 -3 -4 -5 -6 -7 -8 -9 10 9 8 7 6 5 4 3 2 1; do + psplash-write "PROGRESS ${x}0" || exit 0 + psplash-write "MSG $(journalctl -n1 -ocat)" || exit 0 + sleep .1 + done +done diff --git a/meta-agl-profile-core/recipes-core/psplash/files/psplash-colors.h b/meta-agl-profile-core/recipes-core/psplash/files/psplash-colors.h new file mode 100644 index 000000000..447490397 --- /dev/null +++ b/meta-agl-profile-core/recipes-core/psplash/files/psplash-colors.h @@ -0,0 +1,34 @@ +/* + * pslash - a lightweight framebuffer splashscreen for embedded devices. + * + * Copyright (c) 2012 sleep(5) ltd + * Author: Tomas Frydrych <tomas@sleepfive.com> + * + * 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, 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. + * + */ + +#ifndef _HAVE_PSPLASH_COLORS_H +#define _HAVE_PSPLASH_COLORS_H + +/* This is the overall background color */ +#define PSPLASH_BACKGROUND_COLOR 0xff,0xff,0xff + +/* This is the color of any text output */ +#define PSPLASH_TEXT_COLOR 0x00,0x00,0x00 + +/* This is the color of the progress bar indicator */ +#define PSPLASH_BAR_COLOR 0x00,0x00,0x00 + +/* This is the color of the progress bar background */ +#define PSPLASH_BAR_BACKGROUND_COLOR 0xff,0xff,0xff + +#endif diff --git a/meta-agl-profile-core/recipes-core/psplash/files/psplash-poky-img.h b/meta-agl-profile-core/recipes-core/psplash/files/psplash-poky-img.h new file mode 100644 index 000000000..c0e8b0818 --- /dev/null +++ b/meta-agl-profile-core/recipes-core/psplash/files/psplash-poky-img.h @@ -0,0 +1,5411 @@ +/* GdkPixbuf RGB C-Source image dump 1-byte-run-length-encoded */ + +#define POKY_IMG_ROWSTRIDE (1800) +#define POKY_IMG_WIDTH (600) +#define POKY_IMG_HEIGHT (400) +#define POKY_IMG_BYTES_PER_PIXEL (3) /* 3:RGB, 4:RGBA */ +#define POKY_IMG_RLE_PIXEL_DATA ((uint8*) \ + "\377\377\377\377\377\377\377\377\203\377\377\377\1\376\376\376\221\377" \ + "\377\377\1\376\376\376\215\377\377\377\1\376\376\376\203\377\377\377" \ + "\1\376\376\376\233\377\377\377\1\376\376\376\203\377\377\377\1\376\376" \ + "\376\202\377\377\377\5\376\376\376\377\377\377\376\376\376\377\377\377" \ + "\376\376\376\206\377\377\377\1\376\376\376\203\377\377\377\1\376\376" \ + "\376\204\377\377\377\1\376\376\376\203\377\377\377\5\376\376\376\377" \ + "\377\377\376\376\376\377\377\377\376\376\376\377\377\377\377\377\377" \ + "\377\377\377\377\377\377\377\377\377\377\202\376\376\376\207\377\377" \ + "\377\1\376\376\376\205\377\377\377\1\376\376\376\211\377\377\377\3\376" \ + "\376\376\377\377\377\376\376\376\235\377\377\377\1\376\376\376\203\377" \ + "\377\377\1\376\376\376\213\377\377\377\3\376\376\376\377\377\377\376" \ + "\376\376\216\377\377\377\1\376\376\376\202\377\377\377\1\376\376\376" \ + "\377\377\377\377\377\377\377\377\377\377\377\377\365\377\377\377\1\376" \ + "\376\376\203\377\377\377\1\376\376\376\207\377\377\377\1\376\376\376" \ + "\203\377\377\377\1\376\376\376\202\377\377\377\1\376\376\376\205\377" \ + "\377\377\1\376\376\376\203\377\377\377\12\376\376\376\377\377\377\346" \ + "\346\346\315\315\315\316\316\316\265\265\265\235\235\235\234\234\234" \ + "\233\233\233\204\204\204\203kkm\202lln\2EEG;;=\215::<\204kkm\3kkkxxx" \ + "\235\235\235\202\234\234\234\1\265\265\265\202\316\316\316\1\332\332" \ + "\332\207\377\377\377\202\376\376\376\2\377\377\377\376\376\376\211\377" \ + "\377\377\3\376\376\376\377\377\377\376\376\376\203\377\377\377\5\376" \ + "\376\376\377\377\377\376\376\376\377\377\377\376\376\376\377\377\377" \ + "\377\377\377\377\377\377\377\377\377\366\377\377\377\1\376\376\376\205" \ + "\377\377\377\1\376\376\376\214\377\377\377\11\376\376\376\332\332\332" \ + "\316\316\320\247\247\251\236\236\240\204\204\206kkm__a<<>\202::<\11;" \ + ";=99;;;=99;::<;;=::<;;=99;\203::<\1<<>\213::<\13;;=::<;;=::<;;=::<;;" \ + "=::<;;=::<;;=\207::<\3SSUllnxxz\202\234\234\236\202\316\316\316\2\377" \ + "\377\377\376\376\376\214\377\377\377\1\376\376\376\203\377\377\377\1" \ + "\376\376\376\377\377\377\377\377\377\377\377\377\377\377\377\376\377" \ + "\377\377\1\376\376\376\203\377\377\377\1\376\376\376\203\377\377\377" \ + "\7\332\332\334\302\302\304\234\234\236\203\203\205llnEEG;;=\202::<\6" \ + ";;=::<;;=::<;;=99;\204::<\1""99;\202;;=\1""99;\205::<\1;;=\213::<\11" \ + ";;=::<;;=::<;;=::<;;=::<;;=\202::<\1""99;\206::<\1;;=\203::<\13;;=99" \ + ";;;=::<;;=::<kkmxxz\234\234\236\300\300\302\316\316\316\203\377\377\377" \ + "\1\376\376\376\202\377\377\377\1\376\376\376\203\377\377\377\1\376\376" \ + "\376\204\377\377\377\1\376\376\376\377\377\377\377\377\377\377\377\377" \ + "\377\377\377\374\377\377\377\7\346\346\350\301\301\303\235\235\237ww" \ + "y``b99;;;=\202::<\1;;=\204::<\203;;=\3::<99;;;=\207::<\202;;=\204::<" \ + "\203;;=\215::<\1;;=\207::<\11;;=::<;;=99;::<;;=::<99;::<\202;;=\5::<" \ + ";;=::<;;=99;\202::<\2;;=::<\202;;=\6::<SSUkkm\235\235\237\264\264\266" \ + "\332\332\334\210\377\377\377\1\376\376\376\202\377\377\377\1\376\376" \ + "\376\377\377\377\377\377\377\377\377\377\377\377\377\362\377\377\377" \ + "\1\376\376\376\202\377\377\377\11\346\346\350\265\265\267\221\221\223" \ + "kkm::<;;=::<99;;;=\203::<\1;;=\202::<\3""99;::<;;=\202::<\4;;=99;::<" \ + ";;=\204::<\1;;=\202::<\202;;=\1::<\202;;=\202::<\1;;=\203::<\1;;=\211" \ + "::<\2;;=99;\202::<\2;;=99;\206::<\1;;=\202::<\2""99;;;=\210::<\1;;=\202" \ + "::<\1;;=\203::<\1;;=\203::<\1;;=\202::<\4kkm\222\222\224\265\265\267" \ + "\332\332\334\204\377\377\377\1\376\376\376\377\377\377\377\377\377\377" \ + "\377\377\377\377\377\362\377\377\377\12\363\363\363\316\316\316\235\235" \ + "\235jjjFFH;;=::<;;=::<;;=\202::<\1;;=\204::<\1""99;\202::<\2;;=::<\202" \ + ";;=\204::<\7;;=::<;;=::<;;=::<;;=\203::<\1;;=\202::<\1;;=\217::<\2""9" \ + "9;;;=\203::<\1;;=\202::<\4""99;;;=::<;;=\203::<\2;;=99;\202::<\1;;=\207" \ + "::<\1;;=\213::<\1;;=\204::<\7kkk\221\221\221\301\301\301\363\363\363" \ + "\376\376\376\377\377\377\376\376\376\377\377\377\377\377\377\377\377" \ + "\377\377\377\377\321\377\377\377\1\376\376\376\202\377\377\377\1\376" \ + "\376\376\221\377\377\377\1\376\376\376\204\377\377\377\4\363\363\365" \ + "\301\301\303\222\222\224__a\220::<\3;;=::<;;=\204::<\203;;=\203::<\2" \ + ";;=::<\202;;=\4::<;;=::<;;=\204::<\1;;=\202::<\4;;=::<99;;;=\211::<\1" \ + "99;\205::<\202;;=\210::<\5;;=::<;;=::<;;=\203::<\1;;=\212::<\4;;=99;" \ + ";;=99;\211::<\4SSU\204\204\206\266\266\270\345\345\345\221\377\377\377" \ + "\1\376\376\376\204\377\377\377\202\376\376\376\377\377\377\377\377\377" \ + "\377\377\377\377\377\377\266\377\377\377\1\376\376\376\203\377\377\377" \ + "\1\376\376\376\202\377\377\377\1\376\376\376\207\377\377\377\1\376\376" \ + "\376\210\377\377\377\10\363\363\363\301\301\301\221\221\221``b99;;;=" \ + "::<;;=\213::<\3;;=::<;;=\203::<\1;;=\204::<\2;;=99;\202::<\1""99;\202" \ + ";;=\204::<\1;;=\210::<\202;;=\202::<\2;;=99;\215::<\1;;=\204::<\1;;=" \ + "\205::<\5;;=99;;;=::<;;=\202::<\202;;=\4""99;;;=::<;;=\203::<\1;;=\204" \ + "::<\3;;=99;;;=\210::<\11;;=::<;;=99;;;=SSS\205\205\205\266\266\266\363" \ + "\363\363\202\377\377\377\1\376\376\376\206\377\377\377\1\376\376\376" \ + "\204\377\377\377\1\376\376\376\205\377\377\377\1\376\376\376\377\377" \ + "\377\377\377\377\377\377\377\377\377\377\266\377\377\377\1\376\376\376" \ + "\204\377\377\377\1\376\376\376\205\377\377\377\1\376\376\376\207\377" \ + "\377\377\5\376\376\376\333\333\335\250\250\252kkm;;=\203::<\202;;=\212" \ + "::<\10;;=::<;;=::<;;=::<;;=::<\202;;=\206::<\10;;=::<;;=::<;;=::<;;=" \ + "::<\202;;=\2::<;;=\203::<\3;;=::<;;=\202::<\1;;=\202::<\1;;=\211::<\1" \ + "99;\202;;=\203::<\1;;=\205::<\1;;=\204::<\1;;=\206::<\203;;=\202::<\1" \ + ";;=\206::<\1;;=\213::<\1;;=\204::<\1;;=\202::<\3__a\221\221\223\316\316" \ + "\316\204\377\377\377\1\376\376\376\202\377\377\377\1\376\376\376\207" \ + "\377\377\377\1\376\376\376\377\377\377\377\377\377\377\377\377\377\377" \ + "\377\267\377\377\377\202\376\376\376\210\377\377\377\1\376\376\376\207" \ + "\377\377\377\3\301\301\301\204\204\206SSU\203::<\3;;=::<;;=\202::<\2" \ + "99;;;=\215::<\1;;=\204::<\2;;=99;\202::<\202;;=\202::<\7""99;::<;;=:" \ + ":<;;=99;;;=\202::<\2""99;;;=\202::<\1;;=\207::<\1;;=\211::<\2""99;;;" \ + "=\202::<\3;;=::<;;=\202::<\2""99;;;=\206::<\4;;=::<;;=::<\202;;=\206" \ + "::<\3;;=::<;;=\202::<\5;;=::<;;=99;;;=\220::<\2;;=::<\202;;=\5""99;G" \ + "GIxxx\265\265\265\363\363\363\207\377\377\377\1\376\376\376\205\377\377" \ + "\377\1\376\376\376\377\377\377\377\377\377\377\377\377\377\377\377\274" \ + "\377\377\377\1\376\376\376\204\377\377\377\202\376\376\376\4\364\364" \ + "\364\265\265\265xxz;;=\20299;\202::<\1""99;\204::<\3;;=::<;;=\213::<" \ + "\1;;=\203::<\3;;=::<;;=\207::<\2;;=::<\202;;=\4""99;;;=::<;;=\202::<" \ + "\5__allnkkm\221\221\223\235\235\237\202\234\234\236\6\317\317\317\315" \ + "\315\315\317\317\317\315\315\315\316\316\316\346\346\346\213\377\377" \ + "\377\3\376\376\376\377\377\377\346\346\346\204\316\316\316\5\316\316" \ + "\320\251\251\253\234\234\236\233\233\235\235\235\237\203kkm\202::<\1" \ + ";;=\202::<\6;;=::<;;=99;::<;;=\205::<\2;;=::<\203;;=\202::<\1;;=\212" \ + "::<\1;;=\202::<\1;;=\202::<\1;;=\204::<\1;;=\202::<\3lln\250\250\252" \ + "\346\346\350\206\377\377\377\1\376\376\376\204\377\377\377\1\376\376" \ + "\376\377\377\377\377\377\377\377\377\377\377\377\377\271\377\377\377" \ + "\1\376\376\376\202\377\377\377\1\376\376\376\202\377\377\377\4\362\362" \ + "\362\266\266\270xxz::<\202;;=\202::<\10;;=::<99;;;=::<;;=::<;;=\203:" \ + ":<\1;;=\213::<\3;;=::<;;=\205::<\1;;=\202::<\1<<>\202::<\7llnkkm\233" \ + "\233\235\235\235\237\302\302\304\316\316\320\347\347\351\241\377\377" \ + "\377\202\376\376\376\203\377\377\377\17\376\376\376\377\377\377\376\376" \ + "\376\377\377\377\376\376\376\363\363\363\316\316\316\315\315\315\234" \ + "\234\234\235\235\235xxxllnFFH::<;;=\205::<\5;;=99;;;=::<;;=\212::<\202" \ + ";;=\212::<\5;;=99;;;=::<99;\202::<\5__a\250\250\252\346\346\346\377\377" \ + "\377\376\376\376\202\377\377\377\1\376\376\376\377\377\377\377\377\377" \ + "\377\377\377\377\377\377\271\377\377\377\202\376\376\376\2\377\377\377" \ + "\376\376\376\203\377\377\377\3\363\363\363\266\266\266wwy\202;;=\210" \ + "::<\1<<>\203::<\2<<>99;\215::<\1;;=\205::<\11;;=::<;;;___xxx\235\235" \ + "\235\266\266\266\315\315\315\364\364\364\207\377\377\377\1\376\376\376" \ + "\213\377\377\377\1\376\376\376\231\377\377\377\5\376\376\376\377\377" \ + "\377\376\376\376\377\377\377\376\376\376\202\377\377\377\1\376\376\376" \ + "\204\377\377\377\1\376\376\376\202\377\377\377\5\316\316\316\302\302" \ + "\302\233\233\233yyykkk\202::<\6;;=::<;;=::<99;;;=\211::<\1;;=\202::<" \ + "\1;;=\206::<\1""99;\202;;=\202::<\203;;=\1""99;\202::<\3__a\251\251\253" \ + "\346\346\346\204\377\377\377\3\376\376\376\377\377\377\376\376\376\377" \ + "\377\377\377\377\377\377\377\377\377\377\377\266\377\377\377\1\376\376" \ + "\376\202\377\377\377\2\302\302\302xxx\203::<\3;;=::<;;=\232::<\1;;=\202" \ + "::<\6RRTkkm\235\235\237\301\301\303\332\332\334\376\376\376\222\377\377" \ + "\377\1\376\376\376\260\377\377\377\3\376\376\376\377\377\377\376\376" \ + "\376\202\377\377\377\5\345\345\347\316\316\320\235\235\237xxzSSU\215" \ + "::<\202;;=\202::<\203;;=\2::<;;=\203::<\1;;=\204::<\10;;=::<;;=::<;;" \ + "=kkm\266\266\266\363\363\363\202\377\377\377\1\376\376\376\377\377\377" \ + "\377\377\377\377\377\377\377\377\377\245\377\377\377\1\376\376\376\214" \ + "\377\377\377\1\376\376\376\202\377\377\377\5\376\376\376\377\377\377" \ + "\332\332\332\205\205\207GGI\202::<\1;;=\211::<\202;;=\205::<\2;;=::<" \ + "\202;;=\203::<\14;;=99;::<;;=99;;;=FFFxxx\234\234\234\315\315\315\364" \ + "\364\364\376\376\376\323\377\377\377\4\317\317\317\250\250\250xxxSSS" \ + "\202::<\1;;=\206::<\2;;=::<\203;;=\202::<\2;;=99;\204::<\7;;=::<;;=:" \ + ":<;;=::<;;=\204::<\3\204\204\206\301\301\301\376\376\376\220\377\377" \ + "\377\1\376\376\376\377\377\377\377\377\377\377\377\377\377\377\377\225" \ + "\377\377\377\1\376\376\376\203\377\377\377\1\376\376\376\206\377\377" \ + "\377\1\376\376\376\202\377\377\377\4\363\363\363\251\251\251___;;=\202" \ + "::<\1;;=\202::<\202;;=\204::<\1;;=\202::<\7;;=::<;;=::<;;=::<;;=\203" \ + "::<\3""99;::<;;=\202::<\5;;=__a\221\221\223\265\265\267\346\346\346\323" \ + "\377\377\377\1\376\376\376\211\377\377\377\5\363\363\363\301\301\303" \ + "\235\235\237lln::<\202;;=\203::<\1;;=\204::<\1;;=\202::<\2""99;;;=\205" \ + "::<\2;;=99;\203::<\1""99;\204::<\3TTT\233\233\233\346\346\346\207\377" \ + "\377\377\1\376\376\376\377\377\377\377\377\377\377\377\377\377\377\377" \ + "\250\377\377\377\3\316\316\316\204\204\204;;=\203::<\1;;=\203::<\1;;" \ + "=\202::<\1;;=\205::<\3;;=::<;;=\202::<\4""99;;;=::<;;=\202::<\202;;=" \ + "\4___\221\221\221\301\301\303\363\363\365\203\377\377\377\1\376\376\376" \ + "\203\377\377\377\202\376\376\376\321\377\377\377\1\376\376\376\210\377" \ + "\377\377\1\376\376\376\202\377\377\377\4\316\316\316\235\235\235kkk;" \ + ";=\202::<\202;;=\203::<\5;;=::<;;=99;;;=\204::<\202;;=\7::<;;=99;::<" \ + ";;=::<;;=\202::<\202;;=\2xxz\302\302\304\213\377\377\377\1\376\376\376" \ + "\377\377\377\377\377\377\377\377\377\377\377\377\224\377\377\377\1\376" \ + "\376\376\212\377\377\377\3\363\363\363\266\266\266TTV\203::<\3;;=::<" \ + ";;=\202::<\203;;=\202::<\202;;=\205::<\1;;=\202::<\1;;=\204::<\4SSU\221" \ + "\221\223\301\301\301\363\363\363\206\377\377\377\1\376\376\376\203\377" \ + "\377\377\1\376\376\376\202\377\377\377\1\376\376\376\315\377\377\377" \ + "\202\376\376\376\202\377\377\377\1\376\376\376\210\377\377\377\1\376" \ + "\376\376\202\377\377\377\1\376\376\376\202\377\377\377\3\316\316\316" \ + "\221\221\223__a\203::<\1;;=\203::<\3;;=::<;;=\203::<\5;;=99;;;=::<;;" \ + "=\204::<\1""99;\205::<\3SSU\234\234\236\346\346\346\207\377\377\377\3" \ + "\376\376\376\377\377\377\376\376\376\377\377\377\377\377\377\377\377" \ + "\377\377\377\377\233\377\377\377\4\376\376\376\347\347\347\221\221\221" \ + "FFH\207::<\4""99;;;=::<;;=\20299;\202;;=\202::<\1;;=\203::<\2;;=::<\202" \ + ";;=\202::<\3xxz\250\250\252\346\346\350\215\377\377\377\203\376\376\376" \ + "\316\377\377\377\1\376\376\376\202\377\377\377\1\376\376\376\211\377" \ + "\377\377\1\376\376\376\211\377\377\377\4\363\363\363\265\265\267\205" \ + "\205\207FFH\210::<\3;;=::<;;=\204::<\1;;=\207::<\2;;=::<\202;;=\2\203" \ + "\203\205\317\317\321\206\377\377\377\1\376\376\376\377\377\377\377\377" \ + "\377\377\377\377\377\377\377\233\377\377\377\3\316\316\316yy{99;\206" \ + "::<\2;;=99;\202;;=\205::<\5""99;::<;;=::<;;=\202::<\6;;=::<;;=SSU\204" \ + "\204\204\301\301\301\226\377\377\377\1\376\376\376\317\377\377\377\1" \ + "\376\376\376\203\377\377\377\1\376\376\376\204\377\377\377\1\376\376" \ + "\376\204\377\377\377\1\376\376\376\205\377\377\377\1\376\376\376\202" \ + "\377\377\377\3\316\316\316\221\221\221SSU\203::<\3;;=::<99;\204::<\1" \ + ";;=\203::<\2""99;;;=\202::<\1;;=\204::<\5""99;<<>::<kkk\264\264\264\203" \ + "\377\377\377\1\376\376\376\377\377\377\377\377\377\377\377\377\377\377" \ + "\377\232\377\377\377\2\266\266\270__a\202::<\5;;=::<;;=::<99;\202;;=" \ + "\10::<;;=::<;;=::<;;=99;;;=\202::<\11;;=::<99;;;=::<;;=SSU\221\221\223" \ + "\331\331\331\211\377\377\377\1\376\376\376\204\377\377\377\1\376\376" \ + "\376\202\377\377\377\1\376\376\376\324\377\377\377\1\376\376\376\202" \ + "\377\377\377\3\376\376\376\377\377\377\376\376\376\212\377\377\377\1" \ + "\376\376\376\214\377\377\377\14\332\332\332\251\251\251``b::<;;=::<;" \ + ";=99;::<;;=::<;;=\202::<\3;;=99;;;=\203::<\1;;=\202::<\10;;=99;;;=::" \ + "<;;=SSU\250\250\252\363\363\363\377\377\377\377\377\377\377\377\377\377" \ + "\377\377\231\377\377\377\2\265\265\265SSU\216::<\4;;=::<99;;;=\205::" \ + "<\10;;=SSU\222\222\224\332\332\334\377\377\377\376\376\376\377\377\377" \ + "\376\376\376\205\377\377\377\1\376\376\376\203\377\377\377\1\376\376" \ + "\376\202\377\377\377\1\376\376\376\327\377\377\377\1\376\376\376\202" \ + "\377\377\377\1\376\376\376\206\377\377\377\1\376\376\376\207\377\377" \ + "\377\1\376\376\376\216\377\377\377\4\347\347\351\250\250\252``b::<\202" \ + ";;=\202::<\1;;=\203::<\1;;=\203::<\1;;=\202::<\3;;=::<;;=\202::<\6""9" \ + "9;;;=::<FFF\233\233\233\363\363\363\377\377\377\377\377\377\377\377\377" \ + "\377\377\377\206\377\377\377\3\376\376\376\377\377\377\376\376\376\213" \ + "\377\377\377\4\363\363\365\234\234\236FFH;;=\206::<\2""99;;;=\204::<" \ + "\202;;=\2::<;;=\206::<\4FFH\204\204\206\333\333\333\376\376\376\264\377" \ + "\377\377\3\376\376\376\377\377\377\376\376\376\327\377\377\377\4\346" \ + "\346\346\221\221\221SSS:::\202::<\1;;=\204::<\3;;=::<;;=\214::<\3GGI" \ + "\221\221\223\347\347\347\211\377\377\377\1\376\376\376\203\377\377\377" \ + "\1\376\376\376\377\377\377\377\377\377\377\377\371\377\377\377\1\376" \ + "\376\376\207\377\377\377\5\363\363\363\234\234\234FFH::<;;=\204::<\1" \ + ";;=\202::<\1;;=\203::<\1;;=\204::<\1;;=\203::<\5;;=xxz\300\300\302\377" \ + "\377\377\376\376\376\267\377\377\377\1\376\376\376\202\377\377\377\1" \ + "\376\376\376\215\377\377\377\1\376\376\376\303\377\377\377\3\376\376" \ + "\376\377\377\377\376\376\376\204\377\377\377\4\332\332\332\203\203\205" \ + "GGI99;\207::<\202;;=\203::<\6;;=::<;;=::<;;=99;\202;;=\202::<\3\204\204" \ + "\204\346\346\346\376\376\376\205\377\377\377\1\376\376\376\377\377\377" \ + "\377\377\377\377\377\373\377\377\377\1\376\376\376\203\377\377\377\1" \ + "\376\376\376\204\377\377\377\3\362\362\362\234\234\236GGI\203::<\15;" \ + ";=::<;;=::<;;=::<;;=99;;;=::<;;=::<99;\202;;=\7::<;;=99;::<```\250\250" \ + "\250\363\363\363\202\377\377\377\1\375\375\375\272\377\377\377\1\376" \ + "\376\376\214\377\377\377\1\376\376\376\306\377\377\377\1\375\375\375" \ + "\210\377\377\377\6\265\265\265lln::<;;=::<;;=\202::<\5;;=99;;;=::<99" \ + ";\205::<\1;;=\206::<\4\204\204\206\345\345\345\377\377\377\376\376\376" \ + "\207\377\377\377\1\376\376\376\377\377\377\377\377\377\377\377\372\377" \ + "\377\377\1\376\376\376\202\377\377\377\3\364\364\364\233\233\235GGI\202" \ + "::<\203;;=\2""99;;;=\202::<\3""99;::<;;=\202::<\13;;=99;::<;;=::<;;=" \ + "::<FFH\204\204\204\333\333\333\376\376\376\204\377\377\377\1\376\376" \ + "\376\204\377\377\377\1\376\376\376\304\377\377\377\1\376\376\376\317" \ + "\377\377\377\4\346\346\346\221\221\223GGI99;\204::<\1""99;\202;;=\2:" \ + ":<;;=\204::<\1;;=\204::<\202;;=\3::<\221\221\223\364\364\364\203\377" \ + "\377\377\1\376\376\376\203\377\377\377\1\376\376\376\377\377\377\377" \ + "\377\377\377\377\371\377\377\377\1\376\376\376\202\377\377\377\6\265" \ + "\265\267SSU::<99;::<;;=\203::<\1;;=\202::<\1;;=\204::<\3;;=::<;;=\202" \ + "::<\6;;=SSS\264\264\264\363\363\363\377\377\377\376\376\376\204\377\377" \ + "\377\3\376\376\376\377\377\377\376\376\376\267\377\377\377\1\376\376" \ + "\376\221\377\377\377\1\376\376\376\307\377\377\377\1\376\376\376\207" \ + "\377\377\377\4\376\376\376\377\377\377\266\266\266kkm\202::<\1;;=\202" \ + "::<\6;;=::<99;;;=99;;;=\205::<\3;;=::<99;\202::<\4GGI\234\234\234\363" \ + "\363\363\376\376\376\377\377\377\377\377\377\377\377\375\377\377\377" \ + "\4\376\376\376\377\377\377\265\265\265SSU\202::<\1;;=\204::<\1;;=\203" \ + "::<\3;;=99;;;=\205::<\202;;=\2yyy\316\316\316\203\377\377\377\1\376\376" \ + "\376\206\377\377\377\3\376\376\376\377\377\377\376\376\376\263\377\377" \ + "\377\1\376\376\376\205\377\377\377\2\315\315\315;;;\211::<\3;;;:::\315" \ + "\315\315\202\377\377\377\1\376\376\376\312\377\377\377\3\376\376\376" \ + "\377\377\377\376\376\376\205\377\377\377\5\346\346\346\204\204\204FF" \ + "H::<;;=\202::<\4;;=::<;;=::<\203;;=\203::<\2<<>99;\202::<\4""99;;;=F" \ + "FF\234\234\234\377\377\377\377\377\377\377\377\375\377\377\377\11\316" \ + "\316\320kkm::<;;=::<;;=99;::<;;=\203::<\202;;=\2::<99;\205::<\13;;=F" \ + "FH\221\221\221\346\346\346\376\376\376\377\377\377\376\376\376\377\377" \ + "\377\376\376\376\377\377\377\376\376\376\204\377\377\377\1\376\376\376" \ + "\273\377\377\377\2\376\376\376\317\317\317\212::<\6;;=;;;\316\316\316" \ + "\376\376\376\377\377\377\376\376\376\304\377\377\377\1\376\376\376\206" \ + "\377\377\377\5\376\376\376\377\377\377\376\376\376\377\377\377\376\376" \ + "\376\204\377\377\377\4\363\363\363\235\235\235RRT;;=\202::<\202;;=\7" \ + "::<;;=99;::<;;=::<;;=\203::<\1;;=\202::<\6;;=::<SSU\264\264\264\377\377" \ + "\377\376\376\376\377\377\377\377\377\377\377\377\367\377\377\377\3\346" \ + "\346\346xxz;;=\205::<\1;;=\203::<\3;;=::<;;=\207::<\3SSU\247\247\251" \ + "\363\363\363\217\377\377\377\1\376\376\376\272\377\377\377\1\316\316" \ + "\316\213::<\2;;=\316\316\316\306\377\377\377\3\376\376\376\377\377\377" \ + "\376\376\376\221\377\377\377\4\265\265\267SSU;;=99;\202::<\2""99;;;=" \ + "\206::<\1;;=\204::<\1;;=\202::<\3jjj\317\317\317\376\376\376\377\377" \ + "\377\377\377\377\377\377\343\377\377\377\1\376\376\376\211\377\377\377" \ + "\1\376\376\376\206\377\377\377\2\363\363\363\233\233\233\210::<\1;;=" \ + "\203::<\1;;=\203::<\1;;=\203::<\2SSS\265\265\265\315\377\377\377\1\316" \ + "\316\316\214::<\1\316\316\316\334\377\377\377\3\316\316\316kkk::<\202" \ + ";;=\206::<\1;;=\202::<\1;;=\202::<\7""99;;;=::<;;=::<\204\204\206\346" \ + "\346\350\377\377\377\377\377\377\377\377\347\377\377\377\1\376\376\376" \ + "\212\377\377\377\3\265\265\265SSS::<\202;;=\205::<\1;;=\202::<\202;;" \ + "=\202::<\1;;=\203::<\2lln\265\265\267\203\377\377\377\1\376\376\376\313" \ + "\377\377\377\1\316\316\316\214::<\1\316\316\316\336\377\377\377\6\316" \ + "\316\316kkm::<;;=::<;;=\202::<\3;;=::<;;=\204::<\10;;=99;;;=::<99;;;" \ + "=FFH\234\234\234\210\377\377\377\3\376\376\376\377\377\377\376\376\376" \ + "\377\377\377\377\377\377\377\377\327\377\377\377\2\376\376\376\377\377" \ + "\377\202\376\376\376\205\377\377\377\1\376\376\376\203\377\377\377\5" \ + "\332\332\332kkk;;=::<;;=\205::<\4;;=::<;;=::<\202;;=\2::<;;=\203::<\2" \ + "kkm\317\317\317\204\377\377\377\1\376\376\376\314\377\377\377\1\316\316" \ + "\316\214::<\1\316\316\316\336\377\377\377\14\376\376\376\377\377\377" \ + "\316\316\316\204\204\206;;=::<;;=::<;;=99;::<;;=\205::<\11;;=99;;;=9" \ + "9;::<;;;RRR\317\317\317\376\376\376\204\377\377\377\1\376\376\376\377" \ + "\377\377\377\377\377\377\377\332\377\377\377\202\376\376\376\211\377" \ + "\377\377\2\363\363\363\221\221\223\203::<\1;;=\207::<\1;;=\202::<\202" \ + ";;=\10::<99;::<lln\316\316\316\376\376\376\377\377\377\376\376\376\206" \ + "\377\377\377\1\376\376\376\311\377\377\377\1\316\316\316\214::<\1\316" \ + "\316\316\335\377\377\377\7\376\376\376\377\377\377\376\376\376\377\377" \ + "\377\376\376\376\347\347\347kkm\202::<\2""88:;;=\203::<\1;;=\204::<\3" \ + ";;=99;;;=\202::<\4;;=::<xxx\346\346\346\206\377\377\377\1\376\376\376" \ + "\377\377\377\377\377\377\377\377\331\377\377\377\3\376\376\376\377\377" \ + "\377\376\376\376\203\377\377\377\4\376\376\376\377\377\377\300\300\302" \ + "SSU\207::<\1;;=\202::<\1;;=\205::<\4""99;;;=SSU\316\316\316\204\377\377" \ + "\377\1\376\376\376\205\377\377\377\1\376\376\376\202\377\377\377\1\376" \ + "\376\376\307\377\377\377\1\316\316\316\214::<\1\316\316\316\334\377\377" \ + "\377\1\376\376\376\202\377\377\377\1\376\376\376\204\377\377\377\3\317" \ + "\317\317kkm;;=\205::<\3;;=::<99;\203::<\1;;=\204::<\3;;=FFH\250\250\250" \ + "\205\377\377\377\3\376\376\376\377\377\377\376\376\376\377\377\377\377" \ + "\377\377\377\377\326\377\377\377\1\376\376\376\204\377\377\377\4\376" \ + "\376\376\377\377\377\347\347\351xxz\202::<\1;;=\204::<\1;;=\203::<\1" \ + ";;=\204::<\4""99;;;=SSU\266\266\266\205\377\377\377\1\376\376\376\202" \ + "\377\377\377\1\376\376\376\205\377\377\377\1\375\375\375\310\377\377" \ + "\377\1\316\316\316\214::<\1\316\316\316\344\377\377\377\7\376\376\376" \ + "\377\377\377\316\316\316kkm;;=::<99;\202::<\203;;=\2::<;;=\204::<\1;" \ + ";=\202::<\3;;=__a\332\332\334\377\377\377\377\377\377\377\377\335\377" \ + "\377\377\1\376\376\376\204\377\377\377\4\250\250\252FFH::<;;=\202::<" \ + "\3;;=::<;;=\202::<\3""99;::<;;=\202::<\1;;=\202::<\4HHJ\250\250\250\377" \ + "\377\377\376\376\376\206\377\377\377\202\376\376\376\205\377\377\377" \ + "\1\376\376\376\311\377\377\377\1\316\316\316\214::<\1\316\316\316\345" \ + "\377\377\377\1\376\376\376\202\377\377\377\2\301\301\301SSU\202::<\1" \ + ";;=\202::<\2""99;;;=\212::<\3;;=\233\233\233\363\363\363\377\377\377" \ + "\377\377\377\377\377\331\377\377\377\1\376\376\376\204\377\377\377\2" \ + "\346\346\346kkk\211::<\3;;=99;;;=\206::<\2\235\235\237\363\363\363\205" \ + "\377\377\377\1\376\376\376\202\377\377\377\1\376\376\376\321\377\377" \ + "\377\1\316\316\316\214::<\1\316\316\316\352\377\377\377\2\250\250\252" \ + "GGI\206::<\5;;=::<;;=::<;;=\202::<\202;;=\4::<:::SSS\316\316\316\203" \ + "\377\377\377\1\376\376\376\377\377\377\377\377\377\377\377\330\377\377" \ + "\377\2\251\251\251FFH\203::<\1""99;\207::<\1;;=\204::<\3;;=xxx\346\346" \ + "\346\334\377\377\377\1\316\316\316\214::<\1\316\316\316\350\377\377\377" \ + "\13\376\376\376\377\377\377\376\376\376\363\363\363\234\234\23699;;;" \ + "=::<;;=99;;;=\202::<\2""99;;;=\206::<\202;;=\2\221\221\223\363\363\363" \ + "\204\377\377\377\3\376\376\376\377\377\377\376\376\376\202\377\377\377" \ + "\1\376\376\376\377\377\377\377\377\377\377\377\316\377\377\377\2\346" \ + "\346\346kkk\202;;=\206::<\1;;=\203::<\3;;=::<;;=\202::<\2``b\316\316" \ + "\320\336\377\377\377\1\316\316\316\214::<\1\316\316\316\353\377\377\377" \ + "\4\376\376\376\377\377\377\350\350\352kkm\206::<\2;;=99;\203::<\1;;=" \ + "\203::<\6;;=::<TTV\331\331\331\377\377\377\376\376\376\207\377\377\377" \ + "\1\376\376\376\377\377\377\377\377\377\377\377\306\377\377\377\1\376" \ + "\376\376\203\377\377\377\5\376\376\376\377\377\377\266\266\266EEG;;=" \ + "\203::<\1;;=\203::<\1;;=\204::<\202;;=\3::<GGI\250\250\252\205\377\377" \ + "\377\1\376\376\376\202\377\377\377\1\376\376\376\327\377\377\377\1\316" \ + "\316\316\214::<\1\316\316\316\351\377\377\377\1\376\376\376\203\377\377" \ + "\377\5\376\376\376\377\377\377\316\316\316TTV;;=\203::<\3;;=::<;;=\204" \ + "::<\202;;=\5::<;;=99;;;=\234\234\236\207\377\377\377\1\376\376\376\377" \ + "\377\377\377\377\377\377\377\303\377\377\377\3\376\376\376\377\377\377" \ + "\376\376\376\203\377\377\377\6\376\376\376\377\377\377\364\364\364ww" \ + "y::<;;=\202::<\202;;=\202::<\5;;=::<99;::<;;=\202::<\4;;=::<\204\204" \ + "\206\363\363\363\202\377\377\377\1\376\376\376\202\377\377\377\3\376" \ + "\376\376\377\377\377\376\376\376\331\377\377\377\1\316\316\316\214::" \ + "<\1\316\316\316\353\377\377\377\1\376\376\376\204\377\377\377\11\376" \ + "\376\376\234\234\234GGI::<;;=::<;;=::<;;=\207::<\1;;=\202::<\2__a\332" \ + "\332\332\377\377\377\377\377\377\377\377\320\377\377\377\4\316\316\316" \ + "FFH::<;;=\202::<\1;;=\207::<\2;;=99;\202;;=\3__a\316\316\320\376\376" \ + "\376\342\377\377\377\1\316\316\316\214::<\1\316\316\316\361\377\377\377" \ + "\5\376\376\376\347\347\347lln::<;;=\210::<\1""99;\202::<\7;;=::<99;G" \ + "GI\247\247\247\377\377\377\376\376\376\202\377\377\377\1\376\376\376" \ + "\377\377\377\377\377\377\377\377\305\377\377\377\1\376\376\376\203\377" \ + "\377\377\3\221\221\221:::;;=\203::<\1;;=\202::<\1;;=\203::<\1;;=\202" \ + "::<\4;;=FFH\234\234\234\376\376\376\202\377\377\377\1\375\375\375\202" \ + "\377\377\377\1\376\376\376\203\377\377\377\1\376\376\376\332\377\377" \ + "\377\1\316\316\316\214::<\1\316\316\316\364\377\377\377\3\301\301\303" \ + "FFH;;=\206::<\1;;=\205::<\5;;=99;;;=yy{\363\363\363\377\377\377\377\377" \ + "\377\377\377\312\377\377\377\3\346\346\346^^`;;=\207::<\1;;=\203::<\1" \ + ";;=\203::<\2jjl\346\346\350\202\377\377\377\1\376\376\376\213\377\377" \ + "\377\1\375\375\375\327\377\377\377\1\316\316\316\214::<\1\316\316\316" \ + "\360\377\377\377\3\376\376\376\377\377\377\376\376\376\202\377\377\377" \ + "\2\363\363\363\220\220\220\202;;=\203::<\2;;=99;\206::<\1;;=\202::<\2" \ + "SSU\316\316\320\202\377\377\377\1\376\376\376\377\377\377\377\377\377" \ + "\377\377\303\377\377\377\4\376\376\376\377\377\377\302\302\302FFH\217" \ + "::<\2GGI\250\250\252\205\377\377\377\1\376\376\376\211\377\377\377\3" \ + "\376\376\376\377\377\377\376\376\376\326\377\377\377\1\316\316\316\214" \ + "::<\1\316\316\316\356\377\377\377\1\376\376\376\210\377\377\377\3\316" \ + "\316\316SSU;;=\203::<\202;;=\207::<\1;;=\202::<\1\235\235\237\377\377" \ + "\377\377\377\377\377\377\306\377\377\377\1\221\221\221\202::<\2;;=99" \ + ";\203::<\3;;=::<;;=\203::<\1;;=\202::<\2kkm\346\346\346\351\377\377\377" \ + "\1\316\316\316\214::<\1\316\316\316\370\377\377\377\2\362\362\362\221" \ + "\221\221\204::<\3;;=::<;;=\206::<\1;;=\202::<\2xxz\362\362\364\377\377" \ + "\377\377\377\377\377\377\301\377\377\377\3\376\376\376\363\363\363__" \ + "_\204::<\3;;=::<;;=\202::<\2;;=99;\202;;=\4::<99;GGI\250\250\252\353" \ + "\377\377\377\1\316\316\316\214::<\1\316\316\316\366\377\377\377\1\376" \ + "\376\376\203\377\377\377\2\317\317\317SSS\211::<\202;;=\6""99;;;=99;" \ + "::<SSU\332\332\332\202\377\377\377\1\376\376\376\377\377\377\377\377" \ + "\377\377\377\267\377\377\377\11\376\376\376\377\377\377\376\376\376\377" \ + "\377\377\376\376\376\377\377\377\317\317\321FFH;;=\202::<\3;;=::<99;" \ + "\203::<\203;;=\202::<\4;;=lll\346\346\346\376\376\376\353\377\377\377" \ + "\1\316\316\316\214::<\1\316\316\316\367\377\377\377\1\376\376\376\202" \ + "\377\377\377\5\376\376\376\363\363\363\221\221\223;;=99;\202;;=\3::<" \ + "99;;;=\202::<\202;;=\6::<;;=::<;;=::<\265\265\265\202\377\377\377\1\376" \ + "\376\376\377\377\377\377\377\377\377\377\273\377\377\377\1\250\250\252" \ + "\202::<\2""99;;;=\203::<\1;;=\202::<\1;;=\204::<\3;;=\250\250\250\376" \ + "\376\376\205\377\377\377\1\376\376\376\347\377\377\377\1\316\316\316" \ + "\214::<\1\316\316\316\373\377\377\377\5\376\376\376\377\377\377\300\300" \ + "\300FFH;;=\202::<\1;;=\202::<\3;;=::<;;=\202::<\2;;=::<\202;;=\4\205" \ + "\205\207\376\376\376\377\377\377\376\376\376\377\377\377\377\377\377" \ + "\377\377\267\377\377\377\3\376\376\376\364\364\364\205\205\207\202::" \ + "<\202;;=\15""99;;;=::<;;=::<;;=::<99;;;=99;;;=__a\331\331\331\357\377" \ + "\377\377\1\316\316\316\214::<\1\316\316\316\366\377\377\377\1\376\376" \ + "\376\203\377\377\377\1\376\376\376\203\377\377\377\2\363\363\363kkm\215" \ + "::<\4;;=99;__a\363\363\363\202\377\377\377\1\376\376\376\377\377\377" \ + "\377\377\377\377\377\265\377\377\377\4\347\347\351__a::<;;=\203::<\1" \ + ";;=\202::<\1;;=\203::<\1;;=\202::<\2\221\221\223\363\363\363\360\377" \ + "\377\377\1\316\316\316\214::<\1\316\316\316\364\377\377\377\1\376\376" \ + "\376\203\377\377\377\1\376\376\376\207\377\377\377\2\251\251\253;;=\203" \ + "::<\1;;=\203::<\1;;=\203::<\203;;=\3FFH\332\332\332\376\376\376\377\377" \ + "\377\377\377\377\377\377\265\377\377\377\4\331\331\331FFH::<;;=\203:" \ + ":<\1;;=\202::<\1;;=\205::<\2FFH\302\302\302\205\377\377\377\7\376\376" \ + "\376\377\377\377\376\376\376\377\377\377\376\376\376\377\377\377\376" \ + "\376\376\346\377\377\377\1\316\316\316\214::<\1\316\316\316\377\377\377" \ + "\377\202\377\377\377\2\332\332\332SSU\203::<\1;;=\203::<\12""99;;;=:" \ + ":<99;::<;;=99;;;=\266\266\266\376\376\376\377\377\377\377\377\377\377" \ + "\377\263\377\377\377\1\265\265\265\202::<\1;;=\205::<\202;;=\202::<\1" \ + ";;=\202::<\2__a\346\346\350\203\377\377\377\1\376\376\376\357\377\377" \ + "\377\1\316\316\316\214::<\1\316\316\316\377\377\377\377\203\377\377\377" \ + "\2\363\363\363\204\204\204\202::<\1;;=\203::<\1;;=\205::<\1;;=\202::" \ + "<\1\221\221\221\377\377\377\377\377\377\377\377\262\377\377\377\4\235" \ + "\235\237;;=::<;;=\203::<\1;;=\206::<\3;;=::<\222\222\222\202\377\377" \ + "\377\1\376\376\376\362\377\377\377\1\316\316\316\214::<\1\316\316\316" \ + "\377\377\377\377\205\377\377\377\3\265\265\265:::;;=\206::<\5;;=::<;" \ + ";=::<;;=\202::<\2\204\204\206\363\363\363\212\377\377\377\1\376\376\376" \ + "\377\377\377\377\377\377\377\377\236\377\377\377\1\376\376\376\202\377" \ + "\377\377\4\376\376\376\377\377\377\376\376\377\204\204\206\206::<\12" \ + ";;=::<;;=::<;;=::<;;=::<FFH\301\301\301\366\377\377\377\1\316\316\316" \ + "\214::<\1\316\316\316\377\377\377\377\206\377\377\377\4\333\333\333S" \ + "SU::<;;=\205::<\4;;=::<;;=::<\202;;=\3::<__a\364\364\364\202\377\377" \ + "\377\1\376\376\376\205\377\377\377\1\376\376\376\202\377\377\377\1\376" \ + "\376\376\377\377\377\377\377\377\377\377\236\377\377\377\4\376\376\376" \ + "\377\377\377\363\363\365__a\203::<\10""99;;;=::<;;=99;;;=99;;;=\203:" \ + ":<\2__a\332\332\332\203\377\377\377\1\376\376\376\363\377\377\377\1\316" \ + "\316\316\214::<\1\316\316\316\377\377\377\377\207\377\377\377\7\363\363" \ + "\363kkm;;=::<;;=::<;;=\204::<\202;;=\10""99;;;=::<SSU\332\332\332\376" \ + "\376\376\377\377\377\376\376\376\205\377\377\377\1\376\376\376\377\377" \ + "\377\377\377\377\377\377\236\377\377\377\1\376\376\376\202\377\377\377" \ + "\2\346\346\350__a\202::<\4;;=::<;;=99;\204::<\1;;=\203::<\3xxz\362\362" \ + "\362\377\377\377\202\376\376\376\365\377\377\377\1\316\316\316\214::" \ + "<\1\316\316\316\377\377\377\377\210\377\377\377\5\376\376\376\234\234" \ + "\234;;=::<;;=\202::<\14;;=::<;;=99;;;=::<;;=::<;;=FFH\332\332\332\376" \ + "\376\376\203\377\377\377\1\376\376\376\203\377\377\377\3\376\376\376" \ + "\377\377\377\376\376\376\377\377\377\377\377\377\377\377\235\377\377" \ + "\377\4\332\332\332FFH::<;;=\205::<\1;;=\205::<\2;;=\234\234\234\372\377" \ + "\377\377\1\316\316\316\214::<\1\316\316\316\377\377\377\377\212\377\377" \ + "\377\2\300\300\300FFH\203::<\1""99;\202::<\2;;=99;\203::<\4;;=::<FFH" \ + "\266\266\266\205\377\377\377\1\376\376\376\202\377\377\377\1\376\376" \ + "\376\377\377\377\377\377\377\377\377\235\377\377\377\3\332\332\332FF" \ + "H;;=\205::<\1;;=\202::<\1""99;\203::<\6FFH\301\301\301\377\377\377\376" \ + "\376\376\377\377\377\376\376\376\207\377\377\377\1\376\376\376\357\377" \ + "\377\377\1\316\316\316\214::<\1\316\316\316\377\377\377\377\211\377\377" \ + "\377\4\376\376\376\377\377\377\331\331\331SSU\204::<\6""99;::<;;=::<" \ + ";;=::<\202;;=\202::<\1\266\266\270\203\377\377\377\1\376\376\376\377" \ + "\377\377\377\377\377\377\377\240\377\377\377\2\265\265\265EEG\202::<" \ + "\6;;=::<;;=::<;;=99;\203::<\4;;=::<SSU\332\332\332\203\377\377\377\1" \ + "\376\376\376\207\377\377\377\1\376\376\376\360\377\377\377\1\316\316" \ + "\316\214::<\1\316\316\316\377\377\377\377\212\377\377\377\15\376\376" \ + "\376\377\377\377\363\363\363__a::<;;=99;;;=::<99;;;=::<;;=\202::<\4;" \ + ";=99;;;=\250\250\252\204\377\377\377\1\376\376\376\377\377\377\377\377" \ + "\377\377\377\235\377\377\377\5\265\265\265::<;;=::<;;=\202::<\202;;=" \ + "\2::<;;=\204::<\2__a\364\364\364\206\377\377\377\1\376\376\376\366\377" \ + "\377\377\1\316\316\316\214::<\1\316\316\316\377\377\377\377\211\377\377" \ + "\377\1\376\376\376\204\377\377\377\2\204\204\20699;\204::<\1;;=\204:" \ + ":<\5""99;;;=99;::<\204\204\204\377\377\377\377\377\377\377\377\232\377" \ + "\377\377\1\376\376\376\205\377\377\377\2\265\265\267;;=\211::<\1;;=\203" \ + "::<\1\205\205\205\377\377\377\377\1\316\316\316\214::<\1\316\316\316" \ + "\377\377\377\377\215\377\377\377\12\376\376\376\377\377\377\250\250\250" \ + "::<;;=::<99;;;=::<;;=\202::<\3;;=::<99;\202::<\1\205\205\207\212\377" \ + "\377\377\1\376\376\376\377\377\377\377\377\377\377\377\223\377\377\377" \ + "\1\265\265\267\203::<\202;;=\1""99;\204::<\5;;=::<;;=::<\235\235\237" \ + "\377\377\377\377\2\377\377\377\316\316\316\214::<\1\316\316\316\377\377" \ + "\377\377\216\377\377\377\3\376\376\376\377\377\377\265\265\267\202::" \ + "<\3;;=::<;;=\205::<\1;;=\203::<\1\204\204\204\210\377\377\377\1\376\376" \ + "\376\202\377\377\377\1\376\376\376\377\377\377\377\377\377\377\377\220" \ + "\377\377\377\6\234\234\236::<;;=::<;;=99;\204::<\1;;=\204::<\1\265\265" \ + "\265\377\377\377\377\202\377\377\377\1\316\316\316\214::<\1\316\316\316" \ + "\377\377\377\377\215\377\377\377\1\376\376\376\203\377\377\377\2\334" \ + "\334\334FFH\207::<\202;;=\203::<\3;;=\204\204\206\376\376\376\207\377" \ + "\377\377\1\376\376\376\377\377\377\377\377\377\377\377\216\377\377\377" \ + "\11\376\376\376\377\377\377\376\376\376\204\204\206::<99;;;=::<;;=\204" \ + "::<\6;;=99;;;=::<FFH\301\301\301\377\377\377\377\203\377\377\377\1\316" \ + "\316\316\214::<\1\316\316\316\377\377\377\377\215\377\377\377\1\376\376" \ + "\376\202\377\377\377\202\376\376\376\3\332\332\332FFH::<\202;;=\203:" \ + ":<\3;;=99;;;=\204::<\2\205\205\207\376\376\376\203\377\377\377\1\376" \ + "\376\376\203\377\377\377\3\376\376\376\377\377\377\376\376\376\377\377" \ + "\377\377\377\377\377\377\212\377\377\377\7\376\376\376\377\377\377\376" \ + "\376\376\204\204\20499;::<;;=\202::<\1""99;\205::<\4;;=::<GGI\332\332" \ + "\334\377\377\377\377\204\377\377\377\1\316\316\316\214::<\1\316\316\316" \ + "\377\377\377\377\217\377\377\377\6\376\376\376\377\377\377\376\376\376" \ + "\377\377\377\362\362\362__a\203::<\202;;=\11""99;;;=::<99;;;=::<;;=:" \ + ":<\204\204\204\205\377\377\377\1\376\376\376\202\377\377\377\1\376\376" \ + "\376\377\377\377\377\377\377\377\377\215\377\377\377\1\204\204\204\202" \ + "::<\1;;=\207::<\1<<>\202::<\2FFH\331\331\333\377\377\377\377\205\377" \ + "\377\377\1\316\316\316\214::<\1\316\316\316\377\377\377\377\216\377\377" \ + "\377\1\376\376\376\203\377\377\377\4\376\376\376\377\377\377\363\363" \ + "\363__a\204::<\2;;=99;\206::<\2;;=\204\204\204\203\377\377\377\1\376" \ + "\376\376\377\377\377\377\377\377\377\377\220\377\377\377\1\204\204\204" \ + "\205::<\1;;=\203::<\1;;=\203::<\4__a\363\363\363\377\377\377\376\376" \ + "\376\377\377\377\377\204\377\377\377\1\316\316\316\214::<\1\316\316\316" \ + "\377\377\377\377\224\377\377\377\4\376\376\376\363\363\363xxx::<\202" \ + ";;=\202::<\1;;=\203::<\1;;=\203::<\1\205\205\207\204\377\377\377\1\376" \ + "\376\376\377\377\377\377\377\377\377\377\215\377\377\377\1\250\250\250" \ + "\205::<\1;;=\203::<\12;;=99;;;=::<__a\363\363\365\377\377\377\376\376" \ + "\376\377\377\377\376\376\376\377\377\377\377\203\377\377\377\1\316\316" \ + "\316\214::<\1\316\316\316\377\377\377\377\227\377\377\377\5\204\204\204" \ + "::<;;=::<;;=\204::<\1""99;\204::<\1\204\204\204\377\377\377\377\377\377" \ + "\377\377\213\377\377\377\1\376\376\376\202\377\377\377\4\376\376\376" \ + "\377\377\377\265\265\267;;=\212::<\4;;=::<__a\363\363\363\217\377\377" \ + "\377\1\376\376\376\367\377\377\377\1\316\316\316\214::<\1\316\316\316" \ + "\376\377\377\377\202\377\377\375\3\377\376\377\377\377\377\376\377\375" \ + "\224\377\377\377\3\204\204\206::<;;=\211::<\7""99;::<\203\203\205\377" \ + "\377\377\376\376\376\377\377\377\376\376\376\205\377\377\377\1\376\376" \ + "\376\202\377\377\377\202\376\376\376\377\377\377\377\377\377\377\377" \ + "\2\264\264\266;;=\202::<\202;;=\1""99;\207::<\2__a\363\363\365\217\377" \ + "\377\377\3\376\376\376\377\377\377\376\376\376\366\377\377\377\1\316" \ + "\316\316\214::<\1\316\316\316\375\377\377\377\5\377\377\375\377\376\377" \ + "\377\375\377\377\377\375\377\377\377\202\377\376\377\221\377\377\377" \ + "\1\376\376\376\202\377\377\377\1\204\204\206\203::<\1;;=\202::<\2;;=" \ + "::<\202;;=\202::<\3;;=\204\204\204\376\376\376\211\377\377\377\3\376" \ + "\376\376\377\377\377\376\376\376\377\377\377\377\375\377\377\377\7\376" \ + "\376\376\264\264\266;;=99;::<;;=99;\204::<\1;;=\203::<\2aac\363\363\363" \ + "\221\377\377\377\1\376\376\376\367\377\377\377\1\316\316\316\214::<\1" \ + "\316\316\316\375\377\377\377\202\376\376\376\203\377\377\377\202\376" \ + "\377\377\222\377\377\377\10\376\376\376\377\377\377\376\376\376\204\204" \ + "\206::<;;=::<;;=\203::<\202;;=\202::<\6""99;;;=\205\205\207\376\376\376" \ + "\377\377\377\376\376\376\203\377\377\377\202\376\376\376\202\377\377" \ + "\377\1\376\376\376\377\377\377\377\375\377\377\377\3\376\376\376\302" \ + "\302\304;;=\203::<\1;;=\204::<\6;;=99;;;=::<aac\362\362\362\223\377\377" \ + "\377\1\376\376\376\366\377\377\377\1\316\316\316\214::<\1\316\316\316" \ + "\374\377\377\377\6\375\377\376\377\377\375\377\376\377\376\377\377\376" \ + "\376\376\377\377\375\202\377\376\377\225\377\377\377\2\376\376\376\204" \ + "\204\206\206::<\1""99;\203::<\1;;=\202::<\1\251\251\253\204\377\377\377" \ + "\1\376\376\376\377\377\377\377\377\377\377\377\203\377\377\377\4\332" \ + "\332\332FFH::<;;=\202::<\1""99;\205::<\4;;=::<__a\363\363\365\202\377" \ + "\377\377\1\376\376\376\377\377\377\377\211\377\377\377\1\316\316\316" \ + "\214::<\1\316\316\316\374\377\377\377\5\376\377\377\376\376\376\377\376" \ + "\377\377\377\375\376\377\375\202\376\377\377\1\377\377\375\221\377\377" \ + "\377\3\376\376\376\377\377\377\376\376\376\203\377\377\377\2\204\204" \ + "\206;;=\205::<\1;;=\203::<\7;;=::<;;=\265\265\265\376\376\376\377\377" \ + "\377\376\376\376\202\377\377\377\5\376\376\376\377\377\377\376\376\376" \ + "\377\377\377\376\376\376\377\377\377\377\373\377\377\377\6\331\331\331" \ + "GGI::<;;=::<;;=\205::<\1<<>\202::<\2__a\363\363\365\202\377\377\377\1" \ + "\376\376\376\213\377\377\377\1\376\376\376\375\377\377\377\1\316\316" \ + "\316\214::<\1\316\316\316\374\377\377\377\7\377\376\377\376\377\377\376" \ + "\376\374\377\376\377\377\377\375\376\377\377\377\377\375\226\377\377" \ + "\377\1\376\376\376\202\377\377\377\1\203\203\203\214::<\2;;=\265\265" \ + "\265\206\377\377\377\1\376\376\376\377\377\377\377\374\377\377\377\4" \ + "\364\364\364GGI99;;;=\206::<\1;;=\203::<\2__a\363\363\363\205\377\377" \ + "\377\1\376\376\376\212\377\377\377\1\363\363\363\203\377\377\377\1\376" \ + "\376\376\370\377\377\377\1\316\316\316\214::<\1\316\316\316\374\377\377" \ + "\377\10\377\377\375\377\376\377\377\377\377\377\377\375\377\376\377\370" \ + "\373\362\370\373\364\377\376\377\220\377\377\377\1\376\376\376\202\377" \ + "\377\377\1\376\376\376\202\377\377\377\1\376\376\376\202\377\377\377" \ + "\1\204\204\204\203::<\1;;=\210::<\2FFH\332\332\334\204\377\377\377\1" \ + "\376\376\376\377\377\377\377\374\377\377\377\3\363\363\363___;;=\202" \ + "::<\1;;=\204::<\6;;=99;;;=::<__a\363\363\365\220\377\377\377\3\265\265" \ + "\265FFF\333\333\333\373\377\377\377\1\316\316\316\214::<\1\316\316\316" \ + "\376\377\377\377\6\374\377\377\377\377\375\371\374\365\242\320c\240\322" \ + "c\371\372\362\221\377\377\377\1\376\376\376\210\377\377\377\2\203\203" \ + "\203;;=\202::<\1;;=\203::<\1;;=\203::<\3;;=FFH\333\333\333\202\377\377" \ + "\377\1\376\376\376\377\377\377\377\371\377\377\377\1\376\376\376\203" \ + "\377\377\377\2kkm::<\202;;=\1""99;\205::<\202;;=\3::<__a\363\363\363" \ + "\220\377\377\377\5\265\265\267::<;;=FFH\332\332\332\206\377\377\377\3" \ + "\376\376\376\377\377\377\376\376\376\361\377\377\377\1\316\316\316\213" \ + "::<\2;;=\316\316\316\365\377\377\377\22\376\376\377\377\377\375\377\377" \ + "\377\377\377\375\377\377\377\377\376\377\377\377\375\377\377\377\376" \ + "\376\377\377\377\377\371\374\365\242\320c\215\307\77\215\305@\242\322" \ + "e\372\373\365\376\377\375\377\376\377\230\377\377\377\3\205\205\207:" \ + ":<;;=\206::<\1;;=\202::<\4;;=SSU\363\363\365\376\376\376\377\377\377" \ + "\377\374\377\377\377\13\376\376\376\204\204\204::<;;=99;::<;;=::<;;=" \ + "::<;;=\203::<\3__a\364\364\366\376\376\376\217\377\377\377\1\265\265" \ + "\267\203::<\3;;=FFF\332\332\332\206\377\377\377\1\376\376\376\361\377" \ + "\377\377\2\376\376\376\317\317\317\212::<\6;;=;;;\316\316\316\376\376" \ + "\376\377\377\377\376\376\376\361\377\377\377\6\376\376\377\377\376\377" \ + "\375\376\377\376\377\377\377\377\375\375\377\376\202\377\377\377\17\376" \ + "\376\376\377\377\377\371\372\364\240\322a\215\305@\212\307>\215\307\77" \ + "\215\305>\242\320c\370\372\365\377\377\377\377\376\377\376\377\375\377" \ + "\377\375\377\376\377\225\377\377\377\5kkm::<;;=99;;;=\210::<\4__a\364" \ + "\364\364\376\376\376\377\377\377\202\376\376\376\377\377\377\377\363" \ + "\377\377\377\3\376\376\376\377\377\377\376\376\376\202\377\377\377\4" \ + "\250\250\252::<;;=99;\202;;=\205::<\202;;=\3FFH\345\345\345\376\376\376" \ + "\217\377\377\377\4\264\264\266;;=::<;;=\203::<\2GGI\332\332\332\203\377" \ + "\377\377\1\376\376\376\356\377\377\377\1\376\376\376\205\377\377\377" \ + "\2\315\315\315;;;\211::<\3;;;:::\315\315\315\202\377\377\377\1\376\376" \ + "\376\361\377\377\377\23\377\377\375\375\376\377\376\377\377\376\377\375" \ + "\377\374\377\377\377\375\375\377\376\377\377\377\377\377\375\371\372" \ + "\364\242\321g\215\306A\212\307>\215\306A\212\306@\214\305@\212\306B\241" \ + "\322_\367\372\361\204\377\377\377\1\377\377\375\220\377\377\377\1\376" \ + "\376\376\203\377\377\377\3\363\363\363__a99;\202::<\6;;=::<99;;;=99;" \ + ";;=\203::<\1\205\205\207\204\377\377\377\1\376\376\376\377\377\377\377" \ + "\362\377\377\377\1\376\376\376\202\377\377\377\22\376\376\376\265\265" \ + "\267::<99;;;=::<;;=99;;;=::<;;=::<;;=::<FFH\331\331\331\377\377\377\376" \ + "\376\376\216\377\377\377\1\265\265\267\203::<\1;;=\202::<\4;;=::<GGI" \ + "\332\332\332\210\377\377\377\1\376\376\376\353\377\377\377\1\376\376" \ + "\376\221\377\377\377\1\376\376\376\363\377\377\377\17\376\377\377\376" \ + "\377\375\377\375\376\375\377\376\377\377\375\377\377\377\377\376\377" \ + "\367\374\365\240\320b\215\307=\213\305=\215\306A\215\305>\214\305@\214" \ + "\306>\202\214\305@\4\241\321a\371\374\365\376\376\377\377\377\375\202" \ + "\376\377\377\221\377\377\377\1\376\376\376\203\377\377\377\3\362\362" \ + "\362``b99;\205::<\1;;=\203::<\6;;=99;\235\235\237\376\376\376\377\377" \ + "\377\376\376\376\377\377\377\377\366\377\377\377\2\332\332\332FFH\202" \ + ";;=\4""99;;;=::<;;=\205::<\2FFH\332\332\334\202\377\377\377\3\376\376" \ + "\376\377\377\377\376\376\376\213\377\377\377\4\266\266\26699;::<;;=\202" \ + "::<\1;;=\202::<\4;;=::<FFF\332\332\332\203\377\377\377\1\376\376\376" \ + "\202\377\377\377\1\376\376\376\375\377\377\377\1\376\376\376\363\377" \ + "\377\377\202\377\377\375\3\377\374\377\375\377\376\376\377\377\202\377" \ + "\377\377\21\370\373\364\241\321c\216\306\77\212\306@\214\306>\215\305" \ + "@\212\306@\213\310=\214\306<\216\306\77\214\304=\214\306>\241\321c\372" \ + "\375\362\376\376\376\377\376\377\376\376\374\220\377\377\377\2\376\376" \ + "\376\377\377\377\203\376\376\376\4\377\377\377\364\364\364FFH;;=\202" \ + "::<\1;;=\202::<\1;;=\203::<\3;;=::<\265\265\265\377\377\377\377\367\377" \ + "\377\377\4\362\362\362SSU::<;;=\205::<\1""99;\202;;=\3::<;;=\265\265" \ + "\267\216\377\377\377\3\376\376\376\377\377\377\265\265\265\202::<\5;" \ + ";=99;;;=::<;;=\204::<\4;;=FFH\332\332\332\376\376\376\205\377\377\377" \ + "\1\376\376\376\355\377\377\377\1\376\376\376\214\377\377\377\1\376\376" \ + "\376\366\377\377\377\1\375\377\376\202\377\377\375\24\377\377\377\376" \ + "\376\376\373\373\363\243\322b\213\307A\214\306>\215\305@\214\305@\212" \ + "\307>\214\306>\215\305>\213\307A\214\305@\216\310@\214\306>\215\305>" \ + "\242\320c\366\373\364\375\377\376\377\376\377\221\377\377\377\1\376\376" \ + "\376\204\377\377\377\3\376\376\376\333\333\333EEG\202;;=\2::<;;=\207" \ + "::<\3GGI\332\332\332\376\376\376\377\377\377\377\365\377\377\377\1__" \ + "a\205::<\10;;=::<;;=::<;;=::<;;=\265\265\265\202\377\377\377\3\376\376" \ + "\376\377\377\377\376\376\376\213\377\377\377\1\266\266\266\203::<\5""9" \ + "9;<<>::<;;=::<\202;;=\203::<\4;;=FFH\333\333\333\376\376\376\202\377" \ + "\377\377\1\376\376\376\355\377\377\377\1\376\376\376\202\377\377\377" \ + "\1\376\376\376\215\377\377\377\1\376\376\376\363\377\377\377\3\377\376" \ + "\377\377\377\377\375\377\376\202\377\377\377\2\373\373\363\241\321d\202" \ + "\214\306>\17\216\306=\215\305@\215\307\77\214\306>\217\304>\214\306>" \ + "\214\305B\215\307\77\211\305A\215\306A\216\306\77\214\305@\242\322e\370" \ + "\373\364\377\377\375\230\377\377\377\1\333\333\335\203::<\202;;=\206" \ + "::<\3;;=FFH\363\363\363\377\377\377\377\364\377\377\377\1\204\204\206" \ + "\203::<\1;;=\207::<\2;;=\204\204\206\220\377\377\377\1\346\346\346\204" \ + "::<\1;;=\203::<\1;;=\202::<\202;;=\203::<\2FFH\332\332\332\357\377\377" \ + "\377\3\376\376\376\377\377\377\376\376\376\377\377\377\377\204\377\377" \ + "\377\1\377\377\375\202\377\377\377\17\377\376\377\370\373\364\243\322" \ + "b\214\306>\213\310\77\212\307>\214\306>\215\306C\212\307>\214\306<\213" \ + "\310\77\214\305@\214\306<\214\306>\216\306\77\203\214\306>\3\214\306" \ + "<\265\334\211\376\376\376\222\377\377\377\1\376\376\376\205\377\377\377" \ + "\4\376\376\377\265\265\267::<;;=\212::<\1___\377\377\377\377\363\377" \ + "\377\377\1\265\265\267\204::<\1;;=\206::<\2;;=\203\203\203\222\377\377" \ + "\377\2\265\265\265;;=\203::<\1;;=\205::<\1;;=\204::<\3;;=FFH\332\332" \ + "\332\206\377\377\377\3\376\376\376\377\377\377\376\376\376\377\377\377" \ + "\377\345\377\377\377\10\376\376\377\377\377\375\377\377\377\377\377\375" \ + "\377\377\377\377\376\377\377\377\375\376\377\377\202\377\377\377\6\370" \ + "\373\362\243\322b\211\307B\213\310=\214\305@\214\306<\202\215\305@\4" \ + "\214\306<\214\305@\214\306<\215\307\77\202\214\306>\6\212\307>\214\306" \ + ">\215\307\77\214\305@\244\317c\367\375\361\233\377\377\377\3\234\234" \ + "\236::<99;\211::<\2;;=\204\204\206\377\377\377\377\360\377\377\377\13" \ + "\376\376\376\332\332\33299;::<99;;;=::<99;;;=::<;;=\202::<\3;;=^^`\364" \ + "\364\364\223\377\377\377\12\265\265\267;;=::<;;=99;;;=::<;;=::<;;=\202" \ + "::<\1;;=\203::<\3;;=FFF\332\332\332\206\377\377\377\1\376\376\376\377" \ + "\377\377\377\345\377\377\377\6\376\376\377\377\376\377\375\376\377\376" \ + "\377\377\377\377\375\375\377\376\203\377\377\377\27\377\377\375\372\373" \ + "\366\241\321a\217\304@\212\307<\214\306>\215\305>\215\305@\213\310=\212" \ + "\306@\214\306>\214\305B\215\307\77\215\305>\215\306A\212\307>\214\306" \ + ">\215\307\77\214\306>\242\322b\370\373\362\376\376\377\377\375\376\233" \ + "\377\377\377\1\204\204\206\203::<\13;;=::<;;=::<;;=::<;;=::<;;=\266\266" \ + "\266\376\376\376\203\377\377\377\1\376\376\376\377\377\377\377\352\377" \ + "\377\377\2\363\363\363TTV\202::<\3;;=99;;;=\204::<\4;;=99;FFH\363\363" \ + "\363\224\377\377\377\7\376\376\376\265\265\265;;=::<;;=::<;;=\203::<" \ + "\1;;=\203::<\1;;=\203::<\2GGI\332\332\332\203\377\377\377\1\376\376\376" \ + "\377\377\377\377\347\377\377\377\7\377\377\375\375\376\377\376\377\377" \ + "\376\377\375\377\374\377\377\377\375\375\377\376\202\377\377\377\5\372" \ + "\373\366\240\320b\215\307\77\212\306@\215\305>\202\214\305@\20\215\305" \ + "@\212\306@\214\305D\216\306\77\214\306>\215\307\77\214\306>\212\306@" \ + "\214\306>\215\307\77\215\305@\242\320c\370\373\362\377\377\373\377\376" \ + "\377\377\377\375\232\377\377\377\3\376\376\376\377\377\377^^`\202;;=" \ + "\205::<\1""99;\202;;=\5::<;;=\332\332\332\377\377\377\376\376\376\377" \ + "\377\377\377\347\377\377\377\1\376\376\376\204\377\377\377\1lln\204:" \ + ":<\202;;=\203::<\6;;=99;GGI\332\332\332\377\377\377\376\376\376\225\377" \ + "\377\377\2\264\264\264;;=\202::<\2""99;;;=\202::<\3""99;;;=::<\202;;" \ + "=\202::<\4;;=::<GGI\332\332\332\210\377\377\377\1\376\376\376\377\377" \ + "\377\377\342\377\377\377\37\376\377\377\376\377\375\377\375\376\375\377" \ + "\376\377\377\375\377\377\377\377\376\377\370\373\362\241\321a\215\307" \ + "\77\215\307=\214\305@\214\306>\212\307<\214\306>\214\306<\214\306>\216" \ + "\306\77\215\305<\212\307>\213\307A\215\305>\212\307>\215\307\77\214\306" \ + ">\242\321a\373\374\364\377\377\377\376\377\377\376\376\376\376\377\377" \ + "\234\377\377\377\2\364\364\364RRT\202::<\4""99;;;=::<;;=\205::<\3SSU" \ + "\362\362\362\377\377\377\202\376\376\376\377\377\377\377\351\377\377" \ + "\377\1\234\234\236\204::<\1;;=\203::<\1;;=\203::<\1\265\265\267\231\377" \ + "\377\377\2\265\265\267;;=\203::<\2""99;;;=\202::<\1;;=\202::<\1;;=\202" \ + "::<\4;;=::<FFF\332\332\332\203\377\377\377\1\376\376\376\202\377\377" \ + "\377\1\376\376\376\377\377\377\377\342\377\377\377\202\377\377\375\3" \ + "\377\374\377\375\377\376\376\377\377\202\377\377\377\25\370\373\364\243" \ + "\322b\217\304@\212\306@\214\305@\215\305>\212\307>\212\306@\214\305B" \ + "\214\305@\214\305B\214\306>\212\307>\212\310\77\214\306>\217\304@\214" \ + "\306>\214\305@\242\322b\370\373\362\377\377\377\202\377\376\377\1\377" \ + "\377\375\235\377\377\377\3\376\376\376\332\332\334GGI\202;;=\6::<;;=" \ + "99;;;=::<;;=\203::<\1yyy\202\376\376\376\202\377\377\377\1\376\376\376" \ + "\377\377\377\377\345\377\377\377\4\376\376\376\317\317\317::<;;=\202" \ + "::<\3;;=99;;;=\204::<\6;;=\221\221\223\377\377\377\376\376\376\377\377" \ + "\377\376\376\376\226\377\377\377\3\376\376\376\265\265\267;;=\202::<" \ + "\2;;=99;\205::<\1;;=\204::<\4;;=FFH\332\332\332\376\376\376\205\377\377" \ + "\377\1\376\376\376\377\377\377\377\342\377\377\377\1\375\377\376\202" \ + "\377\377\375\34\377\377\377\376\376\376\373\373\363\243\322b\211\307" \ + "B\212\307<\215\305>\214\306>\212\307>\214\305@\217\304>\212\307<\214" \ + "\306<\214\306>\215\307\77\213\307A\214\306>\215\305@\215\307\77\212\307" \ + ">\244\317c\370\373\362\377\377\373\376\377\377\377\376\377\375\376\377" \ + "\377\377\375\377\376\377\236\377\377\377\4\265\265\267::<;;=99;\202;" \ + ";=\205::<\202;;=\1\250\250\250\202\377\377\377\1\376\376\376\377\377" \ + "\377\377\343\377\377\377\1\376\376\376\202\377\377\377\3\363\363\363" \ + "FFH;;=\202::<\5;;=::<;;=::<99;\202;;=\2::<kkm\205\377\377\377\1\376\376" \ + "\376\227\377\377\377\1\265\265\265\204::<\6;;=::<;;=::<;;=::<\202;;=" \ + "\203::<\4;;=FFH\333\333\333\376\376\376\202\377\377\377\1\376\376\376" \ + "\377\377\377\377\343\377\377\377\3\377\376\377\377\377\377\375\377\376" \ + "\202\377\377\377\11\373\373\363\241\321d\214\306>\213\310=\214\306>\214" \ + "\305@\213\310=\212\306@\217\304>\202\215\307=\14\214\306>\215\305>\214" \ + "\306>\215\305>\217\304@\215\307\77\215\307=\242\320c\367\375\361\376" \ + "\376\377\377\376\377\376\376\376\202\377\377\375\2\374\377\377\377\376" \ + "\377\234\377\377\377\1\376\376\376\202\377\377\377\10\221\221\221::<" \ + ";;=99;::<;;=::<;;=\205::<\2\333\333\333\376\376\376\377\377\377\377\347" \ + "\377\377\377\1kkk\202::<\1;;=\205::<\1;;=\202::<\2RRT\363\363\365\236" \ + "\377\377\377\1\265\265\267\203::<\2""99;;;=\203::<\1;;=\202::<\202;;" \ + "=\203::<\2FFH\332\332\332\377\377\377\377\346\377\377\377\1\377\377\375" \ + "\202\377\377\377\32\377\376\377\370\373\364\243\322b\214\306>\213\310" \ + "\77\214\305@\215\305>\215\305@\214\306>\214\305B\212\307<\215\307=\214" \ + "\305B\214\306>\215\306A\212\306@\212\307>\214\306>\212\307<\244\317c" \ + "\370\373\364\377\377\377\377\375\376\377\377\375\376\377\377\377\377" \ + "\377\202\377\376\377\241\377\377\377\2kkm::<\202;;=\1""99;\204::<\203" \ + ";;=\2SSU\364\364\364\377\377\377\377\336\377\377\377\3\376\376\376\377" \ + "\377\377\376\376\376\204\377\377\377\2\376\376\376\250\250\252\202::" \ + "<\1;;=\210::<\2FFH\333\333\333\202\377\377\377\1\376\376\376\235\377" \ + "\377\377\2\265\265\265;;=\203::<\1;;=\205::<\1;;=\204::<\3;;=FFH\332" \ + "\332\332\206\377\377\377\3\376\376\376\377\377\377\376\376\376\243\377" \ + "\377\377\4\376\377\377\377\377\375\377\376\377\376\376\377\202\377\377" \ + "\377\2\376\377\375\376\377\377\230\377\377\377\10\376\377\377\377\376" \ + "\377\376\377\377\376\377\375\376\376\376\376\377\377\377\377\377\377" \ + "\376\377\231\377\377\377\7\377\376\377\376\376\374\376\377\377\377\377" \ + "\375\374\377\377\376\377\377\377\376\377\231\377\377\377\17\375\377\374" \ + "\377\377\375\377\377\377\377\376\377\376\377\377\377\376\377\377\377" \ + "\377\376\377\377\376\376\374\377\377\377\377\377\373\377\377\377\376" \ + "\377\377\377\377\377\377\377\375\220\377\377\377\4\377\377\373\377\377" \ + "\377\377\377\375\377\377\377\202\376\377\377\2\377\377\375\377\377\373" \ + "\251\377\377\377\10\376\376\377\377\377\375\377\377\377\377\377\375\377" \ + "\377\377\377\376\377\377\377\375\376\377\377\202\377\377\377\6\370\373" \ + "\362\243\322b\211\307B\213\310=\214\305@\214\306<\202\215\305@\4\214" \ + "\306<\214\305@\214\306<\215\307\77\202\214\306>\6\212\307>\214\306>\215" \ + "\307\77\214\305@\244\317c\367\375\361\251\377\377\377\6\363\363\363T" \ + "TT::<;;=::<;;=\206::<\2;;=www\204\377\377\377\1\376\376\376\377\377\377" \ + "\377\340\377\377\377\2\332\332\332;;=\203::<\3;;=99;;;=\203::<\3;;=:" \ + ":<\265\265\267\204\377\377\377\1\376\376\376\235\377\377\377\12\265\265" \ + "\267;;=::<;;=99;;;=::<;;=::<;;=\202::<\1;;=\203::<\3;;=FFF\332\332\332" \ + "\206\377\377\377\1\376\376\376\244\377\377\377\202\377\377\375\1\377" \ + "\377\377\202\376\377\375\3\376\376\377\377\377\377\377\376\377\230\377" \ + "\377\377\3\376\377\375\377\377\377\377\377\373\202\377\376\377\2\377" \ + "\377\377\376\376\376\231\377\377\377\10\376\377\373\376\375\377\377\377" \ + "\375\377\376\377\377\375\377\377\377\373\377\376\377\377\377\375\230" \ + "\377\377\377\12\377\376\377\377\377\377\377\375\376\376\377\377\376\377" \ + "\372\376\377\377\377\377\377\376\377\375\377\376\377\377\377\375\203" \ + "\377\377\377\202\376\377\375\1\375\376\377\227\377\377\377\1\377\374" \ + "\377\250\377\377\377\6\376\376\377\377\376\377\375\376\377\376\377\377" \ + "\377\377\375\375\377\376\203\377\377\377\27\377\377\375\372\373\366\241" \ + "\321a\217\304@\212\307<\214\306>\215\305>\215\305@\213\310=\212\306@" \ + "\214\306>\214\305B\215\307\77\215\305>\215\306A\212\307>\214\306>\215" \ + "\307\77\214\306>\242\322b\370\373\362\376\376\377\377\375\376\251\377" \ + "\377\377\2\331\331\331;;=\206::<\1;;=\203::<\2;;=\265\265\265\204\377" \ + "\377\377\1\376\376\376\202\377\377\377\1\376\376\376\377\377\377\377" \ + "\322\377\377\377\1\376\376\376\203\377\377\377\3\376\376\376\377\377" \ + "\377\376\376\376\202\377\377\377\2\363\363\363SSU\203::<\2;;=::<\202" \ + ";;=\2""99;;;=\202::<\1\204\204\204\206\377\377\377\1\376\376\376\234" \ + "\377\377\377\7\376\376\376\265\265\265;;=::<;;=::<;;=\203::<\1;;=\203" \ + "::<\1;;=\203::<\2GGI\332\332\332\203\377\377\377\1\376\376\376\247\377" \ + "\377\377\1\377\377\375\202\377\376\377\1\377\375\377\202\377\377\377" \ + "\1\377\376\377\232\377\377\377\6\377\377\375\377\377\377\375\377\376" \ + "\376\377\375\377\377\375\377\375\377\230\377\377\377\202\377\377\375" \ + "\2\377\377\377\376\376\376\202\377\377\377\2\376\377\377\374\377\377" \ + "\230\377\377\377\1\377\377\375\202\377\376\377\1\375\376\377\203\377" \ + "\377\377\1\377\377\375\202\377\377\377\6\376\376\377\377\377\375\377" \ + "\377\377\377\375\377\377\376\377\377\377\375\220\377\377\377\1\376\377" \ + "\377\202\377\377\377\3\376\377\375\376\376\376\377\376\377\252\377\377" \ + "\377\7\377\377\375\375\376\377\376\377\377\376\377\375\377\374\377\377" \ + "\377\375\375\377\376\202\377\377\377\5\372\373\366\240\320b\215\307\77" \ + "\212\306@\215\305>\202\214\305@\20\215\305@\212\306@\214\305D\216\306" \ + "\77\214\306>\215\307\77\214\306>\212\306@\214\306>\215\307\77\215\305" \ + "@\242\320c\370\373\362\377\377\373\377\376\377\377\377\375\252\377\377" \ + "\377\2\250\250\25099;\204::<\12;;=99;::<;;=99;::<FFH\346\346\346\377" \ + "\377\377\376\376\376\202\377\377\377\1\376\376\376\377\377\377\377\330" \ + "\377\377\377\1\376\376\376\204\377\377\377\3\221\221\221::<;;=\202::" \ + "<\5;;=::<;;=::<;;=\202::<\4___\363\363\363\377\377\377\376\376\376\202" \ + "\377\377\377\5\376\376\376\377\377\377\376\376\376\377\377\377\376\376" \ + "\376\234\377\377\377\2\264\264\264;;=\202::<\2""99;;;=\202::<\3""99;" \ + ";;=::<\202;;=\202::<\4;;=::<GGI\332\332\332\210\377\377\377\1\376\376" \ + "\376\241\377\377\377\7\376\377\377\376\376\377\377\377\377\377\377\375" \ + "\376\377\375\375\377\376\376\377\377\230\377\377\377\3\376\376\377\376" \ + "\377\377\376\376\377\203\377\377\377\1\376\376\374\231\377\377\377\1" \ + "\377\376\377\202\377\377\377\202\376\377\377\1\376\376\376\232\377\377" \ + "\377\11\376\377\377\376\376\376\377\377\377\376\377\377\377\377\377\377" \ + "\377\375\376\377\377\376\376\377\376\377\377\202\377\377\377\5\377\377" \ + "\375\377\377\377\377\376\377\377\377\377\376\377\377\220\377\377\377" \ + "\10\376\376\377\377\376\377\377\377\377\376\376\376\377\376\377\377\377" \ + "\375\377\376\377\377\377\375\251\377\377\377\37\376\377\377\376\377\375" \ + "\377\375\376\375\377\376\377\377\375\377\377\377\377\376\377\370\373" \ + "\362\241\321a\215\307\77\215\307=\214\305@\214\306>\212\307<\214\306" \ + ">\214\306<\214\306>\216\306\77\215\305<\212\307>\213\307A\215\305>\212" \ + "\307>\215\307\77\214\306>\242\321a\373\374\364\377\377\377\376\377\377" \ + "\376\376\376\376\377\377\253\377\377\377\1yyy\205::<\3;;=::<99;\202;" \ + ";=\3::<__a\376\376\376\377\377\377\377\335\377\377\377\1\376\376\376" \ + "\202\377\377\377\5\301\301\301::<;;=99;;;=\207::<\2GGI\332\332\332\203" \ + "\377\377\377\1\376\376\376\243\377\377\377\2\265\265\267;;=\203::<\2" \ + "99;;;=\202::<\1;;=\202::<\1;;=\202::<\4;;=::<FFF\332\332\332\203\377" \ + "\377\377\1\376\376\376\202\377\377\377\1\376\376\376\242\377\377\377" \ + "\1\377\377\375\204\377\377\377\1\376\377\377\231\377\377\377\202\377" \ + "\376\377\202\377\377\377\4\377\377\375\377\377\377\376\377\377\375\377" \ + "\376\230\377\377\377\203\377\377\375\202\377\377\377\2\376\376\376\376" \ + "\377\377\231\377\377\377\1\376\376\376\202\376\377\377\13\377\376\374" \ + "\377\376\377\376\376\374\376\377\377\377\377\377\376\377\377\377\377" \ + "\377\377\377\375\376\376\376\377\377\377\377\376\377\222\377\377\377" \ + "\202\377\377\375\5\377\377\377\376\377\377\377\377\377\377\377\375\376" \ + "\377\377\251\377\377\377\202\377\377\375\3\377\374\377\375\377\376\376" \ + "\377\377\202\377\377\377\25\370\373\364\243\322b\217\304@\212\306@\214" \ + "\305@\215\305>\212\307>\212\306@\214\305B\214\305@\214\305B\214\306>" \ + "\212\307>\212\310\77\214\306>\217\304@\214\306>\214\305@\242\322b\370" \ + "\373\362\377\377\377\202\377\376\377\1\377\377\375\254\377\377\377\4" \ + "\363\363\363SSU;;=99;\202;;=\1""99;\204::<\3;;=::<\235\235\237\377\377" \ + "\377\377\334\377\377\377\1\376\376\376\202\377\377\377\2\363\363\363" \ + "GGI\202::<\7;;=::<99;::<;;=::<;;=\202::<\2\266\266\266\376\376\376\204" \ + "\377\377\377\202\376\376\376\202\377\377\377\1\376\376\376\236\377\377" \ + "\377\3\376\376\376\265\265\267;;=\202::<\2;;=99;\205::<\1;;=\204::<\4" \ + ";;=FFH\332\332\332\376\376\376\205\377\377\377\1\376\376\376\240\377" \ + "\377\377\10\376\377\375\377\375\377\377\377\375\376\377\375\377\377\377" \ + "\377\376\377\377\377\377\376\376\374\230\377\377\377\10\374\377\377\377" \ + "\376\374\377\377\377\376\376\374\377\376\377\376\377\377\377\377\377" \ + "\377\376\377\230\377\377\377\3\377\377\375\377\377\377\376\377\375\203" \ + "\377\377\377\1\377\376\377\231\377\377\377\6\377\375\377\376\376\374" \ + "\377\377\377\377\376\377\376\377\375\377\376\377\202\377\377\377\2\377" \ + "\376\377\377\377\377\202\376\377\377\2\376\376\377\376\377\377\222\377" \ + "\377\377\2\377\377\375\377\375\377\202\376\377\377\4\376\376\376\376" \ + "\377\377\375\377\374\377\375\377\251\377\377\377\1\375\377\376\202\377" \ + "\377\375\34\377\377\377\376\376\376\373\373\363\243\322b\211\307B\212" \ + "\307<\215\305>\214\306>\212\307>\214\305@\217\304>\212\307<\214\306<" \ + "\214\306>\215\307\77\213\307A\214\306>\215\305@\215\307\77\212\307>\244" \ + "\317c\370\373\362\377\377\373\376\377\377\377\376\377\375\376\377\377" \ + "\377\375\377\376\377\252\377\377\377\5\376\376\376\377\377\377\333\333" \ + "\33399;;;=\202::<\5;;=99;;;=99;;;=\203::<\1\332\332\334\377\377\377\377" \ + "\330\377\377\377\1\376\376\376\205\377\377\377\1xxx\202::<\1;;=\202:" \ + ":<\1;;=\204::<\4:::xxx\376\376\376\377\377\377\202\376\376\376\205\377" \ + "\377\377\3\376\376\376\377\377\377\376\376\376\237\377\377\377\1\265" \ + "\265\265\204::<\6;;=::<;;=::<;;=::<\202;;=\203::<\4;;=FFH\333\333\333" \ + "\376\376\376\202\377\377\377\1\376\376\376\242\377\377\377\7\376\376" \ + "\376\377\376\377\326\352\267\247\324o\247\324m\252\324r\247\324o\231" \ + "\252\324p\10\323\353\271\377\376\377\377\377\377\376\377\377\350\365" \ + "\333\253\323p\250\324r\251\324k\230\252\324p\10\250\325n\252\324p\277" \ + "\337\223\376\377\377\377\377\377\375\377\376\376\377\377\276\336\222" \ + "\230\252\324p\7\250\325p\250\324r\247\324o\253\324n\251\323m\346\364" \ + "\332\377\376\377\202\377\377\377\7\323\352\266\253\323p\251\323m\253" \ + "\323r\251\323o\247\324m\252\324r\220\252\324p\10\252\324n\253\324n\247" \ + "\324k\252\324p\254\325o\247\324m\252\324p\324\353\267\250\377\377\377" \ + "\3\377\376\377\377\377\377\375\377\376\202\377\377\377\11\373\373\363" \ + "\241\321d\214\306>\213\310=\214\306>\214\305@\213\310=\212\306@\217\304" \ + ">\202\215\307=\14\214\306>\215\305>\214\306>\215\305>\217\304@\215\307" \ + "\77\215\307=\242\320c\367\375\361\376\376\377\377\376\377\376\376\376" \ + "\202\377\377\375\2\374\377\377\377\376\377\254\377\377\377\2\376\376" \ + "\376\251\251\251\202::<\5;;=::<;;=99;;;=\204::<\1``b\377\377\377\377" \ + "\334\377\377\377\3\376\376\376\301\301\301:::\205::<\1""99;\202::<\4" \ + ";;=::<SSS\362\362\362\207\377\377\377\1\376\376\376\202\377\377\377\202" \ + "\376\376\376\240\377\377\377\1\265\265\267\203::<\2""99;;;=\203::<\1" \ + ";;=\202::<\202;;=\203::<\2FFH\332\332\332\245\377\377\377\10\376\377" \ + "\377\377\377\377\305\342\237\215\306A\215\307\77\215\305@\213\310=\214" \ + "\305@\230\214\306>\10\304\341\237\377\374\377\377\376\377\377\377\377" \ + "\341\362\322\215\305>\212\307>\215\305>\230\214\306>\4\215\305<\214\305" \ + "@\252\324r\376\377\377\202\377\377\377\2\377\377\375\250\324r\230\214" \ + "\306>\20\215\307\77\214\306>\214\306<\214\305B\212\307>\337\363\320\377" \ + "\376\377\376\377\377\376\376\374\305\342\240\214\305@\213\310=\215\305" \ + "@\214\306>\212\307<\214\305@\220\214\306>\10\214\305@\215\306C\212\307" \ + "<\214\306>\215\305>\212\306@\215\305>\304\343\237\250\377\377\377\1\377" \ + "\377\375\202\377\377\377\32\377\376\377\370\373\364\243\322b\214\306" \ + ">\213\310\77\214\305@\215\305>\215\305@\214\306>\214\305B\212\307<\215" \ + "\307=\214\305B\214\306>\215\306A\212\306@\212\307>\214\306>\212\307<" \ + "\244\317c\370\373\364\377\377\377\377\375\376\377\377\375\376\377\377" \ + "\377\377\377\202\377\376\377\257\377\377\377\1kkm\202::<\2;;=::<\202" \ + ";;=\3::<;;=::<\202;;=\1\233\233\233\377\377\377\377\330\377\377\377\1" \ + "\376\376\376\202\377\377\377\3\364\364\366FFH;;=\205::<\3;;=::<;;=\202" \ + "::<\1\316\316\316\256\377\377\377\2\265\265\265;;=\203::<\1;;=\205::" \ + "<\1;;=\204::<\3;;=FFH\332\332\332\206\377\377\377\3\376\376\376\377\377" \ + "\377\376\376\376\235\377\377\377\1\304\343\240\235\214\306>\1\305\342" \ + "\237\203\377\377\377\1\342\362\316\235\214\306>\1\250\325p\204\377\377" \ + "\377\1\252\324p\234\214\306>\2\215\307\77\342\362\316\203\377\377\377" \ + "\3\305\342\237\214\305@\215\305>\202\214\306>\1\214\305@\222\214\306" \ + ">\1\214\305@\205\214\306>\1\305\342\237\241\377\377\377\10\376\376\377" \ + "\377\377\375\377\377\377\377\377\375\377\377\377\377\376\377\377\377" \ + "\375\376\377\377\202\377\377\377\6\370\373\362\243\322b\211\307B\213" \ + "\310=\214\305@\214\306<\202\215\305@\4\214\306<\214\305@\214\306<\215" \ + "\307\77\202\214\306>\6\212\307>\214\306>\215\307\77\214\305@\244\317" \ + "c\367\375\361\267\377\377\377\2\363\363\363FFF\204::<\1;;=\203::<\4:" \ + "9>::<;;=\332\332\332\377\377\377\377\332\377\377\377\1yy{\202::<\2""9" \ + "9;;;=\202::<\6;;=99;::<;;=::<\234\234\236\260\377\377\377\12\265\265" \ + "\267;;=::<;;=99;;;=::<;;=::<;;=\202::<\1;;=\203::<\3;;=FFF\332\332\332" \ + "\206\377\377\377\1\376\376\376\236\377\377\377\1\304\343\240\235\214" \ + "\306>\1\305\342\237\203\377\377\377\1\342\362\316\235\214\306>\1\250" \ + "\325p\204\377\377\377\1\252\324p\234\214\306>\2\215\307\77\342\362\316" \ + "\203\377\377\377\3\305\342\237\214\305@\215\305>\202\214\306>\1\214\305" \ + "@\222\214\306>\1\214\305@\205\214\306>\1\305\342\237\240\377\377\377" \ + "\6\376\376\377\377\376\377\375\376\377\376\377\377\377\377\375\375\377" \ + "\376\203\377\377\377\27\377\377\375\372\373\366\241\321a\217\304@\212" \ + "\307<\214\306>\215\305>\215\305@\213\310=\212\306@\214\306>\214\305B" \ + "\215\307\77\215\305>\215\306A\212\307>\214\306>\215\307\77\214\306>\242" \ + "\322b\370\373\362\376\376\377\377\375\376\267\377\377\377\1\301\301\301" \ + "\205::<\3;;=::<;;=\202::<\2""99;```\377\377\377\377\331\377\377\377\1" \ + "\301\301\301\202::<\1;;=\203::<\1;;=\202::<\3<<>::<__a\261\377\377\377" \ + "\7\376\376\376\265\265\265;;=::<;;=::<;;=\203::<\1;;=\203::<\1;;=\203" \ + "::<\2GGI\332\332\332\203\377\377\377\1\376\376\376\240\377\377\377\1" \ + "\304\343\240\235\214\306>\1\305\342\237\203\377\377\377\1\342\362\316" \ + "\235\214\306>\1\250\325p\204\377\377\377\1\252\324p\234\214\306>\2\215" \ + "\307\77\342\362\316\203\377\377\377\3\305\342\237\214\305@\215\305>\202" \ + "\214\306>\1\214\305@\222\214\306>\1\214\305@\205\214\306>\1\305\342\237" \ + "\240\377\377\377\7\377\377\375\375\376\377\376\377\377\376\377\375\377" \ + "\374\377\377\377\375\375\377\376\202\377\377\377\5\372\373\366\240\320" \ + "b\215\307\77\212\306@\215\305>\202\214\305@\20\215\305@\212\306@\214" \ + "\305D\216\306\77\214\306>\215\307\77\214\306>\212\306@\214\306>\215\307" \ + "\77\215\305@\242\320c\370\373\362\377\377\373\377\376\377\377\377\375" \ + "\270\377\377\377\3\204\204\204::<;;=\206::<\4;;=::<;;=\234\234\236\377" \ + "\377\377\377\325\377\377\377\4\376\376\376\377\377\377\363\363\363SS" \ + "U\211::<\4""99;::<\332\332\334\376\376\376\202\377\377\377\1\376\376" \ + "\376\257\377\377\377\2\264\264\264;;=\202::<\2""99;;;=\202::<\3""99;" \ + ";;=::<\202;;=\202::<\4;;=::<GGI\332\332\332\210\377\377\377\1\376\376" \ + "\376\232\377\377\377\1\304\343\240\235\214\306>\1\305\342\237\203\377" \ + "\377\377\1\342\362\316\235\214\306>\1\250\325p\204\377\377\377\1\252" \ + "\324p\234\214\306>\2\215\307\77\342\362\316\203\377\377\377\3\305\342" \ + "\237\214\305@\215\305>\202\214\306>\1\214\305@\222\214\306>\1\214\305" \ + "@\205\214\306>\1\305\342\237\241\377\377\377\37\376\377\377\376\377\375" \ + "\377\375\376\375\377\376\377\377\375\377\377\377\377\376\377\370\373" \ + "\362\241\321a\215\307\77\215\307=\214\305@\214\306>\212\307<\214\306" \ + ">\214\306<\214\306>\216\306\77\215\305<\212\307>\213\307A\215\305>\212" \ + "\307>\215\307\77\214\306>\242\321a\373\374\364\377\377\377\376\377\377" \ + "\376\376\376\376\377\377\270\377\377\377\3\363\363\363TTT;;=\202::<\1" \ + ";;=\203::<\5""99;;;=::<;;=\332\332\332\377\377\377\377\323\377\377\377" \ + "\1\376\376\376\202\377\377\377\4\221\221\221;;=99;;;=\202::<\1;;=\202" \ + "::<\1;;=\202::<\1\233\233\233\202\377\377\377\1\376\376\376\262\377\377" \ + "\377\2\265\265\267;;=\203::<\2""99;;;=\202::<\1;;=\202::<\1;;=\202::" \ + "<\4;;=::<FFF\332\332\332\203\377\377\377\1\376\376\376\202\377\377\377" \ + "\1\376\376\376\233\377\377\377\1\304\343\240\235\214\306>\1\305\342\237" \ + "\203\377\377\377\1\342\362\316\235\214\306>\1\250\325p\204\377\377\377" \ + "\1\252\324p\234\214\306>\2\215\307\77\342\362\316\203\377\377\377\3\305" \ + "\342\237\214\305@\215\305>\202\214\306>\1\214\305@\222\214\306>\1\214" \ + "\305@\205\214\306>\1\305\342\237\240\377\377\377\202\377\377\375\3\377" \ + "\374\377\375\377\376\376\377\377\202\377\377\377\25\370\373\364\243\322" \ + "b\217\304@\212\306@\214\305@\215\305>\212\307>\212\306@\214\305B\214" \ + "\305@\214\305B\214\306>\212\307>\212\310\77\214\306>\217\304@\214\306" \ + ">\214\305@\242\322b\370\373\362\377\377\377\202\377\376\377\1\377\377" \ + "\375\272\377\377\377\7\316\316\316::<;;=::<99;::<;;=\205::<\1kkm\377" \ + "\377\377\377\325\377\377\377\1\315\315\315\206::<\6""99;::<99;;;=::<" \ + "```\206\377\377\377\1\376\376\376\257\377\377\377\3\376\376\376\265\265" \ + "\267;;=\202::<\2;;=99;\205::<\1;;=\204::<\4;;=FFH\332\332\332\376\376" \ + "\376\205\377\377\377\1\376\376\376\232\377\377\377\1\304\343\240\235" \ + "\214\306>\1\305\342\237\203\377\377\377\1\342\362\316\235\214\306>\1" \ + "\250\325p\204\377\377\377\1\252\324p\234\214\306>\2\215\307\77\342\362" \ + "\316\203\377\377\377\3\305\342\237\214\305@\215\305>\202\214\306>\1\214" \ + "\305@\222\214\306>\1\214\305@\205\214\306>\1\305\342\237\241\377\377" \ + "\377\1\375\377\376\202\377\377\375\34\377\377\377\376\376\376\373\373" \ + "\363\243\322b\211\307B\212\307<\215\305>\214\306>\212\307>\214\305@\217" \ + "\304>\212\307<\214\306<\214\306>\215\307\77\213\307A\214\306>\215\305" \ + "@\215\307\77\212\307>\244\317c\370\373\362\377\377\373\376\377\377\377" \ + "\376\377\375\376\377\377\377\375\377\376\377\272\377\377\377\2\222\222" \ + "\22299;\205::<\1;;=\203::<\2;;=\250\250\250\377\377\377\377\324\377\377" \ + "\377\4```;;=99;;;=\204::<\5;;=::<;;=::<\331\331\331\207\377\377\377\1" \ + "\376\376\376\260\377\377\377\1\265\265\265\204::<\6;;=::<;;=::<;;=::" \ + "<\202;;=\203::<\4;;=FFH\333\333\333\376\376\376\202\377\377\377\1\376" \ + "\376\376\234\377\377\377\1\304\343\240\235\214\306>\1\305\342\237\203" \ + "\377\377\377\1\342\362\316\235\214\306>\1\250\325p\204\377\377\377\1" \ + "\252\324p\234\214\306>\2\215\307\77\342\362\316\203\377\377\377\3\305" \ + "\342\237\214\305@\215\305>\202\214\306>\1\214\305@\222\214\306>\1\214" \ + "\305@\205\214\306>\1\305\342\237\240\377\377\377\3\377\376\377\377\377" \ + "\377\375\377\376\202\377\377\377\11\373\373\363\241\321d\214\306>\213" \ + "\310=\214\306>\214\305@\213\310=\212\306@\217\304>\202\215\307=\14\214" \ + "\306>\215\305>\214\306>\215\305>\217\304@\215\307\77\215\307=\242\320" \ + "c\367\375\361\376\376\377\377\376\377\376\376\376\202\377\377\375\2\374" \ + "\377\377\377\376\377\262\377\377\377\2\376\376\376\377\377\377\202\376" \ + "\376\376\204\377\377\377\5\363\363\363SSU99;::<;;=\207::<\2GGG\363\363" \ + "\363\377\377\377\377\322\377\377\377\4\234\234\234:::::<;;=\202::<\1" \ + ";;=\203::<\202;;=\1\234\234\236\207\377\377\377\1\376\376\376\262\377" \ + "\377\377\1\265\265\267\203::<\2""99;;;=\203::<\1;;=\202::<\202;;=\203" \ + "::<\2FFH\332\332\332\237\377\377\377\1\304\343\240\235\214\306>\1\305" \ + "\342\237\203\377\377\377\1\342\362\316\235\214\306>\1\250\325p\204\377" \ + "\377\377\1\252\324p\234\214\306>\2\215\307\77\342\362\316\203\377\377" \ + "\377\3\305\342\237\214\305@\215\305>\202\214\306>\1\214\305@\222\214" \ + "\306>\1\214\305@\205\214\306>\1\305\342\237\240\377\377\377\1\377\377" \ + "\375\202\377\377\377\32\377\376\377\370\373\364\243\322b\214\306>\213" \ + "\310\77\214\305@\215\305>\215\305@\214\306>\214\305B\212\307<\215\307" \ + "=\214\305B\214\306>\215\306A\212\306@\212\307>\214\306>\212\307<\244" \ + "\317c\370\373\364\377\377\377\377\375\376\377\377\375\376\377\377\377" \ + "\377\377\202\377\376\377\273\377\377\377\2\376\376\376\316\316\316\206" \ + "::<\202;;=\4::<;;=::<xxx\377\377\377\377\321\377\377\377\2\346\346\350" \ + "FFH\203::<\1;;=\206::<\1__a\202\377\377\377\1\377\377\375\271\377\377" \ + "\377\2\265\265\265;;=\203::<\1;;=\205::<\1;;=\203::<\4;;=::<GGI\331\331" \ + "\331\236\377\377\377\1\304\343\240\235\214\306>\1\305\342\237\203\377" \ + "\377\377\1\342\362\316\235\214\306>\1\250\325p\204\377\377\377\1\252" \ + "\324p\234\214\306>\2\215\307\77\342\362\316\203\377\377\377\3\305\342" \ + "\237\214\305@\215\305>\202\214\306>\1\214\305@\222\214\306>\1\214\305" \ + "@\205\214\306>\1\305\342\237\231\377\377\377\10\376\376\377\377\377\375" \ + "\377\377\377\377\377\375\377\377\377\377\376\377\377\377\375\376\377" \ + "\377\202\377\377\377\6\370\373\362\243\322b\211\307B\213\310=\214\305" \ + "@\214\306<\202\215\305@\4\214\306<\214\305@\214\306<\215\307\77\202\214" \ + "\306>\6\212\307>\214\306>\215\307\77\214\305@\244\317c\367\375\361\305" \ + "\377\377\377\2xxz;;=\203::<\3;;=::<;;=\203::<\2;;=\315\315\315\377\377" \ + "\377\377\313\377\377\377\203\376\376\376\202\377\377\377\3xxz;;=::<\202" \ + ";;=\1""99;\202;;=\202::<\4;;=::<\333\333\335\376\376\376\274\377\377" \ + "\377\12\265\265\267;;=::<;;=99;;;=::<;;=::<;;=\202::<\1;;=\202::<\4;" \ + ";=99;GGI\332\332\332\235\377\377\377\1\304\343\240\235\214\306>\1\305" \ + "\342\237\203\377\377\377\1\342\362\316\235\214\306>\1\250\325p\204\377" \ + "\377\377\1\252\324p\234\214\306>\2\215\307\77\342\362\316\203\377\377" \ + "\377\3\305\342\237\214\305@\215\305>\202\214\306>\1\214\305@\222\214" \ + "\306>\1\214\305@\205\214\306>\1\305\342\237\230\377\377\377\6\376\376" \ + "\377\377\376\377\375\376\377\376\377\377\377\377\375\375\377\376\203" \ + "\377\377\377\27\377\377\375\372\373\366\241\321a\217\304@\212\307<\214" \ + "\306>\215\305>\215\305@\213\310=\212\306@\214\306>\214\305B\215\307\77" \ + "\215\305>\215\306A\212\307>\214\306>\215\307\77\214\306>\242\322b\370" \ + "\373\362\376\376\377\377\375\376\304\377\377\377\2\364\364\364FFH\203" \ + "::<\2""99;;;=\203::<\4<<>99;TTT\376\376\376\377\377\377\377\310\377\377" \ + "\377\1\376\376\376\205\377\377\377\3\316\316\316::<99;\206::<\1;;=\202" \ + "::<\1\221\221\221\203\377\377\377\1\376\376\376\272\377\377\377\7\376" \ + "\376\376\265\265\265;;=::<;;=::<;;=\203::<\1;;=\203::<\6;;=::<;;=::<" \ + "FFH\332\332\332\234\377\377\377\1\304\343\240\235\214\306>\1\305\342" \ + "\237\203\377\377\377\1\342\362\316\235\214\306>\1\250\325p\204\377\377" \ + "\377\1\252\324p\234\214\306>\2\215\307\77\342\362\316\203\377\377\377" \ + "\3\305\342\237\214\305@\215\305>\202\214\306>\1\214\305@\222\214\306" \ + ">\1\214\305@\205\214\306>\1\305\342\237\230\377\377\377\7\377\377\375" \ + "\375\376\377\376\377\377\376\377\375\377\374\377\377\377\375\375\377" \ + "\376\202\377\377\377\5\372\373\366\240\320b\215\307\77\212\306@\215\305" \ + ">\202\214\305@\20\215\305@\212\306@\214\305D\216\306\77\214\306>\215" \ + "\307\77\214\306>\212\306@\214\306>\215\307\77\215\305@\242\320c\370\373" \ + "\362\377\377\373\377\376\377\377\377\375\304\377\377\377\3\376\376\376" \ + "\265\265\267;;=\204::<\1""99;\203::<\3;;=::<\234\234\234\203\377\377" \ + "\377\1\376\376\376\377\377\377\377\306\377\377\377\7\376\376\376\377" \ + "\377\377\376\376\376\377\377\377__a::<;;=\203::<\7;;=::<;;=::<;;=SSU" \ + "\363\363\363\300\377\377\377\2\264\264\264;;=\202::<\2""99;;;=\202::" \ + "<\3""99;;;=::<\202;;=\204::<\2FFH\332\332\332\233\377\377\377\1\304\343" \ + "\240\235\214\306>\1\305\342\237\203\377\377\377\1\342\362\316\235\214" \ + "\306>\1\250\325p\204\377\377\377\1\252\324p\234\214\306>\2\215\307\77" \ + "\342\362\316\203\377\377\377\3\305\342\237\214\305@\215\305>\202\214" \ + "\306>\1\214\305@\222\214\306>\1\214\305@\205\214\306>\1\305\342\237\231" \ + "\377\377\377\37\376\377\377\376\377\375\377\375\376\375\377\376\377\377" \ + "\375\377\377\377\377\376\377\370\373\362\241\321a\215\307\77\215\307" \ + "=\214\305@\214\306>\212\307<\214\306>\214\306<\214\306>\216\306\77\215" \ + "\305<\212\307>\213\307A\215\305>\212\307>\215\307\77\214\306>\242\321" \ + "a\373\374\364\377\377\377\376\377\377\376\376\376\376\377\377\301\377" \ + "\377\377\1\376\376\376\204\377\377\377\2kkm99;\203::<\202;;=\1""99;\203" \ + "::<\2FFH\363\363\363\377\377\377\377\310\377\377\377\1\376\376\376\203" \ + "\377\377\377\3\250\250\252::<;;=\203::<\1;;=\202::<\5;;=::<;;=\301\301" \ + "\301\376\376\376\301\377\377\377\2\265\265\267;;=\203::<\2""99;;;=\202" \ + "::<\1;;=\202::<\2;;=::<\202;;=\3::<GGI\332\332\332\232\377\377\377\1" \ + "\304\343\240\235\214\306>\1\305\342\237\203\377\377\377\1\342\362\316" \ + "\235\214\306>\1\250\325p\204\377\377\377\1\252\324p\234\214\306>\2\215" \ + "\307\77\342\362\316\203\377\377\377\3\305\342\237\214\305@\215\305>\202" \ + "\214\306>\1\214\305@\222\214\306>\1\214\305@\205\214\306>\1\305\342\237" \ + "\230\377\377\377\202\377\377\375\3\377\374\377\375\377\376\376\377\377" \ + "\202\377\377\377\25\370\373\364\243\322b\217\304@\212\306@\214\305@\215" \ + "\305>\212\307>\212\306@\214\305B\214\305@\214\305B\214\306>\212\307>" \ + "\212\310\77\214\306>\217\304@\214\306>\214\305@\242\322b\370\373\362" \ + "\377\377\377\202\377\376\377\1\377\377\375\301\377\377\377\1\376\376" \ + "\376\204\377\377\377\2\376\376\376\346\346\350\203::<\4;;=99;::<;;=\204" \ + "::<\3\203\203\203\377\377\377\376\376\376\377\377\377\377\311\377\377" \ + "\377\2\364\364\364FFH\202::<\5;;=::<;;=::<;;=\202::<\2;;=kkm\202\377" \ + "\377\377\1\376\376\376\300\377\377\377\3\376\376\376\265\265\267;;=\202" \ + "::<\2;;=99;\204::<\3;;=99;;;=\202::<\3;;=::<\265\265\265\232\377\377" \ + "\377\1\304\343\240\235\214\306>\1\305\342\237\203\377\377\377\1\342\362" \ + "\316\235\214\306>\1\250\325p\204\377\377\377\1\252\324p\234\214\306>" \ + "\2\215\307\77\342\362\316\203\377\377\377\3\305\342\237\214\305@\215" \ + "\305>\202\214\306>\1\214\305@\222\214\306>\1\214\305@\205\214\306>\1" \ + "\305\342\237\231\377\377\377\1\375\377\376\202\377\377\375\34\377\377" \ + "\377\376\376\376\373\373\363\243\322b\211\307B\212\307<\215\305>\214" \ + "\306>\212\307>\214\305@\217\304>\212\307<\214\306<\214\306>\215\307\77" \ + "\213\307A\214\306>\215\305@\215\307\77\212\307>\244\317c\370\373\362" \ + "\377\377\373\376\377\377\377\376\377\375\376\377\377\377\375\377\376" \ + "\377\301\377\377\377\202\376\376\376\2\377\377\377\376\376\376\202\377" \ + "\377\377\1\234\234\236\203::<\1;;=\206::<\2;;=\331\331\331\377\377\377" \ + "\377\306\377\377\377\1\376\376\376\203\377\377\377\4\233\233\233;;=:" \ + ":<;;=\202::<\3;;=99;;;=\203::<\1\346\346\350\305\377\377\377\1\265\265" \ + "\265\204::<\3;;=::<;;=\203::<\5;;=99;;;=::<\265\265\267\233\377\377\377" \ + "\1\304\343\240\235\214\306>\1\305\342\237\203\377\377\377\1\342\362\316" \ + "\235\214\306>\1\250\325p\204\377\377\377\1\252\324p\234\214\306>\2\215" \ + "\307\77\342\362\316\203\377\377\377\3\305\342\237\214\305@\215\305>\202" \ + "\214\306>\1\214\305@\222\214\306>\1\214\305@\205\214\306>\1\305\342\237" \ + "\230\377\377\377\3\377\376\377\377\377\377\375\377\376\202\377\377\377" \ + "\11\373\373\363\241\321d\214\306>\213\310=\214\306>\214\305@\213\310" \ + "=\212\306@\217\304>\202\215\307=\14\214\306>\215\305>\214\306>\215\305" \ + ">\217\304@\215\307\77\215\307=\242\320c\367\375\361\376\376\377\377\376" \ + "\377\376\376\376\202\377\377\375\2\374\377\377\377\376\377\301\377\377" \ + "\377\1\376\376\376\202\377\377\377\1\376\376\376\202\377\377\377\6\364" \ + "\364\364SSU::<;;=::<;;=\205::<\4""99;kkk\377\377\377\376\376\376\377" \ + "\377\377\377\307\377\377\377\2\346\346\346;;;\204::<\3;;=99;;;=\203:" \ + ":<\1\234\234\236\205\377\377\377\1\376\376\376\301\377\377\377\1\265" \ + "\265\267\203::<\2""99;;;=\202::<\1;;;\204::<\1\265\265\267\234\377\377" \ + "\377\1\304\343\240\235\214\306>\1\305\342\237\203\377\377\377\1\342\362" \ + "\316\235\214\306>\1\250\325p\204\377\377\377\1\252\324p\234\214\306>" \ + "\2\215\307\77\342\362\316\203\377\377\377\3\305\342\237\214\305@\215" \ + "\305>\202\214\306>\1\214\305@\222\214\306>\1\214\305@\205\214\306>\1" \ + "\305\342\237\230\377\377\377\1\377\377\375\202\377\377\377\32\377\376" \ + "\377\370\373\364\243\322b\214\306>\213\310\77\214\305@\215\305>\215\305" \ + "@\214\306>\214\305B\212\307<\215\307=\214\305B\214\306>\215\306A\212" \ + "\306@\212\307>\214\306>\212\307<\244\317c\370\373\364\377\377\377\377" \ + "\375\376\377\377\375\376\377\377\377\377\377\202\377\376\377\306\377" \ + "\377\377\1\376\376\376\202\377\377\377\2\301\301\303::<\202;;=\11::<" \ + ";;=::<;;=::<99;;;=::<\301\301\301\377\377\377\377\306\377\377\377\12" \ + "\376\376\376\377\377\377\204\204\204;;=::<:9>;;=::<99;;;=\203::<\5SS" \ + "U\363\363\363\376\376\376\377\377\377\376\376\376\305\377\377\377\5\265" \ + "\265\26599;;;=::<;;=\206::<\1\266\266\270\235\377\377\377\1\304\343\240" \ + "\235\214\306>\1\305\342\237\203\377\377\377\1\342\362\316\235\214\306" \ + ">\1\250\325p\204\377\377\377\1\252\324p\234\214\306>\2\215\307\77\342" \ + "\362\316\203\377\377\377\3\305\342\237\214\305@\215\305>\202\214\306" \ + ">\1\214\305@\222\214\306>\1\214\305@\205\214\306>\1\305\342\237\221\377" \ + "\377\377\10\376\376\377\377\377\375\377\377\377\377\377\375\377\377\377" \ + "\377\376\377\377\377\375\376\377\377\202\377\377\377\6\370\373\362\243" \ + "\322b\211\307B\213\310=\214\305@\214\306<\202\215\305@\4\214\306<\214" \ + "\305@\214\306<\215\307\77\202\214\306>\6\212\307>\214\306>\215\307\77" \ + "\214\305@\244\317c\367\375\361\322\377\377\377\1kkk\203::<\4;;=99;::" \ + "<;;=\203::<\1SSU\210\377\377\377\1\376\376\376\377\377\377\377\276\377" \ + "\377\377\1\316\316\316\202::<\1;;=\202::<\202;;=\202::<\4;;=::<\265\265" \ + "\267\376\376\376\307\377\377\377\3\376\376\376\377\377\377\265\265\267" \ + "\207::<\3""99;\266\266\270\376\376\377\202\377\377\377\1\376\376\376" \ + "\232\377\377\377\1\304\343\240\235\214\306>\1\305\342\237\203\377\377" \ + "\377\1\342\362\316\235\214\306>\1\250\325p\204\377\377\377\1\252\324" \ + "p\234\214\306>\2\215\307\77\342\362\316\203\377\377\377\3\305\342\237" \ + "\214\305@\215\305>\202\214\306>\1\214\305@\222\214\306>\1\214\305@\205" \ + "\214\306>\1\305\342\237\220\377\377\377\6\376\376\377\377\376\377\375" \ + "\376\377\376\377\377\377\377\375\375\377\376\203\377\377\377\27\377\377" \ + "\375\372\373\366\241\321a\217\304@\212\307<\214\306>\215\305>\215\305" \ + "@\213\310=\212\306@\214\306>\214\305B\215\307\77\215\305>\215\306A\212" \ + "\307>\214\306>\215\307\77\214\306>\242\322b\370\373\362\376\376\377\377" \ + "\375\376\321\377\377\377\1\346\346\346\204::<\1;;=\202::<\5;;=99;;;=" \ + "::<\266\266\266\205\377\377\377\202\376\376\376\2\377\377\377\376\376" \ + "\376\377\377\377\377\273\377\377\377\5\376\376\376\377\377\377kkm::<" \ + ";;=\202::<\1;;=\203::<\3;;=::<kkm\203\377\377\377\1\376\376\376\306\377" \ + "\377\377\4\376\376\376\377\377\377\265\265\265::<\202;;=\202::<\2""9" \ + "9;\266\266\270\237\377\377\377\1\304\343\240\235\214\306>\1\305\342\237" \ + "\203\377\377\377\1\342\362\316\235\214\306>\1\250\325p\204\377\377\377" \ + "\1\252\324p\234\214\306>\2\215\307\77\342\362\316\203\377\377\377\3\305" \ + "\342\237\214\305@\215\305>\202\214\306>\1\214\305@\222\214\306>\1\214" \ + "\305@\205\214\306>\1\305\342\237\220\377\377\377\7\377\377\375\375\376" \ + "\377\376\377\377\376\377\375\377\374\377\377\377\375\375\377\376\202" \ + "\377\377\377\5\372\373\366\240\320b\215\307\77\212\306@\215\305>\202" \ + "\214\305@\20\215\305@\212\306@\214\305D\216\306\77\214\306>\215\307\77" \ + "\214\306>\212\306@\214\306>\215\307\77\215\305@\242\320c\370\373\362" \ + "\377\377\373\377\376\377\377\377\375\322\377\377\377\1\221\221\223\202" \ + "::<\12;;=99;::<;;=::<;;=99;;;=EEG\364\364\364\203\377\377\377\1\376\376" \ + "\376\202\377\377\377\1\376\376\376\377\377\377\377\275\377\377\377\2" \ + "\316\316\320;;=\205::<\2""99;;;=\203::<\3\316\316\316\377\377\377\376" \ + "\376\376\313\377\377\377\3\265\265\265;;=99;\202::<\1\266\266\270\203" \ + "\377\377\377\3\376\376\376\377\377\377\376\376\376\232\377\377\377\1" \ + "\304\343\240\235\214\306>\1\305\342\237\203\377\377\377\1\342\362\316" \ + "\235\214\306>\1\250\325p\204\377\377\377\1\252\324p\234\214\306>\2\215" \ + "\307\77\342\362\316\203\377\377\377\3\305\342\237\214\305@\215\305>\202" \ + "\214\306>\1\214\305@\222\214\306>\1\214\305@\205\214\306>\1\305\342\237" \ + "\221\377\377\377\37\376\377\377\376\377\375\377\375\376\375\377\376\377" \ + "\377\375\377\377\377\377\376\377\370\373\362\241\321a\215\307\77\215" \ + "\307=\214\305@\214\306>\212\307<\214\306>\214\306<\214\306>\216\306\77" \ + "\215\305<\212\307>\213\307A\215\305>\212\307>\215\307\77\214\306>\242" \ + "\321a\373\374\364\377\377\377\376\377\377\376\376\376\376\377\377\322" \ + "\377\377\377\2\363\363\363FFH\203::<\202;;=\203::<\3;;=::<\235\235\235" \ + "\204\377\377\377\1\376\376\376\377\377\377\377\277\377\377\377\1__a\202" \ + "::<\1;;=\203::<\5;;=::<;;=::<\204\204\206\312\377\377\377\1\376\376\376" \ + "\202\377\377\377\7\376\376\376\377\377\377\265\265\267;;=99;\266\266" \ + "\270\376\376\377\203\377\377\377\202\376\376\376\233\377\377\377\1\304" \ + "\343\240\235\214\306>\1\305\342\237\203\377\377\377\1\342\362\316\235" \ + "\214\306>\1\250\325p\204\377\377\377\1\252\324p\234\214\306>\2\215\307" \ + "\77\342\362\316\203\377\377\377\3\305\342\237\214\305@\215\305>\202\214" \ + "\306>\1\214\305@\222\214\306>\1\214\305@\205\214\306>\1\305\342\237\220" \ + "\377\377\377\202\377\377\375\3\377\374\377\375\377\376\376\377\377\202" \ + "\377\377\377\25\370\373\364\243\322b\217\304@\212\306@\214\305@\215\305" \ + ">\212\307>\212\306@\214\305B\214\305@\214\305B\214\306>\212\307>\212" \ + "\310\77\214\306>\217\304@\214\306>\214\305@\242\322b\370\373\362\377" \ + "\377\377\202\377\376\377\1\377\377\375\324\377\377\377\4\234\234\234" \ + ";;=::<<<>\204::<\1;;=\202::<\2FFH\363\363\363\204\377\377\377\1\376\376" \ + "\376\202\377\377\377\1\376\376\376\377\377\377\377\272\377\377\377\1" \ + "\265\265\265\202::<\5;;=99;::<;;=::<\202;;=\3""99;;;=\346\346\346\320" \ + "\377\377\377\2\264\264\266\265\265\267\203\377\377\377\202\376\376\376" \ + "\235\377\377\377\1\304\343\240\235\214\306>\1\305\342\237\203\377\377" \ + "\377\1\342\362\316\235\214\306>\1\250\325p\204\377\377\377\1\252\324" \ + "p\234\214\306>\2\215\307\77\342\362\316\203\377\377\377\3\305\342\237" \ + "\214\305@\215\305>\202\214\306>\1\214\305@\222\214\306>\1\214\305@\205" \ + "\214\306>\1\305\342\237\221\377\377\377\1\375\377\376\202\377\377\375" \ + "\34\377\377\377\376\376\376\373\373\363\243\322b\211\307B\212\307<\215" \ + "\305>\214\306>\212\307>\214\305@\217\304>\212\307<\214\306<\214\306>" \ + "\215\307\77\213\307A\214\306>\215\305@\215\307\77\212\307>\244\317c\370" \ + "\373\362\377\377\373\376\377\377\377\376\377\375\376\377\377\377\375" \ + "\377\376\377\320\377\377\377\1\376\376\376\203\377\377\377\2SSU;;=\203" \ + "::<\1;;=\203::<\3""99;::<\234\234\236\203\377\377\377\1\376\376\376\377" \ + "\377\377\377\276\377\377\377\5RRT99;;;=99;;;=\203::<\4""99;;;=::<\234" \ + "\234\236\314\377\377\377\1\376\376\376\212\377\377\377\1\376\376\376" \ + "\235\377\377\377\1\304\343\240\235\214\306>\1\305\342\237\203\377\377" \ + "\377\1\342\362\316\235\214\306>\1\250\325p\204\377\377\377\1\252\324" \ + "p\234\214\306>\2\215\307\77\342\362\316\203\377\377\377\3\305\342\237" \ + "\214\305@\215\305>\202\214\306>\1\214\305@\222\214\306>\1\214\305@\205" \ + "\214\306>\1\305\342\237\220\377\377\377\3\377\376\377\377\377\377\375" \ + "\377\376\202\377\377\377\11\373\373\363\241\321d\214\306>\213\310=\214" \ + "\306>\214\305@\213\310=\212\306@\217\304>\202\215\307=\14\214\306>\215" \ + "\305>\214\306>\215\305>\217\304@\215\307\77\215\307=\242\320c\367\375" \ + "\361\376\376\377\377\376\377\376\376\376\202\377\377\375\2\374\377\377" \ + "\377\376\377\324\377\377\377\3\265\265\265;;=99;\202;;=\1""99;\202;;" \ + "=\5::<;;=::<GGI\363\363\363\206\377\377\377\1\376\376\376\377\377\377" \ + "\377\271\377\377\377\2\266\266\270;;=\202::<\1;;=\202::<\6;;=::<;;=:" \ + ":<FFH\363\363\363\324\377\377\377\3\376\376\376\377\377\377\376\376\376" \ + "\236\377\377\377\1\304\343\240\235\214\306>\1\305\342\237\203\377\377" \ + "\377\1\342\362\316\235\214\306>\1\250\325p\204\377\377\377\1\252\324" \ + "p\234\214\306>\2\215\307\77\342\362\316\203\377\377\377\3\305\342\237" \ + "\214\305@\215\305>\202\214\306>\1\214\305@\222\214\306>\1\214\305@\205" \ + "\214\306>\1\305\342\237\220\377\377\377\1\377\377\375\202\377\377\377" \ + "\32\377\376\377\370\373\364\243\322b\214\306>\213\310\77\214\305@\215" \ + "\305>\215\305@\214\306>\214\305B\212\307<\215\307=\214\305B\214\306>" \ + "\215\306A\212\306@\212\307>\214\306>\212\307<\244\317c\370\373\364\377" \ + "\377\377\377\375\376\377\377\375\376\377\377\377\377\377\202\377\376" \ + "\377\326\377\377\377\1__a\203::<\1;;=\203::<\1;;=\202::<\1\234\234\234" \ + "\377\377\377\377\274\377\377\377\1\376\376\376\203\377\377\377\3SSU;" \ + ";=99;\210::<\1\234\234\234\365\377\377\377\7\376\377\375\304\341\236" \ + "\215\306A\214\305B\215\307=\212\307>\212\306@\230\214\305@\1\304\341" \ + "\236\203\377\377\377\4\341\362\320\214\306>\213\310\77\215\305@\231\214" \ + "\305@\2\215\307\77\252\322q\202\377\376\377\202\377\377\377\1\250\325" \ + "n\230\214\305@\3\215\305>\215\306A\215\307\77\202\214\306<\10\342\360" \ + "\317\376\377\377\377\377\375\376\377\377\305\342\240\215\305@\212\306" \ + "@\215\305>\202\214\305@\1\215\307=\220\214\305@\10\214\306>\212\306@" \ + "\216\306A\212\307>\215\305>\215\305@\214\305@\304\343\237\211\377\377" \ + "\377\10\376\376\377\377\377\375\377\377\377\377\377\375\377\377\377\377" \ + "\376\377\377\377\375\376\377\377\202\377\377\377\6\370\373\362\243\322" \ + "b\211\307B\213\310=\214\305@\214\306<\202\215\305@\4\214\306<\214\305" \ + "@\214\306<\215\307\77\202\214\306>\6\212\307>\214\306>\215\307\77\214" \ + "\305@\244\317c\367\375\361\335\377\377\377\2\376\376\376\316\316\316" \ + "\211::<\3;;=GGI\363\363\365\203\377\377\377\1\376\376\376\377\377\377" \ + "\377\266\377\377\377\10\376\376\376\377\377\377\376\376\376\377\377\377" \ + "\265\265\265;;=::<;;=\207::<\2GGI\363\363\363\364\377\377\377\7\377\376" \ + "\377\377\377\375\304\341\236\215\305>\215\307\77\214\306>\214\305@\231" \ + "\214\306>\7\304\343\237\377\377\377\375\376\377\377\377\375\341\360\321" \ + "\215\306A\214\305@\233\214\306>\6\252\324n\376\376\376\377\377\377\376" \ + "\377\377\377\376\377\252\324p\230\214\306>\7\215\306A\212\307>\214\306" \ + ">\212\307>\214\306>\343\361\320\376\377\377\202\377\377\377\7\305\342" \ + "\237\215\305>\213\310\77\214\306>\214\305@\212\306@\215\307\77\222\214" \ + "\306>\6\215\305>\212\307>\214\306>\215\307=\215\305@\305\342\237\210" \ + "\377\377\377\6\376\376\377\377\376\377\375\376\377\376\377\377\377\377" \ + "\375\375\377\376\203\377\377\377\27\377\377\375\372\373\366\241\321a" \ + "\217\304@\212\307<\214\306>\215\305>\215\305@\213\310=\212\306@\214\306" \ + ">\214\305B\215\307\77\215\305>\215\306A\212\307>\214\306>\215\307\77" \ + "\214\306>\242\322b\370\373\362\376\376\377\377\375\376\336\377\377\377" \ + "\1kkm\202::<\1;;=\205::<\202;;=\3\233\233\235\377\377\377\376\376\376" \ + "\377\377\377\377\274\377\377\377\3SSU99;;;=\20299;\1;;=\203::<\3;;=:" \ + ":<\234\234\236\366\377\377\377\7\376\377\375\305\342\240\213\304\77\213" \ + "\310\77\214\305@\215\306A\216\306=\230\214\306>\10\305\342\240\377\377" \ + "\375\376\377\377\377\376\377\341\360\317\214\306<\214\305@\212\306@\231" \ + "\214\306>\7\215\305@\252\324p\377\377\377\377\377\375\376\377\377\377" \ + "\376\374\252\324p\230\214\306>\7\212\307>\215\307\77\216\306A\212\307" \ + ">\213\304\77\343\361\320\377\377\375\202\377\377\377\3\307\342\237\214" \ + "\304\77\213\310\77\203\214\306>\1\215\307\77\220\214\306>\4\214\305@" \ + "\214\306<\215\304B\213\310\77\202\212\307>\2\215\305@\305\342\240\210" \ + "\377\377\377\7\377\377\375\375\376\377\376\377\377\376\377\375\377\374" \ + "\377\377\377\375\375\377\376\202\377\377\377\5\372\373\366\240\320b\215" \ + "\307\77\212\306@\215\305>\202\214\305@\20\215\305@\212\306@\214\305D" \ + "\216\306\77\214\306>\215\307\77\214\306>\212\306@\214\306>\215\307\77" \ + "\215\305@\242\320c\370\373\362\377\377\373\377\376\377\377\377\375\331" \ + "\377\377\377\1\376\376\376\203\377\377\377\4\376\376\376\317\317\321" \ + "::<;;=\203::<\3;;=::<;;=\202::<\4FFH\363\363\363\377\377\377\376\376" \ + "\376\377\377\377\377\264\377\377\377\1\376\376\376\205\377\377\377\1" \ + "\265\265\267\202;;=\3::<99;;;=\202::<\202;;=\2::<SSU\366\377\377\377" \ + "\7\377\376\377\375\377\374\304\341\237\216\306\77\212\307<\213\310\77" \ + "\212\307>\231\214\306>\2\305\342\240\377\377\377\202\377\376\377\3\341" \ + "\362\316\216\306\77\214\306<\231\214\306>\3\215\305@\212\307>\252\324" \ + "p\203\377\377\377\2\377\376\377\247\324o\230\214\306>\20\215\306A\214" \ + "\305B\215\307\77\211\305\77\214\304;\342\362\315\377\377\377\377\376" \ + "\377\376\376\376\305\342\237\215\306A\210\307;\215\306A\216\306A\214" \ + "\306>\212\306@\220\214\306>\202\214\305@\6\216\305C\213\305=\214\305" \ + "B\215\307\77\216\306\77\303\344\237\211\377\377\377\37\376\377\377\376" \ + "\377\375\377\375\376\375\377\376\377\377\375\377\377\377\377\376\377" \ + "\370\373\362\241\321a\215\307\77\215\307=\214\305@\214\306>\212\307<" \ + "\214\306>\214\306<\214\306>\216\306\77\215\305<\212\307>\213\307A\215" \ + "\305>\212\307>\215\307\77\214\306>\242\321a\373\374\364\377\377\377\376" \ + "\377\377\376\376\376\376\377\377\331\377\377\377\3\376\376\376\377\377" \ + "\377\376\376\376\203\377\377\377\1kkm\202::<\6;;=::<;;=::<;;=::<\202" \ + ";;=\1\233\233\235\377\377\377\377\267\377\377\377\1\376\376\376\204\377" \ + "\377\377\2kkm;;=\202::<\2;;=::<\202;;=\203::<\5\265\265\267\377\377\377" \ + "\376\376\376\377\377\377\376\376\376\362\377\377\377\2\376\377\377\377" \ + "\376\377\202\377\377\377\202\377\376\377\2\377\377\377\377\377\375\231" \ + "\377\377\377\4\377\376\377\376\377\377\375\377\376\377\377\377\202\376" \ + "\377\377\231\377\377\377\10\374\377\375\377\376\377\377\377\375\376\376" \ + "\376\377\377\377\376\377\377\376\376\374\377\376\377\230\377\377\377" \ + "\1\377\376\377\203\377\377\375\4\376\377\377\377\375\377\377\377\377" \ + "\376\377\377\202\377\377\377\3\376\376\376\377\376\377\377\377\375\202" \ + "\376\377\377\1\377\377\375\220\377\377\377\10\377\377\375\377\377\377" \ + "\376\376\376\377\377\377\377\377\375\377\377\377\376\377\377\377\375" \ + "\377\210\377\377\377\202\377\377\375\3\377\374\377\375\377\376\376\377" \ + "\377\202\377\377\377\25\370\373\364\243\322b\217\304@\212\306@\214\305" \ + "@\215\305>\212\307>\212\306@\214\305B\214\305@\214\305B\214\306>\212" \ + "\307>\212\310\77\214\306>\217\304@\214\306>\214\305@\242\322b\370\373" \ + "\362\377\377\377\202\377\376\377\1\377\377\375\340\377\377\377\1\316" \ + "\316\316\203::<\3;;=99;;;=\204::<\2FFH\363\363\363\202\377\377\377\1" \ + "\376\376\376\377\377\377\377\264\377\377\377\1\376\376\376\202\377\377" \ + "\377\1\316\316\320\206::<\1;;=\203::<\2SSU\376\376\376\366\377\377\377" \ + "\1\377\377\375\202\377\376\377\202\377\377\377\3\377\377\375\377\377" \ + "\377\376\377\377\230\377\377\377\202\376\377\377\6\377\377\375\377\377" \ + "\377\376\377\375\377\377\377\376\377\375\377\377\375\231\377\377\377" \ + "\2\376\377\377\377\377\375\202\377\377\377\1\376\376\376\232\377\377" \ + "\377\5\377\376\377\377\377\377\376\377\375\377\377\377\377\377\375\204" \ + "\377\377\377\202\376\377\377\1\376\376\376\202\377\377\377\202\376\377" \ + "\377\220\377\377\377\1\377\377\375\202\377\377\377\4\376\376\374\377" \ + "\376\377\377\377\377\376\377\375\212\377\377\377\1\375\377\376\202\377" \ + "\377\375\34\377\377\377\376\376\376\373\373\363\243\322b\211\307B\212" \ + "\307<\215\305>\214\306>\212\307>\214\305@\217\304>\212\307<\214\306<" \ + "\214\306>\215\307\77\213\307A\214\306>\215\305@\215\307\77\212\307>\244" \ + "\317c\370\373\362\377\377\373\376\377\377\377\376\377\375\376\377\377" \ + "\377\375\377\376\377\334\377\377\377\1\376\376\376\202\377\377\377\10" \ + "\376\376\376kkm::<;;=99;;;=::<;;=\202::<\202;;=\1\234\234\236\203\377" \ + "\377\377\1\376\376\376\377\377\377\377\262\377\377\377\5\376\376\376" \ + "\377\377\377\376\376\376\377\377\377lln\210::<\3""99;;;=\265\265\265" \ + "\202\377\377\377\1\376\376\376\202\377\377\377\1\376\376\376\370\377" \ + "\377\377\1\376\377\377\230\377\377\377\7\377\376\377\377\377\375\377" \ + "\376\377\376\376\377\377\377\375\377\377\377\377\377\375\233\377\377" \ + "\377\1\377\376\377\203\377\377\377\1\376\377\375\231\377\377\377\5\377" \ + "\377\375\377\377\377\377\377\375\377\377\377\377\377\375\202\377\377" \ + "\377\1\377\377\375\203\377\377\377\2\376\376\376\377\376\377\226\377" \ + "\377\377\5\377\377\375\377\377\377\376\377\377\377\377\375\376\377\377" \ + "\210\377\377\377\3\377\376\377\377\377\377\375\377\376\202\377\377\377" \ + "\11\373\373\363\241\321d\214\306>\213\310=\214\306>\214\305@\213\310" \ + "=\212\306@\217\304>\202\215\307=\14\214\306>\215\305>\214\306>\215\305" \ + ">\217\304@\215\307\77\215\307=\242\320c\367\375\361\376\376\377\377\376" \ + "\377\376\376\376\202\377\377\375\2\374\377\377\377\376\377\333\377\377" \ + "\377\1\376\376\376\202\377\377\377\3\376\376\376\377\377\377\316\316" \ + "\320\203::<\1;;=\202::<\1;;=\203::<\2FFH\377\377\377\202\376\376\376" \ + "\377\377\377\377\262\377\377\377\5\376\376\376\377\377\377\376\376\376" \ + "\377\377\377\332\332\332\206::<\1;;=\202::<\5;;=FFH\363\363\363\377\377" \ + "\377\376\376\376\203\377\377\377\1\376\376\376\365\377\377\377\1\377" \ + "\377\375\202\377\377\377\1\377\377\375\230\377\377\377\2\376\377\377" \ + "\377\377\375\204\377\377\377\2\377\376\377\376\377\375\230\377\377\377" \ + "\4\377\377\375\377\377\377\377\377\373\376\377\377\203\377\377\377\1" \ + "\377\376\377\230\377\377\377\13\376\377\377\377\377\375\377\377\377\376" \ + "\377\377\377\375\376\377\377\377\377\377\375\376\377\377\377\376\377" \ + "\377\377\377\376\376\376\202\377\377\377\1\377\377\375\226\377\377\377" \ + "\202\376\377\377\2\377\377\375\377\376\377\210\377\377\377\1\377\377" \ + "\375\202\377\377\377\32\377\376\377\370\373\364\243\322b\214\306>\213" \ + "\310\77\214\305@\215\305>\215\305@\214\306>\214\305B\212\307<\215\307" \ + "=\214\305B\214\306>\215\306A\212\306@\212\307>\214\306>\212\307<\244" \ + "\317c\370\373\364\377\377\377\377\375\376\377\377\375\376\377\377\377" \ + "\377\377\202\377\376\377\333\377\377\377\1\376\376\376\204\377\377\377" \ + "\11\376\376\376\377\377\377kkm::<;;=99;;;=::<;;=\202::<\3;;=::<\264\264" \ + "\264\377\377\377\377\265\377\377\377\1\376\376\376\202\377\377\377\1" \ + "\204\204\204\203::<\1;;=\206::<\1\235\235\237\377\377\377\377\377\377" \ + "\377\377\203\377\377\377\10\376\376\377\377\377\375\377\377\377\377\377" \ + "\375\377\377\377\377\376\377\377\377\375\376\377\377\202\377\377\377" \ + "\6\370\373\362\243\322b\211\307B\213\310=\214\305@\214\306<\202\215\305" \ + "@\4\214\306<\214\305@\214\306<\215\307\77\202\214\306>\6\212\307>\214" \ + "\306>\215\307\77\214\305@\244\317c\367\375\361\352\377\377\377\1\316" \ + "\316\316\203::<\1;;=\203::<\202;;=\2::<RRT\377\377\377\377\267\377\377" \ + "\377\3\346\346\346::<;;=\203::<\202;;=\5""99;::<;;=FFH\363\363\365\377" \ + "\377\377\377\377\377\377\377\202\377\377\377\6\376\376\377\377\376\377" \ + "\375\376\377\376\377\377\377\377\375\375\377\376\203\377\377\377\27\377" \ + "\377\375\372\373\366\241\321a\217\304@\212\307<\214\306>\215\305>\215" \ + "\305@\213\310=\212\306@\214\306>\214\305B\215\307\77\215\305>\215\306" \ + "A\212\307>\214\306>\215\307\77\214\306>\242\322b\370\373\362\376\376" \ + "\377\377\375\376\352\377\377\377\2kkm;;=\207::<\3;;=::<\301\301\301\377" \ + "\377\377\377\266\377\377\377\2\221\221\221;;=\202::<\202;;=\202::<\1" \ + ";;=\202::<\1\235\235\237\377\377\377\377\377\377\377\377\203\377\377" \ + "\377\7\377\377\375\375\376\377\376\377\377\376\377\375\377\374\377\377" \ + "\377\375\375\377\376\202\377\377\377\5\372\373\366\240\320b\215\307\77" \ + "\212\306@\215\305>\202\214\305@\20\215\305@\212\306@\214\305D\216\306" \ + "\77\214\306>\215\307\77\214\306>\212\306@\214\306>\215\307\77\215\305" \ + "@\242\320c\370\373\362\377\377\373\377\376\377\377\377\375\350\377\377" \ + "\377\4\376\376\376\377\377\377\265\265\26799;\203::<\3;;=::<;;=\203:" \ + ":<\2kkk\376\376\376\377\377\377\377\264\377\377\377\2\362\362\362FFH" \ + "\202::<\1;;=\203::<\5;;=::<;;=::<\363\363\363\377\377\377\377\377\377" \ + "\377\377\204\377\377\377\37\376\377\377\376\377\375\377\375\376\375\377" \ + "\376\377\377\375\377\377\377\377\376\377\370\373\362\241\321a\215\307" \ + "\77\215\307=\214\305@\214\306>\212\307<\214\306>\214\306<\214\306>\216" \ + "\306\77\215\305<\212\307>\213\307A\215\305>\212\307>\215\307\77\214\306" \ + ">\242\321a\373\374\364\377\377\377\376\377\377\376\376\376\376\377\377" \ + "\352\377\377\377\2\376\376\376TTV\204::<\7;;=99;::<;;=99;::<\332\332" \ + "\332\377\377\377\377\263\377\377\377\3\376\376\376\266\266\266;;=\203" \ + "::<\202;;=\204::<\1\205\205\207\377\377\377\377\377\377\377\377\204\377" \ + "\377\377\202\377\377\375\3\377\374\377\375\377\376\376\377\377\202\377" \ + "\377\377\25\370\373\364\243\322b\217\304@\212\306@\214\305@\215\305>" \ + "\212\307>\212\306@\214\305B\214\305@\214\305B\214\306>\212\307>\212\310" \ + "\77\214\306>\217\304@\214\306>\214\305@\242\322b\370\373\362\377\377" \ + "\377\202\377\376\377\1\377\377\375\354\377\377\377\2\265\265\267::<\202" \ + ";;=\205::<\4;;=::<\204\204\204\376\376\376\377\377\377\377\263\377\377" \ + "\377\1SSU\202::<\1;;=\206::<\2;;=\346\346\346\377\377\377\377\377\377" \ + "\377\377\205\377\377\377\1\375\377\376\202\377\377\375\34\377\377\377" \ + "\376\376\376\373\373\363\243\322b\211\307B\212\307<\215\305>\214\306" \ + ">\212\307>\214\305@\217\304>\212\307<\214\306<\214\306>\215\307\77\213" \ + "\307A\214\306>\215\305@\215\307\77\212\307>\244\317c\370\373\362\377" \ + "\377\373\376\377\377\377\376\377\375\376\377\377\377\375\377\376\377" \ + "\354\377\377\377\4FFH;;=99;;;=\203::<\5;;=99;;;=99;\364\364\364\377\377" \ + "\377\377\262\377\377\377\1\316\316\316\202;;=\1""99;\203::<\1;;=\203" \ + "::<\1xxz\377\377\377\377\377\377\377\377\205\377\377\377\3\377\376\377" \ + "\377\377\377\375\377\376\202\377\377\377\11\373\373\363\241\321d\214" \ + "\306>\213\310=\214\306>\214\305@\213\310=\212\306@\217\304>\202\215\307" \ + "=\14\214\306>\215\305>\214\306>\215\305>\217\304@\215\307\77\215\307" \ + "=\242\320c\367\375\361\376\376\377\377\376\377\376\376\376\202\377\377" \ + "\375\2\374\377\377\377\376\377\354\377\377\377\1\235\235\237\204::<\1" \ + "<<>\202::<\4;;=::<;;=\247\247\251\377\377\377\377\262\377\377\377\4\204" \ + "\204\204;;=::<;;=\206::<\2;;=\316\316\316\377\377\377\377\377\377\377" \ + "\377\205\377\377\377\1\377\377\375\202\377\377\377\32\377\376\377\370" \ + "\373\364\243\322b\214\306>\213\310\77\214\305@\215\305>\215\305@\214" \ + "\306>\214\305B\212\307<\215\307=\214\305B\214\306>\215\306A\212\306@" \ + "\212\307>\214\306>\212\307<\244\317c\370\373\364\377\377\377\377\375" \ + "\376\377\377\375\376\377\377\377\377\377\202\377\376\377\355\377\377" \ + "\377\1\363\363\363\212::<\1TTV\377\377\377\377\261\377\377\377\5\347" \ + "\347\351::<;;=::<;;=\204::<\3;;=::<TTT\377\377\377\377\376\377\377\377" \ + "\10\376\376\377\377\377\375\377\377\377\377\377\375\377\377\377\377\376" \ + "\377\377\377\375\376\377\377\202\377\377\377\6\370\373\362\243\322b\211" \ + "\307B\213\310=\214\305@\214\306<\202\215\305@\4\214\306<\214\305@\214" \ + "\306<\215\307\77\202\214\306>\6\212\307>\214\306>\215\307\77\214\305" \ + "@\244\317c\367\375\361\361\377\377\377\1\376\376\376\204\377\377\377" \ + "\1\204\204\204\202;;=\203::<\1;;=\202::<\202;;=\1\302\302\302\203\377" \ + "\377\377\1\376\376\376\377\377\377\377\244\377\377\377\1\376\376\376" \ + "\203\377\377\377\1\376\376\376\203\377\377\377\1\234\234\236\202::<\1" \ + ";;=\204::<\6;;=::<;;=\264\264\264\377\377\377\376\376\376\377\377\377" \ + "\377\373\377\377\377\6\376\376\377\377\376\377\375\376\377\376\377\377" \ + "\377\377\375\375\377\376\203\377\377\377\27\377\377\375\372\373\366\241" \ + "\321a\217\304@\212\307<\214\306>\215\305>\215\305@\213\310=\212\306@" \ + "\214\306>\214\305B\215\307\77\215\305>\215\306A\212\307>\214\306>\215" \ + "\307\77\214\306>\242\322b\370\373\362\376\376\377\377\375\376\365\377" \ + "\377\377\1\332\332\332\202::<\1;;=\202::<\6""99;::<;;=99;;;=xxx\205\377" \ + "\377\377\1\376\376\376\377\377\377\377\243\377\377\377\1\376\376\376" \ + "\206\377\377\377\4SSU;;=::<;;=\202::<\1;;=\203::<\3GGI\362\362\362\376" \ + "\376\376\377\377\377\377\374\377\377\377\7\377\377\375\375\376\377\376" \ + "\377\377\376\377\375\377\374\377\377\377\375\375\377\376\202\377\377" \ + "\377\5\372\373\366\240\320b\215\307\77\212\306@\215\305>\202\214\305" \ + "@\20\215\305@\212\306@\214\305D\216\306\77\214\306>\215\307\77\214\306" \ + ">\212\306@\214\306>\215\307\77\215\305@\242\320c\370\373\362\377\377" \ + "\373\377\376\377\377\377\375\364\377\377\377\3\376\376\376\377\377\377" \ + "__a\203::<\202;;=\6::<99;;;=::<;;=\345\345\345\203\377\377\377\1\376" \ + "\376\376\377\377\377\377\245\377\377\377\3\376\376\376\377\377\377\376" \ + "\376\376\202\377\377\377\2\316\316\316::<\202;;=\205::<\202;;=\1\203" \ + "\203\205\204\377\377\377\1\376\376\376\377\377\377\377\372\377\377\377" \ + "\37\376\377\377\376\377\375\377\375\376\375\377\376\377\377\375\377\377" \ + "\377\377\376\377\370\373\362\241\321a\215\307\77\215\307=\214\305@\214" \ + "\306>\212\307<\214\306>\214\306<\214\306>\216\306\77\215\305<\212\307" \ + ">\213\307A\215\305>\212\307>\215\307\77\214\306>\242\321a\373\374\364" \ + "\377\377\377\376\377\377\376\376\376\376\377\377\362\377\377\377\202" \ + "\376\376\376\3\377\377\377\376\376\376\265\265\267\202::<\1;;=\207::" \ + "<\3\251\251\253\377\377\377\376\376\376\203\377\377\377\1\376\376\376" \ + "\377\377\377\377\247\377\377\377\2\376\376\376\204\204\206\207::<\1;" \ + ";=\202::<\3\346\346\346\377\377\377\376\376\376\377\377\377\377\374\377" \ + "\377\377\202\377\377\375\3\377\374\377\375\377\376\376\377\377\202\377" \ + "\377\377\25\370\373\364\243\322b\217\304@\212\306@\214\305@\215\305>" \ + "\212\307>\212\306@\214\305B\214\305@\214\305B\214\306>\212\307>\212\310" \ + "\77\214\306>\217\304@\214\306>\214\305@\242\322b\370\373\362\377\377" \ + "\377\202\377\376\377\1\377\377\375\364\377\377\377\17\376\376\376\377" \ + "\377\377\376\376\376\377\377\377FFH;;=99;::<;;=::<;;=99;;;=::<SSU\377" \ + "\377\377\377\251\377\377\377\1\376\376\376\203\377\377\377\3\363\363" \ + "\365::<;;=\202::<\11;;=::<;;=::<;;=::<kkm\377\377\377\376\376\376\377" \ + "\377\377\377\376\377\377\377\1\375\377\376\202\377\377\375\34\377\377" \ + "\377\376\376\376\373\373\363\243\322b\211\307B\212\307<\215\305>\214" \ + "\306>\212\307>\214\305@\217\304>\212\307<\214\306<\214\306>\215\307\77" \ + "\213\307A\214\306>\215\305@\215\307\77\212\307>\244\317c\370\373\362" \ + "\377\377\373\376\377\377\377\376\377\375\376\377\377\377\375\377\376" \ + "\377\361\377\377\377\202\376\376\376\2\377\377\377\376\376\376\202\377" \ + "\377\377\1\221\221\221\205::<\202;;=\5::<;;=99;\316\316\320\376\376\376" \ + "\377\377\377\377\250\377\377\377\1\376\376\376\202\377\377\377\4\266" \ + "\266\270::<99;;;=\203::<\1;;=\203::<\1\265\265\265\377\377\377\377\377" \ + "\377\377\377\3\377\376\377\377\377\377\375\377\376\202\377\377\377\11" \ + "\373\373\363\241\321d\214\306>\213\310=\214\306>\214\305@\213\310=\212" \ + "\306@\217\304>\202\215\307=\14\214\306>\215\305>\214\306>\215\305>\217" \ + "\304@\215\307\77\215\307=\242\320c\367\375\361\376\376\377\377\376\377" \ + "\376\376\376\202\377\377\375\2\374\377\377\377\376\377\360\377\377\377" \ + "\1\376\376\376\202\377\377\377\202\376\376\376\202\377\377\377\6\346" \ + "\346\346;;=99;::<99;;;=\204::<\2;;=\204\204\206\202\377\377\377\1\376" \ + "\376\376\377\377\377\377\251\377\377\377\1__a\203::<\3;;=::<;;=\203:" \ + ":<\4FFF\363\363\363\377\377\377\376\376\376\377\377\377\377\375\377\377" \ + "\377\1\377\377\375\202\377\377\377\32\377\376\377\370\373\364\243\322" \ + "b\214\306>\213\310\77\214\305@\215\305>\215\305@\214\306>\214\305B\212" \ + "\307<\215\307=\214\305B\214\306>\215\306A\212\306@\212\307>\214\306>" \ + "\212\307<\244\317c\370\373\364\377\377\377\377\375\376\377\377\375\376" \ + "\377\377\377\377\377\202\377\376\377\371\377\377\377\4^^`;;=::<;;=\202" \ + "::<\5;;=::<;;=::<FFH\377\377\377\377\253\377\377\377\3\346\346\346::" \ + "<;;=\210::<\1\204\204\204\202\377\377\377\202\376\376\376\377\377\377" \ + "\377\365\377\377\377\10\376\376\377\377\377\375\377\377\377\377\377\375" \ + "\377\377\377\377\376\377\377\377\375\376\377\377\202\377\377\377\6\370" \ + "\373\362\243\322b\211\307B\213\310=\214\305@\214\306<\202\215\305@\4" \ + "\214\306<\214\305@\214\306<\215\307\77\202\214\306>\6\212\307>\214\306" \ + ">\215\307\77\214\305@\244\317c\367\375\361\377\377\377\377\202\377\377" \ + "\377\3\265\265\267::<;;=\204::<\1;;=\202::<\2;;=\265\265\265\202\377" \ + "\377\377\1\376\376\376\377\377\377\377\246\377\377\377\2\376\376\376" \ + "\234\234\234\202;;=\203::<\1;;=\202::<\3""99;::<\332\332\332\377\377" \ + "\377\377\370\377\377\377\6\376\376\377\377\376\377\375\376\377\376\377" \ + "\377\377\377\375\375\377\376\203\377\377\377\27\377\377\375\372\373\366" \ + "\241\321a\217\304@\212\307<\214\306>\215\305>\215\305@\213\310=\212\306" \ + "@\214\306>\214\305B\215\307\77\215\305>\215\306A\212\307>\214\306>\215" \ + "\307\77\214\306>\242\322b\370\373\362\376\376\377\377\375\376\377\377" \ + "\377\377\5\377\377\377\363\363\365;;=::<;;=\202::<\3;;=::<;;=\202::<" \ + "\3xxz\377\377\377\376\376\376\377\377\377\377\246\377\377\377\3\376\376" \ + "\376\377\377\377SSS\202::<\1;;=\202::<\1;;=\202::<\6;;=SSU\377\377\377" \ + "\376\376\376\377\377\377\376\376\376\202\377\377\377\1\376\376\376\377" \ + "\377\377\377\362\377\377\377\7\377\377\375\375\376\377\376\377\377\376" \ + "\377\375\377\374\377\377\377\375\375\377\376\202\377\377\377\5\372\373" \ + "\366\240\320b\215\307\77\212\306@\215\305>\202\214\305@\20\215\305@\212" \ + "\306@\214\305D\216\306\77\214\306>\215\307\77\214\306>\212\306@\214\306" \ + ">\215\307\77\215\305@\242\320c\370\373\362\377\377\373\377\376\377\377" \ + "\377\375\377\377\377\377\11\377\377\377\376\376\376\204\204\206;;=::" \ + "<99;;;=::<;;=\204::<\3\362\362\362\377\377\377\376\376\376\377\377\377" \ + "\377\246\377\377\377\1\333\333\333\203::<\202;;=\202::<\5<<>99;::<\250" \ + "\250\252\376\376\376\203\377\377\377\1\376\376\376\377\377\377\377\365" \ + "\377\377\377\37\376\377\377\376\377\375\377\375\376\375\377\376\377\377" \ + "\375\377\377\377\377\376\377\370\373\362\241\321a\215\307\77\215\307" \ + "=\214\305@\214\306>\212\307<\214\306>\214\306<\214\306>\216\306\77\215" \ + "\305<\212\307>\213\307A\215\305>\212\307>\215\307\77\214\306>\242\321" \ + "a\373\374\364\377\377\377\376\377\377\376\376\376\376\377\377\377\377" \ + "\377\377\202\377\377\377\1\301\301\301\202::<\1;;=\203::<\1;;=\203::" \ + "<\1\266\266\270\377\377\377\377\250\377\377\377\2\220\220\220;;=\204" \ + "::<\6;;=::<99;;;=::<\346\346\346\205\377\377\377\1\376\376\376\377\377" \ + "\377\377\363\377\377\377\202\377\377\375\3\377\374\377\375\377\376\376" \ + "\377\377\202\377\377\377\25\370\373\364\243\322b\217\304@\212\306@\214" \ + "\305@\215\305>\212\307>\212\306@\214\305B\214\305@\214\305B\214\306>" \ + "\212\307>\212\310\77\214\306>\217\304@\214\306>\214\305@\242\322b\370" \ + "\373\362\377\377\377\202\377\376\377\1\377\377\375\377\377\377\377\204" \ + "\377\377\377\2TTV99;\202::<\1;;=\202::<\6;;=::<;;=__a\377\377\377\376" \ + "\376\376\377\377\377\377\244\377\377\377\3\376\376\376\377\377\377TT" \ + "V\207::<\3;;=99;```\377\377\377\377\373\377\377\377\1\375\377\376\202" \ + "\377\377\375\34\377\377\377\376\376\376\373\373\363\243\322b\211\307" \ + "B\212\307<\215\305>\214\306>\212\307>\214\305@\217\304>\212\307<\214" \ + "\306<\214\306>\215\307\77\213\307A\214\306>\215\305@\215\307\77\212\307" \ + ">\244\317c\370\373\362\377\377\373\376\377\377\377\376\377\375\376\377" \ + "\377\377\375\377\376\377\377\377\377\377\203\377\377\377\3\221\221\221" \ + "::<;;=\202::<\202;;=\203::<\2;;=\345\345\347\377\377\377\377\246\377" \ + "\377\377\4\332\332\332;;=::<;;=\203::<\1;;=\203::<\1\265\265\265\203" \ + "\377\377\377\3\376\376\376\377\377\377\376\376\376\377\377\377\377\364" \ + "\377\377\377\3\377\376\377\377\377\377\375\377\376\202\377\377\377\11" \ + "\373\373\363\241\321d\214\306>\213\310=\214\306>\214\305@\213\310=\212" \ + "\306@\217\304>\202\215\307=\14\214\306>\215\305>\214\306>\215\305>\217" \ + "\304@\215\307\77\215\307=\242\320c\367\375\361\376\376\377\377\376\377" \ + "\376\376\376\202\377\377\375\2\374\377\377\377\376\377\377\377\377\377" \ + "\202\377\377\377\5\376\376\376\332\332\332;;=::<;;=\202::<\6;;=::<;;" \ + "=99;::<\250\250\252\377\377\377\377\244\377\377\377\6\376\376\376\377" \ + "\377\377\221\221\223::<;;=99;\202::<\3;;=::<;;=\202::<\1\363\363\363" \ + "\377\377\377\377\372\377\377\377\1\377\377\375\202\377\377\377\32\377" \ + "\376\377\370\373\364\243\322b\214\306>\213\310\77\214\305@\215\305>\215" \ + "\305@\214\306>\214\305B\212\307<\215\307=\214\305B\214\306>\215\306A" \ + "\212\306@\212\307>\214\306>\212\307<\244\317c\370\373\364\377\377\377" \ + "\377\375\376\377\377\375\376\377\377\377\377\377\202\377\376\377\377" \ + "\377\377\377\204\377\377\377\2\376\376\376SSU\204::<\204;;=\2::<__a\377" \ + "\377\377\377\243\377\377\377\6\376\376\376\377\377\377\376\376\376TT" \ + "V99;;;=\204::<\4;;=99;<<>xxz\377\377\377\377\364\377\377\377\10\376\376" \ + "\377\377\377\375\377\377\377\377\377\375\377\377\377\377\376\377\377" \ + "\377\375\376\377\377\202\377\377\377\6\370\373\362\243\322b\211\307B" \ + "\213\310=\214\305@\214\306<\202\215\305@\4\214\306<\214\305@\214\306" \ + "<\215\307\77\202\214\306>\6\212\307>\214\306>\215\307\77\214\305@\244" \ + "\317c\367\375\361\377\377\377\377\213\377\377\377\5\376\376\376\377\377" \ + "\377\221\221\223::<;;=\204::<\5;;=::<;;=::<\363\363\363\204\377\377\377" \ + "\1\376\376\376\202\377\377\377\202\376\376\376\377\377\377\377\233\377" \ + "\377\377\5\332\332\332::<;;=99;<<>\202::<\1;;=\203::<\1\265\265\267\377" \ + "\377\377\377\363\377\377\377\6\376\376\377\377\376\377\375\376\377\376" \ + "\377\377\377\377\375\375\377\376\203\377\377\377\27\377\377\375\372\373" \ + "\366\241\321a\217\304@\212\307<\214\306>\215\305>\215\305@\213\310=\212" \ + "\306@\214\306>\214\305B\215\307\77\215\305>\215\306A\212\307>\214\306" \ + ">\215\307\77\214\306>\242\322b\370\373\362\376\376\377\377\375\376\377" \ + "\377\377\377\213\377\377\377\2\375\375\375\333\333\333\202::<\1;;=\202" \ + "::<\1;;=\202::<\3""99;::<\265\265\265\206\377\377\377\3\376\376\376\377" \ + "\377\377\376\376\376\377\377\377\377\233\377\377\377\2\235\235\23599" \ + ";\202;;=\1""99;\202;;=\202::<\3;;=::<\363\363\365\377\377\377\377\363" \ + "\377\377\377\7\377\377\375\375\376\377\376\377\377\376\377\375\377\374" \ + "\377\377\377\375\375\377\376\202\377\377\377\5\372\373\366\240\320b\215" \ + "\307\77\212\306@\215\305>\202\214\305@\20\215\305@\212\306@\214\305D" \ + "\216\306\77\214\306>\215\307\77\214\306>\212\306@\214\306>\215\307\77" \ + "\215\305@\242\320c\370\373\362\377\377\373\377\376\377\377\377\375\377" \ + "\377\377\377\214\377\377\377\2\376\376\376SSU\207::<\3;;=::<xxx\203\377" \ + "\377\377\202\376\376\376\202\377\377\377\1\376\376\376\377\377\377\377" \ + "\234\377\377\377\1^^`\211::<\3xxz\377\377\377\376\376\376\377\377\377" \ + "\377\363\377\377\377\37\376\377\377\376\377\375\377\375\376\375\377\376" \ + "\377\377\375\377\377\377\377\376\377\370\373\362\241\321a\215\307\77" \ + "\215\307=\214\305@\214\306>\212\307<\214\306>\214\306<\214\306>\216\306" \ + "\77\215\305<\212\307>\213\307A\215\305>\212\307>\215\307\77\214\306>" \ + "\242\321a\373\374\364\377\377\377\376\377\377\376\376\376\376\377\377" \ + "\377\377\377\377\212\377\377\377\4\376\376\376\377\377\377\376\376\376" \ + "\222\222\222\205::<\1;;=\20299;\202::<\3\363\363\363\377\377\377\376" \ + "\376\376\377\377\377\377\240\377\377\377\1\346\346\346\202::<\1;;=\204" \ + "::<\1;;=\202::<\1\250\250\252\202\377\377\377\1\376\376\376\377\377\377" \ + "\377\361\377\377\377\202\377\377\375\3\377\374\377\375\377\376\376\377" \ + "\377\202\377\377\377\25\370\373\364\243\322b\217\304@\212\306@\214\305" \ + "@\215\305>\212\307>\212\306@\214\305B\214\305@\214\305B\214\306>\212" \ + "\307>\212\310\77\214\306>\217\304@\214\306>\214\305@\242\322b\370\373" \ + "\362\377\377\377\202\377\376\377\1\377\377\375\377\377\377\377\212\377" \ + "\377\377\1\376\376\376\203\377\377\377\2\332\332\332<<>\203::<\3;;=:" \ + ":<<<>\203::<\2\301\301\303\376\376\376\202\377\377\377\5\376\376\376" \ + "\377\377\377\376\376\376\377\377\377\376\376\376\377\377\377\377\231" \ + "\377\377\377\4\376\376\376\251\251\253::<;;=\204::<\5;;=::<99;::<\346" \ + "\346\346\377\377\377\377\365\377\377\377\1\375\377\376\202\377\377\375" \ + "\34\377\377\377\376\376\376\373\373\363\243\322b\211\307B\212\307<\215" \ + "\305>\214\306>\212\307>\214\305@\217\304>\212\307<\214\306<\214\306>" \ + "\215\307\77\213\307A\214\306>\215\305@\215\307\77\212\307>\244\317c\370" \ + "\373\362\377\377\373\376\377\377\377\376\377\375\376\377\377\377\375" \ + "\377\376\377\377\377\377\377\212\377\377\377\1\376\376\376\203\377\377" \ + "\377\1SSS\207::<\3;;=::<\205\205\207\205\377\377\377\1\376\376\376\377" \ + "\377\377\377\234\377\377\377\3wwy::<;;=\206::<\2;;=__a\377\377\377\377" \ + "\365\377\377\377\3\377\376\377\377\377\377\375\377\376\202\377\377\377" \ + "\11\373\373\363\241\321d\214\306>\213\310=\214\306>\214\305@\213\310" \ + "=\212\306@\217\304>\202\215\307=\14\214\306>\215\305>\214\306>\215\305" \ + ">\217\304@\215\307\77\215\307=\242\320c\367\375\361\376\376\377\377\376" \ + "\377\376\376\376\202\377\377\375\2\374\377\377\377\376\377\377\377\377" \ + "\377\211\377\377\377\1\376\376\376\203\377\377\377\3\376\376\376\204" \ + "\204\204::<\202;;=\1::<\202;;=\203::<\1SSU\204\377\377\377\1\376\376" \ + "\376\377\377\377\377\235\377\377\377\1;;=\203::<\1;;=\202::<\1;;=\202" \ + "::<\1\234\234\234\202\377\377\377\1\376\376\376\377\377\377\377\362\377" \ + "\377\377\1\377\377\375\202\377\377\377\32\377\376\377\370\373\364\243" \ + "\322b\214\306>\213\310\77\214\305@\215\305>\215\305@\214\306>\214\305" \ + "B\212\307<\215\307=\214\305B\214\306>\215\306A\212\306@\212\307>\214" \ + "\306>\212\307<\244\317c\370\373\364\377\377\377\377\375\376\377\377\375" \ + "\376\377\377\377\377\377\202\377\376\377\377\377\377\377\212\377\377" \ + "\377\1\376\376\376\204\377\377\377\6\301\301\301;;=::<;;=::<;;=\205:" \ + ":<\1\333\333\333\202\377\377\377\1\376\376\376\377\377\377\377\231\377" \ + "\377\377\1\376\376\376\203\377\377\377\1\301\301\303\204::<\1;;=\202" \ + "::<\1:9>\202::<\1\332\332\332\377\377\377\377\356\377\377\377\10\376" \ + "\376\377\377\377\375\377\377\377\377\377\375\377\377\377\377\376\377" \ + "\377\377\375\376\377\377\202\377\377\377\6\370\373\362\243\322b\211\307" \ + "B\213\310=\214\305@\214\306<\202\215\305@\4\214\306<\214\305@\214\306" \ + "<\215\307\77\202\214\306>\6\212\307>\214\306>\215\307\77\214\305@\244" \ + "\317c\367\375\361\377\377\377\377\230\377\377\377\2""99;;;=\210::<\1" \ + "\250\250\250\377\377\377\377\240\377\377\377\3\221\221\223::<;;=\207" \ + "::<\2SSU\376\376\376\377\377\377\377\355\377\377\377\6\376\376\377\377" \ + "\376\377\375\376\377\376\377\377\377\377\375\375\377\376\203\377\377" \ + "\377\27\377\377\375\372\373\366\241\321a\217\304@\212\307<\214\306>\215" \ + "\305>\215\305@\213\310=\212\306@\214\306>\214\305B\215\307\77\215\305" \ + ">\215\306A\212\307>\214\306>\215\307\77\214\306>\242\322b\370\373\362" \ + "\376\376\377\377\375\376\377\377\377\377\227\377\377\377\1yy{\211::<" \ + "\6lll\376\376\376\377\377\377\376\376\376\377\377\377\376\376\376\377" \ + "\377\377\377\224\377\377\377\202\376\376\376\7\377\377\377\376\376\376" \ + "\377\377\377\376\376\376\377\377\377__a;;=\202::<\4<<>;;=::<;;=\202:" \ + ":<\1\204\204\206\203\377\377\377\1\376\376\376\377\377\377\377\352\377" \ + "\377\377\7\377\377\375\375\376\377\376\377\377\376\377\375\377\374\377" \ + "\377\377\375\375\377\376\202\377\377\377\5\372\373\366\240\320b\215\307" \ + "\77\212\306@\215\305>\202\214\305@\20\215\305@\212\306@\214\305D\216" \ + "\306\77\214\306>\215\307\77\214\306>\212\306@\214\306>\215\307\77\215" \ + "\305@\242\320c\370\373\362\377\377\373\377\376\377\377\377\375\377\377" \ + "\377\377\221\377\377\377\3\376\376\376\377\377\377\376\376\376\203\377" \ + "\377\377\1\265\265\267\212::<\1\363\363\363\377\377\377\377\227\377\377" \ + "\377\1\376\376\376\202\377\377\377\1\376\376\376\203\377\377\377\1\345" \ + "\345\345\202::<\202;;=\1""99;\203::<\4;;=::<\301\301\301\376\376\376" \ + "\203\377\377\377\1\376\376\376\377\377\377\377\352\377\377\377\37\376" \ + "\377\377\376\377\375\377\375\376\375\377\376\377\377\375\377\377\377" \ + "\377\376\377\370\373\362\241\321a\215\307\77\215\307=\214\305@\214\306" \ + ">\212\307<\214\306>\214\306<\214\306>\216\306\77\215\305<\212\307>\213" \ + "\307A\215\305>\212\307>\215\307\77\214\306>\242\321a\373\374\364\377" \ + "\377\377\376\377\377\376\376\376\376\377\377\377\377\377\377\222\377" \ + "\377\377\3\376\376\376\377\377\377\376\376\376\202\377\377\377\1\347" \ + "\347\347\212::<\1\302\302\304\205\377\377\377\1\376\376\376\377\377\377" \ + "\377\222\377\377\377\1\376\376\376\202\377\377\377\1\376\376\376\202" \ + "\377\377\377\5\265\265\265::<;;=99;;;=\203::<\1;;=\202::<\1\363\363\363" \ + "\377\377\377\377\356\377\377\377\202\377\377\375\3\377\374\377\375\377" \ + "\376\376\377\377\202\377\377\377\25\370\373\364\243\322b\217\304@\212" \ + "\306@\214\305@\215\305>\212\307>\212\306@\214\305B\214\305@\214\305B" \ + "\214\306>\212\307>\212\310\77\214\306>\217\304@\214\306>\214\305@\242" \ + "\322b\370\373\362\377\377\377\202\377\376\377\1\377\377\375\377\377\377" \ + "\377\230\377\377\377\2\376\376\376TTT\211::<\3\221\221\223\377\377\377" \ + "\376\376\376\202\377\377\377\1\376\376\376\377\377\377\377\231\377\377" \ + "\377\2\204\204\204::<\202;;=\202::<\1;;=\203::<\2``b\376\376\376\377" \ + "\377\377\377\357\377\377\377\1\375\377\376\202\377\377\375\34\377\377" \ + "\377\376\376\376\373\373\363\243\322b\211\307B\212\307<\215\305>\214" \ + "\306>\212\307>\214\305@\217\304>\212\307<\214\306<\214\306>\215\307\77" \ + "\213\307A\214\306>\215\305@\215\307\77\212\307>\244\317c\370\373\362" \ + "\377\377\373\376\377\377\377\376\377\375\376\377\377\377\375\377\376" \ + "\377\377\377\377\377\225\377\377\377\1\376\376\376\202\377\377\377\1" \ + "\221\221\221\210::<\2;;=__a\202\377\377\377\1\376\376\376\377\377\377" \ + "\377\227\377\377\377\1\376\376\376\203\377\377\377\1SSU\202::<\1;;=\204" \ + "::<\202;;=\1\234\234\234\204\377\377\377\1\376\376\376\377\377\377\377" \ + "\352\377\377\377\3\377\376\377\377\377\377\375\377\376\202\377\377\377" \ + "\11\373\373\363\241\321d\214\306>\213\310=\214\306>\214\305@\213\310" \ + "=\212\306@\217\304>\202\215\307=\14\214\306>\215\305>\214\306>\215\305" \ + ">\217\304@\215\307\77\215\307=\242\320c\367\375\361\376\376\377\377\376" \ + "\377\376\376\376\202\377\377\375\2\374\377\377\377\376\377\377\377\377" \ + "\377\222\377\377\377\1\376\376\376\205\377\377\377\1\301\301\301\210" \ + "::<\4""99;;;=\364\364\366\376\376\376\377\377\377\377\233\377\377\377" \ + "\1\346\346\346\207::<\4;;=99;::<\316\316\316\203\377\377\377\1\376\376" \ + "\376\377\377\377\377\353\377\377\377\1\377\377\375\202\377\377\377\32" \ + "\377\376\377\370\373\364\243\322b\214\306>\213\310\77\214\305@\215\305" \ + ">\215\305@\214\306>\214\305B\212\307<\215\307=\214\305B\214\306>\215" \ + "\306A\212\306@\212\307>\214\306>\212\307<\244\317c\370\373\364\377\377" \ + "\377\377\375\376\377\377\375\376\377\377\377\377\377\202\377\376\377" \ + "\377\377\377\377\224\377\377\377\1\376\376\376\204\377\377\377\1\363" \ + "\363\363\210::<\3;;=::<\302\302\304\377\377\377\377\231\377\377\377\1" \ + "\376\376\376\202\377\377\377\1\266\266\270\203::<\203;;=\203::<\1:::" \ + "\377\377\377\377\351\377\377\377\10\376\376\377\377\377\375\377\377\377" \ + "\377\377\375\377\377\377\377\376\377\377\377\375\376\377\377\202\377" \ + "\377\377\6\370\373\362\243\322b\211\307B\213\310=\214\305@\214\306<\202" \ + "\215\305@\4\214\306<\214\305@\214\306<\215\307\77\202\214\306>\6\212" \ + "\307>\214\306>\215\307\77\214\305@\244\317c\367\375\361\377\377\377\377" \ + "\242\377\377\377\3__a::<;;=\207::<\1\221\221\221\377\377\377\377\234" \ + "\377\377\377\1\204\204\206\204::<\202;;=\203::<\1lll\203\377\377\377" \ + "\1\375\375\375\377\377\377\377\344\377\377\377\6\376\376\377\377\376" \ + "\377\375\376\377\376\377\377\377\377\375\375\377\376\203\377\377\377" \ + "\27\377\377\375\372\373\366\241\321a\217\304@\212\307<\214\306>\215\305" \ + ">\215\305@\213\310=\212\306@\214\306>\214\305B\215\307\77\215\305>\215" \ + "\306A\212\307>\214\306>\215\307\77\214\306>\242\322b\370\373\362\376" \ + "\376\377\377\375\376\377\377\377\377\241\377\377\377\2\221\221\223;;" \ + "=\202::<\202;;=\203::<\2;;=^^^\204\377\377\377\1\376\376\376\377\377" \ + "\377\377\224\377\377\377\1\376\376\376\202\377\377\377\1``b\202::<\1" \ + ";;=\206::<\1\234\234\234\205\377\377\377\1\376\376\376\377\377\377\377" \ + "\342\377\377\377\7\377\377\375\375\376\377\376\377\377\376\377\375\377" \ + "\374\377\377\377\375\375\377\376\202\377\377\377\5\372\373\366\240\320" \ + "b\215\307\77\212\306@\215\305>\202\214\305@\20\215\305@\212\306@\214" \ + "\305D\216\306\77\214\306>\215\307\77\214\306>\212\306@\214\306>\215\307" \ + "\77\215\305@\242\320c\370\373\362\377\377\373\377\376\377\377\377\375" \ + "\377\377\377\377\241\377\377\377\6\301\301\303::<;;=::<99;;;=\203::<" \ + "\6;;=:::\377\377\377\376\376\376\377\377\377\376\376\376\377\377\377" \ + "\377\224\377\377\377\1\376\376\376\202\377\377\377\2\363\363\363;;=\211" \ + "::<\1\316\316\316\203\377\377\377\1\376\376\376\202\377\377\377\1\376" \ + "\376\376\377\377\377\377\342\377\377\377\37\376\377\377\376\377\375\377" \ + "\375\376\375\377\376\377\377\375\377\377\377\377\376\377\370\373\362" \ + "\241\321a\215\307\77\215\307=\214\305@\214\306>\212\307<\214\306>\214" \ + "\306<\214\306>\216\306\77\215\305<\212\307>\213\307A\215\305>\212\307" \ + ">\215\307\77\214\306>\242\321a\373\374\364\377\377\377\376\377\377\376" \ + "\376\376\376\377\377\377\377\377\377\241\377\377\377\1\363\363\365\202" \ + "::<\1;;=\202::<\2""99;;;=\202::<\2;;=\316\316\316\377\377\377\377\231" \ + "\377\377\377\10\376\376\376\316\316\316::<;;=::<;;=99;;;=\204::<\202" \ + "\377\377\377\3\376\376\376\377\377\377\376\376\376\377\377\377\377\344" \ + "\377\377\377\202\377\377\375\3\377\374\377\375\377\376\376\377\377\202" \ + "\377\377\377\25\370\373\364\243\322b\217\304@\212\306@\214\305@\215\305" \ + ">\212\307>\212\306@\214\305B\214\305@\214\305B\214\306>\212\307>\212" \ + "\310\77\214\306>\217\304@\214\306>\214\305@\242\322b\370\373\362\377" \ + "\377\377\202\377\376\377\1\377\377\375\377\377\377\377\243\377\377\377" \ + "\1``b\203::<\203;;=\6::<<<>::<\234\234\234\377\377\377\376\376\376\377" \ + "\377\377\377\230\377\377\377\1\234\234\236\204::<\12;;=99;::<;;=::<k" \ + "km\377\377\377\376\376\376\377\377\377\376\376\376\377\377\377\377\346" \ + "\377\377\377\1\375\377\376\202\377\377\375\34\377\377\377\376\376\376" \ + "\373\373\363\243\322b\211\307B\212\307<\215\305>\214\306>\212\307>\214" \ + "\305@\217\304>\212\307<\214\306<\214\306>\215\307\77\213\307A\214\306" \ + ">\215\305@\215\307\77\212\307>\244\317c\370\373\362\377\377\373\376\377" \ + "\377\377\376\377\375\376\377\377\377\375\377\376\377\377\377\377\377" \ + "\242\377\377\377\2\222\222\222::<\202;;=\7""99;::<;;=::<99;;;=lln\202" \ + "\377\377\377\1\376\376\376\377\377\377\377\225\377\377\377\3\376\376" \ + "\376\377\377\377jjl\204;;=\2""99;;;=\202::<\2;;=\221\221\223\202\377" \ + "\377\377\1\376\376\376\202\377\377\377\1\376\376\376\377\377\377\377" \ + "\343\377\377\377\3\377\376\377\377\377\377\375\377\376\202\377\377\377" \ + "\11\373\373\363\241\321d\214\306>\213\310=\214\306>\214\305@\213\310" \ + "=\212\306@\217\304>\202\215\307=\14\214\306>\215\305>\214\306>\215\305" \ + ">\217\304@\215\307\77\215\307=\242\320c\367\375\361\376\376\377\377\376" \ + "\377\376\376\376\202\377\377\375\2\374\377\377\377\376\377\377\377\377" \ + "\377\242\377\377\377\2\264\264\264;;=\206::<\6;;=::<FFH\376\376\376\377" \ + "\377\377\376\376\376\377\377\377\377\227\377\377\377\1GGI\204::<\6;;" \ + "=::<;;=::<;;=\302\302\304\206\377\377\377\1\376\376\376\377\377\377\377" \ + "\342\377\377\377\1\377\377\375\202\377\377\377\32\377\376\377\370\373" \ + "\364\243\322b\214\306>\213\310\77\214\305@\215\305>\215\305@\214\306" \ + ">\214\305B\212\307<\215\307=\214\305B\214\306>\215\306A\212\306@\212" \ + "\307>\214\306>\212\307<\244\317c\370\373\364\377\377\377\377\375\376" \ + "\377\377\375\376\377\377\377\377\377\202\377\376\377\377\377\377\377" \ + "\243\377\377\377\2\346\346\346;;=\211::<\1\346\346\350\377\377\377\377" \ + "\230\377\377\377\3\346\346\350::<;;=\202::<\1;;=\205::<\1\346\346\346" \ + "\302\377\377\377\5\376\376\376\377\377\377\376\376\376\377\377\377\376" \ + "\376\376\377\377\377\377\233\377\377\377\10\376\376\377\377\377\375\377" \ + "\377\377\377\377\375\377\377\377\377\376\377\377\377\375\376\377\377" \ + "\202\377\377\377\6\370\373\362\243\322b\211\307B\213\310=\214\305@\214" \ + "\306<\202\215\305@\4\214\306<\214\305@\214\306<\215\307\77\202\214\306" \ + ">\6\212\307>\214\306>\215\307\77\214\305@\244\317c\367\375\361\345\377" \ + "\377\377\1\376\376\376\305\377\377\377\3FFF::<;;=\202::<\3;;=::<;;=\202" \ + "::<\1\301\301\303\377\377\377\377\230\377\377\377\4\301\301\30399;::" \ + "<;;=\204::<\3;;=::<GGI\215\377\377\377\1\376\376\376\266\377\377\377" \ + "\1\376\376\376\203\377\377\377\1\376\376\376\377\377\377\377\231\377" \ + "\377\377\6\376\376\377\377\376\377\375\376\377\376\377\377\377\377\375" \ + "\375\377\376\203\377\377\377\27\377\377\375\372\373\366\241\321a\217" \ + "\304@\212\307<\214\306>\215\305>\215\305@\213\310=\212\306@\214\306>" \ + "\214\305B\215\307\77\215\305>\215\306A\212\307>\214\306>\215\307\77\214" \ + "\306>\242\322b\370\373\362\376\376\377\377\375\376\341\377\377\377\5" \ + "\376\376\376\377\377\377\376\376\376\377\377\377\376\376\376\265\377" \ + "\377\377\3\376\376\376\377\377\377\376\376\376\212\377\377\377\3\376" \ + "\376\376\377\377\377lll\206::<\202;;=\2::<\234\234\236\377\377\377\377" \ + "\224\377\377\377\1\376\376\376\203\377\377\377\2\233\233\235;;=\203:" \ + ":<\2""99;;;=\202::<\2;;=xxz\213\377\377\377\1\376\376\376\265\377\377" \ + "\377\1\376\376\376\377\377\377\377\240\377\377\377\7\377\377\375\375" \ + "\376\377\376\377\377\376\377\375\377\374\377\377\377\375\375\377\376" \ + "\202\377\377\377\5\372\373\366\240\320b\215\307\77\212\306@\215\305>" \ + "\202\214\305@\20\215\305@\212\306@\214\305D\216\306\77\214\306>\215\307" \ + "\77\214\306>\212\306@\214\306>\215\307\77\215\305@\242\320c\370\373\362" \ + "\377\377\373\377\376\377\377\377\375\377\377\377\377\233\377\377\377" \ + "\3\376\376\376\377\377\377\376\376\376\213\377\377\377\6\376\376\376" \ + "\377\377\377\233\233\233;;=::<;;=\206::<\1lln\377\377\377\377\226\377" \ + "\377\377\3\376\376\376\377\377\377kkm\210::<\2;;=\234\234\236\214\377" \ + "\377\377\1\315\315\315\202\234\234\234\262\234\234\236\2\234\234\234" \ + "\265\265\265\377\377\377\377\240\377\377\377\37\376\377\377\376\377\375" \ + "\377\375\376\375\377\376\377\377\375\377\377\377\377\376\377\370\373" \ + "\362\241\321a\215\307\77\215\307=\214\305@\214\306>\212\307<\214\306" \ + ">\214\306<\214\306>\216\306\77\215\305<\212\307>\213\307A\215\305>\212" \ + "\307>\215\307\77\214\306>\242\321a\373\374\364\377\377\377\376\377\377" \ + "\376\376\376\376\377\377\344\377\377\377\4\376\376\376\347\347\347\234" \ + "\234\234\235\235\235\260\234\234\236\204\234\234\234\216\377\377\377" \ + "\1\301\301\301\202::<\1;;=\203::<\202;;=\2::<EEG\377\377\377\377\230" \ + "\377\377\377\1FFH\204::<\202;;=\4::<;;=99;\302\302\304\212\377\377\377" \ + "\5\376\376\376\377\377\377\234\234\234::<;;=\263::<\1jjj\205\377\377" \ + "\377\1\376\376\376\377\377\377\377\231\377\377\377\202\377\377\375\3" \ + "\377\374\377\375\377\376\376\377\377\202\377\377\377\25\370\373\364\243" \ + "\322b\217\304@\212\306@\214\305@\215\305>\212\307>\212\306@\214\305B" \ + "\214\305@\214\305B\214\306>\212\307>\212\310\77\214\306>\217\304@\214" \ + "\306>\214\305@\242\322b\370\373\362\377\377\377\202\377\376\377\1\377" \ + "\377\375\346\377\377\377\2\316\316\316:::\263::<\4;;=:::\377\377\377" \ + "\376\376\376\214\377\377\377\3\346\346\346::<;;=\205::<\4;;=::<;;=\346" \ + "\346\346\377\377\377\377\226\377\377\377\2\362\362\362;;=\204::<\3""9" \ + "9;::<;;=\202::<\1\346\346\350\214\377\377\377\2\234\234\234;;=\264::" \ + "<\1kkm\377\377\377\377\240\377\377\377\1\375\377\376\202\377\377\375" \ + "\34\377\377\377\376\376\376\373\373\363\243\322b\211\307B\212\307<\215" \ + "\305>\214\306>\212\307>\214\305@\217\304>\212\307<\214\306<\214\306>" \ + "\215\307\77\213\307A\214\306>\215\305@\215\307\77\212\307>\244\317c\370" \ + "\373\362\377\377\373\376\377\377\377\376\377\375\376\377\377\377\375" \ + "\377\376\377\345\377\377\377\2\316\316\31699;\265::<\216\377\377\377" \ + "\2\376\376\376FFH\203::<\1;;=\203::<\3;;=99;\316\316\316\377\377\377" \ + "\377\226\377\377\377\1\317\317\317\206::<\202;;=\4""99;FFH\377\377\377" \ + "\376\376\376\213\377\377\377\1\234\234\236\202::<\1;;=\261::<\2;;=kk" \ + "m\205\377\377\377\1\376\376\376\377\377\377\377\231\377\377\377\3\377" \ + "\376\377\377\377\377\375\377\376\202\377\377\377\11\373\373\363\241\321" \ + "d\214\306>\213\310=\214\306>\214\305@\213\310=\212\306@\217\304>\202" \ + "\215\307=\14\214\306>\215\305>\214\306>\215\305>\217\304@\215\307\77" \ + "\215\307=\242\320c\367\375\361\376\376\377\377\376\377\376\376\376\202" \ + "\377\377\375\2\374\377\377\377\376\377\345\377\377\377\1\316\316\316" \ + "\264::<\202;;=\215\377\377\377\4\376\376\376\377\377\377lln99;\210::" \ + "<\2\234\234\234\376\376\376\377\377\377\377\225\377\377\377\5\234\234" \ + "\234::<;;=99;::<\202;;=\5::<;;=::<kkm\376\376\377\214\377\377\377\1\234" \ + "\234\236\203::<\1:9>\261::<\1kkm\377\377\377\377\237\377\377\377\1\377" \ + "\377\375\202\377\377\377\32\377\376\377\370\373\364\243\322b\214\306" \ + ">\213\310\77\214\305@\215\305>\215\305@\214\306>\214\305B\212\307<\215" \ + "\307=\214\305B\214\306>\215\306A\212\306@\212\307>\214\306>\212\307<" \ + "\244\317c\370\373\364\377\377\377\377\375\376\377\377\375\376\377\377" \ + "\377\377\377\202\377\376\377\346\377\377\377\1\316\316\316\266::<\217" \ + "\377\377\377\2\234\234\236;;=\206::<\3""99;;;=www\377\377\377\377\226" \ + "\377\377\377\3\204\204\206::<;;=\207::<\3\222\222\222\377\377\377\376" \ + "\376\376\213\377\377\377\1\234\234\236\265::<\1kkm\377\377\377\377\210" \ + "\377\377\377\7\376\376\376\377\377\377\377\377\375\376\377\375\376\377" \ + "\377\377\377\377\377\376\377\203\377\377\377\1\376\376\376\203\377\377" \ + "\377\1\376\377\377\203\377\377\377\16\377\377\375\377\377\377\377\376" \ + "\377\377\377\377\377\377\373\376\377\377\377\377\377\377\377\373\371" \ + "\372\364\242\322d\214\306<\215\307\77\214\305@\214\306<\202\215\305@" \ + "\4\214\306<\214\305@\214\306<\215\307\77\202\214\306>\6\212\307>\214" \ + "\306>\215\307\77\214\305@\244\317c\367\375\361\356\377\377\377\1\316" \ + "\316\316\266::<\214\377\377\377\1\376\376\376\202\377\377\377\1\266\266" \ + "\266\202::<\1;;=\203::<\1;;=\202::<\3__a\377\377\377\376\376\376\377" \ + "\377\377\377\224\377\377\377\2kkm;;=\202::<\202;;=\202::<\3;;=::<\265" \ + "\265\265\215\377\377\377\1\234\234\236\265::<\1kkm\377\377\377\377\214" \ + "\377\377\377\2\376\377\377\376\377\375\202\377\377\375\203\377\377\377" \ + "\204\377\377\375\205\377\377\377\1\376\376\377\202\377\377\377\6\377" \ + "\377\375\377\377\377\371\372\362\242\320c\214\305@\215\305@\202\214\306" \ + ">\20\215\305@\213\310=\212\306@\214\306>\214\305B\215\307\77\215\305" \ + ">\215\306A\212\307>\214\306>\215\307\77\214\306>\242\322b\370\373\362" \ + "\376\376\377\377\375\376\355\377\377\377\1\316\316\316\266::<\215\377" \ + "\377\377\4\376\376\376\377\377\377\315\315\315;;=\203::<\1;;=\203::<" \ + "\2;;=99;\377\377\377\377\226\377\377\377\203::<\1;;=\202::<\1;;=\203" \ + "::<\2\317\317\317\376\376\376\214\377\377\377\1\234\234\236\265::<\1" \ + "kkm\377\377\377\377\211\377\377\377\3\376\376\376\377\376\377\377\377" \ + "\377\203\377\376\377\204\377\377\377\1\376\376\376\202\377\377\377\1" \ + "\377\376\377\203\377\377\377\1\376\376\376\203\377\377\377\31\376\376" \ + "\377\377\376\377\371\372\365\241\322e\212\307<\216\306\77\212\311<\216" \ + "\303\77\212\307>\215\305@\212\306@\214\305D\216\306\77\214\306>\215\307" \ + "\77\214\306>\212\306@\214\306>\215\307\77\215\305@\242\320c\370\373\362" \ + "\377\377\373\377\376\377\377\377\375\355\377\377\377\1\316\316\316\266" \ + "::<\220\377\377\377\202::<\4;;=::<;;=::<\202;;=\3""99;;;=\346\346\346" \ + "\377\377\377\377\224\377\377\377\2\362\362\362;;=\202::<\7""99;::<;;" \ + "=88:;;=::<;;=\216\377\377\377\1\234\234\236\265::<\1kkm\377\377\377\377" \ + "\212\377\377\377\202\376\377\377\202\377\377\377\1\377\376\377\206\377" \ + "\377\377\1\376\376\376\202\377\377\377\1\376\376\376\203\377\377\377" \ + "\1\376\376\376\202\377\377\377\6\370\373\364\242\322b\214\306>\214\305" \ + "@\215\305>\214\305@\202\215\306A\20\214\306<\214\306>\216\306\77\215" \ + "\305<\212\307>\213\307A\215\305>\212\307>\215\307\77\214\306>\242\321" \ + "a\373\374\364\377\377\377\376\377\377\376\376\376\376\377\377\355\377" \ + "\377\377\1\316\316\316\266::<\216\377\377\377\6\376\376\376\377\377\377" \ + "SSU;;=99;;;=\206::<\1\316\316\316\377\377\377\377\224\377\377\377\2\316" \ + "\316\31699;\205::<\1;;=\202::<\1FFH\216\377\377\377\1\234\234\236\265" \ + "::<\1kkm\377\377\377\377\207\377\377\377\202\377\376\377\2\377\377\377" \ + "\377\377\375\203\377\377\377\1\376\377\375\202\377\377\375\203\377\377" \ + "\377\202\377\377\375\2\377\377\377\377\377\375\205\377\377\377\26\377" \ + "\377\375\371\372\362\243\322b\211\305A\215\305>\215\307\77\214\305@\214" \ + "\306>\215\305@\212\307>\214\305@\214\305B\214\306>\212\307>\212\310\77" \ + "\214\306>\217\304@\214\306>\214\305@\242\322b\370\373\362\377\377\377" \ + "\202\377\376\377\1\377\377\375\356\377\377\377\1\316\316\316\266::<\220" \ + "\377\377\377\3kkm::<;;=\202::<\6;;=::<;;=::<;;=\233\233\233\377\377\377" \ + "\377\223\377\377\377\2\376\376\376\265\265\265\205::<\1;;=\202::<\2""9" \ + "9;lln\216\377\377\377\1\234\234\236\265::<\1kkm\377\377\377\377\207\377" \ + "\377\377\3\376\377\375\375\377\376\377\377\377\202\377\376\377\3\377" \ + "\376\374\377\377\377\376\377\377\202\377\377\377\1\377\377\375\204\377" \ + "\377\377\2\375\377\376\377\377\375\202\377\377\377\1\377\377\375\202" \ + "\377\377\377\32\376\376\374\365\367\354\223\312K\215\305>\214\306<\211" \ + "\305\77\214\306>\212\307>\215\307\77\214\306>\214\306<\214\306>\215\307" \ + "\77\213\307A\214\306>\215\305@\215\307\77\212\307>\244\317c\370\373\362" \ + "\377\377\373\376\377\377\377\376\377\375\376\377\377\377\375\377\376" \ + "\377\355\377\377\377\1\316\316\316\266::<\217\377\377\377\5\376\376\376" \ + "\234\234\236;;=::<;;=\202::<\2""99;::<\202;;=\1\221\221\221\377\377\377" \ + "\377\224\377\377\377\1\235\235\235\211::<\2\221\221\223\376\376\376\215" \ + "\377\377\377\1\234\234\236\265::<\1kkm\377\377\377\377\207\377\377\377" \ + "\1\377\376\377\202\377\377\375\202\377\377\377\202\377\377\375\1\377" \ + "\377\377\202\376\377\377\1\377\377\377\202\377\377\375\5\376\376\377" \ + "\377\377\377\377\377\373\377\377\377\376\376\376\203\377\377\377\27\376" \ + "\376\376\377\377\375\376\377\372\347\365\333\225\311K\217\304>\214\305" \ + "B\215\307\77\212\306B\214\306>\215\306A\214\306>\215\305>\214\306>\215" \ + "\305>\217\304@\215\307\77\215\307=\242\320c\367\375\361\376\376\377\377" \ + "\376\377\376\376\376\202\377\377\375\2\374\377\377\377\376\377\355\377" \ + "\377\377\1\316\316\316\266::<\214\377\377\377\1\376\376\376\203\377\377" \ + "\377\3\250\250\252::<;;=\203::<\202;;=\202::<\1kkk\377\377\377\377\224" \ + "\377\377\377\4www;;=::<;;=\202::<\202;;=\202::<\1\234\234\236\216\377" \ + "\377\377\1\234\234\236\265::<\1kkm\377\377\377\377\207\377\377\377\15" \ + "\367\374\365\343\361\316\316\346\254\305\342\240\304\343\240\303\342" \ + "\236\305\342\237\312\346\251\345\356\317\365\373\357\376\377\377\376" \ + "\376\377\377\377\375\214\377\377\377\24\350\365\333\223\312K\216\306" \ + "\77\212\307>\215\304B\214\306>\215\307=\214\306>\215\306A\212\306@\212" \ + "\307>\214\306>\212\307<\244\317c\370\373\364\377\377\377\377\375\376" \ + "\377\377\375\376\377\377\377\377\377\202\377\376\377\356\377\377\377" \ + "\1\316\316\316\266::<\217\377\377\377\2\376\376\376\316\316\320\207:" \ + ":<\3;;=::<SSS\377\377\377\377\223\377\377\377\2\376\376\376kkm\202::" \ + "<\1;;=\206::<\1\316\316\316\377\377\377\377\276\377\377\377\4\377\377" \ + "\375\376\377\377\377\377\377\377\376\377\202\377\377\377\10\377\377\375" \ + "\377\376\377\376\377\375\376\376\376\377\377\377\350\365\333\277\337" \ + "\224\232\315V\210\214\306>\10\212\306@\212\307>\232\315W\277\337\224" \ + "\352\364\333\377\377\377\377\376\377\377\377\375\202\376\377\377\202" \ + "\377\377\377\2\377\376\377\377\377\375\202\377\377\377\17\377\377\375" \ + "\377\376\377\347\365\333\226\312L\215\306A\213\310=\212\306@\217\304" \ + ">\216\307<\214\305@\215\305<\214\305@\215\307=\244\317c\366\373\364\377" \ + "\377\377\377\276\377\377\377\6\346\346\346;;=99;;;=::<;;=\205::<\377" \ + "\377\377\377\224\377\377\377\1::<\202;;=\2::<;;=\203::<\4;;=::<\316\316" \ + "\316\376\376\376\377\377\377\377\274\377\377\377\14\377\375\377\377\377" \ + "\377\376\376\374\377\377\375\377\376\377\377\377\375\376\377\377\377" \ + "\377\377\376\377\377\377\376\377\324\353\265\231\316Z\202\214\306<\1" \ + "\215\305>\210\214\306>\202\215\305>\16\214\306>\213\307A\211\306;\233" \ + "\314V\324\353\265\377\377\377\377\376\377\377\377\375\375\377\376\376" \ + "\377\377\377\377\377\377\376\377\376\377\377\377\377\373\202\377\377" \ + "\377\6\376\376\377\350\365\333\222\312K\215\306A\217\304>\212\306@\202" \ + "\214\305@\6\213\310\77\212\307>\242\322d\370\373\364\377\377\377\377" \ + "\377\375\377\377\377\377\276\377\377\377\203::<\3;;=::<99;\202;;=\202" \ + "::<\1\346\346\350\377\377\377\377\222\377\377\377\2\376\376\376;;=\202" \ + "::<\202;;=\205::<\377\377\377\377\275\377\377\377\4\377\377\375\377\377" \ + "\377\377\377\373\377\376\374\202\376\377\377\12\377\377\375\377\377\377" \ + "\376\377\375\342\360\317\232\315V\214\306<\220\306=\215\306A\215\306" \ + "C\215\306A\210\214\306>\202\215\307\77\7\215\306A\214\306>\214\305@\213" \ + "\307A\214\305@\230\315W\341\361\315\203\377\377\377\2\376\376\374\374" \ + "\377\375\202\377\377\377\2\377\377\375\377\376\377\202\377\377\377\13" \ + "\352\364\331\221\311J\215\306A\213\310=\216\306\77\214\305@\214\306<" \ + "\242\322e\370\373\364\376\376\377\377\377\375\377\377\377\377\277\377" \ + "\377\377\1``b\202::<\2;;=99;\202;;=\4::<;;=::<\316\316\320\377\377\377" \ + "\377\222\377\377\377\4\316\316\316;;=::<99;\202::<\2;;=::<\202;;=\3:" \ + ":<\376\376\376\377\377\377\202\376\376\376\377\377\377\377\271\377\377" \ + "\377\17\376\377\377\376\376\374\377\376\374\376\377\377\377\377\377\377" \ + "\377\375\376\377\377\370\373\364\277\336\222\215\305<\214\305@\215\307" \ + "\77\212\307>\215\307\77\213\307A\211\214\306>\16\216\306A\214\305B\213" \ + "\307A\214\306>\215\305<\213\305=\215\306A\214\306<\215\305>\300\337\223" \ + "\370\373\362\376\376\377\377\377\375\376\377\377\204\377\377\377\16\377" \ + "\376\377\376\376\377\376\377\377\352\364\331\222\312K\215\306A\214\306" \ + "<\214\305@\243\321d\371\373\360\376\376\377\376\377\377\377\377\377\376" \ + "\377\377\377\377\377\377\273\377\377\377\4\376\376\376\377\377\377\376" \ + "\376\376lln\203::<\1;;=\20299;\1;;=\202::<\1\266\266\270\377\377\377" \ + "\377\222\377\377\377\5\316\316\316::<;;=::<;;=\205::<\3kkm\377\377\377" \ + "\376\376\376\377\377\377\377\274\377\377\377\14\377\377\375\376\377\377" \ + "\377\377\377\377\377\375\376\376\376\367\374\365\244\317c\214\305@\215" \ + "\307=\211\306=\213\307A\215\306A\202\212\306@\1\213\310<\210\214\306" \ + ">\202\212\307>\3\212\307<\214\306>\216\306\77\202\214\306>\12\215\305" \ + "<\215\307\77\212\306@\242\322b\371\374\365\377\377\375\376\376\374\376" \ + "\377\377\377\376\377\376\377\377\202\377\377\377\13\376\377\375\376\376" \ + "\377\377\377\377\350\365\333\225\311K\214\305B\242\320c\371\374\361\377" \ + "\377\377\376\377\377\377\376\377\377\377\377\377\300\377\377\377\7\221" \ + "\221\223::<99;::<;;=::<;;=\203::<\1\234\234\236\377\377\377\377\222\377" \ + "\377\377\2\250\250\25099;\206::<\3;;=::<jjl\377\377\377\377\275\377\377" \ + "\377\202\377\376\377\16\376\377\377\377\377\375\376\376\376\352\364\333" \ + "\223\312K\220\306=\215\306A\214\305B\213\310=\215\306C\215\305>\216\306" \ + "\77\215\305>\215\305@\210\214\306>\37\215\305@\215\307\77\212\306@\215" \ + "\307\77\214\304\77\215\306A\212\307;\212\306@\214\306>\216\307B\214\306" \ + ">\222\312K\354\364\334\377\376\377\377\377\377\377\377\373\376\377\377" \ + "\377\375\376\376\377\375\377\377\377\377\376\377\377\377\377\376\376" \ + "\377\347\365\333\260\327z\371\374\363\375\377\376\376\377\377\377\376" \ + "\377\377\377\377\377\377\375\377\377\377\377\276\377\377\377\3\376\376" \ + "\376\234\234\23699;\203;;=\205::<\1\221\221\223\377\377\377\377\222\377" \ + "\377\377\2\234\234\234;;=\204::<\202;;=\3::<;;=\235\235\237\377\377\377" \ + "\377\276\377\377\377\202\377\377\375\15\376\377\377\367\374\365\223\312" \ + "K\214\306>\213\310\77\215\305@\214\306<\215\307=\214\305@\213\307A\211" \ + "\305\77\215\307\77\215\305>\210\214\306>\20\215\306A\213\305=\215\307" \ + "=\214\305@\215\306A\214\306>\213\304A\220\305\77\216\306\77\212\306@" \ + "\215\305@\213\307A\221\311L\367\375\363\376\377\377\377\377\377\202\377" \ + "\377\373\1\377\375\376\202\377\377\377\4\377\376\377\376\377\377\377" \ + "\376\377\376\377\377\203\377\377\377\3\377\376\377\376\376\377\374\377" \ + "\375\377\377\377\377\277\377\377\377\2\265\265\267<<>\20299;\7::<;;=" \ + "::<99;;;=::<lln\377\377\377\377\222\377\377\377\3\221\221\221::<;;=\205" \ + "::<\3;;=::<\234\234\236\377\377\377\377\276\377\377\377\17\376\377\377" \ + "\377\377\377\366\373\364\244\317c\220\306=\213\310\77\212\306@\211\307" \ + "@\216\306\77\215\305@\215\307\77\213\310\77\215\307\77\215\305>\214\305" \ + "@\210\214\306>\22\216\306A\215\307\77\213\305=\216\306\77\214\306>\212" \ + "\307>\213\310\77\214\305@\215\306C\214\306<\215\307=\215\305>\213\310" \ + "=\242\320d\372\372\362\376\377\375\377\375\377\377\377\375\202\376\377" \ + "\377\5\377\377\377\377\377\375\377\377\377\377\377\375\377\377\377\202" \ + "\377\376\377\5\376\377\375\376\377\377\377\377\377\377\375\376\377\377" \ + "\375\377\377\377\377\274\377\377\377\5\376\376\376\377\377\377\316\316" \ + "\320::<;;=\202::<\1;;=\202::<\3""99;::<kkm\377\377\377\377\222\377\377" \ + "\377\2kkm::<\203;;=\205::<\1\264\264\264\377\377\377\377\275\377\377" \ + "\377\10\377\376\377\376\377\377\377\377\377\300\336\224\212\307>\214" \ + "\306<\214\306>\211\307>\231\214\306>\1\216\306\77\203\214\306>\2\214" \ + "\305@\266\334\207\202\377\377\377\7\377\376\377\377\377\377\377\376\377" \ + "\377\377\375\377\377\377\377\377\375\376\377\377\377\377\377\377\303" \ + "\377\377\377\1\376\376\376\202\377\377\377\1\316\316\316\206::<\6;;=" \ + "::<;;=FFH\377\377\377\376\376\376\205\377\377\377\1\376\376\376\377\377" \ + "\377\377\212\377\377\377\1lln\202::<\3;;=99;;;=\204::<\3\317\317\317" \ + "\377\377\377\376\376\376\377\377\377\377\273\377\377\377\10\377\375\377" \ + "\374\377\375\343\361\320\214\306>\215\306A\214\304=\212\307>\215\305" \ + ">\230\214\306>\20\214\306<\213\304\77\212\307>\212\306B\214\306<\212" \ + "\307>\220\304>\337\363\316\377\376\377\377\377\377\376\377\377\377\377" \ + "\377\376\376\377\377\377\377\376\376\376\376\377\377\377\377\377\377" \ + "\302\377\377\377\1\376\376\376\202\377\377\377\2\376\376\376\377\377" \ + "\377\204::<\1;;=\202::<\3;;=99;;;=\203\377\377\377\1\376\376\376\202" \ + "\377\377\377\1\376\376\376\377\377\377\377\213\377\377\377\2SSU;;=\202" \ + "::<\2;;=99;\204::<\1\315\315\315\203\377\377\377\1\376\376\376\377\377" \ + "\377\377\271\377\377\377\10\376\376\376\377\377\377\233\316W\214\305" \ + "@\212\306@\216\306=\214\305@\215\305@\230\214\306>\17\214\306<\215\306" \ + "C\211\306=\213\307A\214\304\77\212\306@\214\305B\234\313W\376\377\375" \ + "\377\377\377\376\377\375\377\377\375\376\377\377\376\376\377\376\377" \ + "\375\377\377\377\377\302\377\377\377\1\376\376\376\202\377\377\377\4" \ + "\376\376\376\377\377\377\376\376\376;;=\206::<\202;;=\3::<\377\377\377" \ + "\376\376\376\203\377\377\377\3\376\376\376\377\377\377\376\376\376\377" \ + "\377\377\377\212\377\377\377\3::<99;;;=\202::<\10;;=::<;;=99;;;=\363" \ + "\363\363\377\377\377\376\376\376\377\377\377\377\274\377\377\377\7\323" \ + "\354\265\214\305@\215\307\77\215\306A\216\305C\213\304\77\212\307<\230" \ + "\214\306>\20\215\307\77\215\304B\214\305@\214\306>\215\305>\215\307=" \ + "\212\307<\215\307\77\323\351\270\377\376\377\377\377\377\376\376\376" \ + "\376\377\375\376\376\376\376\377\377\377\376\374\377\377\377\377\302" \ + "\377\377\377\202\376\376\376\202\377\377\377\2\376\376\376FFH\210::<" \ + "\2;;=\316\316\316\202\377\377\377\1\376\376\376\377\377\377\377\215\377" \ + "\377\377\1\376\376\376\202;;=\4""99;;;=::<;;=\202::<\2;;=::<\377\377" \ + "\377\377\277\377\377\377\7\231\316X\220\304>\214\305@\215\307\77\214" \ + "\306<\214\311>\214\305@\231\214\306>\11\215\304B\214\306>\215\306A\214" \ + "\306<\215\306A\214\305B\215\307\77\234\315X\375\377\374\204\377\377\377" \ + "\2\376\377\377\377\376\377\377\377\377\377\304\377\377\377\202\376\376" \ + "\376\4\377\377\377jjl::<99;\202;;=\205::<\7\316\316\316\377\377\377\376" \ + "\376\376\377\377\377\376\376\376\377\377\377\376\376\376\377\377\377" \ + "\377\212\377\377\377\6\363\363\363::<99;;;=::<;;=\202::<\1;;=\202::<" \ + "\377\377\377\377\276\377\377\377\2\342\361\320\214\306<\202\215\305>" \ + "\4\212\307>\215\307=\211\306=\215\305>\230\214\306>\2\213\310=\214\306" \ + "<\202\214\305@\7\215\306A\214\306>\215\307=\214\304\77\211\310<\343\362" \ + "\321\377\377\375\202\377\376\377\2\377\377\375\376\376\376\377\377\377" \ + "\377\310\377\377\377\4kkm::<;;=::<\202;;=\202::<\3;;=::<\316\316\316" \ + "\202\377\377\377\1\376\376\376\377\377\377\377\215\377\377\377\3\316" \ + "\316\316::<;;=\202::<\1;;=\204::<\1__a\202\377\377\377\3\376\376\376" \ + "\377\377\377\376\376\376\377\377\377\377\271\377\377\377\4\270\333\207" \ + "\214\306>\214\305@\214\306>\203\214\305@\1\215\305>\230\214\306>\17\215" \ + "\306A\213\310=\212\307<\214\306>\214\306<\215\306A\214\306>\214\305@" \ + "\213\306E\267\332\206\377\377\375\376\377\377\377\377\375\377\377\377" \ + "\377\377\375\377\377\377\377\303\377\377\377\1\376\376\376\204\377\377" \ + "\377\6lln;;=::<99;::<;;=\204::<\1\250\250\250\204\377\377\377\1\376\376" \ + "\376\377\377\377\377\213\377\377\377\1\316\316\316\203::<\1;;=\205::" \ + "<\1lln\203\377\377\377\1\376\376\376\377\377\377\377\272\377\377\377" \ + "\10\232\315V\215\305@\212\306@\215\305>\214\306<\215\304D\215\305<\212" \ + "\306@\230\214\306>\3\217\304@\214\306<\215\306A\202\215\305@\7\214\306" \ + ">\214\305@\212\307>\215\305<\233\316W\376\376\377\376\377\375\203\377" \ + "\377\377\1\376\377\377\377\377\377\377\305\377\377\377\3\376\376\376" \ + "\377\377\377\234\234\236\203::<\2;;=99;\204::<\1\234\234\234\202\377" \ + "\377\377\1\376\376\376\377\377\377\377\215\377\377\377\5\316\316\320" \ + "::<;;=::<;;=\202::<\1;;=\202::<\1kkm\377\377\377\377\266\377\377\377" \ + "\10\375\377\374\376\377\377\376\376\376\377\377\375\377\377\377\376\377" \ + "\377\377\377\375\360\371\350\250\214\306>\4\214\305@\212\307>\360\371" \ + "\346\376\377\375\202\377\377\377\1\377\377\375\377\377\377\377\304\377" \ + "\377\377\1\376\376\376\203\377\377\377\1\234\234\234\211::<\1\234\234" \ + "\234\205\377\377\377\1\376\376\376\377\377\377\377\212\377\377\377\4" \ + "\316\316\320llnkkmlln\203kkm\1jjl\202kkm\1\221\221\223\377\377\377\377" \ + "\270\377\377\377\1\377\376\377\202\377\377\377\3\375\376\377\377\377" \ + "\375\341\361\315\251\214\306>\2\215\307\77\342\360\314\377\377\377\377" \ + "\310\377\377\377\202\376\376\376\202\377\377\377\2\266\266\266kkk\210" \ + "kkm\1\265\265\265\206\377\377\377\1\376\376\376\377\377\377\377\211\377" \ + "\377\377\1\376\376\376\203\377\377\377\3\376\376\376\377\377\377\376" \ + "\376\376\202\377\377\377\1\376\376\376\202\377\377\377\1\376\376\376" \ + "\377\377\377\377\264\377\377\377\1\377\376\377\205\377\377\377\2\375" \ + "\377\374\310\340\246\252\214\306>\1\310\340\246\377\377\377\377\307\377" \ + "\377\377\1\376\376\376\202\377\377\377\3\375\375\375\377\377\377\376" \ + "\376\376\211\377\377\377\7\376\376\376\377\377\377\376\376\376\377\377" \ + "\377\376\376\376\377\377\377\376\376\376\377\377\377\377\213\377\377" \ + "\377\1\376\376\376\204\377\377\377\1\376\376\376\206\377\377\377\1\376" \ + "\376\376\377\377\377\377\263\377\377\377\1\377\376\377\204\377\377\377" \ + "\3\376\376\377\376\377\375\304\342\234\251\214\306>\7\215\305@\305\343" \ + "\235\376\376\377\377\377\377\376\376\377\377\376\377\377\377\375\377" \ + "\377\377\377\306\377\377\377\1\376\376\376\217\377\377\377\3\376\376" \ + "\376\377\377\377\376\376\376\377\377\377\377\214\377\377\377\5\376\376" \ + "\376\377\377\377\376\376\376\377\377\377\376\376\376\203\377\377\377" \ + "\1\376\376\376\377\377\377\377\267\377\377\377\1\377\377\375\202\377" \ + "\377\377\3\377\376\377\376\377\375\305\342\237\251\214\306>\3\215\305" \ + "@\303\344\235\376\376\376\202\377\377\377\1\377\376\377\377\377\377\377" \ + "\305\377\377\377\1\376\376\376\203\377\377\377\1\376\376\376\214\377" \ + "\377\377\1\376\376\376\377\377\377\377\216\377\377\377\1\376\376\376" \ + "\203\377\377\377\1\376\376\376\206\377\377\377\1\376\376\376\377\377" \ + "\377\377\266\377\377\377\5\376\377\377\376\376\377\377\376\377\377\377" \ + "\377\305\342\242\251\214\306>\4\215\306A\302\341\236\377\377\375\376" \ + "\376\376\377\377\377\377\305\377\377\377\1\376\376\376\203\377\377\377" \ + "\1\376\376\376\214\377\377\377\1\376\376\376\377\377\377\377\231\377" \ + "\377\377\3\376\376\376\377\377\377\376\376\376\377\377\377\377\264\377" \ + "\377\377\2\376\376\376\377\376\377\202\376\377\377\202\377\377\377\1" \ + "\305\342\240\251\214\306>\7\214\305@\306\343\240\377\376\374\377\377" \ + "\377\376\377\377\377\377\377\376\376\376\377\377\377\377\325\377\377" \ + "\377\1\376\376\376\377\377\377\377\222\377\377\377\1\376\376\376\205" \ + "\377\377\377\1\376\376\376\377\377\377\377\265\377\377\377\4\377\377" \ + "\375\377\376\377\375\377\376\376\377\375\202\377\377\377\1\305\343\235" \ + "\251\214\306>\4\213\310\77\306\341\234\377\376\377\377\377\377\202\376" \ + "\377\375\377\377\377\377\311\377\377\377\1\377\377\375\215\377\377\377" \ + "\1\376\376\376\377\377\377\377\377\377\377\377\314\377\377\377\3\377" \ + "\377\375\377\377\377\376\377\375\203\377\377\377\11\376\377\377\345\360" \ + "\320\214\305@\214\306>\214\305@\214\304\77\214\306<\215\305>\212\307" \ + ">\231\214\306>\1\214\305@\202\215\307\77\205\214\306>\5\212\307>\214" \ + "\306>\342\360\315\377\377\377\376\376\376\202\377\377\377\1\377\377\375" \ + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\244" \ + "\377\377\377\3\377\376\377\377\377\377\376\377\375\203\377\377\377\11" \ + "\376\377\377\362\371\347\214\306>\214\305B\215\310<\215\306A\214\305" \ + "@\215\307\77\214\305@\231\214\306>\4\215\307\77\213\305=\214\306>\215" \ + "\307\77\202\214\306>\5\215\307\77\214\306>\216\306\77\215\306A\360\367" \ + "\345\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" \ + "\251\377\377\377\2\377\376\377\377\377\375\203\377\377\377\13\377\377" \ + "\375\377\377\377\375\377\374\233\316W\214\305@\213\304\77\212\306@\215" \ + "\307\77\214\305@\215\306A\214\305@\230\214\306>\3\215\307\77\214\306" \ + ">\215\306A\203\214\305@\7\215\306A\214\305@\215\304B\232\315T\377\377" \ + "\375\376\377\377\377\377\375\377\377\377\377\377\377\377\377\377\377" \ + "\377\377\377\377\377\377\250\377\377\377\1\377\377\375\205\377\377\377" \ + "\11\377\376\377\267\333\204\213\307A\213\307C\215\307\77\213\304\77\215" \ + "\307\77\215\305<\212\306@\231\214\306>\1\215\307\77\203\214\305@\202" \ + "\214\306>\7\215\307\77\212\306@\267\333\204\377\376\377\376\377\377\377" \ + "\377\375\376\376\376\377\377\377\377\377\377\377\377\377\377\377\377" \ + "\377\377\377\377\247\377\377\377\17\377\377\375\377\377\377\377\377\375" \ + "\376\376\376\377\377\377\377\377\375\376\376\377\334\354\305\211\306" \ + "=\213\307A\213\305;\215\306A\214\306<\215\305>\213\307A\232\214\306>" \ + "\202\214\305@\11\214\306>\214\306<\214\306>\215\307\77\212\311=\333\355" \ + "\305\377\376\377\377\377\377\376\376\376\377\377\377\377\377\377\377" \ + "\377\377\377\377\377\377\377\377\377\252\377\377\377\3\377\377\375\377" \ + "\377\377\377\376\377\203\377\377\375\7\233\314V\215\307\77\215\305>\214" \ + "\306>\215\307\77\214\305@\212\307>\232\214\306>\14\214\305@\214\306>" \ + "\214\306<\215\307=\215\307\77\214\305@\232\315V\374\377\373\376\376\377" \ + "\377\377\375\377\377\377\376\376\376\377\377\377\377\377\377\377\377" \ + "\377\377\377\377\377\377\377\377\255\377\377\377\10\377\377\375\377\376" \ + "\377\324\353\267\214\304\77\215\305>\214\305@\212\307<\214\305@\232\214" \ + "\306>\2\215\307\77\215\306A\202\214\306>\4\215\307\77\213\304\77\215" \ + "\306E\316\346\254\202\377\377\377\3\377\377\375\376\376\377\376\377\377" \ + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\247" \ + "\377\377\377\1\376\376\376\206\377\377\377\10\377\377\373\375\376\377" \ + "\232\315W\214\306>\215\307=\211\307>\215\306A\215\305>\232\214\306>\1" \ + "\214\305@\202\215\307\77\13\214\305@\215\306E\227\317P\377\377\377\377" \ + "\377\375\376\377\377\377\377\377\377\377\375\375\377\376\377\377\377" \ + "\377\377\375\377\377\377\377\377\377\377\377\377\377\377\377\377\377" \ + "\377\377\254\377\377\377\20\376\377\377\377\375\377\331\356\303\215\305" \ + "@\213\310\77\215\305>\216\306\77\213\307A\215\306A\214\306<\214\306>" \ + "\216\306\77\213\304\77\212\307<\214\306>\215\305@\210\214\306>\1\214" \ + "\305@\202\215\307\77\205\214\306>\10\214\305@\212\307>\215\305>\214\305" \ + "@\215\305>\214\305@\215\305>\331\356\305\377\377\377\377\377\377\377" \ + "\377\377\377\377\377\377\377\377\377\264\377\377\377\20\376\376\374\377" \ + "\377\375\376\376\374\261\330{\214\306>\216\306A\214\306>\213\307A\215" \ + "\305>\215\306A\215\307\77\213\304A\215\307\77\214\305@\214\306<\216\306" \ + "A\210\214\306>\4\215\307\77\213\305=\214\306>\215\307\77\202\214\306" \ + ">\12\215\307\77\214\306>\212\307>\220\305\77\212\307>\214\306>\213\310" \ + "=\214\306<\262\327z\376\377\377\377\377\377\377\377\377\377\377\377\377" \ + "\377\377\377\377\377\377\265\377\377\377\17\374\377\377\377\377\377\370" \ + "\373\362\241\321d\211\310<\215\305>\215\305@\216\306=\214\305@\214\306" \ + ">\215\307\77\214\306>\212\307<\212\306@\212\307<\210\214\306>\3\215\307" \ + "\77\214\306>\215\306A\203\214\305@\12\215\306A\214\305@\215\305>\212" \ + "\307>\213\307A\216\305C\215\307=\242\322e\371\372\364\375\377\376\377" \ + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\264\377" \ + "\377\377\1\375\377\374\203\377\377\377\4\352\364\333\223\311O\212\306" \ + "@\215\305@\202\213\310\77\202\214\306>\4\216\307F\213\305=\215\307\77" \ + "\215\305@\211\214\306>\1\215\307\77\203\214\305@\202\214\306>\1\215\307" \ + "\77\202\214\305@\6\216\305C\215\307\77\225\311K\351\363\332\377\377\377" \ + "\376\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" \ + "\377\377\265\377\377\377\17\377\375\376\377\376\377\377\377\377\377\377" \ + "\375\352\365\327\223\313L\212\307<\215\305>\214\305@\215\307=\214\305" \ + "@\214\306<\213\310\77\213\304\77\220\305A\212\214\306>\202\214\305@\12" \ + "\214\306>\214\306<\214\306>\215\307\77\214\306>\213\310=\215\307=\225" \ + "\311K\347\365\334\377\377\375\377\377\377\377\377\377\377\377\377\377" \ + "\377\377\377\377\377\377\267\377\377\377\1\377\377\375\202\377\377\377" \ + "\13\377\376\377\376\377\377\353\363\334\245\320d\214\305B\214\305@\215" \ + "\306A\213\305=\214\306>\213\307A\213\310=\213\214\306>\5\214\305@\214" \ + "\306>\214\306<\215\307=\215\307\77\202\214\305@\5\214\306<\242\322e\351" \ + "\363\332\377\377\375\376\376\376\377\377\377\377\377\377\377\377\377" \ + "\377\377\377\377\377\377\377\267\377\377\377\1\376\376\374\202\377\377" \ + "\375\6\376\377\377\377\376\377\377\377\375\371\372\364\255\330|\217\304" \ + ">\202\212\306@\2\215\306A\214\303A\202\214\305@\211\214\306>\2\215\307" \ + "\77\215\306A\202\214\306>\6\215\307\77\213\304\77\215\306E\215\305>\262" \ + "\327z\371\372\364\203\377\377\377\2\376\377\377\377\377\375\377\377\377" \ + "\377\377\377\377\377\377\377\377\377\377\377\377\377\264\377\377\377" \ + "\1\376\376\376\202\377\377\377\2\377\377\375\377\376\377\203\377\377" \ + "\377\6\377\377\375\331\356\303\233\314W\215\310<\214\305@\215\307\77" \ + "\214\214\306>\1\214\305@\202\215\307\77\7\214\305@\215\306E\227\317P" \ + "\331\356\305\376\377\377\375\377\376\376\377\377\202\377\377\377\2\377" \ + "\377\375\376\377\377\377\377\377\377\377\377\377\377\377\377\377\377" \ + "\377\377\377\377\274\377\377\377\10\377\377\375\377\376\377\365\375\362" \ + "\307\342\237\234\315Z\212\306@\212\307>\214\305@\202\215\307\77\16\214" \ + "\306>\215\307\77\214\306>\215\306A\214\306>\213\310\77\214\306>\215\305" \ + "<\216\306A\213\310\77\212\307>\232\315T\307\341\242\370\373\362\377\377" \ + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\304\377\377" \ + "\377\1\377\377\375\202\377\377\377\10\377\376\377\376\376\374\335\354" \ + "\303\270\333\207\222\311J\214\305@\215\306A\213\305=\202\214\306>\13" \ + "\215\307\77\216\306\77\215\305>\212\306@\212\307>\226\312K\270\333\211" \ + "\334\354\307\376\377\377\376\376\376\377\377\375\377\377\377\377\377" \ + "\377\377\377\377\377\377\377\377\377\377\377\306\377\377\377\2\376\377" \ + "\375\376\377\377\204\377\377\377\16\350\366\334\332\354\302\311\341\245" \ + "\306\341\234\305\342\237\304\341\237\305\342\240\305\342\237\334\355" \ + "\303\352\364\333\377\377\375\377\375\376\377\376\377\377\377\375\377" \ + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\307\377" \ + "\377\377\15\376\376\376\377\376\377\377\377\375\377\377\373\376\377\377" \ + "\376\377\375\376\377\377\377\377\375\377\377\377\376\376\376\376\377" \ + "\377\376\377\375\377\377\377\202\377\376\377\204\377\377\377\1\376\376" \ + "\376\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" \ + "\307\377\377\377\3\376\377\377\377\377\377\376\376\376\202\377\377\377" \ + "\1\376\376\376\210\377\377\377\3\375\377\376\376\377\377\377\377\377" \ + "\203\377\376\377\4\376\377\375\376\377\377\377\377\377\377\376\377\377" \ + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\304\377" \ + "\377\377\10\377\377\375\377\376\377\377\377\373\377\377\377\375\377\376" \ + "\376\377\377\376\376\376\377\376\377\202\376\377\377\1\377\377\377\202" \ + "\376\376\376\202\377\377\377\202\376\377\377\5\376\377\375\377\377\377" \ + "\376\376\374\377\377\377\377\377\375\377\377\377\377\377\377\377\377" \ + "\377\377\377\377\377\377\377\377\307\377\377\377\1\376\376\377\202\377" \ + "\377\377\2\377\377\375\376\376\377\202\377\377\377\2\376\377\375\377" \ + "\377\375\204\377\377\377\202\377\377\375\1\376\377\375\202\376\377\377" \ + "\202\377\377\375\202\377\377\377\1\377\376\377\377\377\377\377\377\377" \ + "\377\377\377\377\377\377\377\377\377\377\310\377\377\377\5\377\377\375" \ + "\377\376\377\377\377\375\376\376\377\377\376\377\207\377\377\377\202" \ + "\377\376\377\1\376\376\376\377\377\377\377\377\377\377\377\377\377\377" \ + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" \ + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" \ + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" \ + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" \ + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" \ + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" \ + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" \ + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" \ + "\377\377\377\377\377\377\377\377\377\377\377\377\377\261\377\377\377" \ + "\1\376\376\376\210\377\377\377\3\376\376\376\377\377\377\376\376\376" \ + "\331\377\377\377\1\376\376\376\204\377\377\377\1\376\376\376\257\377" \ + "\377\377\1\376\376\376\212\377\377\377\1\376\376\376\211\377\377\377" \ + "\1\376\376\376\221\377\377\377\1\376\376\376\203\377\377\377\1\376\376" \ + "\376\205\377\377\377\1\376\376\376\312\377\377\377\1\376\376\376\214" \ + "\377\377\377\1\376\376\376\202\377\377\377\6\377\376\375\377\377\377" \ + "\376\377\377\377\377\377\377\376\377\376\377\377\270\377\377\377\7\376" \ + "\377\377\377\376\377\376\377\377\377\377\375\377\377\377\377\375\377" \ + "\377\376\377\273\377\377\377\1\376\376\376\202\377\377\377\1\376\376" \ + "\376\302\377\377\377\1\376\376\376\305\377\377\377\1\376\376\376\241" \ + "\377\377\377\1\376\376\376\214\377\377\377\1\376\376\376\235\377\377" \ + "\377\1\376\376\376\202\377\377\377\1\376\376\376\202\377\377\377\1\376" \ + "\376\376\202\377\377\377\1\376\376\376\252\377\377\377\1\376\376\376" \ + "\212\377\377\377\3\376\376\376\377\377\377\376\376\376\202\377\377\377" \ + "\1\376\376\376\251\377\377\377\202\376\376\376\215\377\377\377\1\376" \ + "\376\376\202\377\377\377\1\376\376\376\205\377\377\377\1\376\376\376" \ + "\224\377\377\377\1\376\376\376\203\377\377\377\1\376\376\376\202\377" \ + "\377\377\1\376\376\376\232\377\377\377\1\376\376\376\202\377\377\377" \ + "\1\376\376\376\202\377\377\377\1\376\376\376\206\377\377\377\1\376\376" \ + "\376\243\377\377\377\1\376\376\376\204\377\377\377\1\376\376\376\202" \ + "\377\377\377\3\376\376\376\377\377\377\376\376\376\202\377\377\377\2" \ + "\376\376\376\377\377\377\202\377\377\375\3\377\377\377\376\377\377\377" \ + "\377\375\202\377\376\377\1\377\377\377\270\377\376\377\14\377\377\377" \ + "\377\376\377\377\376\374\377\377\375\375\376\377\376\377\377\377\377" \ + "\375\376\376\376\377\377\377\376\376\376\377\377\377\376\376\376\203" \ + "\377\377\377\1\376\376\376\266\377\377\377\1\376\376\376\203\377\377" \ + "\377\1\376\376\376\202\377\377\377\1\376\376\376\214\377\377\377\202" \ + "\376\376\376\207\377\377\377\1\376\376\376\272\377\377\377\1\376\376" \ + "\376\252\377\377\377\202\376\376\376\247\377\377\377\5\376\376\376\377" \ + "\377\377\376\376\376\377\377\377\376\376\376\202\377\377\377\1\376\376" \ + "\376\203\377\377\377\1\376\376\376\311\377\377\377\1\376\376\376\221" \ + "\377\377\377\1\376\376\376\203\377\377\377\1\376\376\376\302\377\377" \ + "\377\1\376\376\376\207\377\377\377\1\346\346\346\204\316\316\316\10\317" \ + "\317\317\315\315\315\316\316\316\363\363\365\377\377\377\376\376\376" \ + "\377\377\377\376\376\376\204\377\377\377\1\376\376\376\202\377\377\377" \ + "\1\376\376\376\234\377\377\377\1\376\376\376\262\377\377\377\1\376\376" \ + "\376\213\377\377\377\1\377\377\375\202\376\377\377\1\376\376\377\202" \ + "\377\377\377\2\377\376\377\377\377\375\270\276\317\331\1\377\376\377" \ + "\205\377\377\377\3\376\377\375\377\377\375\376\376\376\257\377\377\377" \ + "\1\376\376\376\210\377\377\377\202\376\376\376\210\377\377\377\1\376" \ + "\376\376\220\377\377\377\1\376\376\376\207\377\377\377\1\376\376\376" \ + "\243\377\377\377\1\376\376\376\203\377\377\377\3\376\376\376\377\377" \ + "\377\376\376\376\207\377\377\377\1\376\376\376\331\377\377\377\12\376" \ + "\376\376\377\377\377\235\235\235kkmllnkkmllnjjlkkm\346\346\346\202\377" \ + "\377\377\1\376\376\376\237\377\377\377\2\346\346\346\317\317\317\204" \ + "\316\316\316\2\317\317\317\346\346\346\234\377\377\377\1\376\376\376" \ + "\203\377\377\377\1\376\376\376\202\377\377\377\1\332\332\332\203\316" \ + "\316\316\1\317\317\317\202\316\316\316\213\377\377\377\5\346\346\346" \ + "\317\317\317\315\315\315\316\316\316\315\315\315\252\316\316\316\1\363" \ + "\363\363\205\377\377\377\1\376\376\376\212\377\377\377\1\376\376\376" \ + "\211\377\377\377\4\346\346\346\250\250\250\204\204\206``b\202::<\1;;" \ + "=\202::<\3;;=99;;;=\203::<\4lln\220\220\222\266\266\266\363\363\363\202" \ + "\376\376\376\240\377\377\377\1\346\346\346\202\316\316\316\10\317\317" \ + "\317\315\315\315\317\317\317\316\316\316\332\332\332\376\376\376\377" \ + "\377\377\376\376\376\203\377\377\377\1\376\376\376\241\377\377\377\6" \ + "\376\376\376\377\377\377\346\346\346\316\316\320\317\317\321\316\316" \ + "\320\203\316\316\316\2\347\347\347\376\376\376\205\377\377\377\1\376" \ + "\376\376\202\377\377\375\5\376\377\377\377\377\375\377\377\377\317\334" \ + "\344\37V\177\270\0>i\12\37U{\317\334\344\377\376\374\377\377\375\376" \ + "\377\377\377\376\374\376\377\377\376\376\376\377\377\377\363\363\363" \ + "\202\316\316\316\1\315\315\315\202\317\317\317\251\316\316\316\1\332" \ + "\332\332\202\377\377\377\1\376\376\376\203\377\377\377\202\376\376\376" \ + "\204\377\377\377\3\346\346\346\316\316\316\316\316\320\204\316\316\316" \ + "\2\346\346\346\376\376\376\212\377\377\377\1\347\347\347\206\316\316" \ + "\316\2\317\317\317\363\363\363\250\377\377\377\2\376\376\376\331\331" \ + "\331\206\316\316\316\1\332\332\332\202\377\377\377\1\376\376\376\204" \ + "\377\377\377\1\376\376\376\203\377\377\377\3\332\332\332\316\316\316" \ + "\316\316\320\250\316\316\316\1\363\363\363\205\377\377\377\1\376\376" \ + "\376\242\377\377\377\4\346\346\346::<;;=99;\204::<\1\204\204\206\237" \ + "\377\377\377\1\376\376\376\202\377\377\377\3\235\235\235::<;;=\202::" \ + "<\3;;=::<\235\235\235\202\377\377\377\1\376\376\376\232\377\377\377\1" \ + "\376\376\376\205\377\377\377\4kkm;;;99;;;=\202::<\1;;;\213\377\377\377" \ + "\4\234\234\234:::::<;;=\202::<\1;;;\250::<\1\316\316\316\202\377\377" \ + "\377\1\376\376\376\203\377\377\377\1\376\376\376\212\377\377\377\203" \ + "\376\376\376\203\377\377\377\3\346\346\346\250\250\250```\204::<\202" \ + ";;=\202::<\3;;=::<;;=\203::<\1;;=\202::<\5;;=::<```\265\265\265\362\362" \ + "\362\203\377\377\377\1\376\376\376\233\377\377\377\1\234\234\236\204" \ + "::<\5""99;;;=::<\333\333\335\376\376\376\203\377\377\377\1\376\376\376" \ + "\241\377\377\377\4\376\376\376\377\377\377\363\363\363FFH\202::<\1;;" \ + "=\203::<\1\234\234\234\210\377\377\377\6\376\377\377\377\377\375\375" \ + "\376\377\356\363\366\40Vz\0\77h\270\0=i\20\0>i\22Ip\356\363\367\376\377" \ + "\377\377\377\375\377\377\377\376\376\377\377\376\377\377\377\377\315" \ + "\315\315:::::<;;=::<99;;;;\250::<\1kkm\205\377\377\377\1\376\376\376" \ + "\203\377\377\377\4\376\376\376\377\377\377\376\376\376\234\234\234\203" \ + "::<\6;;=::<:::\234\234\234\377\377\377\376\376\376\211\377\377\377\3" \ + "\332\332\332:::;;=\202::<\202;;=\2::<\204\204\206\250\377\377\377\2\364" \ + "\364\364FFF\204::<\202:::\1\234\234\234\206\377\377\377\1\376\376\376" \ + "\204\377\377\377\2kkk;;=\251::<\1\316\316\316\202\377\377\377\1\376\376" \ + "\376\203\377\377\377\1\376\376\376\240\377\377\377\6\376\376\376\234" \ + "\234\236::<;;=::<;;=\203::<\2FFH\362\362\362\235\377\377\377\1\376\376" \ + "\376\203\377\377\377\3\234\234\236::<;;=\202::<\3;;=::<\234\234\236\203" \ + "\377\377\377\1\376\376\376\233\377\377\377\1\376\376\376\203\377\377" \ + "\377\7kkm::<;;=::<;;=::<;;=\213\377\377\377\4\235\235\235::<;;=99;\202" \ + ";;=\251::<\1\315\315\315\203\377\377\377\202\376\376\376\213\377\377" \ + "\377\1\376\376\376\202\377\377\377\6\376\376\376\377\377\377\315\315" \ + "\315\205\205\205::<;;=\213::<\4;;=::<;;=::<\203;;=\204::<\4FFF\204\204" \ + "\204\346\346\346\376\376\376\234\377\377\377\3\234\234\236::<;;=\202" \ + "::<\4;;=99;::<``b\244\377\377\377\1\376\376\376\203\377\377\377\1xxz" \ + "\202::<\10;;=99;;;=::<;;=\233\233\235\377\377\377\376\376\376\202\377" \ + "\377\377\1\376\376\376\203\377\377\377\4\375\377\376\377\376\373\377" \ + "\377\375\235\267\310\202\0>i\271\0=i\4\0\77j\237\266\306\377\376\377" \ + "\377\375\374\202\376\377\377\4\377\377\377\376\376\376\316\316\31699" \ + ";\202;;=\2::<;;=\251::<\1kkm\203\377\377\377\1\376\376\376\210\377\377" \ + "\377\4\235\235\235::<99;;;=\203::<\1\235\235\235\214\377\377\377\2ll" \ + "n99;\202;;=\1::<\203;;=\2\362\362\364\376\376\376\245\377\377\377\2\376" \ + "\376\376\250\250\250\204::<\4;;=::<:::\346\346\346\203\377\377\377\1" \ + "\376\376\376\205\377\377\377\3\376\376\376\377\377\377jjl\252::<\1\315" \ + "\315\315\203\377\377\377\202\376\376\376\242\377\377\377\3\362\362\364" \ + "GGI::<\202;;=\2""99;;;=\202::<\2""99;\235\235\235\237\377\377\377\3\376" \ + "\376\376\377\377\377\235\235\237\202::<\202;;=\202::<\3\235\235\237\377" \ + "\377\377\376\376\376\233\377\377\377\1\376\376\376\203\377\377\377\4" \ + "\376\376\376\377\377\377kkm;;=\202::<\5""99;;;=99;\377\377\377\376\376" \ + "\376\211\377\377\377\1\233\233\233\202::<\3;;=::<99;\251::<\1\317\317" \ + "\317\205\377\377\377\1\376\376\376\214\377\377\377\3\376\376\376\347" \ + "\347\347xxz\203::<\1;;=\202::<\1;;=\204::<\1;;=\203::<\1;;=\205::<\1" \ + ";;=\203::<\1;;=\203::<\2\234\234\236\362\362\362\233\377\377\377\2\233" \ + "\233\235;;=\204::<\1;;=\202::<\1\234\234\236\245\377\377\377\4\376\376" \ + "\376\302\302\304::<;;=\206::<\1\235\235\237\202\377\377\377\1\376\376" \ + "\376\203\377\377\377\7\375\376\377\377\377\377\377\377\375\376\377\377" \ + "\377\377\377\177\235\265\0\77k\271\0\77j\7\0\77k\0\77j~\236\265\377\376" \ + "\377\376\377\377\375\377\374\377\377\375\202\377\377\377\5\315\315\315" \ + ";;=::<99;;;=\252::<\3kkm\377\377\377\376\376\376\203\377\377\377\1\376" \ + "\376\376\203\377\377\377\1\376\376\376\202\377\377\377\3\233\233\233" \ + "::<;;=\202::<\3;;=::<\234\234\234\202\377\377\377\1\376\376\376\211\377" \ + "\377\377\4\264\264\264;;=::<;;=\204::<\3\247\247\251\377\377\377\376" \ + "\376\376\245\377\377\377\1SSS\203::<\1;;=\202::<\1\204\204\204\213\377" \ + "\377\377\4\376\376\376lln::<:9>\250::<\1\317\317\317\205\377\377\377" \ + "\1\376\376\376\241\377\377\377\1\265\265\267\204::<\1;;=\204::<\1FFF" \ + "\241\377\377\377\2\234\234\236;;=\204::<\2;;=\234\234\236\234\377\377" \ + "\377\3\376\376\376\377\377\377\376\376\376\204\377\377\377\1kkm\203:" \ + ":<\4;;=::<;;=\376\376\376\212\377\377\377\1\234\234\234\204::<\1;;=\251" \ + "::<\1\316\316\316\203\377\377\377\202\376\376\376\215\377\377\377\4\234" \ + "\234\234;;=::<;;=\202::<\1""99;\204::<\1;;=\203::<\1;;=\211::<\1""99" \ + ";\207::<\2FFF\301\301\301\232\377\377\377\2\234\234\23699;\210::<\1\333" \ + "\333\333\241\377\377\377\6\376\376\376\377\377\377\376\376\376\363\363" \ + "\363FFH;;=\205::<\3;;=::<\234\234\236\206\377\377\377\7\377\376\377\377" \ + "\377\377\377\377\375\375\376\377\377\376\377\201\235\263\0>g\272\0>i" \ + "\13\0>e\177\236\263\377\375\374\377\377\377\377\377\375\376\376\376\377" \ + "\376\377\377\377\377\316\316\316::<;;=\202::<\2""99;;;=\250::<\1kkm\204" \ + "\377\377\377\5\376\376\376\377\377\377\376\376\376\377\377\377\376\376" \ + "\376\202\377\377\377\2\376\376\376\234\234\234\206::<\1\234\234\234\215" \ + "\377\377\377\2RRT;;=\205::<\1SSU\246\377\377\377\2\316\316\316999\206" \ + "::<\1\316\316\316\202\377\377\377\3\376\376\376\377\377\377\376\376\376" \ + "\207\377\377\377\3jjl::<:9>\250::<\1\316\316\316\203\377\377\377\202" \ + "\376\376\376\242\377\377\377\2SSU99;\202;;=\204::<\4;;=99;::<\264\264" \ + "\266\240\377\377\377\1\234\234\234\206::<\1\234\234\234\243\377\377\377" \ + "\1kkm\206::<\213\377\377\377\2\234\234\236;;=\216::<\4""99;;;=::<;;=" \ + "\206::<\3;;=::<;;=\222::<\1\316\316\316\205\377\377\377\1\376\376\376" \ + "\207\377\377\377\1\376\376\376\202\377\377\377\2\346\346\350__a\202:" \ + ":<\3;;=::<;;=\204::<\1;;=\202::<\3;;=::<;;=\203::<\1;;=\202::<\2""99" \ + ";;;=\202::<\1;;=\204::<\7;;=::<;;=::<;;=\204\204\206\363\363\363\203" \ + "\377\377\377\3\376\376\376\377\377\377\376\376\376\222\377\377\377\4" \ + "\234\234\236::<;;=99;\204::<\3;;=::<__a\244\377\377\377\1xxx\205::<\1" \ + ";;=\203::<\1\234\234\236\213\377\377\377\3\177\236\263\0=i\0>i\211\0" \ + "=i\2\0>j\0=i\202\1>j\2\0\77k\0>j\232\0>i\2\0>j\0\77k\202\1>j\2\0=i\0" \ + ">j\211\0=i\3\0>i\0=i\177\236\263\206\377\377\377\6\316\316\316:::::<" \ + ";;=::<;;=\217::<\1;;=\203::<\1;;=\202::<\1;;=\222::<\1kkk\205\377\377" \ + "\377\1\376\376\376\206\377\377\377\1\234\234\236\206::<\1\234\234\236" \ + "\215\377\377\377\3\234\234\234;;=::<\202;;=\203::<\3\316\316\320\377" \ + "\377\377\376\376\376\240\377\377\377\1\376\376\376\202\377\377\377\3" \ + "xxz::<;;=\202::<\3;;=::<__a\215\377\377\377\1kkm\204::<\1;;=\202::<\1" \ + ";;=\242::<\1\316\316\316\205\377\377\377\1\376\376\376\240\377\377\377" \ + "\1\265\265\265\202::<\5;;=::<;;=::<;;=\204::<\2TTV\376\376\376\237\377" \ + "\377\377\1\234\234\234\206::<\1\234\234\234\243\377\377\377\1kkm\206" \ + "::<\213\377\377\377\3\234\234\23499;;;=\214::<\1""99;\207::<\1;;=\227" \ + "::<\1\316\316\316\204\377\377\377\3\376\376\376\377\377\377\376\376\376" \ + "\203\377\377\377\1\376\376\376\204\377\377\377\2\333\333\335FFH\214:" \ + ":<\16``b\221\221\223\251\251\251\315\315\315\316\316\316\363\363\363" \ + "\377\377\377\332\332\332\316\316\316\301\301\301\235\235\237jjlFFH;;" \ + "=\207::<\1;;=\202::<\3;;=__a\363\363\363\227\377\377\377\4\234\234\236" \ + "99;::<;;=\205::<\3;;=::<\233\233\233\240\377\377\377\12\376\376\376\377" \ + "\377\377\301\301\301;;=::<;;=::<;;=::<99;\203::<\1\234\234\236\213\377" \ + "\377\377\3\177\236\263\0=i\0>i\211\0=i\7\1>j\0=i\1>j\0=i\0>g\3>h\2=g" \ + "\230\0=i\7\2=g\3>h\0>g\0=i\1>j\0=i\1>j\211\0=i\3\0>i\0=i\177\236\263" \ + "\206\377\377\377\2\317\317\317:::\221::<\202;;=\202::<\3;;=::<99;\203" \ + "::<\2;;=99;\220::<\1kkk\214\377\377\377\1\234\234\236\206::<\1\234\234" \ + "\236\213\377\377\377\3\376\376\376\377\377\377\363\363\363\204::<\4;" \ + ";=::<;;=xxz\202\377\377\377\1\376\376\376\236\377\377\377\1\376\376\376" \ + "\202\377\377\377\3\346\346\346::<;;=\202::<\4;;=99;;;=\266\266\270\215" \ + "\377\377\377\1kkm\203::<\1;;=\202::<\1;;=\243::<\1\316\316\316\204\377" \ + "\377\377\3\376\376\376\377\377\377\376\376\376\232\377\377\377\1\376" \ + "\376\376\204\377\377\377\1kkm\202;;=\202::<\202;;=\2::<;;=\204::<\3\317" \ + "\317\317\377\377\377\376\376\376\235\377\377\377\1\234\234\234\206::" \ + "<\1\234\234\234\243\377\377\377\1kkm\206::<\212\377\377\377\1\376\376" \ + "\376\224\377\377\377\1lln\203::<\1;;=\202::<\1\234\234\236\234\377\377" \ + "\377\1\376\376\376\204\377\377\377\4\376\376\376\265\265\267::<;;=\202" \ + "::<\1;;=\202::<\1;;=\203::<\5__a\266\266\270\363\363\363\377\377\377" \ + "\376\376\376\204\377\377\377\1\376\376\376\203\377\377\377\1\376\376" \ + "\376\202\377\377\377\4\301\301\303\204\204\206;;=::<\203;;=\202::<\2" \ + ";;=::<\202;;=\3GGI\332\332\334\376\376\376\203\377\377\377\1\376\376" \ + "\376\221\377\377\377\2\235\235\237::<\202;;=\202::<\1;;=\202::<\4""9" \ + "9;::<;;=\331\331\331\240\377\377\377\2\363\363\363GGI\203::<\2;;=::<" \ + "\203;;=\202::<\1\234\234\236\213\377\377\377\3\177\236\263\0=i\0>i\210" \ + "\0=i\10\0\77k\0=i\1>j\0>i\0\77j\0=i\0>i\0>j\230\0>i\10\0>j\0>i\0=i\0" \ + "\77j\0>i\1>j\0=i\0\77k\210\0=i\3\0>i\0=i\177\236\263\206\377\377\377" \ + "\1\376\376\376\217\377\377\377\1\376\376\376\203\377\377\377\1\315\315" \ + "\317\204::<\3;;=::<kkm\240\377\377\377\1\234\234\236\206::<\1\234\234" \ + "\236\214\377\377\377\3\376\376\376\377\377\377\204\204\206\202::<\1;" \ + ";=\202::<\202;;=\1\345\345\345\242\377\377\377\2\376\376\376\234\234" \ + "\234\206::<\2GGI\363\363\363\215\377\377\377\1kkm\203::<\4""99;::<;;" \ + "=\316\316\320\311\377\377\377\2\317\317\32199;\203::<\5;;=::<FFH;;=:" \ + ":<\202;;=\202::<\1kkm\237\377\377\377\1\234\234\234\206::<\1\234\234" \ + "\234\243\377\377\377\1kkm\206::<\213\377\377\377\3\376\376\376\377\377" \ + "\377\376\376\376\216\377\377\377\1\376\376\376\202\377\377\377\5lln:" \ + ":<;;=::<;;=\202::<\2\234\234\234\376\376\376\227\377\377\377\1\376\376" \ + "\376\210\377\377\377\1\264\264\266\202;;=\4::<;;=::<99;\204::<\3jjl\317" \ + "\317\321\376\376\376\202\377\377\377\1\375\375\375\203\377\377\377\3" \ + "\376\376\376\377\377\377\376\376\376\204\377\377\377\1\376\376\376\203" \ + "\377\377\377\3\363\363\365\234\234\236FFH\202::<\1;;=\202::<\1;;=\203" \ + "::<\2FFH\332\332\334\225\377\377\377\1\233\233\235\202;;=\211::<\1__" \ + "a\240\377\377\377\2xxz;;=\202::<\3;;=::<;;=\205::<\1\234\234\236\213" \ + "\377\377\377\3\177\236\263\0=i\0>i\211\0=i\202\0>i\5\0<h\1>j\0=i\1>j" \ + "\0>i\230\0=i\5\0>i\1>j\0=i\1>j\0<h\202\0>i\211\0=i\3\0>i\0=i\177\236" \ + "\263\212\377\377\377\3\376\376\376\377\377\377\376\376\376\212\377\377" \ + "\377\1\376\376\376\202\377\377\377\10\316\316\320::<;;=::<;;=99;::<j" \ + "jl\225\377\377\377\1\376\376\376\202\377\377\377\1\376\376\376\207\377" \ + "\377\377\1\234\234\236\206::<\1\234\234\236\216\377\377\377\3\332\332" \ + "\332;;=99;\202::<\4;;=::<99;\234\234\236\237\377\377\377\1\376\376\376" \ + "\203\377\377\377\1SSU\202::<\1;;=\203::<\1\221\221\221\216\377\377\377" \ + "\1kkm\206::<\1\316\316\316\250\377\377\377\1\376\376\376\235\377\377" \ + "\377\1\376\376\376\202\377\377\377\5xxz::<;;=::<;;=\202::<\3\316\316" \ + "\320RRT;;=\203::<\4;;=::<\332\332\332\376\376\376\235\377\377\377\1\234" \ + "\234\234\206::<\1\234\234\234\243\377\377\377\1kkm\206::<\214\377\377" \ + "\377\3\376\376\376\377\377\377\376\376\376\213\377\377\377\1\376\376" \ + "\376\204\377\377\377\4kkm;;=::<;;=\203::<\1\235\235\235\202\377\377\377" \ + "\1\376\376\376\221\377\377\377\1\376\376\376\213\377\377\377\4\301\301" \ + "\301;;=::<;;=\203::<\202;;=\3::<RRT\316\316\316\203\377\377\377\1\376" \ + "\376\376\202\377\377\377\1\376\376\376\204\377\377\377\3\376\376\376" \ + "\377\377\377\376\376\376\203\377\377\377\1\376\376\376\204\377\377\377" \ + "\4\346\346\346xxz;;=99;\207::<\4GGI\362\362\362\377\377\377\376\376\376" \ + "\222\377\377\377\1\234\234\236\206::<\203;;=\202::<\2;;=\233\233\235" \ + "\236\377\377\377\10\301\301\301::<;;=:9>::<99;::<99;\202;;=\203::<\1" \ + "\234\234\236\213\377\377\377\3\177\236\263\0=i\0>i\210\0=i\7\2=g\0>i" \ + "\0>j\0\77j\0=i\0\77j\0=h\232\1>j\7\0=h\0\77j\0=i\0\77j\0>j\0>i\2=g\210" \ + "\0=i\3\0>i\0=i\177\236\263\213\377\377\377\1\376\376\376\216\377\377" \ + "\377\1\317\317\321\202::<\6;;=::<;;=::<lln\376\376\376\225\377\377\377" \ + "\1\376\376\376\203\377\377\377\1\376\376\376\205\377\377\377\1\234\234" \ + "\236\206::<\1\234\234\236\213\377\377\377\1\376\376\376\203\377\377\377" \ + "\2kkm;;=\204::<\2;;=GGI\236\377\377\377\1\376\376\376\203\377\377\377" \ + "\1\265\265\267\202::<\6;;=::<;;=::<;;=\345\345\345\216\377\377\377\1" \ + "kkm\202::<\5;;=99;;;=99;\317\317\317\244\377\377\377\1\376\376\376\241" \ + "\377\377\377\3\376\376\376\377\377\377\347\347\351\206::<\3``b\377\377" \ + "\377\234\234\236\202::<\1;;=\202::<\4;;=\204\204\206\377\377\377\376" \ + "\376\376\234\377\377\377\1\234\234\234\206::<\1\234\234\234\243\377\377" \ + "\377\1kkm\206::<\215\377\377\377\1\375\375\375\202\377\377\377\1\376" \ + "\376\376\213\377\377\377\5\376\376\376\377\377\377\376\376\376lln;;=" \ + "\203::<\3;;=::<\234\234\234\234\377\377\377\1\376\376\376\202\377\377" \ + "\377\4\331\331\331FFH::<;;=\202::<\11;;=::<99;;;=\203\203\203\363\363" \ + "\363\376\376\376\377\377\377\376\376\376\222\377\377\377\7\376\376\376" \ + "\377\377\377\376\376\376\377\377\377\300\300\300GGI::<\202;;=\205::<" \ + "\4``b\362\362\362\377\377\377\376\376\376\221\377\377\377\1\234\234\236" \ + "\204::<\202;;=\203::<\5;;=99;::<;;=\332\332\332\234\377\377\377\4\363" \ + "\363\363GGI;;=::<\202;;=\203::<\1;;=\202::<\3;;=::<\234\234\236\213\377" \ + "\377\377\3\177\236\263\0=i\0>i\210\0=i\10\0\77j\0>j\0\77k\0=i\3>h\2=" \ + "g\1>j\0\77k\230\0=i\10\0\77k\1>j\2=g\3>h\0=i\0\77k\0>j\0\77j\210\0=i" \ + "\3\0>i\0=i\177\236\263\232\377\377\377\12\316\316\316;;=::<;;=::<;;=" \ + "::<kkm\377\377\377\376\376\376\222\377\377\377\1\376\376\376\202\377" \ + "\377\377\1\376\376\376\210\377\377\377\1\234\234\236\206::<\1\234\234" \ + "\236\214\377\377\377\1\376\376\376\202\377\377\377\2\266\266\26699;\202" \ + "::<\202;;=\202::<\3\266\266\270\377\377\377\376\376\376\234\377\377\377" \ + "\203\376\376\376\1lln\202;;=\204::<\3xxx\377\377\377\376\376\376\215" \ + "\377\377\377\1kkm\205::<\2;;=\316\316\316\305\377\377\377\1\376\376\376" \ + "\202\377\377\377\1\203\203\205\206::<\4\265\265\267\377\377\377\363\363" \ + "\363GGG\203::<\1;;=\202::<\1\346\346\346\235\377\377\377\1\234\234\234" \ + "\206::<\1\234\234\234\243\377\377\377\1kkm\206::<\216\377\377\377\1\376" \ + "\376\376\220\377\377\377\1jjl\206::<\1\234\234\234\202\377\377\377\1" \ + "\376\376\376\232\377\377\377\3\376\376\376\364\364\364SSU\202::<\7;;" \ + "=::<;;=99;::<;;=\265\265\265\205\377\377\377\203\376\376\376\214\377" \ + "\377\377\5\376\376\376\377\377\377\376\376\376\377\377\377\376\376\376" \ + "\203\377\377\377\7\332\332\332__a::<;;=::<;;=::<\202;;=\3::<\205\205" \ + "\207\376\376\377\222\377\377\377\3\234\234\236::<;;=\202::<\2;;=99;\202" \ + ";;=\1""99;\202::<\3;;=::<__a\234\377\377\377\1xxz\202;;=\205::<\1;;=" \ + "\202::<\1;;=\202::<\1\234\234\236\213\377\377\377\3\177\236\263\0=i\0" \ + ">i\210\0=i\10\0>i\0=i\0>i\0\77k\0>j\2=g\1\77h\0>l\230\0>i\10\0>l\1\77" \ + "h\2=g\0>j\0\77k\0>i\0=i\0>i\210\0=i\3\0>i\0=i\177\236\263\205\377\377" \ + "\377\1\376\376\376\202\377\377\377\1\376\376\376\221\377\377\377\3\316" \ + "\316\316::<;;=\204::<\1kkm\225\377\377\377\202\376\376\376\211\377\377" \ + "\377\1\234\234\236\206::<\1\234\234\236\217\377\377\377\3\376\376\376" \ + "TTV99;\202::<\4""99;;;=::<kkm\240\377\377\377\1\346\346\346\202::<\1" \ + "99;\204::<\1\316\316\316\217\377\377\377\1kkm\204::<\3;;=99;\316\316" \ + "\316\305\377\377\377\7\376\376\376\377\377\377\363\363\363::<;;=::<;" \ + ";=\202::<\1SSU\203\377\377\377\2\204\204\204;;=\203::<\4;;=99;\222\222" \ + "\222\376\376\376\234\377\377\377\1\234\234\234\206::<\1\234\234\234\243" \ + "\377\377\377\1kkm\206::<\214\377\377\377\3\376\376\376\377\377\377\376" \ + "\376\376\220\377\377\377\1kkm\206::<\1\234\234\236\236\377\377\377\1" \ + "\204\204\206\203::<\1;;=\202::<\3;;=::<\265\265\267\221\377\377\377\1" \ + "\376\376\376\202\377\377\377\1\376\376\376\203\377\377\377\1\376\376" \ + "\376\204\377\377\377\11\376\376\376\363\363\365__a::<;;=::<;;=::<;;=" \ + "\202::<\1\301\301\303\222\377\377\377\2\234\234\236;;=\202::<\10;;=:" \ + ":<;;=FFH::<;;=::<;;=\203::<\1\235\235\237\232\377\377\377\2\301\301\303" \ + ";;=\205::<\2;;=RRT\204::<\3;;=::<\234\234\236\213\377\377\377\3\177\236" \ + "\263\0=i\0>i\210\0=i\7\0>j\2=g\0>g\0>j\40V|o\224\256\177\236\262\232" \ + "\177\236\263\7\177\236\262o\224\256\40V|\0>j\0>g\2=g\0>j\210\0=i\3\0" \ + ">i\0=i\177\236\263\232\377\377\377\3\316\316\316::<;;=\203::<\2;;=kk" \ + "m\232\377\377\377\1\376\376\376\205\377\377\377\1\234\234\236\206::<" \ + "\1\234\234\236\220\377\377\377\2\233\233\235;;=\202::<\1<<>\203::<\1" \ + "\346\346\346\237\377\377\377\1\204\204\204\206::<\2SSU\376\376\376\217" \ + "\377\377\377\1kkm\203::<\4;;=::<;;=\316\316\320\304\377\377\377\1\376" \ + "\376\376\202\377\377\377\2\234\234\236;;=\202::<\4;;=::<;;=\234\234\234" \ + "\203\377\377\377\1\346\346\346\205::<\3;;=FFH\363\363\365\203\377\377" \ + "\377\1\376\376\376\230\377\377\377\1\234\234\234\206::<\1\234\234\234" \ + "\243\377\377\377\1kkm\206::<\237\377\377\377\1kkm\206::<\1\234\234\236" \ + "\235\377\377\377\2\316\316\316;;=\202::<\6;;=::<;;=::<:::\265\265\265" \ + "\237\377\377\377\7\376\376\376\363\363\363___::<;;=::<;;=\203::<\2GG" \ + "I\363\363\363\204\377\377\377\1\376\376\376\214\377\377\377\1\234\234" \ + "\234\203::<\202;;=\5::<\266\266\266GGI99;;;=\202::<\1;;=\202::<\1\332" \ + "\332\332\206\377\377\377\1\376\376\376\211\377\377\377\1\376\376\376" \ + "\207\377\377\377\2\363\363\363FFH\206::<\3FFH\301\301\30399;\202::<\202" \ + ";;=\2::<\234\234\236\206\377\377\377\7\377\377\375\377\377\377\377\377" \ + "\375\376\377\377\376\376\376\200\237\263\0\77i\211\0>i\7\0>g\1>j\0>g" \ + "_\210\236\377\377\377\376\377\377\377\376\377\231\377\377\377\10\377" \ + "\377\375\376\377\375\377\377\377\377\377\375`\210\242\3>h\0\77j\1\77" \ + "h\210\0=i\3\0>i\0=i\177\236\263\232\377\377\377\1\316\316\316\206::<" \ + "\1kkm\240\377\377\377\1\234\234\236\206::<\1\234\234\236\220\377\377" \ + "\377\1\363\363\363\204::<\202;;=\2""99;\205\205\207\207\377\377\377\1" \ + "\376\376\376\224\377\377\377\4\376\376\376\377\377\377\363\363\363FF" \ + "H\202::<\5;;=99;;;=::<\265\265\265\220\377\377\377\1kkm\206::<\1\316" \ + "\316\316\305\377\377\377\5\376\376\376\364\364\364FFH::<;;=\202::<\4" \ + ";;=FFH\363\363\363\377\377\377\202\376\376\376\6\377\377\377xxz::<;;" \ + "=::<;;=\202::<\1\234\234\236\206\377\377\377\202\376\376\376\224\377" \ + "\377\377\1\234\234\234\206::<\1\234\234\234\243\377\377\377\1kkm\206" \ + "::<\237\377\377\377\1kkm\206::<\1\234\234\236\225\377\377\377\1\376\376" \ + "\376\207\377\377\377\2SSS;;=\202::<\1;;=\203::<\1\234\234\234\202\377" \ + "\377\377\3\376\376\376\377\377\377\376\376\376\232\377\377\377\1\376" \ + "\376\376\202\377\377\377\4\332\332\332FFH::<;;=\202::<\1;;=\202::<\1" \ + "\222\222\224\205\377\377\377\1\376\376\376\213\377\377\377\3\234\234" \ + "\234::<;;=\202::<\5""99;;;=\315\315\315\250\250\252;;=\206::<\2``b\376" \ + "\376\376\202\377\377\377\1\376\376\376\216\377\377\377\1\376\376\376" \ + "\205\377\377\377\2xxx;;=\202::<\1;;=\203::<\2\300\300\300\317\317\321" \ + "\203::<\1;;=\202::<\1\234\234\236\207\377\377\377\1\377\376\377\202\377" \ + "\377\377\4\377\376\377\201\235\263\0=j\3>j\210\0=i\5\1>j\0=j\37V\177" \ + "\377\376\377\376\376\376\202\377\377\377\1\376\377\377\230\377\377\377" \ + "\10\376\377\377\377\377\375\374\377\377\377\376\374\376\377\377#W\177" \ + "\0>g\0\77i\210\0=i\3\0>i\0=i\177\236\263\232\377\377\377\1\316\316\316" \ + "\206::<\1kkm\240\377\377\377\1\234\234\236\206::<\1\234\234\236\220\377" \ + "\377\377\2\376\376\376\204\204\206\205::<\3;;=FFH\362\362\362\204\377" \ + "\377\377\202\376\376\376\2\377\377\377\376\376\376\224\377\377\377\3" \ + "\376\376\376\265\265\265;;=\203::<\4;;=99;FFH\363\363\363\220\377\377" \ + "\377\1kkm\206::<\1\316\316\316\306\377\377\377\4\265\265\26599;;;=::" \ + "<\202;;=\2""99;\222\222\224\204\377\377\377\12\376\376\376\316\316\320" \ + ";;=::<;;=99;;;=99;SSU\376\376\376\202\377\377\377\3\376\376\376\377\377" \ + "\377\376\376\376\226\377\377\377\1\234\234\234\206::<\1\234\234\234\243" \ + "\377\377\377\1kkm\206::<\237\377\377\377\1kkm\206::<\1\234\234\236\234" \ + "\377\377\377\11\234\234\234::<;;=99;;;=99;::<;;=kkm\241\377\377\377\1" \ + "\376\376\376\202\377\377\377\1\301\301\303\203::<\6;;=99;::<;;=::<\346" \ + "\346\350\203\377\377\377\1\376\376\376\214\377\377\377\1\234\234\234" \ + "\203::<\202;;=\10""99;\316\316\316\377\377\377kkm::<;;=::<;;=\203::<" \ + "\1\235\235\237\203\377\377\377\1\376\376\376\214\377\377\377\1\376\376" \ + "\376\205\377\377\377\3\302\302\304::<;;=\202::<\7""99;;;=99;xxz\377\377" \ + "\377\315\315\315;;=\203::<\3:9>::<\234\234\236\206\377\377\377\3\376" \ + "\377\377\377\377\375\377\377\377\202\377\377\375\3|\237\265\0\77k\0>" \ + "g\210\0=i\10\0@h\3<i~\236\263\376\377\377\377\377\377\377\376\377\377" \ + "\376\374\377\376\377\230\377\377\377\10\377\375\377\377\377\375\377\376" \ + "\374\377\377\377\376\376\374\220\251\275\2=i\0>j\210\0=i\3\0>i\0=i\177" \ + "\236\263\232\377\377\377\1\316\316\316\206::<\1kkm\240\377\377\377\1" \ + "\234\234\236\206::<\1\234\234\236\215\377\377\377\1\376\376\376\203\377" \ + "\377\377\2\332\332\334;;=\206::<\2\266\266\266\376\376\376\202\377\377" \ + "\377\1\376\376\376\202\377\377\377\1\376\376\376\222\377\377\377\1\376" \ + "\376\376\203\377\377\377\1SSS\203::<\4""99;::<;;=\221\221\223\221\377" \ + "\377\377\1kkm\206::<\1\316\316\316\306\377\377\377\4RRT;;=::<;;=\202" \ + "::<\2;;=\345\345\345\202\377\377\377\1\376\376\376\203\377\377\377\2" \ + "__a;;=\202::<\1;;=\202::<\1\264\264\264\206\377\377\377\1\376\376\376" \ + "\224\377\377\377\1\234\234\234\206::<\1\234\234\234\243\377\377\377\1" \ + "kkm\206::<\237\377\377\377\1kkm\206::<\1\234\234\236\226\377\377\377" \ + "\1\376\376\376\204\377\377\377\2\363\363\363FFH\203::<\1;;=\202::<\2" \ + "FFH\346\346\346\204\377\377\377\1\376\376\376\233\377\377\377\1\376\376" \ + "\376\203\377\377\377\3\376\376\376xxz99;\202::<\1""99;\202::<\4;;=\204" \ + "\204\206\377\377\377\376\376\376\202\377\377\377\1\376\376\376\213\377" \ + "\377\377\1\234\234\234\202::<\10;;=99;;;=::<\317\317\317\376\376\376" \ + "\363\363\363GGI\203::<\1;;=\203::<\3\331\331\331\377\377\377\376\376" \ + "\376\202\377\377\377\1\376\376\376\217\377\377\377\5\363\363\363GGI;" \ + ";=::<;;=\202::<\7""99;FFH\363\363\363\377\377\377\316\316\316::<;;=\202" \ + "::<\3:9>::<\234\234\236\207\377\377\377\7\376\377\377\376\376\376\377" \ + "\377\377\377\377\375\377\377\377\377\375\374\376\377\377\210\377\377" \ + "\377\10\376\376\374\376\377\377\354\364\366\377\377\375\376\377\377\377" \ + "\376\374\377\377\375\376\377\377\230\377\377\377\10\377\377\375\376\377" \ + "\377\377\376\375\375\376\377\376\377\377\301\317\330\0>g\0>j\210\0=i" \ + "\3\0>i\0=i\177\236\263\232\377\377\377\1\316\316\316\206::<\1kkm\240" \ + "\377\377\377\1\234\234\236\206::<\1\234\234\236\220\377\377\377\5\376" \ + "\376\376\377\377\377kkm::<;;=\202::<\3""99;::<^^`\204\377\377\377\1\376" \ + "\376\376\227\377\377\377\1\316\316\316\202::<\203;;=\202::<\1\347\347" \ + "\347\221\377\377\377\1kkm\206::<\1\316\316\316\303\377\377\377\12\376" \ + "\376\376\377\377\377\301\301\301;;=::<;;=::<99;::<\204\204\206\204\377" \ + "\377\377\4\376\376\376\377\377\377\376\376\376\266\266\266\202::<\5;" \ + ";=::<;;=::<``b\203\377\377\377\1\376\376\376\227\377\377\377\1\234\234" \ + "\234\206::<\1\234\234\234\243\377\377\377\1kkm\206::<\237\377\377\377" \ + "\1kkm\206::<\1\234\234\236\233\377\377\377\1\265\265\267\204::<\4""9" \ + "9;;;=::<\234\234\234\203\377\377\377\3\376\376\376\377\377\377\376\376" \ + "\376\231\377\377\377\5\376\376\376\377\377\377\376\376\376\377\377\377" \ + "\376\376\376\202\377\377\377\5\363\363\363GGI99;::<;;=\202::<\3;;=::" \ + "<\346\346\346\204\377\377\377\1\376\376\376\212\377\377\377\3\234\234" \ + "\234::<99;\202;;=\202::<\1\315\315\315\202\377\377\377\3\301\301\303" \ + ";;=99;\202;;=\5::<;;=::<``b\376\376\376\202\377\377\377\1\376\376\376" \ + "\215\377\377\377\6\376\376\376\377\377\377\376\376\376xxz::<;;=\203:" \ + ":<\202;;=\1\300\300\302\202\377\377\377\3\316\316\316;;=99;\202::<\3" \ + ";:\77::<\234\234\236\206\377\377\377\2\377\377\375\376\377\375\202\376" \ + "\377\377\4\377\377\375\377\377\377\377\376\377\377\377\375\211\377\377" \ + "\377\1\376\376\374\202\377\377\377\3\377\376\377\377\377\377\375\376" \ + "\377\231\377\377\377\202\376\377\377\5\377\376\377\376\377\377\377\377" \ + "\375\277\320\332\0\77j\211\0=i\3\0>i\0=i\177\236\263\232\377\377\377" \ + "\1\316\316\316\206::<\1kkm\240\377\377\377\1\234\234\236\206::<\1\234" \ + "\234\236\213\377\377\377\3\376\376\376\377\377\377\376\376\376\204\377" \ + "\377\377\1\265\265\265\202::<\1;;=\204::<\1\315\315\317\204\377\377\377" \ + "\1\376\376\376\202\377\377\377\1\376\376\376\220\377\377\377\1\376\376" \ + "\376\202\377\377\377\3\204\204\204::<;;=\204::<\2yy{\376\376\376\221" \ + "\377\377\377\1kkm\206::<\1\316\316\316\305\377\377\377\4kkm;;=::<;;=" \ + "\203::<\1\316\316\316\210\377\377\377\1TTV\206::<\2\317\317\321\376\376" \ + "\376\231\377\377\377\1\234\234\234\206::<\1\234\234\234\243\377\377\377" \ + "\1kkm\206::<\237\377\377\377\1kkm\206::<\1\234\234\236\233\377\377\377" \ + "\1TTV\202::<\7;;=::<;;=::<RRT\377\377\377\376\376\376\203\377\377\377" \ + "\1\376\376\376\233\377\377\377\1\376\376\376\206\377\377\377\2\233\233" \ + "\235;;=\203::<\4;;=::<;;=\234\234\234\217\377\377\377\4\234\234\234:" \ + ":<;;=99;\203::<\1\316\316\316\203\377\377\377\4xxz;;=::<99;\202::<\3" \ + ";;=::<\234\234\236\216\377\377\377\1\376\376\376\202\377\377\377\16\376" \ + "\376\376\302\302\304::<;;=::<;;=::<;;=::<\221\221\223\377\377\377\376" \ + "\376\376\377\377\377\316\316\316\202::<\202;;=\202::<\1\234\234\236\206" \ + "\377\377\377\2\377\376\377\377\377\377\202\377\376\377\4\376\376\376" \ + "\353\366\374\327\355\370\323\356\371\210\326\356\372\7\325\354\372\327" \ + "\355\372\365\372\376\376\376\376\377\377\377\376\377\377\377\377\373" \ + "\231\377\377\377\2\377\376\377\376\377\375\202\377\377\377\4\374\377" \ + "\377\300\316\327\0=i\1\77h\210\0=i\3\0>i\0=i\177\236\263\232\377\377" \ + "\377\1\316\316\316\206::<\1kkm\240\377\377\377\1\234\234\236\206::<\1" \ + "\234\234\236\221\377\377\377\4\376\376\376\377\377\377SSU;;=\202::<\4" \ + ";;=99;;;=\204\204\206\203\377\377\377\1\376\376\376\226\377\377\377\11" \ + "\363\363\36399;;;=::<;;=::<;;=::<\316\316\316\202\377\377\377\1\376\376" \ + "\376\217\377\377\377\1kkm\206::<\1\316\316\316\304\377\377\377\1\316" \ + "\316\316\206::<\1kkk\211\377\377\377\2\235\235\23599;\202;;=\6::<;;=" \ + "::<kkm\377\377\377\376\376\376\203\377\377\377\1\376\376\376\224\377" \ + "\377\377\1\234\234\234\206::<\1\234\234\234\243\377\377\377\1kkm\206" \ + "::<\237\377\377\377\1kkm\206::<\1\234\234\236\232\377\377\377\1\332\332" \ + "\332\204::<\1;;=\202::<\4\266\266\270\376\376\376\377\377\377\376\376" \ + "\376\240\377\377\377\1\376\376\376\204\377\377\377\2\363\363\363FFH\202" \ + "::<\5;;=::<;;=::<SSS\217\377\377\377\2\235\235\23599;\205::<\11\316\316" \ + "\316\377\377\377\376\376\376\377\377\377\363\363\363FFH::<;;=99;\203" \ + ";;=\2::<\331\331\333\220\377\377\377\2\363\363\363FFH\202::<\6;;=::<" \ + ";;=::<TTV\364\364\364\203\377\377\377\3\316\316\316<<>99;\202::<\3;;" \ + "=::<\234\234\236\211\377\377\377\4\377\375\376\376\377\377\254\334\363" \ + "Z\266\347\211[\267\350\6\\\266\350X\267\347\326\354\367\377\376\377\376" \ + "\377\377\377\377\375\232\377\377\377\3\377\377\373\375\377\376\376\377" \ + "\377\202\377\377\375\3\276\320\336\0>g\0>i\210\0=i\3\0>i\0=i\177\236" \ + "\263\232\377\377\377\1\316\316\316\206::<\1kkm\240\377\377\377\1\234" \ + "\234\236\206::<\1\234\234\236\223\377\377\377\1\235\235\237\204::<\4" \ + "<<>::<;;=\363\363\363\206\377\377\377\1\376\376\376\222\377\377\377\2" \ + "\234\234\234;;=\205::<\1SSU\204\377\377\377\1\376\376\376\216\377\377" \ + "\377\1kkm\206::<\1\316\316\316\304\377\377\377\1\204\204\204\203::<\1" \ + "99;\202::<\1\265\265\265\211\377\377\377\2\363\363\363FFH\205::<\2;;" \ + "=\346\346\346\231\377\377\377\1\234\234\234\206::<\1\234\234\234\243" \ + "\377\377\377\1kkm\206::<\237\377\377\377\1kkm\206::<\1\234\234\236\232" \ + "\377\377\377\1\222\222\222\202::<\1;;=\202::<\3;;=FFH\362\362\364\251" \ + "\377\377\377\1\235\235\235\203::<\7;;=::<;;=;;;\331\331\331\377\377\377" \ + "\376\376\376\214\377\377\377\2\234\234\234;;=\205::<\1\316\316\316\202" \ + "\377\377\377\3\376\376\376\377\377\377\301\301\301\205::<\4;;=::<__a" \ + "\376\376\376\216\377\377\377\4\376\376\376yyy::<;;=\205::<\1\316\316" \ + "\320\204\377\377\377\2\316\316\31699;\203::<\3""99;::<\234\234\236\207" \ + "\377\377\377\2\376\377\377\376\376\374\202\377\376\377\3\254\332\362" \ + "Y\267\352[\267\350\210Y\270\350\7[\267\350Y\267\352\326\356\370\376\376" \ + "\377\377\376\377\377\375\377\376\377\377\231\377\377\377\10\377\377\375" \ + "\376\377\377\377\377\377\377\376\377\377\377\375\276\317\331\1>j\0>j" \ + "\210\0=i\3\0>i\0=i\177\236\263\232\377\377\377\1\316\316\316\206::<\1" \ + "kkm\240\377\377\377\1\234\234\236\206::<\1\234\234\236\220\377\377\377" \ + "\1\376\376\376\202\377\377\377\4\363\363\365;;=::<;;=\204::<\1\234\234" \ + "\234\231\377\377\377\1SSS\202::<\1;;=\203::<\1\265\265\267\223\377\377" \ + "\377\1kkm\206::<\1\316\316\316\300\377\377\377\1\376\376\376\202\377" \ + "\377\377\1\346\346\350\203::<\4;;=::<;;=SSU\213\377\377\377\1\204\204" \ + "\204\203::<\1;;=\202::<\1\204\204\206\202\377\377\377\1\376\376\376\226" \ + "\377\377\377\1\234\234\234\206::<\1\234\234\234\243\377\377\377\1kkm" \ + "\206::<\237\377\377\377\1kkm\206::<\1\234\234\236\227\377\377\377\1\376" \ + "\376\376\202\377\377\377\3TTV::<;;=\203::<\2;;=\205\205\205\252\377\377" \ + "\377\1\347\347\347\202::<\202;;=\203::<\1\235\235\237\204\377\377\377" \ + "\1\376\376\376\211\377\377\377\1\234\234\234\206::<\1\316\316\316\205" \ + "\377\377\377\1\205\205\205\202::<\6;;=::<;;=::<;;=\234\234\236\213\377" \ + "\377\377\1\376\376\376\202\377\377\377\1\302\302\302\202;;=\203::<\3" \ + ";;=::<\221\221\221\202\377\377\377\1\376\376\376\202\377\377\377\1\316" \ + "\316\316\206::<\1\234\234\236\213\377\377\377\2\255\333\363Y\270\350" \ + "\211[\267\350\3Y\270\350[\267\350\326\354\371\242\377\377\377\3\276\317" \ + "\331\0=i\0>i\210\0=i\3\0>i\0=i\177\236\263\232\377\377\377\1\316\316" \ + "\316\206::<\1kkm\240\377\377\377\1\234\234\236\206::<\1\234\234\236\224" \ + "\377\377\377\4\204\204\204;;=::<;;=\203::<\1TTT\204\377\377\377\1\376" \ + "\376\376\223\377\377\377\1\300\300\300\203::<\5;;=::<;;=FFF\363\363\363" \ + "\223\377\377\377\1kkm\203::<\4;;=::<;;=\316\316\320\277\377\377\377\14" \ + "\376\376\376\377\377\377\376\376\376\377\377\377\204\204\206::<;;=::" \ + "<99;<<>99;\265\265\267\213\377\377\377\3\346\346\346::<;;=\202::<\1;" \ + ";=\202::<\2\347\347\347\376\376\376\227\377\377\377\1\234\234\234\206" \ + "::<\1\234\234\234\243\377\377\377\1kkm\206::<\237\377\377\377\1kkm\206" \ + "::<\1\234\234\236\226\377\377\377\4\376\376\376\377\377\377\376\376\376" \ + "\346\346\350\202;;=\203::<\3""99;<<>\301\301\301\253\377\377\377\1aa" \ + "c\202::<\1;;=\202::<\2;;=jjl\205\377\377\377\1\376\376\376\210\377\377" \ + "\377\1\234\234\234\206::<\1\316\316\316\202\377\377\377\1\376\376\376" \ + "\202\377\377\377\3\362\362\362SSU;;=\205::<\2;;=\332\332\332\210\377" \ + "\377\377\1\376\376\376\203\377\377\377\2\363\363\363FFH\202::<\202;;" \ + "=\5::<;;=SSS\363\363\363\376\376\376\204\377\377\377\1\316\316\316\206" \ + "::<\1\234\234\236\213\377\377\377\2\255\333\363Y\270\350\211[\267\350" \ + "\3Y\270\350[\267\350\326\354\371\242\377\377\377\3\276\317\331\0=i\0" \ + ">i\210\0=i\3\0>i\0=i\177\236\263\232\377\377\377\1\316\316\316\206::" \ + "<\1kkm\240\377\377\377\1\234\234\236\206::<\1\234\234\236\224\377\377" \ + "\377\1\332\332\332\207::<\1\301\301\301\227\377\377\377\1lll\204::<\3" \ + ";;=::<\221\221\221\202\377\377\377\3\376\376\376\377\377\377\376\376" \ + "\376\217\377\377\377\1kkm\204::<\3;;=99;\316\316\316\241\377\377\377" \ + "\1\376\376\376\234\377\377\377\10\376\376\376\377\377\377\376\376\376" \ + "\377\377\377\363\363\363FFH;;=::<\202;;=\3::<FFH\364\364\364\214\377" \ + "\377\377\1xxz\204::<\3;;=::<\233\233\233\230\377\377\377\1\234\234\234" \ + "\206::<\1\234\234\234\243\377\377\377\1kkm\206::<\237\377\377\377\1k" \ + "km\206::<\1\234\234\236\224\377\377\377\1\376\376\376\204\377\377\377" \ + "\4\266\266\270;;=::<;;=\203::<\1""99;\254\377\377\377\3\234\234\234:" \ + ":<;;=\205::<\204\377\377\377\1\376\376\376\211\377\377\377\1\234\234" \ + "\234\206::<\1\316\316\316\203\377\377\377\1\376\376\376\202\377\377\377" \ + "\1\316\316\320\204::<\4;;=99;::<__a\205\377\377\377\1\376\376\376\206" \ + "\377\377\377\4yy{;;=::<;;=\202::<\3;;=::<\316\316\316\206\377\377\377" \ + "\1\316\316\316\206::<\1\234\234\236\213\377\377\377\2\255\333\363Y\270" \ + "\350\211[\267\350\3Y\270\350[\267\350\326\354\371\242\377\377\377\3\276" \ + "\317\331\0=i\0>i\210\0=i\3\0>i\0=i\177\236\263\232\377\377\377\1\316" \ + "\316\316\206::<\1kkm\240\377\377\377\1\234\234\236\206::<\1\234\234\236" \ + "\225\377\377\377\1__a\204;;=\5""99;::<yy{\377\377\377\376\376\376\216" \ + "\377\377\377\1\376\376\376\205\377\377\377\1\346\346\346\202::<\203;" \ + ";=\202::<\1\346\346\346\224\377\377\377\1kkm\205::<\2;;=\316\316\316" \ + "\235\377\377\377\1\376\376\376\244\377\377\377\1\234\234\234\202;;=\204" \ + "::<\2\235\235\235\376\376\376\212\377\377\377\4\376\376\376\377\377\377" \ + "\317\317\317::<\202;;=\202::<\3;;=GGI\362\362\362\202\377\377\377\1\376" \ + "\376\376\224\377\377\377\1\234\234\234\206::<\1\234\234\234\243\377\377" \ + "\377\1kkm\206::<\237\377\377\377\1kkm\206::<\1\234\234\236\231\377\377" \ + "\377\1\220\220\222\205::<\3;;=kkm\376\376\376\253\377\377\377\3\316\316" \ + "\316<<>99;\202::<\4;;=::<;;=\331\331\331\215\377\377\377\1\234\234\234" \ + "\206::<\1\316\316\316\207\377\377\377\1\222\222\224\202::<\3;;=99;<<" \ + ">\202::<\4\234\234\236\376\376\376\377\377\377\376\376\376\203\377\377" \ + "\377\1\376\376\376\203\377\377\377\6\302\302\304;;=99;;;=::<;;=\202:" \ + ":<\1\234\234\234\202\377\377\377\1\376\376\376\204\377\377\377\1\316" \ + "\316\316\206::<\1\234\234\236\213\377\377\377\2\255\333\363Y\270\350" \ + "\211[\267\350\3Y\270\350[\267\350\326\354\371\242\377\377\377\3\276\317" \ + "\331\0=i\0>i\210\0=i\3\0>i\0=i\177\236\263\232\377\377\377\1\316\316" \ + "\316\206::<\1kkm\240\377\377\377\1\234\234\236\206::<\1\234\234\236\225" \ + "\377\377\377\2\265\265\265;;=\202::<\2""99;;;=\202::<\2\347\347\347\376" \ + "\376\376\215\377\377\377\3\376\376\376\377\377\377\376\376\376\204\377" \ + "\377\377\3\221\221\223;;=99;\204::<\3xxz\377\377\377\376\376\376\202" \ + "\377\377\377\202\376\376\376\217\377\377\377\1kkm\202::<\5;;=99;;;=9" \ + "9;\317\317\317\233\377\377\377\1\376\376\376\237\377\377\377\1\376\376" \ + "\376\204\377\377\377\3\376\376\376\377\377\377GGI\202::<\5;;=::<;;=:" \ + ":<\346\346\346\213\377\377\377\1\376\376\376\202\377\377\377\2``b99;" \ + "\202;;=\203::<\3\247\247\247\377\377\377\376\376\376\225\377\377\377" \ + "\1\234\234\234\206::<\1\234\234\234\243\377\377\377\1kkm\206::<\237\377" \ + "\377\377\1kkm\206::<\1\234\234\236\231\377\377\377\10kkm::<;;=::<;;=" \ + "99;::<\235\235\237\255\377\377\377\202::<\1;;=\204::<\1\301\301\301\215" \ + "\377\377\377\1\234\234\234\206::<\1\316\316\316\206\377\377\377\5\376" \ + "\376\376\364\364\364TTV::<99;\202;;=\203::<\4\332\332\334\376\376\376" \ + "\377\377\377\376\376\376\203\377\377\377\6\376\376\376\377\377\377\363" \ + "\363\363FFH::<;;=\204::<\1__a\210\377\377\377\1\316\316\316\206::<\1" \ + "\234\234\236\213\377\377\377\2\255\333\363Y\270\350\211[\267\350\3Y\270" \ + "\350[\267\350\326\354\371\242\377\377\377\3\276\317\331\0=i\0>i\210\0" \ + "=i\3\0>i\0=i\177\236\263\232\377\377\377\1\316\316\316\206::<\1kkm\240" \ + "\377\377\377\1\234\234\236\206::<\1\234\234\236\224\377\377\377\5\376" \ + "\376\376\377\377\377GGI::<;;=\203::<\4;;=\220\220\222\377\377\377\376" \ + "\376\376\214\377\377\377\1\376\376\376\203\377\377\377\10\376\376\376" \ + "\377\377\377\363\363\363FFH::<;;=99;;;=\202::<\1\316\316\320\202\377" \ + "\377\377\1\376\376\376\204\377\377\377\1\376\376\376\215\377\377\377" \ + "\1kkm\206::<\1\316\316\316\277\377\377\377\3\376\376\376\377\377\377" \ + "\265\265\267\204::<\3;;=::<\205\205\205\213\377\377\377\1\376\376\376" \ + "\202\377\377\377\2\376\376\376\265\265\265\202::<\5""99;<<>::<;;=SSU" \ + "\202\377\377\377\1\376\376\376\224\377\377\377\1\234\234\234\206::<\1" \ + "\234\234\234\243\377\377\377\1kkm\206::<\237\377\377\377\1kkm\206::<" \ + "\1\234\234\236\230\377\377\377\2\376\376\376SSU\204::<\3;;=::<\266\266" \ + "\266\253\377\377\377\3\376\376\376\377\377\377^^`\206::<\1\234\234\234" \ + "\202\377\377\377\1\376\376\376\212\377\377\377\1\234\234\234\206::<\1" \ + "\316\316\316\205\377\377\377\6\376\376\376\377\377\377\376\376\376\315" \ + "\315\317::<;;=\202::<\4;;=99;::<``b\210\377\377\377\4xxz99;<<>::<\202" \ + ";;=\202::<\1\332\332\332\203\377\377\377\1\376\376\376\204\377\377\377" \ + "\1\316\316\316\206::<\1\234\234\236\213\377\377\377\2\255\333\363Y\270" \ + "\350\211[\267\350\3Y\270\350[\267\350\326\354\371\242\377\377\377\3\276" \ + "\317\331\0=i\0>i\210\0=i\3\0>i\0=i\177\236\263\232\377\377\377\1\316" \ + "\316\316\206::<\1kkm\240\377\377\377\1\234\234\236\206::<\1\234\234\236" \ + "\226\377\377\377\1\234\234\234\206::<\2FFH\376\376\376\214\377\377\377" \ + "\1\376\376\376\202\377\377\377\1\376\376\376\203\377\377\377\3\265\265" \ + "\265;;=99;\202;;=\202::<\1SSU\202\377\377\377\1\376\376\376\223\377\377" \ + "\377\1kkm\203::<\4""99;::<;;=\316\316\320\275\377\377\377\202\376\376" \ + "\376\4\377\377\377\376\376\376SSU;;=\202::<\4;;=::<;;=\332\332\332\215" \ + "\377\377\377\5\376\376\376\377\377\377\376\376\376SSU;;=\204::<\2;;=" \ + "\264\264\264\226\377\377\377\1\234\234\234\206::<\1\234\234\234\243\377" \ + "\377\377\1kkm\206::<\237\377\377\377\1kkm\206::<\1\234\234\236\231\377" \ + "\377\377\207::<\1\316\316\316\254\377\377\377\2\376\376\376lln\202::" \ + "<\1;;=\202::<\4;;=\233\233\233\377\377\377\376\376\376\202\377\377\377" \ + "\1\376\376\376\210\377\377\377\1\234\234\234\206::<\1\316\316\316\203" \ + "\377\377\377\202\376\376\376\204\377\377\377\1\234\234\234\207::<\1\234" \ + "\234\236\205\377\377\377\4\376\376\376\300\300\302::<;;=\205::<\2\234" \ + "\234\234\376\376\376\202\377\377\377\1\376\376\376\205\377\377\377\1" \ + "\316\316\316\206::<\1\234\234\236\213\377\377\377\2\255\333\363Y\270" \ + "\350\211[\267\350\3Y\270\350[\267\350\326\354\371\242\377\377\377\3\276" \ + "\317\331\0=i\0>i\210\0=i\3\0>i\0=i\177\236\263\232\377\377\377\1\316" \ + "\316\316\206::<\1kkm\240\377\377\377\1\234\234\236\206::<\1\234\234\236" \ + "\226\377\377\377\1\347\347\347\204::<\5;;=99;;;=\265\265\265\376\376" \ + "\376\222\377\377\377\2___99;\202::<\4;;=::<;;=\265\265\265\207\377\377" \ + "\377\1\376\376\376\216\377\377\377\1kkm\203::<\1;;=\202::<\1;;=\233:" \ + ":<\5""99;;;=::<:::\234\234\234\240\377\377\377\2\316\316\316;;=\204:" \ + ":<\2;;=kkm\221\377\377\377\1\234\234\236\203::<\1;;=\202::<\3kkk\377" \ + "\377\377\376\376\376\224\377\377\377\1\234\234\234\206::<\1\234\234\234" \ + "\243\377\377\377\1kkm\206::<\237\377\377\377\1kkm\206::<\1\234\234\236" \ + "\231\377\377\377\207::<\1\316\316\316\255\377\377\377\2\221\221\221;" \ + ";=\205::<\1\204\204\204\203\377\377\377\1\376\376\376\211\377\377\377" \ + "\1\234\234\234\206::<\1\316\316\316\210\377\377\377\3\376\376\376\377" \ + "\377\377``b\202::<\7;;=::<;;=::<;;=\332\332\332\376\376\376\202\377\377" \ + "\377\3\376\376\376\363\363\363GGI\203::<\4;;=::<;;=__a\206\377\377\377" \ + "\1\376\376\376\203\377\377\377\1\316\316\316\206::<\1\234\234\236\213" \ + "\377\377\377\2\255\333\363Y\270\350\211[\267\350\3Y\270\350[\267\350" \ + "\326\354\371\242\377\377\377\3\276\317\331\0=i\0>i\210\0=i\3\0>i\0=i" \ + "\177\236\263\232\377\377\377\1\316\316\316\206::<\1kkm\240\377\377\377" \ + "\1\234\234\236\206::<\1\234\234\236\227\377\377\377\1\204\204\206\204" \ + "::<\3;;=::<kkk\217\377\377\377\5\376\376\376\377\377\377\376\376\376" \ + "\333\333\333:::\202::<\1;;=\202::<\2FFH\363\363\363\226\377\377\377\1" \ + "kkm\204::<\1;;=\202::<\1;;=\234::<\4;;=::<\234\234\234\376\376\376\237" \ + "\377\377\377\1kkm\206::<\1\316\316\316\221\377\377\377\2\363\363\363" \ + "GGG\204::<\3;;=::<\315\315\315\225\377\377\377\1\234\234\234\206::<\1" \ + "\234\234\234\237\377\377\377\1\376\376\376\203\377\377\377\1kkm\206:" \ + ":<\237\377\377\377\1kkm\206::<\1\234\234\236\230\377\377\377\2\376\376" \ + "\376;;=\203::<\1;;=\202::<\1\363\363\363\252\377\377\377\6\376\376\376" \ + "\377\377\377\376\376\376\234\234\23699;;;=\204::<\1kkm\215\377\377\377" \ + "\1\234\234\234\206::<\1\316\316\316\210\377\377\377\7\377\377\375\377" \ + "\377\377\332\332\332::<;;=::<;;=\203::<\2``b\376\376\376\202\377\377" \ + "\377\2\376\376\376xxz\206::<\2:::\332\332\332\212\377\377\377\1\316\316" \ + "\316\206::<\1\234\234\236\213\377\377\377\2\255\333\363Y\270\350\211" \ + "[\267\350\3Y\270\350[\267\350\326\354\371\242\377\377\377\3\276\317\331" \ + "\0=i\0>i\210\0=i\3\0>i\0=i\177\236\263\232\377\377\377\1\316\316\316" \ + "\206::<\1kkm\240\377\377\377\1\234\234\236\206::<\1\234\234\236\227\377" \ + "\377\377\1\315\315\315\205::<\3;;=::<\332\332\334\221\377\377\377\1\204" \ + "\204\206\205::<\2;;=\205\205\205\227\377\377\377\1kkm\203::<\3;;=::<" \ + ";;=\234::<\1:9>\203::<\1\234\234\236\237\377\377\377\1\331\331\331\202" \ + ";;=\204::<\1SSU\217\377\377\377\5\376\376\376\377\377\377\376\376\376" \ + "\377\377\377\204\204\204\204::<\3;;=99;yyy\203\377\377\377\1\376\376" \ + "\376\221\377\377\377\1\234\234\234\206::<\1\234\234\234\235\377\377\377" \ + "\1\376\376\376\205\377\377\377\1kkm\206::<\237\377\377\377\1kkm\206:" \ + ":<\1\234\234\236\231\377\377\377\203::<\1;;=\203::<\202\377\377\377\1" \ + "\376\376\376\253\377\377\377\2\233\233\235;;=\205::<\3kkm\377\377\377" \ + "\376\376\376\202\377\377\377\1\376\376\376\210\377\377\377\1\234\234" \ + "\234\206::<\1\316\316\316\213\377\377\377\1\234\234\236\202;;=\1""99" \ + ";\203::<\5;;=\235\235\235\377\377\377\376\376\376\302\302\302\207::<" \ + "\1\251\251\251\213\377\377\377\1\316\316\316\206::<\1\234\234\236\213" \ + "\377\377\377\2\255\333\363Y\270\350\211[\267\350\3Y\270\350[\267\350" \ + "\326\354\371\242\377\377\377\3\276\317\331\0=i\0>i\210\0=i\3\0>i\0=i" \ + "\177\236\263\232\377\377\377\1\316\316\316\206::<\1kkm\240\377\377\377" \ + "\1\234\234\236\206::<\1\234\234\236\223\377\377\377\1\376\376\376\204" \ + "\377\377\377\1^^`\202::<\202;;=\3::<<<>\204\204\206\213\377\377\377\1" \ + "\376\376\376\204\377\377\377\1\363\363\363\205::<\3;;=::<\346\346\346" \ + "\227\377\377\377\1kkm\204::<\3;;=::<;;=\234::<\1;;=\202::<\1\234\234" \ + "\236\237\377\377\377\4\204\204\20499;::<;;=\203::<\3\266\266\270\377" \ + "\377\377\376\376\376\221\377\377\377\5\346\346\346;;=::<;;=::<\202;;" \ + "=\4::<\346\346\350\377\377\377\376\376\376\202\377\377\377\1\376\376" \ + "\376\217\377\377\377\1\234\234\234\206::<\1\234\234\234\237\377\377\377" \ + "\202\376\376\376\202\377\377\377\1kkm\206::<\237\377\377\377\1kkm\206" \ + "::<\1\234\234\236\224\377\377\377\6\376\376\376\377\377\377\376\376\376" \ + "\377\377\377\376\376\376;;=\206::<\1\331\331\331\255\377\377\377\1\234" \ + "\234\236\202::<\1;;=\203::<\2kkm\376\376\376\202\377\377\377\1\376\376" \ + "\376\211\377\377\377\1\234\234\234\206::<\1\316\316\316\212\377\377\377" \ + "\3\376\376\376\377\377\377___\204::<\7;;=99;::<\332\332\332\363\363\365" \ + "FFH;;=\204::<\3;;=kkm\376\376\376\213\377\377\377\1\316\316\316\206:" \ + ":<\1\234\234\236\213\377\377\377\2\255\333\363Y\270\350\211[\267\350" \ + "\3Y\270\350[\267\350\326\354\371\242\377\377\377\3\276\317\331\0=i\0" \ + ">i\210\0=i\3\0>i\0=i\177\236\263\232\377\377\377\1\316\316\316\206::" \ + "<\1kkm\240\377\377\377\1\234\234\236\206::<\1\234\234\236\224\377\377" \ + "\377\1\376\376\376\203\377\377\377\4\265\265\267::<;;=::<\202;;=\3::" \ + "<FFH\363\363\363\213\377\377\377\1\376\376\376\203\377\377\377\2\251" \ + "\251\251;;=\205::<\1lln\202\377\377\377\1\376\376\376\225\377\377\377" \ + "\1kkm\202::<\2;;=99;\204::<\1;;=\234::<\2;;=\234\234\234\235\377\377" \ + "\377\5\376\376\376\345\345\345;;=::<;;=\202::<\2;;=FFH\215\377\377\377" \ + "\3\376\376\376\377\377\377\376\376\376\205\377\377\377\10xxz;;=::<;;" \ + "=99;;;=::<\204\204\206\202\377\377\377\1\376\376\376\221\377\377\377" \ + "\1\234\234\234\206::<\1\234\234\234\234\377\377\377\1\376\376\376\204" \ + "\377\377\377\3\376\376\376\377\377\377kkm\206::<\237\377\377\377\1kk" \ + "m\206::<\1\234\234\236\231\377\377\377\202::<\1;;=\204::<\1\316\316\316" \ + "\253\377\377\377\3\376\376\376\377\377\377\220\220\222\202;;=\2::<;;" \ + "=\202::<\1\222\222\224\215\377\377\377\1\234\234\234\206::<\1\316\316" \ + "\316\213\377\377\377\3\376\376\376\332\332\332GGI\204::<\10;;=::<__a" \ + "xxz::<;;=::<;;=\202::<\2FFH\346\346\346\214\377\377\377\1\316\316\316" \ + "\206::<\1\234\234\236\213\377\377\377\2\255\333\363Y\270\350\211[\267" \ + "\350\3Y\270\350[\267\350\326\354\371\242\377\377\377\3\276\317\331\0" \ + "=i\0>i\210\0=i\3\0>i\0=i\177\236\263\232\377\377\377\1\316\316\316\206" \ + "::<\1kkm\240\377\377\377\1\234\234\236\206::<\1\234\234\236\231\377\377" \ + "\377\10FFH::<;;=99;;;=::<;;=\265\265\265\216\377\377\377\4\376\376\376" \ + "TTV99;;;=\202::<\202;;=\1\301\301\301\230\377\377\377\1kkm\202::<\1;" \ + ";=\204::<\3;;=::<;;=\232::<\5;;=::<\234\234\234\377\377\377\376\376\376" \ + "\232\377\377\377\3\376\376\376\377\377\377\221\221\221\202::<\1""99;" \ + "\203::<\5\234\234\236\377\377\377\376\376\376\377\377\377\376\376\376" \ + "\216\377\377\377\1\376\376\376\202\377\377\377\2\316\316\320::<\202;" \ + ";=\204::<\2\363\363\363\376\376\376\202\377\377\377\1\376\376\376\217" \ + "\377\377\377\1\234\234\234\206::<\1\234\234\234\243\377\377\377\1kkm" \ + "\206::<\237\377\377\377\1kkm\206::<\1\234\234\236\224\377\377\377\1\376" \ + "\376\376\204\377\377\377\1""99;\202::<\1;;=\203::<\1\316\316\316\252" \ + "\377\377\377\10\376\376\376\377\377\377\376\376\376kkm;;=::<;;=99;\202" \ + "::<\1\234\234\236\215\377\377\377\1\234\234\234\206::<\1\316\316\316" \ + "\215\377\377\377\5\247\247\247;;=99;::<;;=\210::<\5""99;::<\250\250\252" \ + "\377\377\377\376\376\376\213\377\377\377\1\316\316\316\206::<\1\234\234" \ + "\236\213\377\377\377\2\255\333\363Y\270\350\211[\267\350\3Y\270\350[" \ + "\267\350\326\354\371\242\377\377\377\3\276\317\331\0=i\0>i\210\0=i\3" \ + "\0>i\0=i\177\236\263\232\377\377\377\1\316\316\316\206::<\1kkm\240\377" \ + "\377\377\1\234\234\236\206::<\1\234\234\236\223\377\377\377\3\376\376" \ + "\376\377\377\377\376\376\376\203\377\377\377\1\234\234\236\202::<\1;" \ + ";=\202::<\2""99;SSU\214\377\377\377\5\376\376\376\377\377\377\301\301" \ + "\301;;=<<>\202::<\3;;=::<SSU\202\377\377\377\1\376\376\376\226\377\377" \ + "\377\1kkm\203::<\1;;=\202::<\1\204\204\206\202\234\234\234\1\235\235" \ + "\235\232\234\234\236\202\234\234\234\1\315\315\315\233\377\377\377\6" \ + "\376\376\376\377\377\377\362\362\362HHJ99;;;=\204::<\2\364\364\364\376" \ + "\376\376\220\377\377\377\1\376\376\376\204\377\377\377\1kkm\206::<\1" \ + "\234\234\234\223\377\377\377\1\234\234\234\206::<\1\234\234\234\242\377" \ + "\377\377\2\376\376\376lln\206::<\237\377\377\377\1kkm\206::<\1\234\234" \ + "\236\231\377\377\377\2TTV99;\202::<\5;;=::<;;=\250\250\250\376\376\376" \ + "\254\377\377\377\1``b\203::<\202;;=\3::<\235\235\237\376\376\376\202" \ + "\377\377\377\1\376\376\376\211\377\377\377\1\234\234\234\206::<\1\316" \ + "\316\316\216\377\377\377\2kkm;;=\203::<\5;;=::<;;=99;;;=\202::<\2;;=" \ + "jjl\216\377\377\377\1\316\316\316\206::<\1\234\234\236\213\377\377\377" \ + "\2\255\333\363Y\270\350\211[\267\350\3Y\270\350[\267\350\326\354\371" \ + "\242\377\377\377\3\276\317\331\0=i\0>i\210\0=i\3\0>i\0=i\177\236\263" \ + "\232\377\377\377\1\316\316\316\206::<\1kkm\240\377\377\377\1\234\234" \ + "\236\206::<\1\234\234\236\224\377\377\377\1\376\376\376\204\377\377\377" \ + "\2\346\346\34699;\202::<\2;;=::<\202;;=\1\315\315\315\212\377\377\377" \ + "\1\376\376\376\202\377\377\377\1yy{\203::<\4;;=99;;;=\250\250\250\202" \ + "\377\377\377\1\376\376\376\226\377\377\377\1kkm\206::<\1\317\317\317" \ + "\240\377\377\377\1\376\376\376\234\377\377\377\1\234\234\234\202::<\2" \ + "99;;;=\202::<\1\204\204\206\203\377\377\377\1\376\376\376\220\377\377" \ + "\377\1\376\376\376\202\377\377\377\2\264\264\264::<\202;;=\203::<\3G" \ + "GI\364\364\364\376\376\376\202\377\377\377\1\376\376\376\216\377\377" \ + "\377\1\234\234\234\206::<\1\234\234\234\241\377\377\377\3\376\376\376" \ + "\377\377\377kkm\206::<\237\377\377\377\1kkm\206::<\1\234\234\236\225" \ + "\377\377\377\202\376\376\376\202\377\377\377\12kkm::<;;=99;::<;;=::<" \ + "\204\204\204\377\377\377\376\376\376\251\377\377\377\4\376\376\376\377" \ + "\377\377::<99;\202;;=\203::<\1\316\316\320\215\377\377\377\1\234\234" \ + "\234\206::<\1\316\316\316\216\377\377\377\5\346\346\350GGI;;=::<;;=\202" \ + "::<\2""99;;;=\202::<\3;;=GGI\346\346\350\216\377\377\377\1\316\316\316" \ + "\206::<\1\234\234\236\213\377\377\377\2\255\333\363Y\270\350\211[\267" \ + "\350\3Y\270\350[\267\350\326\354\371\242\377\377\377\3\276\317\331\0" \ + "=i\0>i\210\0=i\3\0>i\0=i\177\236\263\232\377\377\377\1\316\316\316\206" \ + "::<\1kkm\240\377\377\377\1\234\234\236\206::<\1\234\234\236\231\377\377" \ + "\377\2\376\376\376\205\205\205\202::<\5""99;;;=::<;;=\205\205\207\213" \ + "\377\377\377\12\376\376\376\346\346\346::<;;=99;::<99;;;=FFH\363\363" \ + "\363\231\377\377\377\1kkm\202::<\2;;=::<\202;;=\3\316\316\316\377\377" \ + "\377\376\376\376\234\377\377\377\1\376\376\376\236\377\377\377\1SSS\204" \ + "::<\3;;=99;\347\347\351\204\377\377\377\1\376\376\376\215\377\377\377" \ + "\1\376\376\376\205\377\377\377\1SSU\203::<\4;;=99;::<\265\265\265\202" \ + "\377\377\377\1\376\376\376\217\377\377\377\1\234\234\234\206::<\1\234" \ + "\234\234\242\377\377\377\2\376\376\376SSU\206::<\237\377\377\377\1kk" \ + "m\206::<\1\234\234\236\231\377\377\377\4\221\221\223;;=::<;;=\202::<" \ + "\3;;=___\376\376\376\253\377\377\377\1\332\332\332\204::<\1;;=\202::" \ + "<\1\346\346\350\203\377\377\377\1\376\376\376\211\377\377\377\1\234\234" \ + "\234\206::<\1\316\316\316\217\377\377\377\1\250\250\252\204::<\202;;" \ + "=\2::<;;=\202::<\1\265\265\267\217\377\377\377\1\316\316\316\206::<\1" \ + "\234\234\236\213\377\377\377\2\255\333\363Y\270\350\211[\267\350\3Y\270" \ + "\350[\267\350\326\354\371\242\377\377\377\3\276\317\331\0=i\0>i\210\0" \ + "=i\3\0>i\0=i\177\236\263\232\377\377\377\1\316\316\316\206::<\1kkm\240" \ + "\377\377\377\1\234\234\236\206::<\1\234\234\236\232\377\377\377\1\316" \ + "\316\316\203::<\2""99;<<>\202::<\1\346\346\350\213\377\377\377\4\221" \ + "\221\223;;=::<;;=\203::<\1\204\204\206\232\377\377\377\1kkm\203::<\1" \ + ";;=\202::<\1\316\316\316\274\377\377\377\2\265\265\267;;=\205::<\1xx" \ + "x\231\377\377\377\1\250\250\250\206::<\1TTV\222\377\377\377\1\234\234" \ + "\234\204::<\3;;=::<\235\235\235\203\377\377\377\1\376\376\376\237\377" \ + "\377\377\202;;=\203::<\3;;=::<\376\376\376\236\377\377\377\1kkm\206:" \ + ":<\1\234\234\236\225\377\377\377\1\376\376\376\203\377\377\377\1\265" \ + "\265\267\204::<\1;;=\202::<\1\363\363\363\253\377\377\377\1\250\250\250" \ + "\204::<\3;;=::<GGI\216\377\377\377\1\234\234\234\206::<\1\316\316\316" \ + "\220\377\377\377\4kkm;;=::<;;=\204::<\3;;=xxx\376\376\376\217\377\377" \ + "\377\1\316\316\316\206::<\1\234\234\236\213\377\377\377\2\255\333\363" \ + "Y\270\350\212[\267\350\2X\266\351\326\356\370\202\377\377\377\3\377\377" \ + "\375\377\377\377\376\377\375\234\377\377\377\4\377\377\375\276\317\327" \ + "\0\77j\1>j\210\0=i\3\0>i\0=i\177\236\263\232\377\377\377\1\316\316\316" \ + "\206::<\1kkm\240\377\377\377\1\234\234\236\206::<\1\234\234\236\233\377" \ + "\377\377\1``b\205::<\2;;=\235\235\237\210\377\377\377\1\376\376\376\202" \ + "\377\377\377\2FFH;;=\205::<\1\346\346\346\202\377\377\377\1\376\376\376" \ + "\227\377\377\377\1kkm\206::<\1\316\316\316\266\377\377\377\1\376\376" \ + "\376\205\377\377\377\5__a::<;;=::<;;=\202::<\1SSU\202kkm\1lln\203kkm" \ + "\1lln\222kkm\4__a;;=99;;;=\204::<\3\301\301\301\377\377\377\376\376\376" \ + "\215\377\377\377\202\376\376\376\1\235\235\235\204::<\3""99;;;=\221\221" \ + "\221\243\377\377\377\203::<\1;;=\202::<\1""99;\237\377\377\377\1kkm\206" \ + "::<\1\234\234\236\231\377\377\377\1\332\332\332\202::<\3;;=::<99;\202" \ + ";;=\1\264\264\264\210\377\377\377\1\376\376\376\232\377\377\377\1\376" \ + "\376\376\206\377\377\377\2\376\376\376xxx\202::<\1;;=\203::<\1xxz\216" \ + "\377\377\377\1\234\234\234\206::<\1\316\316\316\220\377\377\377\3\363" \ + "\363\365FFH;;=\202::<\1;;=\202::<\2FFH\363\363\363\220\377\377\377\1" \ + "\316\316\316\206::<\1\234\234\236\213\377\377\377\2\255\333\363Y\270" \ + "\350\211[\267\350\10X\267\347Y\267\352\326\354\371\377\377\377\376\376" \ + "\376\377\376\377\377\377\377\377\376\377\234\377\377\377\2\376\376\374" \ + "\277\320\330\212\0=i\3\0>i\0=i\177\236\263\232\377\377\377\1\316\316" \ + "\316\206::<\1kkm\240\377\377\377\1\234\234\236\206::<\1\234\234\236\233" \ + "\377\377\377\1\265\265\267\203::<\4""99;;;=::<SSU\207\377\377\377\6\376" \ + "\376\376\377\377\377\376\376\376\265\265\265;;=99;\202;;=\4""99;;;=k" \ + "km\377\377\377\202\376\376\376\230\377\377\377\1kkm\206::<\1\316\316" \ + "\316\267\377\377\377\1\376\376\376\203\377\377\377\7\316\316\320<<>9" \ + "9;::<;;=::<99;\203::<\2;;=99;\202::<\1;;=\224::<\1;;=\202::<\1;;=\203" \ + "::<\1kkm\203\377\377\377\1\376\376\376\215\377\377\377\1\300\300\300" \ + "\202::<\11;;=::<99;;;=jjl\377\377\377\376\376\376\377\377\377\376\376" \ + "\376\236\377\377\377\1\346\346\350\206::<\1__a\237\377\377\377\1kkm\206" \ + "::<\1\234\234\236\231\377\377\377\2\376\376\376SSU\206::<\2yy{\376\376" \ + "\376\206\377\377\377\1\376\376\376\234\377\377\377\1\376\376\376\205" \ + "\377\377\377\4\363\363\363::<<<>99;\202::<\3;;=::<\265\265\267\203\377" \ + "\377\377\3\376\376\376\377\377\377\376\376\376\210\377\377\377\1\234" \ + "\234\234\206::<\1\316\316\316\221\377\377\377\4\301\301\30199;::<;;=" \ + "\202::<\6;;=\301\301\301\377\377\377\376\376\376\377\377\377\376\376" \ + "\376\215\377\377\377\1\316\316\316\206::<\1\234\234\236\213\377\377\377" \ + "\2\255\333\363Y\270\350\211[\267\350\6Y\270\350Y\267\352\325\353\370" \ + "\377\377\377\376\377\375\377\375\377\234\377\377\377\5\376\376\376\377" \ + "\377\377\377\377\375\276\317\327\2\77k\211\0=i\3\0>i\0=i\177\236\263" \ + "\232\377\377\377\1\316\316\316\206::<\1kkm\240\377\377\377\1\234\234" \ + "\236\206::<\1\234\234\236\234\377\377\377\1GGI\203::<\1;;=\202::<\2\301" \ + "\301\301\376\376\376\204\377\377\377\1\376\376\376\203\377\377\377\3" \ + "lln::<;;=\202::<\202;;=\4\301\301\303\376\376\376\377\377\377\376\376" \ + "\376\230\377\377\377\1kkm\206::<\1\316\316\316\265\377\377\377\1\376" \ + "\376\376\205\377\377\377\3kkm::<;;=\202::<\2""99;<<>\202::<\3;;=::<;" \ + ";=\202::<\1;;=\222::<\4""99;;;=::<;;=\203::<\1;;=\202::<\3\316\316\316" \ + "\377\377\377\376\376\376\215\377\377\377\3\376\376\376\316\316\316;;" \ + "=\203::<\3;;=::<FFH\234\377\377\377\202\376\376\376\202\377\377\377\3" \ + "\376\376\376\377\377\377\316\316\320\203::<\4;;=::<;;=kkm\237\377\377" \ + "\377\1kkm\206::<\1\234\234\236\226\377\377\377\7\376\376\376\377\377" \ + "\377\376\376\376\377\377\377\204\204\204::<;;=\204::<\2;;=\346\346\346" \ + "\241\377\377\377\1\376\376\376\202\377\377\377\3\376\376\376\377\377" \ + "\377\376\376\376\202\377\377\377\1\250\250\250\202::<\1<<>\204::<\3\346" \ + "\346\346\377\377\377\376\376\376\202\377\377\377\1\376\376\376\211\377" \ + "\377\377\1\234\234\234\206::<\1\316\316\316\220\377\377\377\14\376\376" \ + "\376\377\377\377yy{::<99;;;=::<xxz\377\377\377\376\376\376\377\377\377" \ + "\376\376\376\203\377\377\377\1\376\376\376\212\377\377\377\1\316\316" \ + "\316\206::<\1\234\234\236\213\377\377\377\2\255\333\363Y\270\350\211" \ + "[\267\350\10X\267\347Z\266\351\326\356\370\376\377\377\377\377\375\377" \ + "\377\377\377\376\377\376\377\377\234\377\377\377\4\376\376\374\277\320" \ + "\330\0=i\1>j\210\0=i\3\0>i\0=i\177\236\263\232\377\377\377\1\316\316" \ + "\316\206::<\1kkm\240\377\377\377\1\234\234\236\206::<\1\234\234\236\234" \ + "\377\377\377\1\234\234\234\206::<\3jjj\377\377\377\376\376\376\204\377" \ + "\377\377\4\376\376\376\377\377\377\332\332\33299;\203::<\3;;=::<SSU\202" \ + "\377\377\377\1\376\376\376\231\377\377\377\1kkm\206::<\1\316\316\316" \ + "\267\377\377\377\5\376\376\376\377\377\377\376\376\376\346\346\350;;" \ + "=\203::<\1;;=\202::<\202;;=\202::<\3""99;::<;;=\222::<\202;;=\3""99;" \ + "::<;;=\202::<\1;;=\203::<\2\204\204\206\376\376\376\217\377\377\377\1" \ + "\363\363\363\203::<\6;;=::<;;=::<\347\347\347\376\376\376\234\377\377" \ + "\377\202\376\376\376\5\377\377\377\376\376\376\234\234\236::<;;=\202" \ + "::<\3;;=::<\234\234\236\237\377\377\377\1kkm\206::<\1\234\234\236\231" \ + "\377\377\377\5\376\376\376\316\316\316;;=99;;;=\204::<\1\222\222\224" \ + "\204\377\377\377\1\376\376\376\235\377\377\377\1\376\376\376\202\377" \ + "\377\377\1\376\376\376\203\377\377\377\5SSU;;=::<99;;;=\202::<\3kkk\377" \ + "\377\377\376\376\376\203\377\377\377\1\376\376\376\211\377\377\377\1" \ + "\234\234\234\206::<\1\316\316\316\222\377\377\377\6\363\363\363GGI::" \ + "<;;=FFH\363\363\363\205\377\377\377\1\376\376\376\214\377\377\377\1\316" \ + "\316\316\206::<\1\234\234\236\213\377\377\377\2\255\333\363Y\270\350" \ + "\212[\267\350\3Y\267\352\330\354\363\376\377\377\203\377\377\377\1\377" \ + "\377\375\235\377\377\377\3\276\317\331\0=i\1>j\210\0=i\3\0>i\0=i\177" \ + "\236\263\232\377\377\377\1\316\316\316\206::<\1kkm\240\377\377\377\1" \ + "\234\234\236\206::<\1\234\234\236\233\377\377\377\2\376\376\376\347\347" \ + "\347\202::<\2;;=::<\203;;=\1\346\346\346\207\377\377\377\5\204\204\204" \ + "<<>99;::<;;=\202::<\2\251\251\251\376\376\376\205\377\377\377\1\376\376" \ + "\376\225\377\377\377\1kkm\206::<\1\316\316\316\264\377\377\377\1\376" \ + "\376\376\205\377\377\377\3\204\204\206::<;;=\203::<\1;;=\205::<\1;;=" \ + "\225::<\3;;=::<;;=\202::<\1;;=\202::<\1;;=\202::<\1\347\347\347\220\377" \ + "\377\377\2SSU;;=\203::<\3;;=::<\265\265\265\237\377\377\377\7\376\376" \ + "\376\377\377\377lln99;::<;;=99;\202::<\1\265\265\267\237\377\377\377" \ + "\1kkm\206::<\1\234\234\236\225\377\377\377\1\376\376\376\204\377\377" \ + "\377\3\376\376\376SSU;;=\204::<\3;;=FFH\346\346\346\202\377\377\377\1" \ + "\376\376\376\237\377\377\377\1\376\376\376\204\377\377\377\2\265\265" \ + "\267;;=\202::<\1;;=\203::<\1\265\265\265\217\377\377\377\1\234\234\234" \ + "\206::<\1\316\316\316\223\377\377\377\4\301\301\301::<:::\302\302\302" \ + "\223\377\377\377\1\316\316\316\206::<\1\234\234\236\213\377\377\377\2" \ + "\255\333\363Y\270\350\212[\267\350\2Y\270\350\332\354\370\202\377\377" \ + "\377\3\376\376\376\376\377\377\377\376\373\235\377\377\377\1\276\317" \ + "\331\202\0>i\210\0=i\3\0>i\0=i\177\236\263\232\377\377\377\1\316\316" \ + "\316\206::<\1kkm\240\377\377\377\1\234\234\236\206::<\1\234\234\236\235" \ + "\377\377\377\1\204\204\204\206::<\1\221\221\223\206\377\377\377\2\363" \ + "\363\363GGI\202::<\5""99;;;=::<GGI\363\363\363\204\377\377\377\202\376" \ + "\376\376\226\377\377\377\1kkm\206::<\1\316\316\316\266\377\377\377\1" \ + "\376\376\376\202\377\377\377\3\346\346\350::<;;=\204::<\5""99;;;=:::" \ + "99;;;=\203::<\3;;=99;;;=\220::<\5;;=::<;;=::<;;=\202::<\6;;=::<99;;;" \ + "=::<\204\204\206\220\377\377\377\5yy{99;::<99;;;=\202::<\1xxz\236\377" \ + "\377\377\10\376\376\376\377\377\377\363\363\36399;::<;;=99;;;=\202::" \ + "<\2\346\346\350\376\376\376\236\377\377\377\1kkm\206::<\1\234\234\236" \ + "\231\377\377\377\3\376\376\376\377\377\377\233\233\235\202::<\7;;=::" \ + "<;;=99;;;=\204\204\204\376\376\376\245\377\377\377\2\363\363\363SSU\205" \ + "::<\2;;=FFH\205\377\377\377\3\376\376\376\377\377\377\376\376\376\210" \ + "\377\377\377\1\234\234\234\206::<\1\316\316\316\224\377\377\377\3\205" \ + "\205\205\221\221\221\376\376\376\204\377\377\377\202\376\376\376\215" \ + "\377\377\377\1\316\316\316\206::<\1\234\234\236\213\377\377\377\2\255" \ + "\333\363Y\270\350\212[\267\350\7Y\270\350\321\356\376\377\376\377\377" \ + "\377\377\377\377\375\376\377\375\377\376\377\232\377\377\377\1\377\377" \ + "\375\202\377\377\377\3\275\317\333\0\77k\0>i\210\0=i\3\0>i\0=i\177\236" \ + "\263\232\377\377\377\1\316\316\316\206::<\1kkm\240\377\377\377\1\234" \ + "\234\236\206::<\1\234\234\236\235\377\377\377\1\316\316\316\206::<\1" \ + "FFH\203\377\377\377\1\376\376\376\202\377\377\377\1\250\250\250\203:" \ + ":<\1;;=\202::<\1\204\204\206\203\377\377\377\1\376\376\376\231\377\377" \ + "\377\1kkm\206::<\1\316\316\316\271\377\377\377\1\234\234\236\204::<\4" \ + ";;=::<kkm\234\234\236\202\234\234\234\1\233\233\233\202\234\234\234\3" \ + "\235\235\235\234\234\234\235\235\235\224\234\234\234\202\234\234\236" \ + "\1\204\204\206\206::<\2FFH\363\363\363\217\377\377\377\2\250\250\252" \ + ";;=\206::<\1\364\364\364\237\377\377\377\2\265\265\265;;=\205::<\1TT" \ + "V\240\377\377\377\1kkm\206::<\1\234\234\236\224\377\377\377\3\376\376" \ + "\376\377\377\377\376\376\376\204\377\377\377\3\364\364\366FFH;;=\203" \ + "::<\4;;=::<:::\316\316\316\245\377\377\377\1\221\221\221\202::<\2;;=" \ + "::<\202;;=\2::<\234\234\236\220\377\377\377\1\234\234\234\206::<\1\316" \ + "\316\316\224\377\377\377\1\376\376\376\225\377\377\377\1\316\316\316" \ + "\206::<\1\234\234\236\213\377\377\377\2\255\333\363Y\270\350\212[\267" \ + "\350\4[\267\346\265\340\361\377\376\377\376\376\377\202\377\377\375\1" \ + "\374\377\377\230\377\377\377\3\376\376\376\377\377\377\377\377\375\202" \ + "\377\377\377\3\243\265\301\0>j\0>i\210\0=i\3\0>i\0=i\177\236\263\232" \ + "\377\377\377\1\316\316\316\206::<\1kkm\240\377\377\377\1\234\234\236" \ + "\206::<\1\234\234\236\236\377\377\377\2__a;;=\204::<\5;;=\265\265\265" \ + "\376\376\376\377\377\377\376\376\376\202\377\377\377\1SSU\204::<\3;;" \ + "=::<\346\346\350\235\377\377\377\1kkm\206::<\1\316\316\316\270\377\377" \ + "\377\2\363\363\365GGI\205::<\3;;=\333\333\333\376\376\376\237\377\377" \ + "\377\10FFH::<;;=::<;;=99;;;=\233\233\235\217\377\377\377\5\346\346\346" \ + "::<;;=::<;;=\203::<\1\234\234\234\210\377\377\377\1\376\376\376\217\377" \ + "\377\377\1\376\376\376\206\377\377\377\1TTT\205::<\3;;=\221\221\221\376" \ + "\376\376\237\377\377\377\1kkm\206::<\1\234\234\236\234\377\377\377\12" \ + "\233\233\233::<;;=::<;;=::<;;=::<SSU\363\363\363\212\377\377\377\3\376" \ + "\376\376\377\377\377\376\376\376\221\377\377\377\1\376\376\376\204\377" \ + "\377\377\1\315\315\317\203::<\1;;=\203::<\2FFH\363\363\365\220\377\377" \ + "\377\1\234\234\234\206::<\1\316\316\316\252\377\377\377\1\316\316\316" \ + "\206::<\1\234\234\236\213\377\377\377\2\255\333\363Y\270\350\211[\267" \ + "\350\6Y\270\350[\267\346\227\324\363\377\375\376\377\377\377\376\377" \ + "\375\213\377\377\377\6\376\376\376\377\377\377\373\377\376\377\377\377" \ + "\377\376\377\376\377\377\211\377\377\377\10\377\376\377\374\377\377\377" \ + "\377\375\377\377\377\377\376\377_\207\240\0>l\0\77j\210\0=i\3\0>i\0=" \ + "i\177\236\263\232\377\377\377\1\316\316\316\206::<\1kkm\240\377\377\377" \ + "\1\234\234\236\206::<\1\234\234\236\236\377\377\377\1\265\265\265\204" \ + "::<\3;;=::<__a\204\377\377\377\1\317\317\321\206::<\1kkk\236\377\377" \ + "\377\1kkm\206::<\1\316\316\316\267\377\377\377\3\376\376\376\250\250" \ + "\25299;\202;;=\203::<\1kkm\233\377\377\377\1\376\376\376\205\377\377" \ + "\377\10\234\234\236;;=::<;;=::<;;=99;GGI\204\377\377\377\3\376\376\376" \ + "\377\377\377\376\376\376\210\377\377\377\5\376\376\376__a::<;;=99;\203" \ + ";;=\2FFH\363\363\363\204\377\377\377\3\376\376\376\377\377\377\376\376" \ + "\376\224\377\377\377\5\376\376\376\377\377\377\301\301\301:::;;=\202" \ + "::<\202;;=\4::<\332\332\332\377\377\377\376\376\376\236\377\377\377\1" \ + "kkm\206::<\1\234\234\236\233\377\377\377\3\376\376\376\364\364\364FF" \ + "H\205::<\4;;=99;xxx\376\376\376\203\377\377\377\1\376\376\376\203\377" \ + "\377\377\1\376\376\376\202\377\377\377\1\376\376\376\224\377\377\377" \ + "\4\376\376\376\377\377\377\362\362\362GGI\202::<\6;;=::<;;=::<99;\250" \ + "\250\252\221\377\377\377\1\234\234\234\206::<\1\316\316\316\252\377\377" \ + "\377\1\316\316\316\206::<\1\234\234\236\213\377\377\377\2\255\333\363" \ + "Y\270\350\211[\267\350\7Y\267\352X\267\347[\266\353\301\344\367\377\377" \ + "\377\376\376\376\376\377\377\211\377\377\377\6\377\376\377\377\377\377" \ + "\377\375\376\377\377\377\377\377\375\377\376\377\202\377\377\377\210" \ + "\377\376\377\10\377\377\375\376\377\377\377\377\377\376\377\375\237\266" \ + "\306\0=i\2=g\0>e\210\0=i\3\0>i\0=i\177\236\263\232\377\377\377\1\316" \ + "\316\316\206::<\1kkm\240\377\377\377\1\234\234\236\206::<\1\234\234\236" \ + "\237\377\377\377\1EEG\202::<\202;;=\11""99;;;=\332\332\332\377\377\377" \ + "\376\376\376\377\377\377xxz::<;;=\204::<\1\302\302\302\236\377\377\377" \ + "\1kkm\206::<\1\316\316\316\266\377\377\377\4\376\376\376\377\377\377" \ + "SSU;;=\202::<\1;;=\202::<\1\316\316\320\235\377\377\377\15\376\376\376" \ + "\377\377\377\376\376\376\377\377\377\363\363\365::<;;=99;;;=::<;;=::" \ + "<\265\265\265\215\377\377\377\3\376\376\376\377\377\377\266\266\270\202" \ + "::<\1;;=\203::<\2;;=\204\204\206\205\377\377\377\3\376\376\376\377\377" \ + "\377\376\376\376\213\377\377\377\1\376\376\376\205\377\377\377\1\376" \ + "\376\376\202\377\377\377\2\363\363\363SSU\203::<\4;;=99;;;=SSU\241\377" \ + "\377\377\1kkm\206::<\1\234\234\236\235\377\377\377\3\265\265\265;;=9" \ + "9;\202::<\1;;=\203::<\1\204\204\206\206\377\377\377\1\376\376\376\216" \ + "\377\377\377\3\376\376\376\377\377\377\376\376\376\206\377\377\377\6" \ + "\376\376\376\377\377\377\362\362\364``b::<;;=\202::<\1;;=\202::<\2aa" \ + "c\376\376\376\221\377\377\377\1\234\234\234\206::<\1\316\316\316\252" \ + "\377\377\377\1\316\316\316\206::<\1\234\234\236\213\377\377\377\2\255" \ + "\333\363Y\270\350\211[\267\350\10X\267\347[\267\346[\265\347[\267\346" \ + "\230\320\361\327\360\367\325\356\365\331\355\370\210\326\354\371\10\325" \ + "\355\367\323\355\372\366\373\377\377\376\374\376\377\375\276\320\332" \ + "\277\320\330\301\317\330\210\276\317\331\10\276\317\327\276\320\334\301" \ + "\316\327_\207\241\0>i\0=l\0\77k\0>i\210\0=i\3\0>i\0=i\177\236\263\232" \ + "\377\377\377\1\316\316\316\206::<\1kkm\240\377\377\377\1\234\234\236" \ + "\206::<\1\234\234\236\237\377\377\377\3\222\222\224::<;;=\202::<\3;;" \ + "=99;\205\205\207\202\377\377\377\2\346\346\346;;=\202::<\1;;=\202::<" \ + "\1SSU\237\377\377\377\1kkm\206::<\1\316\316\316\267\377\377\377\5\265" \ + "\265\26799;;;=::<;;=\202::<\1TTV\243\377\377\377\1\204\204\206\205::" \ + "<\2;;=SSU\206\377\377\377\1\376\376\376\210\377\377\377\3\376\376\376" \ + "GGI;;=\202::<\5;;=::<;;=::<\301\301\303\203\377\377\377\1\376\376\376" \ + "\214\377\377\377\1\376\376\376\202\377\377\377\1\376\376\376\202\377" \ + "\377\377\1\376\376\376\204\377\377\377\3\204\204\206;;=::<\202;;=\203" \ + "::<\1\265\265\265\241\377\377\377\1kkm\206::<\1\234\234\236\236\377\377" \ + "\377\12kkk::<99;;;=::<99;;;=::<;;=\204\204\206\210\377\377\377\202\376" \ + "\376\376\213\377\377\377\1\376\376\376\202\377\377\377\1\376\376\376" \ + "\202\377\377\377\1\376\376\376\202\377\377\377\2\364\364\366__a\206:" \ + ":<\3;;=::<\332\332\332\222\377\377\377\1\234\234\234\206::<\1\316\316" \ + "\316\252\377\377\377\1\316\316\316\206::<\1\234\234\236\213\377\377\377" \ + "\2\255\333\363Y\270\350\211[\267\350\3\\\266\350X\270\352\\\266\352\202" \ + "[\267\350\3X\267\347Y\270\350Z\266\347\210Y\270\350\10[\267\350[\265" \ + "\351\327\355\372\376\377\377\377\377\375\0>j\0>i\1\77h\210\0>i\10\0\77" \ + "k\0>g\2=g\0=i\0\77j\0<h\0\77h\1>j\210\0=i\3\0>i\0=i\177\236\263\232\377" \ + "\377\377\1\316\316\316\206::<\1kkm\240\377\377\377\1\234\234\236\206" \ + "::<\1\234\234\236\236\377\377\377\2\376\376\376\346\346\346\202::<\10" \ + ";;=::<99;;;=::<\363\363\363\377\377\377\234\234\236\202::<\6;;=::<;;" \ + "=::<\250\250\250\376\376\376\236\377\377\377\1kkm\206::<\1\316\316\316" \ + "\267\377\377\377\10kkm;;=::<;;=99;::<;;=\264\264\266\236\377\377\377" \ + "\1\376\376\376\204\377\377\377\2\346\346\346;;=\202::<\202;;=\202::<" \ + "\2\316\316\320\376\376\376\203\377\377\377\1\376\376\376\205\377\377" \ + "\377\3\376\376\376\377\377\377\376\376\376\202\377\377\377\3\234\234" \ + "\234::<;;=\202::<\6;;=::<;;=GGI\332\332\332\376\376\376\224\377\377\377" \ + "\1\376\376\376\203\377\377\377\2\266\266\266;;=\202::<\6;;=::<;;=::<" \ + "SSU\376\376\376\241\377\377\377\1kkm\206::<\1\234\234\236\236\377\377" \ + "\377\2\363\363\363GGI\203::<\1;;=\203::<\3""99;\204\204\204\363\363\363" \ + "\225\377\377\377\1\376\376\376\204\377\377\377\4\376\376\376\346\346" \ + "\346``b::<\202;;=\3::<99;<<>\202::<\1\250\250\250\223\377\377\377\1\234" \ + "\234\234\206::<\1\316\316\316\252\377\377\377\1\316\316\316\206::<\1" \ + "\234\234\236\213\377\377\377\2\255\333\363Y\270\350\211[\267\350\10Y" \ + "\270\350X\270\353Y\267\352X\266\351X\271\346[\267\350\\\266\353[\267" \ + "\350\210Y\270\350\7X\267\345]\267\351\323\355\372\377\376\377\376\377" \ + "\377\4=h\0>g\211\0=i\10\2=i\0@j\0>i\1>j\0>i\1\77h\0>g\0>j\210\0=i\3\0" \ + ">i\0=i\177\236\263\232\377\377\377\1\316\316\316\206::<\1kkm\240\377" \ + "\377\377\1\234\234\236\206::<\1\234\234\236\237\377\377\377\6\376\376" \ + "\376yy{::<;;=::<;;=\202::<\4\251\251\251\376\376\376SSU;;=\203::<\3;" \ + ";=FFH\363\363\363\237\377\377\377\1kkm\206::<\1\316\316\316\264\377\377" \ + "\377\5\376\376\376\377\377\377\315\315\317::<;;=\204::<\2FFH\376\376" \ + "\376\237\377\377\377\1\376\376\376\203\377\377\377\3\376\376\376kkm;" \ + ";=\204::<\6""99;lln\377\377\377\376\376\376\377\377\377\376\376\376\202" \ + "\377\377\377\3\376\376\376\377\377\377\376\376\376\205\377\377\377\10" \ + "\376\376\376\377\377\377SSU::<99;;;=99;;;=\202::<\2FFF\332\332\332\203" \ + "\377\377\377\1\376\376\376\212\377\377\377\1\376\376\376\210\377\377" \ + "\377\1\265\265\265\206::<\3""99;::<\265\265\265\203\377\377\377\1\376" \ + "\376\376\236\377\377\377\1kkm\206::<\1\234\234\236\233\377\377\377\1" \ + "\376\376\376\203\377\377\377\1\331\331\331\204::<\3""99;;;=99;\202;;" \ + "=\2^^^\332\332\332\202\377\377\377\1\376\376\376\216\377\377\377\1\376" \ + "\376\376\206\377\377\377\5\376\376\376\316\316\316FFH::<;;=\204::<\7" \ + "99;::<\204\204\204\377\377\377\376\376\376\377\377\377\376\376\376\220" \ + "\377\377\377\1\234\234\234\206::<\1\316\316\316\252\377\377\377\1\316" \ + "\316\316\206::<\1\234\234\236\213\377\377\377\2\255\333\363Y\270\350" \ + "\213[\267\350\6Y\270\350[\266\353[\267\350]\267\351X\266\351X\270\350" \ + "\210[\267\350\10X\266\351Z\266\351\326\354\367\377\376\377\376\377\372" \ + "\0>j\0>i\1>j\210\0=i\10\1\77h\0=h\0>i\1\77h\0>j\0=i\0>i\1>j\210\0=i\3" \ + "\0>i\0=i\177\236\263\232\377\377\377\1\316\316\316\206::<\1kkm\240\377" \ + "\377\377\1\234\234\236\206::<\1\234\234\236\237\377\377\377\2\376\376" \ + "\376\316\316\316\203::<\1;;=\202::<\4SSU\265\265\267;;=99;\202::<\5;" \ + ";=99;\204\204\204\377\377\377\376\376\376\236\377\377\377\1kkm\206::" \ + "<\1\316\316\316\263\377\377\377\1\376\376\376\202\377\377\377\1xxz\202" \ + "::<\1;;=\202::<\3""99;\234\234\236\376\376\376\236\377\377\377\1\375" \ + "\375\375\202\377\377\377\1\376\376\376\202\377\377\377\5\317\317\317" \ + "99;::<;;=::<\202;;=\2::<\332\332\332\210\377\377\377\3\376\376\376\377" \ + "\377\377\376\376\376\204\377\377\377\2\316\316\316;;=\206::<\3;;=::<" \ + "\250\250\252\217\377\377\377\1\376\376\376\204\377\377\377\2\363\363" \ + "\363\222\222\224\202::<\2;;=::<\202;;=\3""99;;;=kkm\205\377\377\377\1" \ + "\376\376\376\235\377\377\377\1kkm\206::<\1\234\234\236\235\377\377\377" \ + "\1\376\376\376\202\377\377\377\2\266\266\26699;\202::<\3;;=::<;;=\202" \ + "::<\3;;=FFH\234\234\234\202\377\377\377\1\376\376\376\223\377\377\377" \ + "\2\364\364\364\204\204\206\202::<\1;;=\202::<\1;;=\202::<\3""99;``b\376" \ + "\376\376\224\377\377\377\1\234\234\234\206::<\1\316\316\316\252\377\377" \ + "\377\1\316\316\316\206::<\1\234\234\236\213\377\377\377\2\255\333\363" \ + "Y\270\350\211[\267\350\10Y\271\353Z\266\347\\\267\344[\267\346X\267\347" \ + "[\267\350X\270\353Z\266\347\210Y\270\350\10Y\267\352\\\267\346\325\355" \ + "\371\377\377\377\376\377\377\0>g\0\77k\0>i\210\0\77j\10\0>i\3>h\0=i\0" \ + "\77i\0=j\0>g\0=j\0=f\210\0=i\3\0>i\0=i\177\236\263\232\377\377\377\1" \ + "\316\316\316\206::<\1kkm\240\377\377\377\1\234\234\236\206::<\1\234\234" \ + "\236\234\377\377\377\3\376\376\376\377\377\377\376\376\376\202\377\377" \ + "\377\2SSU;;=\202::<\202;;=\3::<SSU::<\202;;=\203::<\1\332\332\332\240" \ + "\377\377\377\1kkm\206::<\1\316\316\316\265\377\377\377\1\346\346\346" \ + "\203::<\1;;=\202::<\2;;=\363\363\365\235\377\377\377\1\376\376\376\210" \ + "\377\377\377\1SSU\202;;=\204::<\1\204\204\204\202\377\377\377\202\376" \ + "\376\376\214\377\377\377\1\221\221\221\205::<\202;;=\4::<;;=kkm\316\316" \ + "\316\221\377\377\377\2\301\301\301SSS\210::<\2FFH\363\363\365\243\377" \ + "\377\377\1kkm\206::<\1\234\234\236\241\377\377\377\1\266\266\270\203" \ + "::<\1;;=\205::<\3:::RRR\265\265\265\222\377\377\377\3\363\363\363\234" \ + "\234\234FFF\202::<\1;;=\206::<\2``b\363\363\363\225\377\377\377\1\234" \ + "\234\234\206::<\1\316\316\316\252\377\377\377\1\316\316\316\206::<\1" \ + "\234\234\236\213\377\377\377\2\255\333\363Y\270\350\211[\267\350\10Z" \ + "\266\347[\267\346Z\265\352X\266\351\\\270\351[\267\346X\267\347[\265" \ + "\347\210[\267\350\10Y\267\352[\266\345\325\355\367\376\375\377\377\377" \ + "\375\3>j\0=i\1>j\210\0>i\10\0\77j\1\77h\0>j\0>g\3>j\0\77i\0=j\0>i\210" \ + "\0=i\3\0>i\0=i\177\236\263\232\377\377\377\1\316\316\316\206::<\1kkm" \ + "\240\377\377\377\1\234\234\236\206::<\1\234\234\236\241\377\377\377\6" \ + "\266\266\270::<;;=::<99;::<\202;;=\205::<\2kkm\376\376\376\240\377\377" \ + "\377\1kkm\206::<\1\316\316\316\265\377\377\377\4\205\205\205;;=::<;;" \ + "=\203::<\3\204\204\206\377\377\377\376\376\376\245\377\377\377\1\265" \ + "\265\267\207::<\2\346\346\346\376\376\376\216\377\377\377\4\376\376\376" \ + "lll::<;;=\202::<\13;;=::<;;=::<;;=::<kkm\264\264\266\363\363\365\377" \ + "\377\377\376\376\376\202\377\377\377\1\376\376\376\206\377\377\377\3" \ + "\346\346\350\250\250\252TTV\204::<\3;;=::<;;=\202::<\2;;=\333\333\333" \ + "\202\377\377\377\1\376\376\376\237\377\377\377\3\376\376\376\377\377" \ + "\377kkm\203::<\1;;=\202::<\1\235\235\237\242\377\377\377\1\265\265\265" \ + "\203::<\1;;=\207::<\4GGI\220\220\222\332\332\334\376\376\376\206\377" \ + "\377\377\1\376\376\376\204\377\377\377\5\376\376\376\302\302\302\204" \ + "\204\206::<;;=\202::<\11""99;;;=::<;;=::<;;=::<```\363\363\363\226\377" \ + "\377\377\1\234\234\234\202::<\1;;=\202::<\2;;=\316\316\316\252\377\377" \ + "\377\4\316\316\316::<;;=99;\203::<\3\234\234\234\377\377\377\376\376" \ + "\376\204\377\377\377\7\373\377\376\377\376\377\377\377\377\376\377\377" \ + "\377\376\377\253\333\362[\265\351\203[\267\352\6Y\267\352[\267\350X\267" \ + "\345Y\270\346Y\270\350Y\267\352\220[\267\350\5X\267\347Y\270\350\325" \ + "\355\371\377\376\377\377\377\377\202\0>g\1\1>k\220\0=i\15\0>g\1>j\0>" \ + "i\0\77j\1>j\0=i\0\77j\0>j\0=i\1<h}\237\270\376\377\377\377\376\374\226" \ + "\377\377\377\3\376\376\376\377\377\377\316\316\316\204::<\3""99;;;=l" \ + "ln\240\377\377\377\5\234\234\234::<;;=::<;;=\202::<\1\235\235\237\241" \ + "\377\377\377\10\363\363\363FFF::<;;=::<;;=::<;;=\203::<\3;;=::<\265\265" \ + "\265\237\377\377\377\3\376\376\376\377\377\377kkm\202::<\1;;=\202::<" \ + "\4;;=\316\316\316\377\377\377\376\376\376\250\377\377\377\1\376\376\376" \ + "\202\377\377\377\1\376\376\376\202\377\377\377\1\376\376\376\203\377" \ + "\377\377\6\364\364\364::<99;;;=::<;;=\202::<\1\347\347\351\203\377\377" \ + "\377\1\376\376\376\244\377\377\377\4FFH;;=::<99;\203::<\1\220\220\222" \ + "\220\377\377\377\2\363\363\363``b\202::<\1;;=\203::<\1;;=\205::<\5__" \ + "_\222\222\222\234\234\234\316\316\316\317\317\317\202\316\316\316\7\301" \ + "\301\301\234\234\236\204\204\206__a;;=99;;;=\203::<\2;;=99;\203;;=\2" \ + "::<\265\265\265\204\377\377\377\1\376\376\376\235\377\377\377\5\376\376" \ + "\376\377\377\377\376\376\376kkm::<\202;;=\6::<;;=::<\234\234\236\377" \ + "\377\377\376\376\376\236\377\377\377\1\376\376\376\202\377\377\377\5" \ + "\301\301\303GGI;;=::<;;=\206::<\7;;=::<99;GGIwwy\235\235\235\300\300" \ + "\300\202\316\316\316\10\315\315\315\317\317\317\315\315\315\265\265\265" \ + "\234\234\234jjj<<>99;\203::<\1;;=\202::<\2""99;;;=\203::<\1\204\204\206" \ + "\206\377\377\377\1\376\376\376\221\377\377\377\10\234\234\234;;=::<9" \ + "9;;;=::<99;\316\316\316\252\377\377\377\4\317\317\317;;=88:;;=\202::" \ + "<\3;;=\234\234\234\376\376\376\205\377\377\377\1\377\375\377\202\377" \ + "\377\375\6\377\376\377\377\377\375\253\333\362Y\270\350X\267\347Z\266" \ + "\347\202Y\270\350\1[\267\350\202Z\266\347\2[\267\350Z\266\347\220[\267" \ + "\350\5[\267\352Z\266\351\327\355\372\377\375\376\377\376\377\202\1>j" \ + "\1\1>k\220\0>i\202\0=i\14\0\77k\0>i\0=i\1>j\0=i\0=j\0\77k\0=i\177\236" \ + "\263\377\377\377\376\377\377\375\376\377\224\377\377\377\1\376\376\376" \ + "\202\377\377\377\1\316\316\316\203::<\202;;=\3""99;kkm\376\376\376\234" \ + "\377\377\377\1\376\376\376\202\377\377\377\1\233\233\233\202::<\7;;=" \ + "::<;;=::<\234\234\236\377\377\377\376\376\376\233\377\377\377\3\376\376" \ + "\376\377\377\377\376\376\376\202\377\377\377\4\221\221\221;;=99;;;=\202" \ + "::<\202;;=\203::<\1SSU\203\377\377\377\1\376\376\376\233\377\377\377" \ + "\10\376\376\376\377\377\377\376\376\376kkm::<;;=::<;;=\202::<\1;;=\202" \ + "::<\1;;=\240::<\1kkk\207\377\377\377\1\376\376\376\203\377\377\377\3" \ + "\375\375\375\377\377\377\376\376\376\202\377\377\377\2\233\233\235::" \ + "<\202;;=\203::<\1xxz\251\377\377\377\1\235\235\237\202::<\1;;=\203::" \ + "<\3GGI\363\363\363\376\376\376\217\377\377\377\2\363\363\363yyy\204:" \ + ":<\1;;=\203::<\1;;=\206::<\1""99;\203::<\1;;=\203::<\6;;=99;;;=::<;;" \ + "=99;\202;;=\3""99;GGI\301\301\301\206\377\377\377\1\376\376\376\232\377" \ + "\377\377\1\376\376\376\204\377\377\377\1lln\202::<\1;;=\202::<\2;;=\234" \ + "\234\236\241\377\377\377\1\376\376\376\202\377\377\377\2\332\332\334" \ + "__a\211::<\1;;=\205::<\1;;=\202::<\1;;=\202::<\4;;=::<99;;;=\202::<\1" \ + ";;=\202::<\1;;=\203::<\2FFH\265\265\267\206\377\377\377\3\376\376\376" \ + "\377\377\377\376\376\376\220\377\377\377\3\234\234\236::<;;=\203::<\2" \ + ";;=\316\316\316\252\377\377\377\2\315\315\31599;\203::<\5;;=::<\234\234" \ + "\234\377\377\377\376\376\376\205\377\377\377\7\377\377\375\375\377\376" \ + "\377\377\377\375\376\377\255\333\365Z\266\345[\267\350\202Y\270\350\1" \ + "X\267\347\202Y\267\352\3Z\266\351Z\266\347Y\270\350\221[\267\350\2[\267" \ + "\352\323\355\372\202\376\377\377\1\0=j\222\0=i\204\0>i\14\1\77h\0>g\0" \ + "=f\1>j\0\77i\0>i\177\237\266\377\377\375\377\376\375\377\377\377\376" \ + "\377\377\377\376\377\225\377\377\377\2\316\316\316::<\202;;=\202::<\4" \ + ";;=kkm\377\377\377\376\376\376\235\377\377\377\2\376\376\376\235\235" \ + "\235\202::<\1;;=\202::<\2;;=\234\234\236\242\377\377\377\3\346\346\346" \ + "::<;;=\210::<\2\235\235\237\376\376\376\234\377\377\377\1\376\376\376" \ + "\204\377\377\377\1lln\202::<\3;;=::<;;=\203::<\2;;=99;\240::<\1kkk\210" \ + "\377\377\377\11\376\376\376\377\377\377\376\376\376\377\377\377\376\376" \ + "\376\377\377\377\376\376\376\364\364\366GGI\205::<\6;;=\316\316\316\377" \ + "\377\377\376\376\376\377\377\377\376\376\376\245\377\377\377\11\345\345" \ + "\345;;=::<;;=::<;;=::<;;=\234\234\236\222\377\377\377\7\234\234\234;" \ + ";=::<;;=99;;;=99;\203::<\1;;=\202::<\203;;=\2::<;;=\202::<\1;;=\202:" \ + ":<\1;;=\202::<\12;;=::<;;=99;::<``b\332\332\332\376\376\376\377\377\377" \ + "\376\376\376\202\377\377\377\5\376\376\376\377\377\377\376\376\376\377" \ + "\377\377\376\376\376\232\377\377\377\5\376\376\376\377\377\377\376\376" \ + "\376kkm;;=\202::<\1;;=\202::<\1\234\234\236\236\377\377\377\1\376\376" \ + "\376\207\377\377\377\2\234\234\236;;=\202::<\1;;=\204::<\1;;=\211::<" \ + "\1;;=\202::<\1;;=\202::<\1;;=\202::<\1;;=\203::<\3;;=kkm\346\346\346" \ + "\203\377\377\377\1\376\376\376\204\377\377\377\1\376\376\376\221\377" \ + "\377\377\2\234\234\236;;=\202::<\1;;=\202::<\1\316\316\316\252\377\377" \ + "\377\4\316\316\316;;=99;;;=\203::<\1\234\234\234\210\377\377\377\7\376" \ + "\377\377\377\375\376\377\377\375\256\332\363Y\270\350Y\267\352[\267\352" \ + "\202[\267\350\5X\270\350X\270\352Y\267\352Y\270\350X\267\347\220[\267" \ + "\350\5X\267\347[\267\350\325\355\367\377\377\373\377\377\375\202\0\77" \ + "j\1\0>g\220\0>i\1\0\77j\203\0>i\202\0=i\6\1>j\0>i\0\77h\0>g\177\236\263" \ + "\377\377\375\203\377\377\377\1\377\376\377\222\377\377\377\1\376\376" \ + "\376\202\377\377\377\1\316\316\316\203::<\1;;=\202::<\2kkm\376\376\376" \ + "\233\377\377\377\1\376\376\376\203\377\377\377\5\234\234\234::<;;=::" \ + "<;;=\202::<\1\234\234\236\235\377\377\377\202\376\376\376\202\377\377" \ + "\377\5\376\376\376\377\377\377xxz99;;;=\204::<\4;;=::<;;=\362\362\362" \ + "\237\377\377\377\5\376\376\376\377\377\377\376\376\376kkm;;=\207::<\2" \ + "99;;;=\240::<\1lll\205\377\377\377\1\376\376\376\203\377\377\377\1\376" \ + "\376\376\202\377\377\377\1\376\376\376\202\377\377\377\4\265\265\267" \ + ";;=::<;;=\202::<\2;;=__a\205\377\377\377\1\376\376\376\245\377\377\377" \ + "\3\204\204\206::<;;=\204::<\2SSU\376\376\376\215\377\377\377\1\376\376" \ + "\376\204\377\377\377\2\316\316\316__a\206::<\1;;=\214::<\5;;=::<;;=:" \ + ":<;;=\203::<\2\234\234\234\363\363\363\204\377\377\377\1\376\376\376" \ + "\243\377\377\377\1lln\206::<\2\233\233\235\376\376\376\233\377\377\377" \ + "\1\376\376\376\202\377\377\377\1\376\376\376\207\377\377\377\3\345\345" \ + "\345lln;;=\204::<\5;;=99;::<99;;;=\205::<\1;;=\203::<\3""99;;;=99;\206" \ + "::<\2TTV\265\265\265\234\377\377\377\10\234\234\234;;=::<;;=::<;;=::" \ + "<\316\316\316\252\377\377\377\1\315\315\315\206::<\4\235\235\235\376" \ + "\376\376\377\377\377\376\376\376\205\377\377\377\12\377\377\373\377\377" \ + "\377\377\377\375\267\340\366[\270\344Z\266\351[\267\352Z\266\351[\265" \ + "\347[\267\350\202Y\270\350\2\\\270\351Z\266\347\220[\267\350\10X\267" \ + "\347X\266\351\325\355\371\377\376\377\377\377\377\0\77k\0=h\3>j\220\0" \ + "\77j\16\1>j\0=i\1>j\0=i\0\77j\0>i\0=h\0\77j\0\77h\1<f\177\236\263\377" \ + "\377\375\376\376\377\376\377\377\225\377\377\377\202\376\376\376\2\317" \ + "\317\317::<\202;;=\1::<\202;;=\1kkm\235\377\377\377\1\376\376\376\202" \ + "\377\377\377\2\234\234\234;;=\205::<\2\233\233\235\376\376\376\232\377" \ + "\377\377\1\376\376\376\204\377\377\377\1\376\376\376\202\377\377\377" \ + "\1\316\316\316\203::<\1;;=\204::<\3\204\204\206\377\377\377\376\376\376" \ + "\241\377\377\377\1lln\203::<\202;;=\203::<\1;;=\241::<\1kkk\206\377\377" \ + "\377\3\376\376\376\377\377\377\376\376\376\206\377\377\377\1TTV\203:" \ + ":<\4""99;;;=99;\265\265\267\253\377\377\377\3\331\331\331;;=99;\204:" \ + ":<\2;;=\264\264\264\217\377\377\377\1\376\376\376\204\377\377\377\2\264" \ + "\264\266SSU\202::<\2""99;;;=\203::<\3;;=::<;;=\206::<\5;;=99;;;=::<;" \ + ";=\20299;\6\204\204\206\346\346\346\377\377\377\376\376\376\377\377\377" \ + "\376\376\376\203\377\377\377\202\376\376\376\202\377\377\377\1\376\376" \ + "\376\231\377\377\377\3\376\376\376\377\377\377\376\376\376\202\377\377" \ + "\377\12lll::<;;=::<99;::<;;=\234\234\236\377\377\377\376\376\376\233" \ + "\377\377\377\1\375\375\375\213\377\377\377\4\316\316\316xxx;;=99;\204" \ + "::<\1;;=\202::<\1;;=\204::<\4;;=::<;;=99;\203::<\1;;=\202::<\2SSS\265" \ + "\265\265\210\377\377\377\3\376\376\376\377\377\377\376\376\376\223\377" \ + "\377\377\1\234\234\234\206::<\1\316\316\316\250\377\377\377\3\376\376" \ + "\376\377\377\377\315\315\315\202::<\7;;=::<;;=::<\234\234\234\377\377" \ + "\377\376\376\376\202\377\377\377\21\376\376\376\377\377\377\376\377\373" \ + "\377\377\377\376\377\377\376\377\375\377\376\377\353\366\374X\266\351" \ + "X\270\350W\267\347X\270\350X\267\347Z\266\347\\\270\347X\267\345Y\270" \ + "\350\221[\267\350\7Z\266\347[\267\350\327\355\372\377\375\377\377\377" \ + "\377\0>g\0\77h\221\0=i\1\0>g\202\1\77h\1\0=i\202\0>i\11\0\77j\0>g\0>" \ + "j\0\77m\336\347\354\376\377\377\377\376\377\376\377\377\377\377\375\222" \ + "\377\377\377\1\376\376\376\203\377\377\377\1\316\316\316\202::<\1;;=" \ + "\203::<\2kkm\376\376\376\233\377\377\377\1\376\376\376\202\377\377\377" \ + "\3\376\376\376\234\234\234;;=\202::<\6""99;::<;;=\234\234\236\377\377" \ + "\377\376\376\376\237\377\377\377\1\376\376\376\202\377\377\377\1SSS\202" \ + ";;=\1""99;\204;;=\3\331\331\331\377\377\377\376\376\376\234\377\377\377" \ + "\3\376\376\376\377\377\377\376\376\376\202\377\377\377\3lll::<;;=\202" \ + "::<\202;;=\203::<\1;;=\240::<\1kkk\204\377\377\377\1\376\376\376\211" \ + "\377\377\377\3\302\302\302;;;999\202::<\3;;=::<TTT\210\377\377\377\1" \ + "\376\376\376\244\377\377\377\2kkk;;=\202::<\203:::\1TTT\226\377\377\377" \ + "\3\301\301\301xxz;;=\202::<\1;;=\202::<\1;;=\202::<\5;;=::<;;=::<;;=" \ + "\202::<\5;;=99;SSU\235\235\237\347\347\351\204\377\377\377\1\376\376" \ + "\376\207\377\377\377\3\376\376\376\377\377\377\376\376\376\235\377\377" \ + "\377\10kkk:::::<999;;;:::;;;\233\233\233\236\377\377\377\1\376\376\376" \ + "\211\377\377\377\1\376\376\376\202\377\377\377\3\346\346\350\251\251" \ + "\253``b\202::<\3;;=::<;;=\202::<\1;;=\205::<\1;;=\203::<\5;;=FFH\204" \ + "\204\204\316\316\316\376\376\376\204\377\377\377\1\376\376\376\232\377" \ + "\377\377\1\234\234\234\202::<\5""99;;;=99;;;;\315\315\315\252\377\377" \ + "\377\3\316\316\316:::;;;\202:::\3;;;::<\234\234\234\206\377\377\377\1" \ + "\377\377\375\203\377\376\377\11\377\377\377\377\377\375\303\344\367W" \ + "\270\345^\266\344X\267\347Y\271\353Z\266\351\\\266\350\202Y\270\350\221" \ + "[\267\352\3[\267\350[\265\347\325\355\371\202\376\377\377\3\2=e\0>g\0" \ + "\77m\220\0=i\6\0\77j\0>i\0=h\0\77j\0=i\0\77j\202\0>g\2\1\77h\240\266" \ + "\304\204\377\377\377\2\376\376\376\377\377\375\223\377\377\377\14\376" \ + "\376\376\377\377\377\315\315\315;;=::<:::;;;:::;;;kkk\377\377\377\376" \ + "\376\376\233\377\377\377\1\376\376\376\202\377\377\377\10\235\235\235" \ + "99;::<999;;;:::;;;\233\233\233\234\377\377\377\1\376\376\376\207\377" \ + "\377\377\1\265\265\265\202::<\1;;=\203::<\1kkk\203\377\377\377\1\376" \ + "\376\376\240\377\377\377\2kkk:::\202::<\3;;=99;;;=\244::<\1kkk\205\377" \ + "\377\377\1\376\376\376\210\377\377\377\1\346\346\346\206\316\316\316" \ + "\3\332\332\332\377\377\377\377\377\375\253\377\377\377\2\346\346\346" \ + "\316\316\316\202\316\316\320\203\316\316\316\1\315\315\315\225\377\377" \ + "\377\202\376\376\376\202\377\377\377\4\316\316\320\234\234\236kkmSSU" \ + "\205::<\1;;=\203::<\5kkm\204\204\206\264\264\266\346\346\350\376\376" \ + "\376\214\377\377\377\1\376\376\376\202\377\377\377\202\376\376\376\231" \ + "\377\377\377\1\376\376\376\203\377\377\377\2\331\331\331\317\317\317" \ + "\205\316\316\316\1\347\347\347\243\377\377\377\1\376\376\376\211\377" \ + "\377\377\5\376\376\377\347\347\351\265\265\267\204\204\206lln\212::<" \ + "\4``bxxz\234\234\236\332\332\332\207\377\377\377\1\376\376\376\210\377" \ + "\377\377\1\376\376\376\222\377\377\377\1\346\346\346\203\316\316\320" \ + "\4\316\316\316\316\316\320\315\315\315\364\364\364\251\377\377\377\2" \ + "\376\376\376\364\364\364\205\316\316\316\2\316\316\320\346\346\346\210" \ + "\377\377\377\16\377\376\377\377\377\375\376\377\377\377\377\377\377\375" \ + "\377\326\354\371\241\326\366\206\310\352\200\312\357\202\312\362\204" \ + "\310\357\204\312\356\203\311\355\205\311\360\220\204\312\356\10\203\311" \ + "\355\201\311\361\342\360\371\376\377\377\377\377\375>n\222Bm\215@n\220" \ + "\220@n\217\3@l\217An\217Bo\220\202An\217\5@m\214Dm\213l\223\260\277\320" \ + "\332\376\377\377\202\377\377\377\1\377\377\375\202\377\377\377\1\376" \ + "\377\377\225\377\377\377\3\363\363\363\317\317\321\316\316\320\204\316" \ + "\316\316\1\332\332\332\240\377\377\377\1\346\346\346\202\316\316\320" \ + "\204\316\316\316\1\347\347\347\243\377\377\377\3\376\376\376\363\363" \ + "\363lln\202kkm\1lln\202kkm\1\301\301\301\240\377\377\377\1\376\376\376" \ + "\203\377\377\377\2\331\331\331\317\317\317\202\316\316\316\202\317\317" \ + "\317\245\316\316\316\2\332\332\332\376\376\376\351\377\377\377\5\332" \ + "\332\332\315\315\315\316\316\316\315\315\315\363\363\363\361\377\377" \ + "\377\202\316\316\316\1\317\317\317\202\316\316\316\2\315\315\315\363" \ + "\363\363\377\377\377\377\377\377\377\377\377\377\377\377\334\377\377" \ + "\377\1\376\376\376\375\377\377\377\1\376\376\376\377\377\377\377\377" \ + "\377\377\377\377\377\377\377\340\377\377\377\1\376\376\376\370\377\377" \ + "\377\1\376\376\376\377\377\377\377\377\377\377\377\377\377\377\377\342" \ + "\377\377\377\1\376\376\376\377\377\377\377\377\377\377\377\377\377\377" \ + "\377\377\377\377\377\334\377\377\377\1\376\376\376\362\377\377\377\1" \ + "\376\376\376\377\377\377\377\377\377\377\377\377\377\377\377\346\377" \ + "\377\377\1\376\376\376\363\377\377\377\1\376\376\376\377\377\377\377" \ + "\377\377\377\377\377\377\377\377\342\377\377\377\1\376\376\376\373\377" \ + "\377\377\1\376\376\376\377\377\377\377\377\377\377\377\377\377\377\377" \ + "\340\377\377\377\3\376\376\376\377\377\377\376\376\376\377\377\377\377" \ + "\377\377\377\377\377\377\377\377\377\377\377\377\243\377\377\377\3\376" \ + "\376\376\377\377\377\376\376\376\203\377\377\377\1\376\376\376\233\377" \ + "\377\377\1\376\376\376\205\377\377\377\1\376\376\376\214\377\377\377" \ + "\1\376\376\376\205\377\377\377\1\376\376\376\260\377\377\377\3\376\376" \ + "\376\377\377\377\376\376\376\300\377\377\377\1\376\376\376\306\377\377" \ + "\377\1\376\376\376\233\377\377\377\4\376\377\377\376\376\376\377\376" \ + "\377\377\377\377\203\376\377\375\203\377\377\377\3\377\377\375\376\377" \ + "\375\376\377\377\265\377\377\377\4\377\377\375\377\376\377\376\377\377" \ + "\377\377\375\202\377\376\377\210\377\377\377\7\377\377\375\376\377\377" \ + "\377\377\377\375\377\376\376\377\377\377\376\377\376\377\377\211\377" \ + "\377\377\4\376\377\375\377\377\377\376\376\376\377\377\375\202\377\377" \ + "\377\2\377\377\375\376\376\376\220\377\377\377\1\376\377\375\202\377" \ + "\377\375\5\377\376\377\377\377\373\377\377\377\375\377\376\377\377\375" \ + "\210\377\377\377\1\377\376\377\202\377\377\375\202\377\377\377\3\376" \ + "\377\377\377\377\375\377\376\377\213\377\377\377\3\376\377\377\376\377" \ + "\375\377\377\375\203\377\377\377\203\376\377\375\4\377\377\377\377\376" \ + "\377\376\376\376\376\377\377\233\377\377\377\3\376\377\377\376\377\375" \ + "\377\377\375\203\377\377\377\203\376\377\375\4\377\377\377\377\376\377" \ + "\376\376\376\376\377\377\210\377\377\377\1\377\376\377\203\377\377\377" \ + "\4\376\377\377\377\377\375\377\376\377\376\377\373\211\377\377\377\4" \ + "\376\377\377\376\376\374\377\376\377\377\375\376\226\377\377\377\5\376" \ + "\377\377\375\377\374\377\377\375\376\375\377\377\377\375\210\377\377" \ + "\377\1\377\377\375\202\376\377\377\1\377\377\373\242\377\377\377\1\376" \ + "\376\376\212\377\377\377\1\376\376\376\207\377\377\377\1\376\376\376" \ + "\237\377\377\377\1\376\376\376\203\377\377\377\1\376\376\376\214\377" \ + "\377\377\1\376\376\376\204\377\377\377\202\376\376\376\257\377\377\377" \ + "\1\376\376\376\202\377\377\377\1\376\376\376\202\377\377\377\1\376\376" \ + "\376\246\377\377\377\1\376\376\376\224\377\377\377\1\376\376\376\250" \ + "\377\377\377\1\376\376\376\202\377\377\377\1\376\376\376\236\377\377" \ + "\377\3\376\376\376\377\377\377\376\376\376\230\377\377\377\4\377\377" \ + "\373\376\377\377\376\376\376\377\376\377\203\377\377\377\1\377\377\375" \ + "\202\377\377\377\1\377\376\377\202\377\377\375\3\377\377\377\377\377" \ + "\375\376\376\374\260\377\377\377\2\377\377\375\376\376\376\203\377\376" \ + "\377\214\377\377\377\7\376\377\377\377\376\377\377\377\375\377\377\377" \ + "\377\376\377\375\377\376\377\377\375\210\377\377\377\7\377\376\374\377" \ + "\377\375\377\376\377\377\377\375\376\376\376\377\377\377\376\376\376" \ + "\221\377\377\377\1\377\376\377\203\377\377\377\202\377\377\375\212\377" \ + "\377\377\2\377\377\375\377\377\377\202\377\377\375\214\377\377\377\3" \ + "\376\376\374\377\377\375\377\377\377\202\377\377\375\1\377\376\377\202" \ + "\377\377\377\1\377\377\375\203\377\377\377\4\377\376\377\376\376\376" \ + "\376\377\377\377\377\373\230\377\377\377\3\376\376\374\377\377\375\377" \ + "\377\377\202\377\377\375\1\377\376\377\202\377\377\377\1\377\377\375" \ + "\203\377\377\377\4\377\376\377\376\376\376\376\377\377\377\377\373\213" \ + "\377\377\377\1\377\376\374\214\377\377\377\2\377\377\375\377\376\377" \ + "\202\377\377\375\3\376\377\377\377\377\377\377\377\373\221\377\377\377" \ + "\3\376\377\375\376\377\377\377\376\377\204\377\377\377\1\377\377\375" \ + "\212\377\377\377\5\377\376\377\377\377\375\377\377\377\376\377\375\376" \ + "\377\373\243\377\377\377\1\376\376\376\205\377\377\377\1\376\376\376" \ + "\204\377\377\377\1\376\376\376\242\377\377\377\1\376\376\376\205\377" \ + "\377\377\1\376\376\376\213\377\377\377\1\376\376\376\206\377\377\377" \ + "\1\376\376\376\263\377\377\377\3\376\376\376\377\377\377\376\376\376" \ + "\270\377\377\377\1\376\376\376\312\377\377\377\1\376\376\376\234\377" \ + "\377\377\1\377\377\375\202\376\377\377\7\377\376\377\377\377\377\376" \ + "\377\377\377\376\377\377\377\375\377\377\377\376\377\377\202\377\376" \ + "\377\2\376\377\375\376\377\377\262\377\377\377\10\377\377\375\376\377" \ + "\377\377\376\377\377\377\373\377\377\377\377\376\377\376\377\375\377" \ + "\377\375\211\377\377\377\3\376\377\377\377\376\377\377\377\375\202\377" \ + "\377\377\2\376\377\377\376\376\376\210\377\377\377\202\377\376\377\4" \ + "\374\377\377\376\377\377\377\376\377\377\377\375\222\377\377\377\4\377" \ + "\376\375\376\377\377\377\377\377\376\377\377\202\377\376\377\202\377" \ + "\377\375\210\377\377\377\4\377\377\375\377\377\377\377\377\375\377\377" \ + "\377\202\377\376\377\2\377\377\377\376\377\377\212\377\377\377\2\376" \ + "\377\377\376\377\375\202\377\376\377\7\376\377\377\377\377\377\377\377" \ + "\375\377\376\377\376\377\377\377\377\377\377\376\377\202\376\377\377" \ + "\1\377\377\375\232\377\377\377\2\376\377\377\376\377\375\202\377\376" \ + "\377\7\376\377\377\377\377\377\377\377\375\377\376\377\376\377\377\377" \ + "\377\377\377\376\377\202\376\377\377\1\377\377\375\210\377\377\377\1" \ + "\377\377\375\202\377\377\377\4\377\377\375\377\376\377\377\377\377\376" \ + "\377\377\211\377\377\377\7\375\376\377\377\377\375\377\376\377\376\376" \ + "\377\376\377\375\375\377\376\377\377\375\222\377\377\377\6\376\377\377" \ + "\377\376\377\377\377\377\377\377\375\377\376\377\376\377\377\213\377" \ + "\377\377\202\377\376\377\3\377\377\375\376\377\377\376\377\375\236\377" \ + "\377\377\1\376\376\376\203\377\377\377\1\376\376\376\202\377\377\377" \ + "\1\376\376\376\203\377\377\377\2\376\376\376\377\377\377\202\376\376" \ + "\376\202\377\377\377\1\376\376\376\202\377\377\377\1\376\376\376\204" \ + "\377\377\377\1\376\376\376\235\377\377\377\1\376\376\376\217\377\377" \ + "\377\1\376\376\376\206\377\377\377\1\376\376\376\260\377\377\377\3\376" \ + "\376\376\377\377\377\376\376\376\241\377\377\377\202\376\376\376\204" \ + "\377\377\377\1\376\376\376\222\377\377\377\1\376\376\376\205\377\377" \ + "\377\1\376\376\376\246\377\377\377\1\376\376\376\233\377\377\377\3\376" \ + "\376\376\377\377\377\376\376\376\234\377\377\377\15\376\376\376\377\377" \ + "\377\377\376\377\377\377\375\375\377\376\377\377\377\376\377\375\377" \ + "\377\377\375\376\377\377\377\377\377\377\375\376\377\377\377\377\377" \ + "\202\377\376\377\260\377\377\377\7\377\376\377\376\377\377\377\377\377" \ + "\376\377\377\377\377\377\377\377\375\376\377\377\212\377\377\377\1\376" \ + "\376\374\203\377\377\377\3\376\376\377\377\377\375\376\377\377\210\377" \ + "\377\377\10\376\377\377\377\376\377\374\377\373\376\377\373\377\376\377" \ + "\376\376\376\377\377\377\376\377\375\220\377\377\377\2\377\376\377\377" \ + "\377\377\202\377\377\375\202\377\377\377\2\376\376\374\376\377\377\210" \ + "\377\377\377\1\376\377\377\202\377\377\377\5\376\377\377\377\377\377" \ + "\376\376\376\377\377\377\376\377\375\210\377\377\377\202\377\376\377" \ + "\15\377\377\377\376\377\377\377\377\375\377\377\377\375\376\377\377\377" \ + "\377\376\377\375\377\377\377\375\377\376\377\377\375\377\376\377\377" \ + "\377\377\376\376\376\231\377\377\377\202\377\376\377\15\377\377\377\376" \ + "\377\377\377\377\375\377\377\377\375\376\377\377\377\377\376\377\375" \ + "\377\377\377\375\377\376\377\377\375\377\376\377\377\377\377\376\376" \ + "\376\211\377\377\377\4\377\376\377\377\377\377\376\377\375\376\377\377" \ + "\202\377\377\377\2\376\377\377\376\377\375\210\377\377\377\1\376\377" \ + "\375\202\376\376\376\202\377\377\377\2\377\377\375\375\376\377\221\377" \ + "\377\377\10\377\377\375\377\377\377\376\376\374\376\377\373\376\376\376" \ + "\377\376\377\376\377\377\377\377\375\210\377\377\377\6\376\376\376\377" \ + "\377\377\377\377\375\377\377\377\374\375\377\377\377\375\242\377\377" \ + "\377\1\376\376\376\214\377\377\377\1\376\376\376\204\377\377\377\3\376" \ + "\376\376\377\377\377\376\376\376\235\377\377\377\1\376\376\376\203\377" \ + "\377\377\202\376\376\376\212\377\377\377\1\376\376\376\202\377\377\377" \ + "\202\376\376\376\264\377\377\377\5\376\376\376\377\377\377\376\376\376" \ + "\377\377\377\376\376\376\242\377\377\377\3\376\376\376\377\377\377\376" \ + "\376\376\202\377\377\377\1\376\376\376\223\377\377\377\1\376\376\376" \ + "\244\377\377\377\1\376\376\376\203\377\377\377\1\376\376\376\233\377" \ + "\377\377\1\376\376\376\202\377\377\377\1\376\376\376\234\377\377\377" \ + "\1\375\377\372\202\377\377\377\3\376\376\376\377\377\375\377\377\377" \ + "\202\376\377\377\204\377\377\377\4\376\377\377\377\377\377\377\376\377" \ + "\375\377\372\260\377\377\377\202\377\377\375\2\377\377\377\376\375\377" \ + "\202\377\377\377\1\375\377\376\212\377\377\377\6\377\377\375\377\377" \ + "\377\376\377\375\377\377\375\377\376\377\377\376\375\212\377\377\377" \ + "\1\377\376\377\202\377\377\377\4\377\375\376\377\377\377\377\377\373" \ + "\376\375\377\221\377\377\377\203\376\376\376\4\377\377\375\376\376\374" \ + "\377\376\377\376\376\374\210\377\377\377\5\377\376\377\377\377\375\377" \ + "\376\377\376\376\376\376\377\375\202\377\377\377\1\376\376\376\210\377" \ + "\377\377\4\375\377\372\377\376\377\377\377\377\376\377\377\204\377\377" \ + "\377\202\376\377\377\3\377\377\377\377\377\375\376\376\376\202\377\377" \ + "\377\1\375\377\372\230\377\377\377\4\375\377\372\377\376\377\377\377" \ + "\377\376\377\377\204\377\377\377\202\376\377\377\3\377\377\377\377\377" \ + "\375\376\376\376\202\377\377\377\1\375\377\372\210\377\377\377\3\376" \ + "\377\377\377\377\377\376\376\376\202\376\377\377\202\377\377\377\1\376" \ + "\377\375\210\377\377\377\7\376\376\377\377\377\375\376\377\375\376\376" \ + "\376\377\376\377\377\377\377\376\377\377\221\377\377\377\5\376\376\376" \ + "\376\377\377\377\377\377\375\375\375\377\376\377\202\377\377\377\1\377" \ + "\377\375\211\377\377\377\7\377\376\377\376\376\374\376\377\377\377\377" \ + "\377\377\376\377\377\377\375\377\377\373\233\377\377\377\1\376\376\376" \ + "\205\377\377\377\1\376\376\376\203\377\377\377\1\376\376\376\203\377" \ + "\377\377\1\376\376\376\204\377\377\377\3\376\376\376\377\377\377\376" \ + "\376\376\204\377\377\377\1\376\376\376\237\377\377\377\1\376\376\376" \ + "\212\377\377\377\1\376\376\376\213\377\377\377\1\376\376\376\255\377" \ + "\377\377\1\376\376\376\247\377\377\377\1\376\376\376\202\377\377\377" \ + "\1\376\376\376\224\377\377\377\1\376\376\376\247\377\377\377\1\376\376" \ + "\376\236\377\377\377\1\376\376\376\203\377\377\377\1\376\376\376\232" \ + "\377\377\377\10\377\376\377\377\377\375\377\377\377\376\377\377\376\376" \ + "\376\377\376\377\377\377\375\377\376\377\202\377\377\375\1\377\376\377" \ + "\202\377\377\377\3\377\376\377\377\375\376\377\376\377\260\377\377\377" \ + "\2\377\376\377\377\377\377\202\377\376\377\4\377\377\375\376\376\374" \ + "\377\375\377\377\376\377\210\377\377\377\3\376\376\374\377\376\377\376" \ + "\376\376\204\377\377\377\1\376\377\375\210\377\377\377\4\375\377\374" \ + "\377\377\377\377\375\376\377\376\377\203\377\377\377\1\377\377\375\220" \ + "\377\377\377\3\376\377\377\377\377\375\376\377\377\202\377\377\377\3" \ + "\377\376\377\373\377\377\376\377\377\211\377\377\377\202\376\377\375" \ + "\1\377\377\375\203\377\377\377\1\377\376\377\210\377\377\377\3\377\376" \ + "\377\377\375\376\377\376\377\202\377\377\377\1\377\376\377\202\377\377" \ + "\375\10\377\376\377\377\377\375\377\376\377\376\376\376\376\377\377\377" \ + "\377\377\377\377\375\377\376\377\230\377\377\377\3\377\376\377\377\375" \ + "\376\377\376\377\202\377\377\377\1\377\376\377\202\377\377\375\10\377" \ + "\376\377\377\377\375\377\376\377\376\376\376\376\377\377\377\377\377" \ + "\377\377\375\377\376\377\210\377\377\377\2\377\377\375\375\376\371\202" \ + "\377\376\377\3\377\377\377\377\377\375\377\376\377\212\377\377\377\1" \ + "\377\375\376\202\377\377\377\4\377\377\375\376\376\376\376\377\377\377" \ + "\376\377\220\377\377\377\2\376\377\377\376\376\377\202\377\377\377\2" \ + "\376\377\375\375\377\374\212\377\377\377\10\373\377\376\377\377\377\377" \ + "\377\375\376\376\374\377\377\375\377\376\377\377\377\377\376\377\377" \ + "\235\377\377\377\1\376\376\376\202\377\377\377\7\316\316\320\250\250" \ + "\252\221\221\223llnjjlGGI99;\204::<\7TTVkkmyy{\234\234\236\265\265\267" \ + "\332\332\332\376\376\376\237\377\377\377\3\376\376\376\377\377\377\376" \ + "\376\376\222\377\377\377\1\376\376\376\205\377\377\377\3\376\376\376" \ + "\377\377\377\376\376\376\255\377\377\377\1\376\376\376\246\377\377\377" \ + "\1\376\376\376\227\377\377\377\1\376\376\376\252\377\377\377\1\376\376" \ + "\376\233\377\377\377\1\376\376\376\236\377\377\377\17\305\344\240\303" \ + "\342\237\304\343\240\304\343\237\307\342\237\303\342\236\305\342\240" \ + "\303\342\236\305\342\237\304\343\240\304\343\237\304\341\237\304\343" \ + "\237\323\352\266\376\377\375\250\377\377\377\210\305\342\240\10\305\342" \ + "\237\303\342\234\304\343\237\306\341\236\304\343\240\322\352\270\376" \ + "\377\377\375\377\376\211\377\377\377\5\377\376\377\376\376\376\377\376" \ + "\377\360\371\350\305\342\237\202\304\341\236\210\305\342\240\5\304\341" \ + "\236\327\356\302\376\377\377\377\377\373\376\377\375\202\377\377\375" \ + "\1\377\376\377\220\377\377\377\202\377\377\375\2\376\377\377\377\377" \ + "\377\202\377\377\375\2\304\343\237\306\341\236\210\305\342\240\5\307" \ + "\342\237\303\342\236\304\341\236\341\357\314\377\377\375\213\377\377" \ + "\377\17\376\377\375\323\352\266\304\343\237\304\341\237\304\343\237\304" \ + "\343\240\305\342\237\303\342\236\305\342\240\303\342\236\307\342\237" \ + "\304\343\237\304\343\240\303\342\237\305\344\240\231\377\377\377\17\376" \ + "\377\375\323\352\266\304\343\237\304\341\237\304\343\237\304\343\240" \ + "\305\342\237\303\342\236\305\342\240\303\342\236\307\342\237\304\343" \ + "\237\304\343\240\303\342\237\305\344\240\211\377\377\377\10\360\367\347" \ + "\306\343\241\303\342\237\307\342\237\303\342\237\304\343\235\307\341" \ + "\240\304\343\240\210\305\342\240\7\315\347\252\376\377\375\377\375\376" \ + "\376\377\375\377\377\377\377\377\373\376\377\377\221\377\377\377\10\377" \ + "\377\375\376\377\375\323\352\266\307\341\240\307\342\237\305\342\240" \ + "\307\340\236\306\341\236\210\305\342\240\4\304\343\237\311\335\236\377" \ + "\377\377\377\376\377\203\377\377\377\1\376\377\377\230\377\377\377\1" \ + "\376\376\376\203\377\377\377\3\346\346\346\251\251\251jjl\202;;=\210" \ + "::<\1;;=\202::<\2;;=99;\203::<\5FFHxxx\265\265\265\363\363\363\376\376" \ + "\376\234\377\377\377\2\376\376\376\346\346\346\214\234\234\234\1\235" \ + "\235\235\203\234\234\234\3\235\235\235\234\234\234\250\250\250\203\316" \ + "\316\316\1\346\346\346\263\377\377\377\202\250\250\250\245\377\377\377" \ + "\1\316\316\316\222\234\234\234\1\302\302\302\203\316\316\316\1\363\363" \ + "\363\247\377\377\377\3\316\316\316\234\234\234\235\235\235\240\234\234" \ + "\234\1\316\316\316\231\377\377\377\6\215\305>\216\306A\215\305@\213\310" \ + "=\215\305>\212\307>\202\214\305@\6\214\306>\212\306@\214\306<\215\304" \ + "B\214\306>\252\323m\251\377\377\377\210\214\306>\10\215\305@\215\307" \ + "\77\212\307>\217\304@\214\305@\251\323m\377\377\377\377\377\375\213\377" \ + "\377\377\5\377\375\377\341\363\315\215\305>\212\307>\215\305@\210\214" \ + "\306>\6\215\306A\220\305\77\350\365\333\377\377\377\376\377\377\377\376" \ + "\377\202\376\377\377\225\377\377\377\3\377\376\377\214\306>\215\306A" \ + "\210\214\306>\6\215\305>\212\310\77\215\305@\307\341\240\376\377\377" \ + "\377\376\377\213\377\377\377\6\252\323m\214\306>\215\304B\214\306<\212" \ + "\306@\214\306>\202\214\305@\6\212\307>\215\305>\213\310=\215\305@\216" \ + "\306A\215\305>\232\377\377\377\6\252\323m\214\306>\215\304B\214\306<" \ + "\212\306@\214\306>\202\214\305@\6\212\307>\215\305>\213\310=\215\305" \ + "@\216\306A\215\305>\211\377\377\377\4\376\377\377\242\321a\213\307A\215" \ + "\305>\202\214\306>\2\215\305@\215\307\77\210\214\306>\7\215\305<\332" \ + "\354\304\377\377\377\376\377\375\376\376\376\377\376\377\376\376\376" \ + "\221\377\377\377\10\377\376\377\342\362\316\215\305>\213\310\77\212\305" \ + "D\212\307<\216\306\77\211\307>\211\214\306>\4\304\343\240\373\377\376" \ + "\377\377\377\375\377\376\202\377\377\377\1\377\377\375\225\377\377\377" \ + "\1\376\376\376\204\377\377\377\6\265\265\267__a99;;;=::<;;=\202::<\1" \ + ";;=\202::<\1;;=\202::<\1;;=\203::<\1;;=\203::<\3;;=::<99;\202::<\2xx" \ + "z\301\301\301\202\377\377\377\1\376\376\376\202\377\377\377\1\376\376" \ + "\376\206\377\377\377\1\376\376\376\217\377\377\377\1\316\316\316\205" \ + "::<\202;;=\221::<\4TTVwwy\250\250\252\346\346\350\255\377\377\377\1\316" \ + "\316\320\202::<\1\316\316\316\244\377\377\377\1\234\234\236\204::<\1" \ + ";;=\205::<\3;;=::<;;=\206::<\1;;=\204::<\6SSUkkm\204\204\206\250\250" \ + "\250\316\316\316\376\376\376\206\377\377\377\1\376\376\376\231\377\377" \ + "\377\1\234\234\234\206::<\3;;=::<;;=\222::<\1;;=\204::<\3;;=::<\234\234" \ + "\236\231\377\377\377\3\214\305@\214\306>\214\305@\207\214\306>\4\214" \ + "\305@\215\305>\214\306>\252\324p\251\377\377\377\215\214\306>\1\250\325" \ + "p\216\377\377\377\1\342\361\320\202\214\306>\1\214\305@\210\214\306>" \ + "\15\212\306@\215\307\77\233\316W\365\374\364\377\376\375\376\377\377" \ + "\377\376\377\377\377\375\377\377\377\377\377\375\376\376\376\377\377" \ + "\377\376\376\374\202\377\377\377\1\376\376\376\216\377\377\377\213\214" \ + "\306>\3\215\305>\214\306>\305\342\240\215\377\377\377\4\252\324p\214" \ + "\306>\215\305>\214\305@\207\214\306>\3\214\305@\214\306>\214\305@\232" \ + "\377\377\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306>\3\214" \ + "\305@\214\306>\214\305@\212\377\377\377\7\350\364\334\215\305>\212\307" \ + "<\214\305@\215\304B\215\305@\213\310\77\210\214\306>\10\214\305@\225" \ + "\311J\370\373\362\377\376\377\376\377\377\377\377\375\377\377\377\376" \ + "\377\377\210\377\377\377\40\376\377\377\376\377\375\377\376\377\377\377" \ + "\377\375\376\377\377\377\375\377\376\377\376\377\377\370\373\364\233" \ + "\314W\215\307\77\214\304=\212\306@\215\307\77\213\305=\215\307\77\214" \ + "\306>\217\304@\215\306A\212\307>\214\306<\215\306A\214\306>\211\307@" \ + "\242\321a\377\377\377\377\376\377\376\377\377\377\376\377\377\377\377" \ + "\376\377\377\377\376\377\223\377\377\377\7\376\376\376\377\377\377\376" \ + "\376\376\377\377\377\363\363\365\234\234\236FFH\202::<\10;;=99;;;=::" \ + "<;;=::<99;;;=\203::<\1;;=\203::<\2;;=99;\204::<\11""99;;;=::<;;=::<;" \ + ";=TTV\265\265\265\363\363\363\203\377\377\377\1\376\376\376\207\377\377" \ + "\377\1\376\376\376\215\377\377\377\1\316\316\316\205::<\3;;=::<;;=\202" \ + "::<\1;;=\214::<\3;;=99;;;=\202::<\4lln\316\316\316\376\376\376\377\377" \ + "\377\202\376\376\376\246\377\377\377\2\376\376\376xxz\202::<\2xxx\376" \ + "\376\376\243\377\377\377\1\234\234\236\204::<\202;;=\205::<\1;;=\204" \ + "::<\1;;=\202::<\1""99;\206::<\1;;=\202::<\6;;=kkk\250\250\250\346\346" \ + "\346\377\377\377\376\376\376\205\377\377\377\1\376\376\376\225\377\377" \ + "\377\1\234\234\234\204::<\1;;=\202::<\4;;=::<99;;;=\225::<\3;;=::<\234" \ + "\234\236\231\377\377\377\3\214\305@\214\306>\214\305@\207\214\306>\4" \ + "\214\305@\215\305>\214\306>\252\324p\251\377\377\377\215\214\306>\1\250" \ + "\325p\216\377\377\377\1\342\361\320\202\214\306>\1\214\305@\210\214\306" \ + ">\4\215\306A\213\304\77\215\305@\262\327x\202\377\377\377\1\376\377\375" \ + "\203\377\377\375\204\377\377\377\1\376\376\376\217\377\377\377\213\214" \ + "\306>\3\215\305>\214\306>\305\342\240\215\377\377\377\4\252\324p\214" \ + "\306>\215\305>\214\305@\207\214\306>\3\214\305@\214\306>\214\305@\232" \ + "\377\377\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306>\3\214" \ + "\305@\214\306>\214\305@\212\377\377\377\7\376\376\376\305\342\237\212" \ + "\307>\214\306>\212\307<\214\306>\212\307>\210\214\306>\3\214\306<\215" \ + "\306A\300\337\221\202\377\377\377\3\377\376\377\376\376\376\377\377\375" \ + "\210\377\377\377\1\377\375\377\202\377\377\377\2\376\376\377\376\377" \ + "\375\202\377\376\377\30\377\377\377\277\340\221\215\306A\213\305=\215" \ + "\305>\212\306B\214\306>\216\306\77\214\306<\212\307>\215\307=\213\305" \ + ";\215\307\77\216\305C\214\306>\214\305@\216\306\77\347\365\333\377\376" \ + "\377\377\377\375\376\377\377\377\376\374\377\377\377\377\377\375\222" \ + "\377\377\377\1\376\376\376\204\377\377\377\12\265\265\267FFH;;=::<;;" \ + "=99;::<;;=::<;;=\202::<\4<<>99;::<;;=\202::<\1;;=\203::<\1<<>\204::<" \ + "\5<<>99;;;=99;;;=\202::<\4:::SSS\266\266\266\376\376\376\203\377\377" \ + "\377\1\376\376\376\204\377\377\377\1\376\376\376\216\377\377\377\1\316" \ + "\316\316\204::<\3;;=::<;;=\204::<\1;;=\214::<\1;;=\202::<\1;;=\202::" \ + "<\2yyy\363\363\363\202\377\377\377\1\376\376\376\245\377\377\377\3\346" \ + "\346\346::<;;=\202::<\1\347\347\347\202\377\377\377\1\376\376\376\240" \ + "\377\377\377\1\234\234\236\203::<\4;;=99;::<;;=\202::<\7;;=::<;;=99;" \ + ";;=::<;;=\203::<\202;;=\210::<\1""99;\202::<\4;;=xxz\317\317\317\376" \ + "\376\376\202\377\377\377\1\376\376\376\227\377\377\377\1\234\234\234" \ + "\204::<\1""99;\203;;=\224::<\1;;=\204::<\2<<>\234\234\236\231\377\377" \ + "\377\3\214\305@\214\306>\214\305@\207\214\306>\4\214\305@\215\305>\214" \ + "\306>\252\324p\251\377\377\377\215\214\306>\1\250\325p\216\377\377\377" \ + "\1\342\361\320\202\214\306>\1\214\305@\210\214\306>\10\215\305>\214\306" \ + ">\213\307A\214\306>\315\345\253\377\377\375\377\376\377\376\377\377\226" \ + "\377\377\377\213\214\306>\3\215\305>\214\306>\305\342\240\215\377\377" \ + "\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306>\3\214\305@\214" \ + "\306>\214\305@\232\377\377\377\4\252\324p\214\306>\215\305>\214\305@" \ + "\207\214\306>\3\214\305@\214\306>\214\305@\211\377\377\377\7\377\377" \ + "\375\377\376\377\376\376\376\241\321a\212\307>\211\305\77\215\306A\211" \ + "\214\306>\4\213\310\77\214\305@\213\305=\342\361\320\202\377\376\377" \ + "\2\377\377\375\377\376\377\210\377\377\377\1\377\376\377\202\377\377" \ + "\377\30\377\377\375\376\377\377\377\377\375\376\377\377\351\366\334\214" \ + "\305B\211\306;\215\307\77\214\306>\212\306@\215\305>\215\305@\212\307" \ + ">\214\305@\212\306B\214\306>\213\305=\213\310\77\215\305>\215\307\77" \ + "\314\345\253\377\375\377\377\376\374\376\377\377\203\377\377\377\1\377" \ + "\376\374\225\377\377\377\2\345\345\345kkm\205::<\202;;=\203::<\1;;=\203" \ + "::<\1;;=\202::<\202;;=\202::<\1;;=\210::<\2;;=99;\205::<\2```\331\331" \ + "\331\211\377\377\377\1\376\376\376\214\377\377\377\1\316\316\316\206" \ + "::<\5""99;::<;;=::<99;\212::<\1;;=\202::<\1;;=\204::<\4;;=::<FFF\316" \ + "\316\316\247\377\377\377\3\205\205\207;;=99;\202::<\1\204\204\206\203" \ + "\377\377\377\1\376\376\376\237\377\377\377\1\234\234\236\205::<\1;;=" \ + "\204::<\1""99;\202;;=\202::<\3;;=::<;;=\203::<\1;;=\202::<\1;;=\204:" \ + ":<\1;;=\205::<\2jjl\316\316\316\203\377\377\377\1\376\376\376\225\377" \ + "\377\377\1\234\234\234\204::<\1;;=\202::<\3;;=::<;;=\222::<\7;;=::<;" \ + ";=::<;;=::<\234\234\236\231\377\377\377\3\214\305@\214\306>\214\305@" \ + "\207\214\306>\4\214\305@\215\305>\214\306>\252\324p\251\377\377\377\215" \ + "\214\306>\1\250\325p\216\377\377\377\1\342\361\320\202\214\306>\1\214" \ + "\305@\210\214\306>\10\215\305@\212\307>\214\305@\215\306A\214\305@\352" \ + "\364\334\376\376\377\377\377\373\202\377\377\377\3\376\376\376\377\377" \ + "\377\377\377\375\202\377\377\377\1\376\376\374\216\377\377\377\213\214" \ + "\306>\3\215\305>\214\306>\305\342\240\215\377\377\377\4\252\324p\214" \ + "\306>\215\305>\214\305@\207\214\306>\3\214\305@\214\306>\214\305@\232" \ + "\377\377\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306>\3\214" \ + "\305@\214\306>\214\305@\211\377\377\377\1\376\377\377\202\377\377\375" \ + "\5\347\364\332\215\307\77\215\306C\214\307;\216\306\77\210\214\306>\10" \ + "\214\305@\214\305D\215\307\77\233\314V\371\374\363\376\377\377\377\377" \ + "\377\377\377\375\210\377\377\377\20\375\377\374\377\376\377\376\376\377" \ + "\376\377\377\377\376\377\376\377\375\376\377\377\244\317d\212\307>\215" \ + "\306A\215\305@\214\305@\211\306=\215\307=\215\306A\214\305@\204\214\306" \ + ">\14\211\305A\212\307>\251\324k\377\376\377\377\375\376\376\377\377\377" \ + "\377\377\377\377\375\377\377\377\377\377\375\377\377\377\377\377\375" \ + "\217\377\377\377\1\376\376\376\203\377\377\377\2\265\265\267FFH\205:" \ + ":<\1;;=\203::<\202;;=\7:::TTT\203\203\203\235\235\235\316\316\316\332" \ + "\332\332\377\377\377\202\376\376\376\202\377\377\377\5\316\316\316\317" \ + "\317\317\234\234\234yyyFFF\202::<\1;;=\202::<\3""99;;;=99;\204::<\2;" \ + ";=\233\233\233\206\377\377\377\1\376\376\376\216\377\377\377\1\316\316" \ + "\316\204::<\1;;=\205::<\1;;=\212::<\3""99;::<;;=\202::<\2;;=99;\204:" \ + ":<\2;;=\265\265\265\245\377\377\377\4\346\346\346::<99;;;=\202::<\4""9" \ + "9;\347\347\347\377\377\377\376\376\376\240\377\377\377\1\234\234\236" \ + "\205::<\1;;=\203::<\202;;=\1""99;\203;;=\2::<;;=\203::<\1;;=\202::<\2" \ + ";;=::<\202;;=\7::<;;=99;::<;;=99;;;=\202::<\3;;=xxx\362\362\362\227\377" \ + "\377\377\1\234\234\234\205::<\202;;=\4::<;;=::<;;=\223::<\2;;=99;\202" \ + ";;=\1\234\234\236\231\377\377\377\3\214\305@\214\306>\214\305@\207\214" \ + "\306>\4\214\305@\215\305>\214\306>\252\324p\251\377\377\377\215\214\306" \ + ">\1\250\325p\216\377\377\377\1\342\361\320\202\214\306>\1\214\305@\210" \ + "\214\306>\12\212\307>\215\306A\214\305@\215\307\77\213\306:\226\312N" \ + "\372\374\361\375\376\377\377\377\375\377\377\373\224\377\377\377\213" \ + "\214\306>\3\215\305>\214\306>\305\342\240\215\377\377\377\4\252\324p" \ + "\214\306>\215\305>\214\305@\207\214\306>\3\214\305@\214\306>\214\305" \ + "@\232\377\377\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306>" \ + "\3\214\305@\214\306>\214\305@\211\377\377\377\10\376\377\377\376\376" \ + "\377\376\377\377\377\375\376\307\342\237\214\306<\215\306A\214\305@\210" \ + "\214\306>\5\215\307\77\213\305=\216\306A\213\310\77\277\337\223\202\377" \ + "\377\375\1\377\376\377\210\377\377\377\14\376\377\375\376\376\376\377" \ + "\376\377\377\377\375\377\376\377\377\377\377\303\342\236\215\307\77\216" \ + "\306A\215\305>\214\306<\215\306A\203\214\306>\20\215\307\77\212\307>" \ + "\215\305@\216\306\77\214\305@\216\307<\223\312K\356\372\346\377\377\377" \ + "\376\377\377\375\377\376\377\377\377\377\376\377\377\377\375\377\377" \ + "\377\377\377\375\216\377\377\377\1\376\376\376\203\377\377\377\2\375" \ + "\375\375\205\205\207\202::<\202;;=\3::<;;=::<\202;;=\6::<:::SSS\250\250" \ + "\250\346\346\346\376\376\376\216\377\377\377\3\332\332\332\220\220\220" \ + "SSS\202::<\4;;=99;::<;;=\202::<\1""99;\202;;=\2__a\332\332\334\223\377" \ + "\377\377\1\316\316\316\204::<\6;;=RRT\235\235\237\235\235\235\233\233" \ + "\233\234\234\234\212\234\234\236\5xxzkkm__a99;;;=\204::<\202;;=\1""9" \ + "9;\202::<\1\316\316\316\244\377\377\377\4\204\204\206;;=::<;;=\202::" \ + "<\2;;=\220\220\222\203\377\377\377\1\376\376\376\236\377\377\377\1\234" \ + "\234\236\203::<\3;;=::<kkm\203\234\234\236\3\233\233\235\234\234\236" \ + "\235\235\237\204\234\234\236\2xxzlln\202kkm\1FFH\202;;=\2""99;;;=\202" \ + "::<\3""99;::<;;=\202::<\1;;=\205::<\3GGI\301\301\301\376\376\376\225" \ + "\377\377\377\1\234\234\234\205::<\5lln\234\234\236\233\233\233\235\235" \ + "\235\234\234\234\224\234\234\236\5\234\234\234\235\235\235\233\233\233" \ + "\234\234\234\316\316\316\231\377\377\377\3\214\305@\214\306>\214\305" \ + "@\207\214\306>\4\214\305@\215\305>\214\306>\252\324p\251\377\377\377" \ + "\215\214\306>\1\250\325p\216\377\377\377\1\342\361\320\202\214\306>\1" \ + "\214\305@\210\214\306>\7\212\306@\214\306<\217\307@\214\304\77\214\311" \ + ">\214\306>\251\323m\202\376\377\377\4\376\376\374\377\377\375\377\377" \ + "\377\376\376\376\202\377\377\377\1\376\376\376\216\377\377\377\213\214" \ + "\306>\3\215\305>\214\306>\305\342\240\215\377\377\377\4\252\324p\214" \ + "\306>\215\305>\214\305@\207\214\306>\3\214\305@\214\306>\214\305@\232" \ + "\377\377\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306>\3\214" \ + "\305@\214\306>\214\305@\212\377\377\377\7\377\377\375\377\376\377\376" \ + "\377\377\377\376\377\251\323o\211\307>\214\305@\210\214\306>\7\212\307" \ + ">\215\305>\214\305@\214\306>\215\307\77\347\365\334\377\376\377\211\377" \ + "\377\377\2\377\376\377\375\377\374\203\377\376\377\15\352\364\333\212" \ + "\306@\215\306A\214\306>\215\307\77\213\310\77\214\306>\216\306A\215\306" \ + "A\214\306<\212\307>\213\310=\212\307>\202\214\305@\4\214\306>\314\345" \ + "\253\377\376\377\376\377\377\202\377\377\375\6\377\376\377\375\376\377" \ + "\377\377\377\377\376\377\376\377\375\377\376\377\217\377\377\377\3\376" \ + "\376\376\362\362\362lln\20299;\1;;=\204::<\202;;=\6::<\204\204\204\317" \ + "\317\317\376\376\376\377\377\377\376\376\376\206\377\377\377\1\376\376" \ + "\376\213\377\377\377\2\301\301\301kkm\211::<\6;;=FFH\301\301\301\376" \ + "\376\376\377\377\377\376\376\376\217\377\377\377\1\316\316\316\204::" \ + "<\3;;=kkm\376\376\376\221\377\377\377\3\316\316\316\204\204\204FFF\202" \ + "::<\1;;=\202::<\202;;=\2FFH\363\363\363\242\377\377\377\5\364\364\364" \ + "::<;;=99;;;=\203::<\3GGI\363\363\363\376\376\376\240\377\377\377\1\234" \ + "\234\236\205::<\1\234\234\236\210\377\377\377\1\376\376\376\204\377\377" \ + "\377\1\376\376\376\202\377\377\377\6\362\362\362\316\316\316\265\265" \ + "\265\234\234\234kkmFFH\202::<\2;;=99;\205::<\1;;=\202::<\1\221\221\221" \ + "\225\377\377\377\1\234\234\234\205::<\1\234\234\236\202\377\377\377\1" \ + "\376\376\376\225\377\377\377\1\375\375\375\235\377\377\377\3\214\305" \ + "@\214\306>\214\305@\207\214\306>\4\214\305@\215\305>\214\306>\252\324" \ + "p\251\377\377\377\215\214\306>\1\250\325p\216\377\377\377\1\342\361\320" \ + "\202\214\306>\1\214\305@\210\214\306>\4\215\307\77\214\306>\214\304\77" \ + "\214\306>\202\214\305@\6\215\307\77\307\341\240\376\377\375\376\377\377" \ + "\376\376\374\377\377\373\202\377\377\377\202\377\377\375\216\377\377" \ + "\377\213\214\306>\3\215\305>\214\306>\305\342\240\215\377\377\377\4\252" \ + "\324p\214\306>\215\305>\214\305@\207\214\306>\3\214\305@\214\306>\214" \ + "\305@\232\377\377\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306" \ + ">\3\214\305@\214\306>\214\305@\212\377\377\377\7\377\376\377\376\376" \ + "\377\377\377\377\376\376\377\361\372\347\222\312K\215\305>\210\214\306" \ + ">\10\214\305@\215\306A\214\305@\214\306<\213\304A\243\322b\376\376\374" \ + "\376\377\375\211\377\377\377\24\377\377\373\377\377\377\376\377\377\377" \ + "\377\375\242\320c\215\307=\214\306>\213\310\77\213\304A\212\306@\215" \ + "\307\77\215\305@\214\306>\215\307\77\212\306@\215\305>\215\307\77\213" \ + "\310\77\213\306:\253\325q\202\377\377\377\11\377\377\375\377\376\377" \ + "\377\377\377\377\377\375\376\377\375\377\377\375\377\375\377\376\377" \ + "\377\377\377\375\214\377\377\377\7\376\376\376\377\377\377\376\376\376" \ + "\363\363\363__a::<;;=\203::<\202;;=\202::<\4xxz\347\347\351\377\377\377" \ + "\376\376\376\210\377\377\377\1\376\376\376\204\377\377\377\2\376\376" \ + "\376\377\377\377\203\376\376\376\205\377\377\377\2\316\316\320kkm\202" \ + "::<\3;;=::<;;=\202::<\202;;=\2:::\250\250\250\202\377\377\377\1\376\376" \ + "\376\216\377\377\377\1\316\316\316\205::<\1kkm\203\377\377\377\1\376" \ + "\376\376\215\377\377\377\1\376\376\376\202\377\377\377\3\363\363\363" \ + "xxx::<\202;;=\203::<\2;;=xxz\242\377\377\377\1\234\234\234\202::<\1;" \ + ";=\202::<\1;;=\202::<\1\234\234\234\241\377\377\377\1\234\234\236\202" \ + "::<\10;;=::<;;=\234\234\236\377\377\377\376\376\376\377\377\377\376\376" \ + "\376\216\377\377\377\1\376\376\376\203\377\377\377\3\332\332\332\221" \ + "\221\223FFH\205::<\2;;=::<\202;;=\2::<\204\204\204\224\377\377\377\1" \ + "\234\234\234\205::<\3\234\234\236\377\377\377\376\376\376\264\377\377" \ + "\377\3\214\305@\214\306>\214\305@\207\214\306>\4\214\305@\215\305>\214" \ + "\306>\252\324p\251\377\377\377\215\214\306>\1\250\325p\216\377\377\377" \ + "\1\342\361\320\202\214\306>\1\214\305@\210\214\306>\5\216\306\77\212" \ + "\307>\215\307=\212\306@\214\306>\202\215\305>\5\215\305@\345\356\317" \ + "\376\377\375\376\377\377\377\377\375\202\377\377\377\1\377\377\375\217" \ + "\377\377\377\213\214\306>\3\215\305>\214\306>\305\342\240\215\377\377" \ + "\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306>\3\214\305@\214" \ + "\306>\214\305@\232\377\377\377\4\252\324p\214\306>\215\305>\214\305@" \ + "\207\214\306>\3\214\305@\214\306>\214\305@\211\377\377\377\4\376\377" \ + "\377\377\377\377\377\377\375\376\377\377\202\377\377\377\2\315\347\252" \ + "\212\306@\210\214\306>\10\216\306A\212\306@\212\307>\215\305<\213\310" \ + "\77\215\305>\307\341\240\376\377\377\212\377\377\377\10\375\377\374\377" \ + "\377\377\305\342\237\215\305@\212\306@\216\306\77\215\307=\215\305>\202" \ + "\214\306>\24\213\307A\213\310=\215\304B\214\306>\212\306@\215\304B\212" \ + "\307>\225\311K\370\373\362\377\377\377\376\377\375\377\377\375\377\377" \ + "\377\374\377\375\376\376\376\377\377\377\377\377\375\377\376\377\376" \ + "\377\377\377\377\375\211\377\377\377\1\376\376\376\205\377\377\377\1" \ + "___\204::<\1;;=\203::<\2SSS\316\316\316\235\377\377\377\2\317\317\317" \ + "``b\207::<\3;;=::<\204\204\206\220\377\377\377\1\316\316\316\205::<\1" \ + "kkm\226\377\377\377\3\204\204\206::<;;=\205::<\1\316\316\316\232\377" \ + "\377\377\1\376\376\376\205\377\377\377\2\364\364\364FFF\202;;=\202::" \ + "<\6;;=99;;;=::<FFH\363\363\363\240\377\377\377\1\234\234\236\205::<\1" \ + "\234\234\234\226\377\377\377\1\376\376\376\202\377\377\377\3\265\265" \ + "\265RRR:::\202::<\1;;=\202::<\4;;=::<;;=\204\204\204\203\377\377\377" \ + "\1\376\376\376\217\377\377\377\1\234\234\234\205::<\1\234\234\236\266" \ + "\377\377\377\3\214\305@\214\306>\214\305@\207\214\306>\4\214\305@\215" \ + "\305>\214\306>\252\324p\251\377\377\377\215\214\306>\1\250\325p\216\377" \ + "\377\377\1\342\361\320\202\214\306>\1\214\305@\220\214\306>\2\222\313" \ + "J\366\373\364\202\377\376\377\4\377\377\373\376\376\374\376\377\377\377" \ + "\376\377\216\377\377\377\213\214\306>\3\215\305>\214\306>\305\342\240" \ + "\215\377\377\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306>\3" \ + "\214\305@\214\306>\214\305@\232\377\377\377\4\252\324p\214\306>\215\305" \ + ">\214\305@\207\214\306>\3\214\305@\214\306>\214\305@\211\377\377\377" \ + "-\377\377\375\376\377\377\377\377\377\376\376\374\376\377\377\377\376" \ + "\377\376\377\377\252\324p\212\306@\215\305>\212\307<\215\305@\215\305" \ + "<\214\305B\215\305@\214\306<\212\307>\215\305>\214\306>\211\306=\215" \ + "\305>\212\307>\214\306<\350\364\334\374\377\377\377\376\377\376\376\376" \ + "\374\377\375\377\377\377\376\377\375\377\377\375\377\376\377\377\377" \ + "\375\377\377\377\377\376\377\357\367\350\223\312K\213\310\77\215\305" \ + ">\214\306>\215\305>\213\310\77\212\306@\214\306>\215\305@\202\214\306" \ + ">\10\214\305@\216\306=\212\307>\215\305>\333\355\303\376\376\374\377" \ + "\377\377\377\377\375\223\377\377\377\1\376\376\376\203\377\377\377\1" \ + "\203\203\203\206::<\4;;=::<\204\204\206\363\363\363\230\377\377\377\1" \ + "\376\376\376\207\377\377\377\1\235\235\237\202::<\1;;=\203::<\5;;=99" \ + ";;;=\204\204\204\376\376\376\216\377\377\377\1\316\316\316\205::<\1k" \ + "km\227\377\377\377\12\204\204\206::<;;=::<99;;;=::<\204\204\204\377\377" \ + "\377\376\376\376\232\377\377\377\1\376\376\376\203\377\377\377\2\234" \ + "\234\234;;=\203::<\1;;=\204::<\3<<>\250\250\250\376\376\376\237\377\377" \ + "\377\1\234\234\236\205::<\1\234\234\234\231\377\377\377\10\376\376\376" \ + "\377\377\377\265\265\265FFH::<;;=::<;;=\203::<\2;;=\204\204\204\222\377" \ + "\377\377\1\234\234\234\205::<\1\234\234\236\266\377\377\377\3\214\305" \ + "@\214\306>\214\305@\207\214\306>\4\214\305@\215\305>\214\306>\252\324" \ + "p\251\377\377\377\215\214\306>\1\250\325p\216\377\377\377\1\342\361\320" \ + "\202\214\306>\1\214\305@\220\214\306>\4\216\306\77\250\322n\376\377\375" \ + "\376\377\373\222\377\377\377\213\214\306>\3\215\305>\214\306>\305\342" \ + "\240\215\377\377\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306" \ + ">\3\214\305@\214\306>\214\305@\232\377\377\377\4\252\324p\214\306>\215" \ + "\305>\214\305@\207\214\306>\3\214\305@\214\306>\214\305@\211\377\377" \ + "\377\13\376\376\377\376\377\377\377\376\377\376\376\374\374\377\377\377" \ + "\377\375\377\376\377\356\372\346\225\311K\214\306>\213\310=\203\214\306" \ + ">\2\213\310\77\214\306>\202\214\305@\7\214\306<\213\307A\214\304\77\214" \ + "\305B\212\307>\244\317d\377\376\377\202\377\377\377\1\377\375\377\202" \ + "\377\377\377\25\376\377\377\377\376\377\377\377\377\374\377\375\376\376" \ + "\374\253\324n\214\306<\215\307\77\215\305>\211\307@\216\305C\214\305" \ + "@\215\307\77\214\305@\214\306<\212\307<\211\306=\214\306>\214\305@\213" \ + "\307A\263\327}\202\376\377\377\3\377\377\377\377\375\376\377\377\375" \ + "\221\377\377\377\1\376\376\376\203\377\377\377\1\250\250\250\204::<\1" \ + ";;=\202::<\2;;=\264\264\264\202\377\377\377\1\376\376\376\232\377\377" \ + "\377\1\376\376\376\205\377\377\377\2\332\332\332SSS\202::<\1;;=\204:" \ + ":<\4xxx\364\364\364\377\377\377\376\376\376\214\377\377\377\1\316\316" \ + "\316\205::<\1kkm\227\377\377\377\2\363\363\363SSU\202::<\4;;=99;::<;" \ + ";;\202\377\377\377\1\376\376\376\226\377\377\377\1\376\376\376\204\377" \ + "\377\377\11\376\376\376\363\363\363FFH99;;;=::<;;=99;;;=\203::<\4""9" \ + "9;SSU\377\377\377\376\376\376\236\377\377\377\1\234\234\236\205::<\1" \ + "\234\234\234\225\377\377\377\1\376\376\376\204\377\377\377\10\376\376" \ + "\376\377\377\377\363\363\363yyy::<;;=99;;;=\204::<\1\266\266\266\221" \ + "\377\377\377\1\234\234\234\205::<\1\234\234\236\266\377\377\377\3\214" \ + "\305@\214\306>\214\305@\207\214\306>\4\214\305@\215\305>\214\306>\252" \ + "\324p\251\377\377\377\215\214\306>\1\250\325p\216\377\377\377\1\342\361" \ + "\320\202\214\306>\1\214\305@\220\214\306>\4\214\306<\213\307A\275\335" \ + "\222\376\377\377\203\377\377\377\1\377\377\375\216\377\377\377\213\214" \ + "\306>\3\215\305>\214\306>\305\342\240\215\377\377\377\4\252\324p\214" \ + "\306>\215\305>\214\305@\207\214\306>\3\214\305@\214\306>\214\305@\232" \ + "\377\377\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306>\3\214" \ + "\305@\214\306>\214\305@\211\377\377\377\4\377\376\377\376\376\377\377" \ + "\377\377\377\377\375\202\376\377\377\5\377\375\376\377\376\377\315\346" \ + "\255\212\307>\214\305@\202\215\306A\22\214\305@\212\307<\214\305B\214" \ + "\306>\213\307A\214\306>\213\305=\214\306>\215\305>\213\307A\211\310<" \ + "\313\347\254\377\377\375\377\375\377\376\377\377\376\377\373\376\377" \ + "\377\377\376\377\202\376\377\377\10\377\377\377\315\346\254\212\307>" \ + "\212\306@\215\306A\216\306A\212\307>\214\306<\202\215\306A\10\215\306" \ + "C\214\305B\215\307\77\214\306<\214\305@\213\310<\222\310L\372\373\363" \ + "\225\377\377\377\1\376\376\376\202\377\377\377\6\376\376\376\333\333" \ + "\333::<;;=::<;;=\202::<\3;;=FFH\315\315\315\205\377\377\377\1\376\376" \ + "\376\225\377\377\377\202\376\376\376\202\377\377\377\1\376\376\376\202" \ + "\377\377\377\1\376\376\376\202\377\377\377\2\363\363\363xxx\204::<\2" \ + ";;=\203\203\203\220\377\377\377\1\316\316\316\205::<\1kkm\230\377\377" \ + "\377\3\266\266\27099;;;=\204::<\1\316\316\316\230\377\377\377\1\376\376" \ + "\376\202\377\377\377\1\376\376\376\202\377\377\377\3\265\265\267::<;" \ + ";=\204::<\202;;=\202::<\202;;=\1\265\265\265\237\377\377\377\1\234\234" \ + "\236\205::<\1\234\234\234\236\377\377\377\5\234\234\234::<;;=::<;;=\202" \ + "::<\3;;=FFH\332\332\332\220\377\377\377\1\234\234\234\205::<\1\234\234" \ + "\236\266\377\377\377\3\214\305@\214\306>\214\305@\207\214\306>\4\214" \ + "\305@\215\305>\214\306>\252\324p\251\377\377\377\215\214\306>\1\250\325" \ + "p\216\377\377\377\1\342\361\320\202\214\306>\1\214\305@\220\214\306>" \ + "\4\215\307\77\214\304\77\213\310\77\333\355\303\202\377\377\377\1\376" \ + "\377\375\217\377\377\377\213\214\306>\3\215\305>\214\306>\305\342\240" \ + "\215\377\377\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306>\3" \ + "\214\305@\214\306>\214\305@\232\377\377\377\4\252\324p\214\306>\215\305" \ + ">\214\305@\207\214\306>\3\214\305@\214\306>\214\305@\213\377\377\377" \ + "\5\377\377\373\377\376\377\377\377\377\375\377\374\376\377\377\202\376" \ + "\376\376\22\260\331{\212\307>\214\306>\215\305>\215\305@\215\307\77\215" \ + "\307=\214\305@\214\306>\215\306A\214\306>\213\307C\214\306>\214\304;" \ + "\213\307A\222\312K\357\370\345\377\377\375\202\377\377\377\15\377\375" \ + "\376\377\377\375\376\376\376\377\377\375\361\367\351\222\311J\213\310" \ + "\77\214\305B\215\310<\213\305=\216\306\77\212\307<\214\305B\202\214\306" \ + ">\6\216\306\77\215\305@\215\306A\214\305@\215\305<\333\356\301\202\377" \ + "\376\377\3\377\377\375\377\377\377\377\376\377\225\377\377\377\1``b\202" \ + "::<\6;;=::<;;=::<FFH\331\331\333\233\377\377\377\1\376\376\376\202\377" \ + "\377\377\1\376\376\376\206\377\377\377\1\376\376\376\202\377\377\377" \ + "\1\205\205\207\203::<\1\204\204\206\221\377\377\377\1\316\316\316\205" \ + "::<\1kkm\231\377\377\377\1GGI\203;;=\202::<\3\235\235\237\377\377\377" \ + "\376\376\376\233\377\377\377\2\376\376\376SSU\203::<\5;;=99;llnkkm::" \ + "<\202;;=\202::<\1SSU\237\377\377\377\1\234\234\236\205::<\1\234\234\234" \ + "\224\377\377\377\1\376\376\376\205\377\377\377\1\376\376\376\203\377" \ + "\377\377\4\376\376\376\266\266\270::<;;=\203::<\5""99;::<__a\377\377" \ + "\377\376\376\376\216\377\377\377\1\234\234\234\205::<\1\234\234\236\266" \ + "\377\377\377\3\214\305@\214\306>\214\305@\207\214\306>\4\214\305@\215" \ + "\305>\214\306>\252\324p\251\377\377\377\215\214\306>\1\250\325p\216\377" \ + "\377\377\1\342\361\320\202\214\306>\1\214\305@\220\214\306>\10\216\306" \ + "\77\215\306A\214\305@\224\310J\360\371\350\377\377\377\377\376\377\376" \ + "\377\377\216\377\377\377\213\214\306>\3\215\305>\214\306>\305\342\240" \ + "\215\377\377\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306>\3" \ + "\214\305@\214\306>\214\305@\232\377\377\377\4\252\324p\214\306>\215\305" \ + ">\214\305@\207\214\306>\3\214\305@\214\306>\214\305@\212\377\377\377" \ + "\1\377\377\375\202\377\377\377\2\377\376\377\377\377\377\202\376\377" \ + "\377\25\377\377\375\370\373\362\223\312K\212\307>\215\305>\216\306A\212" \ + "\307<\214\305B\215\307\77\214\305@\214\306>\214\305@\212\306@\215\307" \ + "=\216\306A\215\305>\214\306<\252\324n\376\377\377\376\376\376\377\376" \ + "\377\202\377\377\375\4\377\376\377\376\376\377\252\324n\215\306A\202" \ + "\214\306>\21\214\305@\215\307\77\215\305>\212\307>\214\306<\213\304A" \ + "\215\307=\214\304=\215\307\77\212\307>\214\306>\277\337\226\377\376\377" \ + "\376\377\375\377\377\375\377\377\377\376\376\376\225\377\377\377\3\234" \ + "\234\236::<;;=\204::<\4;;=\265\265\267\377\377\377\376\376\376\204\377" \ + "\377\377\202\376\376\376\202\377\377\377\1\376\376\376\225\377\377\377" \ + "\1\376\376\376\203\377\377\377\1\376\376\376\202\377\377\377\1\376\376" \ + "\376\202\377\377\377\3\250\250\250::<\204\204\206\205\377\377\377\1\376" \ + "\376\376\214\377\377\377\1\316\316\316\205::<\1kkm\226\377\377\377\1" \ + "\376\376\376\202\377\377\377\2kkm99;\202::<\4;;=::<\204\204\206\376\376" \ + "\376\202\377\377\377\1\376\376\376\224\377\377\377\1\376\376\376\203" \ + "\377\377\377\2\376\376\376\265\265\265\202::<\1;;=\202::<\3;;=\316\316" \ + "\320\316\316\316\204::<\3;;=::<\266\266\266\236\377\377\377\1\234\234" \ + "\236\205::<\1\234\234\234\226\377\377\377\202\376\376\376\2\377\377\377" \ + "\376\376\376\205\377\377\377\4\376\376\376\251\251\253;;=99;\202::<\4" \ + "<<>99;::<\250\250\252\217\377\377\377\1\234\234\234\205::<\1\234\234" \ + "\236\266\377\377\377\3\214\305@\214\306>\214\305@\207\214\306>\4\214" \ + "\305@\215\305>\214\306>\252\324p\251\377\377\377\215\214\306>\1\250\325" \ + "p\216\377\377\377\1\342\361\320\202\214\306>\1\214\305@\220\214\306>" \ + "\202\214\305@\6\212\306@\215\307\77\243\321d\377\377\375\377\375\377" \ + "\376\377\377\216\377\377\377\213\214\306>\3\215\305>\214\306>\305\342" \ + "\240\215\377\377\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306" \ + ">\3\214\305@\214\306>\214\305@\232\377\377\377\4\252\324p\214\306>\215" \ + "\305>\214\305@\207\214\306>\3\214\305@\214\306>\214\305@\211\377\377" \ + "\377\2\376\377\377\377\377\375\202\377\377\377\1\376\376\376\202\377" \ + "\377\377\6\376\377\372\376\377\377\377\376\377\331\357\301\213\304\77" \ + "\215\307=\202\214\305@\25\214\305B\214\306<\215\305@\212\307<\214\306" \ + ">\216\306=\212\307>\212\306B\214\305@\215\306E\212\306@\313\347\255\376" \ + "\377\375\376\376\377\376\377\377\377\376\377\377\377\377\333\355\305" \ + "\212\307>\216\306\77\215\307\77\202\214\306>\1\215\307\77\202\214\306" \ + ">\13\215\305<\212\306@\212\307<\215\307\77\211\306=\213\307A\233\314" \ + "V\370\373\362\377\377\375\377\377\377\376\377\377\202\377\377\375\2\374" \ + "\377\377\377\375\376\222\377\377\377\3\363\363\363GGI::<\202;;=\202:" \ + ":<\2;;=\234\234\234\214\377\377\377\1\376\376\376\221\377\377\377\1\376" \ + "\376\376\202\377\377\377\3\376\376\376\377\377\377\376\376\376\206\377" \ + "\377\377\3\376\376\376\377\377\377\316\316\316\203\377\377\377\1\376" \ + "\376\376\203\377\377\377\1\376\376\376\213\377\377\377\1\316\316\316" \ + "\205::<\1kkm\227\377\377\377\5\376\376\376\377\377\377\235\235\237::" \ + "<;;=\203::<\2lln\376\376\376\203\377\377\377\1\376\376\376\224\377\377" \ + "\377\13\376\376\376\377\377\377\376\376\376\377\377\377RRR::<99;::<;" \ + ";=::<kkm\202\377\377\377\1__a\203;;=\202::<\1kkk\236\377\377\377\1\234" \ + "\234\236\205::<\1\234\234\234\241\377\377\377\2\204\204\204;;=\202::" \ + "<\5""99;::<;;=FFH\363\363\363\216\377\377\377\1\234\234\234\205::<\1" \ + "\234\234\236\266\377\377\377\3\214\305@\214\306>\214\305@\207\214\306" \ + ">\4\214\305@\215\305>\214\306>\252\324p\251\377\377\377\215\214\306>" \ + "\1\250\325p\216\377\377\377\1\342\361\320\202\214\306>\1\214\305@\221" \ + "\214\306>\5\213\307A\216\306\77\212\307<\214\306>\277\337\223\220\377" \ + "\377\377\213\214\306>\3\215\305>\214\306>\305\342\240\215\377\377\377" \ + "\4\252\324p\214\306>\215\305>\214\305@\207\214\306>\3\214\305@\214\306" \ + ">\214\305@\232\377\377\377\4\252\324p\214\306>\215\305>\214\305@\207" \ + "\214\306>\3\214\305@\214\306>\214\305@\211\377\377\377\4\376\377\377" \ + "\377\377\375\377\375\377\377\377\377\202\377\377\375\202\377\376\377" \ + "\202\376\377\377\22\377\376\377\262\331~\213\304\77\213\310\77\216\306" \ + "A\212\307<\215\306A\214\304=\213\310\77\214\305@\215\304B\214\305B\214" \ + "\306<\212\307>\212\307<\216\306A\221\312I\370\373\362\203\377\377\377" \ + "\13\370\373\364\226\310K\214\306>\212\307>\215\304B\214\306>\215\306" \ + "A\213\304\77\215\306A\214\306>\215\305@\202\212\306@\13\215\307\77\213" \ + "\310=\220\303@\336\362\315\377\376\377\377\377\377\374\377\377\377\376" \ + "\377\377\377\377\376\376\374\376\377\375\223\377\377\377\1\204\204\206" \ + "\203::<\4""99;;;=::<kkm\211\377\377\377\1\376\376\376\202\377\377\377" \ + "\1\376\376\376\221\377\377\377\1\376\376\376\202\377\377\377\1\376\376" \ + "\376\237\377\377\377\1\316\316\316\205::<\1kkm\231\377\377\377\4\234" \ + "\234\236;;=::<;;=\202::<\3jjl\377\377\377\376\376\376\232\377\377\377" \ + "\10\265\265\265:::::<;;=::<99;::<\316\316\316\202\377\377\377\1\265\265" \ + "\267\204::<\3;;=::<\316\316\316\235\377\377\377\1\234\234\236\205::<" \ + "\1\234\234\234\241\377\377\377\2\363\363\363__a\203::<\4;;=::<;;=\234" \ + "\234\236\216\377\377\377\1\234\234\234\205::<\1\234\234\236\266\377\377" \ + "\377\3\214\305@\214\306>\214\305@\207\214\306>\4\214\305@\215\305>\214" \ + "\306>\252\324p\251\377\377\377\215\214\306>\1\250\325p\216\377\377\377" \ + "\1\342\361\320\202\214\306>\1\214\305@\220\214\306>\10\215\304B\214\306" \ + "<\214\305@\215\305@\212\306@\215\305>\323\354\265\377\376\377\216\377" \ + "\377\377\213\214\306>\3\215\305>\214\306>\305\342\240\215\377\377\377" \ + "\4\252\324p\214\306>\215\305>\214\305@\207\214\306>\3\214\305@\214\306" \ + ">\214\305@\232\377\377\377\4\252\324p\214\306>\215\305>\214\305@\207" \ + "\214\306>\3\214\305@\214\306>\214\305@\212\377\377\377\3\375\377\376" \ + "\377\377\377\377\377\375\202\377\377\377\26\377\377\375\375\377\374\376" \ + "\377\377\377\376\377\377\377\375\365\375\362\225\311K\212\306@\214\306" \ + ">\214\305@\212\306@\216\306=\211\306;\215\306A\214\306>\215\307\77\217" \ + "\304@\214\306>\212\307>\215\305@\214\305@\262\327z\203\377\377\377\13" \ + "\260\331{\213\310\77\214\305B\214\305@\215\305@\215\307\77\212\307<\216" \ + "\306A\213\305;\214\305@\215\305>\202\214\306>\11\215\305@\214\306<\276" \ + "\340\224\377\376\375\377\377\375\376\377\377\377\376\375\376\377\375" \ + "\377\376\377\202\377\377\377\1\376\377\375\221\377\377\377\1\346\346" \ + "\346\206::<\2:::\346\346\346\202\377\377\377\1\376\376\376\276\377\377" \ + "\377\1\316\316\316\205::<\1kkm\216\377\377\377\1\376\376\376\202\377" \ + "\377\377\1\376\376\376\207\377\377\377\3\234\234\236::<;;=\203::<\1k" \ + "km\226\377\377\377\1\376\376\376\204\377\377\377\2\376\376\376lln\205" \ + "::<\1``b\204\377\377\377\1SSS\205::<\1kkm\235\377\377\377\1\234\234\236" \ + "\205::<\1\234\234\234\242\377\377\377\2\316\316\316:::\202::<\5;;=::" \ + "<;;=FFH\363\363\363\206\377\377\377\1\376\376\376\206\377\377\377\1\234" \ + "\234\234\205::<\1\234\234\236\266\377\377\377\3\214\305@\214\306>\214" \ + "\305@\207\214\306>\4\214\305@\215\305>\214\306>\252\324p\251\377\377" \ + "\377\215\214\306>\1\250\325p\216\377\377\377\1\342\361\320\202\214\306" \ + ">\1\214\305@\210\214\306>\27\215\306A\212\307>\215\305>\215\305@\215" \ + "\307=\217\304B\214\306<\214\305@\215\307\77\215\305@\215\307\77\214\305" \ + "@\216\306\77\211\310<\226\312L\347\364\332\377\377\377\377\376\377\377" \ + "\377\375\374\377\377\377\376\377\376\376\376\376\377\377\207\377\377" \ + "\377\213\214\306>\3\215\305>\214\306>\305\342\240\215\377\377\377\4\252" \ + "\324p\214\306>\215\305>\214\305@\207\214\306>\3\214\305@\214\306>\214" \ + "\305@\232\377\377\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306" \ + ">\3\214\305@\214\306>\214\305@\221\377\377\377\1\377\377\375\203\377" \ + "\377\377\5\333\355\303\214\306>\212\307<\216\306A\214\305@\202\214\306" \ + ">\15\215\305@\214\306>\212\306@\213\310\77\215\305>\216\306A\211\306" \ + "=\212\306@\212\307<\334\354\305\377\377\375\335\354\303\212\307>\210" \ + "\214\306>\10\216\306A\212\307;\215\306A\216\306A\214\305@\241\321a\371" \ + "\374\361\375\376\377\223\377\377\377\1\376\376\376\204\377\377\377\2" \ + "\376\376\376\234\234\234\203::<\1""99;\202::<\1\234\234\234\302\377\377" \ + "\377\1\316\316\316\205::<\1kkm\217\377\377\377\1\376\376\376\202\377" \ + "\377\377\3\376\376\376\377\377\377\376\376\376\202\377\377\377\3\376" \ + "\376\376\377\377\377xxz\202::<\5""99;::<;;=xxz\376\376\377\232\377\377" \ + "\377\3\317\317\31799;;;=\202::<\5;;=::<\265\265\265\377\377\377\376\376" \ + "\376\202\377\377\377\2\265\265\265;;=\202::<\203;;=\1\332\332\332\203" \ + "\377\377\377\1\376\376\376\230\377\377\377\1\234\234\236\205::<\1\234" \ + "\234\234\242\377\377\377\4\376\376\376\204\204\204::<;;=\202::<\3;;=" \ + "::<\266\266\266\207\377\377\377\1\376\376\376\205\377\377\377\1\234\234" \ + "\234\205::<\1\234\234\236\266\377\377\377\3\214\305@\214\306>\214\305" \ + "@\207\214\306>\4\214\305@\215\305>\214\306>\252\324p\251\377\377\377" \ + "\215\214\306>\1\250\325p\216\377\377\377\1\342\361\320\202\214\306>\1" \ + "\214\305@\211\214\306>\27\216\306A\214\306>\212\306@\214\306<\213\310" \ + "\77\215\305@\215\307\77\213\305=\216\306\77\212\307;\212\306@\215\305" \ + ">\215\306A\212\307>\245\320d\367\375\361\376\377\377\377\376\377\377" \ + "\377\377\376\376\377\377\376\377\375\377\376\377\377\375\206\377\377" \ + "\377\213\214\306>\3\215\305>\214\306>\305\342\240\215\377\377\377\4\252" \ + "\324p\214\306>\215\305>\214\305@\207\214\306>\3\214\305@\214\306>\214" \ + "\305@\232\377\377\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306" \ + ">\3\214\305@\214\306>\214\305@\221\377\377\377\6\376\376\376\377\376" \ + "\377\377\377\377\375\377\376\376\377\377\270\333\207\203\214\306>\17" \ + "\211\306=\212\307<\214\306<\214\305@\215\307\77\214\305@\216\305C\214" \ + "\306>\212\310A\215\305@\216\306\77\223\312K\360\371\346\222\311I\214" \ + "\305@\210\214\306>\10\214\305@\212\307>\214\305@\216\306A\215\307=\350" \ + "\364\334\375\377\376\377\376\377\225\377\377\377\7\376\376\376\377\377" \ + "\377\376\376\376\377\377\377SSS::<;;=\203::<\5FFH\364\364\364\376\376" \ + "\376\377\377\377\376\376\376\277\377\377\377\1\316\316\316\205::<\1k" \ + "km\222\377\377\377\1\376\376\376\204\377\377\377\3\376\376\376\377\377" \ + "\377SSU\205::<\1\234\234\236\202\377\377\377\1\376\376\376\202\377\377" \ + "\377\1\376\376\376\220\377\377\377\1\376\376\376\204\377\377\377\2kk" \ + "m;;=\202::<\5;;=::<SSU\377\377\377\376\376\376\204\377\377\377\7SSU:" \ + ":<;;=::<;;=::<\205\205\205\234\377\377\377\1\234\234\236\205::<\1\234" \ + "\234\234\240\377\377\377\1\376\376\376\202\377\377\377\1\346\346\346" \ + "\202::<\1;;=\202::<\2;;=__a\205\377\377\377\1\376\376\376\202\377\377" \ + "\377\1\376\376\376\204\377\377\377\1\234\234\234\205::<\1\234\234\236" \ + "\266\377\377\377\3\214\305@\214\306>\214\305@\207\214\306>\4\214\305" \ + "@\215\305>\214\306>\252\324p\251\377\377\377\215\214\306>\1\250\325p" \ + "\216\377\377\377\1\342\361\320\202\214\306>\1\214\305@\211\214\306>\27" \ + "\214\304=\215\305>\213\307A\212\306@\214\305B\215\305<\213\310=\215\307" \ + "\77\215\304B\214\306<\213\307A\215\305>\216\306A\212\306@\212\307>\270" \ + "\332\204\377\376\377\377\377\377\377\376\377\376\376\374\377\377\373" \ + "\377\376\377\377\377\375\206\377\377\377\213\214\306>\3\215\305>\214" \ + "\306>\305\342\240\215\377\377\377\4\252\324p\214\306>\215\305>\214\305" \ + "@\207\214\306>\3\214\305@\214\306>\214\305@\232\377\377\377\4\252\324" \ + "p\214\306>\215\305>\214\305@\207\214\306>\3\214\305@\214\306>\214\305" \ + "@\223\377\377\377\1\377\377\375\202\377\377\377\2\371\372\364\232\315" \ + "W\202\214\305@\4\214\306<\215\307\77\214\305B\215\306C\202\215\306A\1" \ + "\214\306<\202\212\307>\6\215\305@\212\307>\215\305>\212\306B\216\306" \ + "A\212\307>\210\214\306>\10\214\305B\215\307\77\214\306<\214\306>\304" \ + "\341\237\377\377\377\377\376\377\377\377\375\220\377\377\377\1\376\376" \ + "\376\203\377\377\377\1\376\376\376\203\377\377\377\10\301\301\301::<" \ + ";;=99;;;=::<99;\234\234\236\207\377\377\377\1\376\376\376\273\377\377" \ + "\377\1\316\316\316\205::<\1kkm\216\377\377\377\1\376\376\376\202\377" \ + "\377\377\1\376\376\376\204\377\377\377\3\376\376\376\377\377\377\315" \ + "\315\315\202;;=\203::<\6;;=\265\265\267\377\377\377\376\376\376\377\377" \ + "\377\376\376\376\225\377\377\377\2\376\376\376\317\317\317\203::<\4;" \ + ";=::<;;=\264\264\264\206\377\377\377\10\234\234\234;;=::<;;=99;;;=::" \ + "<\346\346\346\233\377\377\377\1\234\234\236\205::<\1\234\234\234\237" \ + "\377\377\377\1\376\376\376\204\377\377\377\1\204\204\206\202::<\6;;=" \ + "99;;;=::<\346\346\346\376\376\376\204\377\377\377\3\376\376\376\377\377" \ + "\377\376\376\376\204\377\377\377\1\234\234\234\205::<\1\234\234\236\266" \ + "\377\377\377\3\214\305@\214\306>\214\305@\207\214\306>\4\214\305@\215" \ + "\305>\214\306>\252\324p\251\377\377\377\215\214\306>\1\250\325p\216\377" \ + "\377\377\1\342\361\320\202\214\306>\1\214\305@\210\214\306>\22\215\307" \ + "\77\212\307>\216\306A\212\304<\215\307\77\215\305@\216\306\77\213\307" \ + "A\214\306>\214\305@\215\307\77\213\310=\212\307>\214\306>\214\306<\214" \ + "\306>\216\306\77\324\353\267\202\376\376\376\3\377\377\377\376\376\377" \ + "\376\377\375\207\377\377\377\213\214\306>\3\215\305>\214\306>\305\342" \ + "\240\215\377\377\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306" \ + ">\3\214\305@\214\306>\214\305@\232\377\377\377\4\252\324p\214\306>\215" \ + "\305>\214\305@\207\214\306>\3\214\305@\214\306>\214\305@\221\377\377" \ + "\377\3\376\377\377\377\377\377\376\377\375\202\377\377\377\7\377\376" \ + "\377\341\363\315\215\305@\214\305@\215\306A\215\305@\216\306\77\202\214" \ + "\306>\12\214\305B\212\307<\213\304A\213\310=\216\306A\211\306;\213\310" \ + "=\214\305@\212\307>\215\305>\210\214\306>\10\215\307\77\214\304=\212" \ + "\307>\243\322b\377\377\377\376\377\377\377\376\377\377\377\375\226\377" \ + "\377\377\4\376\376\376\377\377\377\204\204\206;;=\203::<\3""99;;;=\364" \ + "\364\364\205\377\377\377\1\376\376\376\275\377\377\377\1\316\316\316" \ + "\205::<\1kkm\217\377\377\377\202\376\376\376\202\377\377\377\1\376\376" \ + "\376\203\377\377\377\4\376\376\376xxz;;=99;\202;;=\4::<;;=\346\346\346" \ + "\376\376\376\204\377\377\377\1\376\376\376\224\377\377\377\1xxz\203:" \ + ":<\3;;=::<SSU\203\377\377\377\1\376\376\376\203\377\377\377\2\363\363" \ + "\363FFH\202::<\4;;=99;::<\204\204\206\233\377\377\377\1\234\234\236\205" \ + "::<\1\234\234\234\244\377\377\377\1\316\316\316\202;;=\5::<;;=99;;;=" \ + "\250\250\252\203\377\377\377\1\376\376\376\210\377\377\377\1\234\234" \ + "\234\205::<\1\234\234\236\266\377\377\377\3\214\305@\214\306>\214\305" \ + "@\207\214\306>\4\214\305@\215\305>\214\306>\252\324p\251\377\377\377" \ + "\215\214\306>\1\250\325p\216\377\377\377\1\342\361\320\202\214\306>\1" \ + "\214\305@\210\214\306>\7\213\305=\214\306<\210\306\77\216\306\77\215" \ + "\307=\214\306>\215\307\77\202\214\306>\14\215\307\77\214\305B\214\306" \ + "<\212\307<\214\305@\216\306\77\215\305>\214\305@\224\313L\352\364\331" \ + "\374\377\377\377\376\377\211\377\377\377\213\214\306>\3\215\305>\214" \ + "\306>\305\342\240\215\377\377\377\4\252\324p\214\306>\215\305>\214\305" \ + "@\207\214\306>\3\214\305@\214\306>\214\305@\232\377\377\377\4\252\324" \ + "p\214\306>\215\305>\214\305@\207\214\306>\3\214\305@\214\306>\214\305" \ + "@\222\377\377\377\1\376\377\377\202\377\377\377\24\376\376\374\376\377" \ + "\375\377\375\377\277\337\224\214\306>\212\307>\215\307\77\214\304=\215" \ + "\307=\213\304A\214\306<\212\307>\215\307\77\214\305@\213\304\77\215\307" \ + "\77\215\305@\214\304=\215\305<\215\306A\210\214\306>\1\212\307>\202\215" \ + "\306A\4\350\365\333\377\375\376\377\376\377\375\376\377\226\377\377\377" \ + "\1\376\376\376\202\377\377\377\3TTV::<99;\202;;=\4::<\203\203\203\377" \ + "\377\377\376\376\376\302\377\377\377\1\316\316\316\205::<\1kkm\222\377" \ + "\377\377\1\376\376\376\204\377\377\377\3\300\300\302;;=::<\202;;=\202" \ + "::<\2```\376\376\376\227\377\377\377\7\376\376\376\377\377\377\346\346" \ + "\346;;=99;::<;;=\202::<\3\251\251\251\377\377\377\376\376\376\206\377" \ + "\377\377\1\234\234\234\202::<\1;;=\202::<\2;;=\346\346\346\232\377\377" \ + "\377\1\234\234\236\205::<\1\234\234\234\235\377\377\377\1\376\376\376" \ + "\207\377\377\377\11SSU::<;;=99;<<>::<xxz\377\377\377\376\376\376\212" \ + "\377\377\377\1\234\234\234\205::<\1\234\234\236\266\377\377\377\3\214" \ + "\305@\214\306>\214\305@\207\214\306>\4\214\305@\215\305>\214\306>\252" \ + "\324p\251\377\377\377\215\214\306>\1\250\325p\216\377\377\377\1\342\361" \ + "\320\202\214\306>\1\214\305@\210\214\306>\25\213\307A\216\306A\232\315" \ + "W\215\306C\212\306@\214\305@\212\307;\216\306A\215\305>\215\307\77\214" \ + "\305@\215\307\77\214\306>\214\305@\212\306B\213\307C\214\306>\215\305" \ + "@\232\315V\372\374\367\376\376\376\202\377\377\375\1\376\376\376\206" \ + "\377\377\377\213\214\306>\3\215\305>\214\306>\305\342\240\215\377\377" \ + "\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306>\3\214\305@\214" \ + "\306>\214\305@\232\377\377\377\4\252\324p\214\306>\215\305>\214\305@" \ + "\207\214\306>\3\214\305@\214\306>\214\305@\221\377\377\377\5\377\376" \ + "\377\376\377\377\377\375\376\377\376\377\376\377\377\202\377\377\377" \ + "\10\370\373\362\233\314V\213\307A\211\306=\215\307\77\212\307<\212\306" \ + "@\215\305<\202\214\306>\7\215\307=\215\306A\214\305@\212\307>\216\306" \ + "A\212\306@\215\307=\210\214\306>\10\212\307>\212\307<\313\347\254\376" \ + "\377\377\377\377\377\377\376\377\376\377\377\377\377\375\223\377\377" \ + "\377\1\376\376\376\203\377\377\377\1\332\332\332\202::<\1;;=\203::<\1" \ + "\302\302\302\203\377\377\377\5\376\376\376\377\377\377\376\376\376\377" \ + "\377\377\376\376\376\274\377\377\377\1\316\316\316\205::<\1kkm\217\377" \ + "\377\377\1\376\376\376\206\377\377\377\3\332\332\334FFH;;=\205::<\1\265" \ + "\265\265\202\377\377\377\1\376\376\376\224\377\377\377\1\376\376\376" \ + "\202\377\377\377\1\205\205\207\202::<\1;;=\202::<\2GGI\363\363\363\202" \ + "\377\377\377\1\376\376\376\205\377\377\377\1\363\363\363\202::<\1;;=" \ + "\202::<\2""99;\234\234\234\203\377\377\377\1\376\376\376\226\377\377" \ + "\377\1\234\234\236\205::<\1\234\234\234\234\377\377\377\1\376\376\376" \ + "\210\377\377\377\3\222\222\222::<99;\202;;=\5""99;GGI\376\376\376\377" \ + "\377\377\376\376\376\211\377\377\377\1\234\234\234\205::<\1\234\234\236" \ + "\266\377\377\377\3\214\305@\214\306>\214\305@\207\214\306>\4\214\305" \ + "@\215\305>\214\306>\252\324p\251\377\377\377\215\214\306>\1\250\325p" \ + "\216\377\377\377\1\342\361\320\202\214\306>\1\214\305@\210\214\306>\10" \ + "\213\307A\214\306>\331\356\303\232\315W\215\305>\215\306A\214\305B\214" \ + "\306>\202\214\305@\7\213\310=\214\306>\215\304B\215\306A\211\306;\213" \ + "\310\77\214\305@\202\215\307\77\2\257\326{\376\377\373\202\377\377\377" \ + "\1\377\377\375\206\377\377\377\213\214\306>\3\215\305>\214\306>\305\342" \ + "\240\215\377\377\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306" \ + ">\3\214\305@\214\306>\214\305@\232\377\377\377\4\252\324p\214\306>\215" \ + "\305>\214\305@\207\214\306>\3\214\305@\214\306>\214\305@\221\377\377" \ + "\377\6\377\377\373\377\377\375\377\377\377\376\376\377\377\376\377\373" \ + "\377\374\202\377\376\377\4\336\362\315\220\303@\213\310=\215\307\77\202" \ + "\212\306@\1\215\305@\202\214\306>\7\213\305=\214\306>\213\305=\214\305" \ + "@\213\310\77\212\306@\213\307A\210\214\306>\10\215\307\77\252\324p\377" \ + "\377\375\376\377\377\377\377\375\377\377\377\377\376\377\377\377\375" \ + "\220\377\377\377\1\376\376\376\203\377\377\377\1\376\376\376\202\377" \ + "\377\377\1\265\265\265\204::<\5;;=::<\363\363\363\377\377\377\376\376" \ + "\376\302\377\377\377\1\316\316\316\205::<\1kkm\225\377\377\377\2\317" \ + "\317\317FFH\206::<\1SSU\204\377\377\377\1\376\376\376\225\377\377\377" \ + "\2\346\346\346;;=\203::<\3;;=::<\234\234\236\202\377\377\377\1\376\376" \ + "\376\207\377\377\377\2\204\204\206;;=\204::<\2FFF\362\362\362\231\377" \ + "\377\377\1\234\234\236\205::<\1\234\234\234\245\377\377\377\1\301\301" \ + "\301\202::<\6;;=::<;;=::<\347\347\347\376\376\376\212\377\377\377\1\234" \ + "\234\234\205::<\1\234\234\236\266\377\377\377\3\214\305@\214\306>\214" \ + "\305@\207\214\306>\4\214\305@\215\305>\214\306>\252\324p\251\377\377" \ + "\377\215\214\306>\1\250\325p\216\377\377\377\1\342\361\320\202\214\306" \ + ">\1\214\305@\210\214\306>\27\214\305@\215\305<\342\362\315\353\365\334" \ + "\223\312K\215\305<\212\306@\215\305<\212\307>\215\306A\214\306>\212\307" \ + ">\215\307\77\215\304B\215\307\77\215\305@\214\306>\215\305>\214\305@" \ + "\215\305<\315\345\253\377\377\375\376\377\377\207\377\377\377\213\214" \ + "\306>\3\215\305>\214\306>\305\342\240\215\377\377\377\4\252\324p\214" \ + "\306>\215\305>\214\305@\207\214\306>\3\214\305@\214\306>\214\305@\232" \ + "\377\377\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306>\3\214" \ + "\305@\214\306>\214\305@\221\377\377\377\14\376\377\377\376\376\377\377" \ + "\377\377\377\377\373\376\377\375\377\376\377\376\377\377\377\377\377" \ + "\377\376\375\276\340\224\214\306<\215\305@\202\214\306>\12\215\305>\214" \ + "\305@\215\305@\214\305@\213\310\77\214\306>\216\306\77\211\305\77\215" \ + "\307=\214\305@\210\214\306>\4\223\312K\360\367\347\377\377\377\377\377" \ + "\375\232\377\377\377\2\376\376\376\234\234\236\204::<\2;;=___\234\377" \ + "\377\377\1\376\376\376\203\377\377\377\1\376\376\376\244\377\377\377" \ + "\1\316\316\316\205::<\1kkm\202\377\377\377\1\376\376\376\216\377\377" \ + "\377\4\376\376\376\377\377\377\347\347\347\204\204\204\203::<\6;;=::" \ + "<;;=::<;;=\301\301\303\226\377\377\377\1\376\376\376\203\377\377\377" \ + "\1\203\203\205\202;;=\5::<;;=::<GGG\363\363\363\206\377\377\377\1\376" \ + "\376\376\203\377\377\377\3\347\347\34799;;;=\202::<\202;;=\1\234\234" \ + "\236\231\377\377\377\1\234\234\236\205::<\1\234\234\234\245\377\377\377" \ + "\1\363\363\363\202::<\1""99;\203::<\1\316\316\316\213\377\377\377\1\234" \ + "\234\234\204::<\2;;=kkm\203\234\234\236\2\235\235\237\234\234\234\220" \ + "\234\234\236\204\234\234\234\4\235\235\235\234\234\234\234\234\236\346" \ + "\346\350\231\377\377\377\3\214\305@\214\306>\214\305@\207\214\306>\4" \ + "\214\305@\215\305>\214\306>\252\324p\251\377\377\377\215\214\306>\1\250" \ + "\325p\216\377\377\377\1\342\361\320\202\214\306>\1\214\305@\210\214\306" \ + ">\40\213\307A\215\305>\341\360\317\377\375\376\324\353\267\215\304B\214" \ + "\306>\215\307=\214\305@\212\307>\212\307<\215\305<\215\306A\214\306>" \ + "\214\306<\212\306@\214\305@\215\307\77\216\306=\212\306B\214\306>\352" \ + "\364\333\377\376\377\377\377\377\377\376\377\377\377\377\377\377\375" \ + "\376\377\373\375\376\377\377\376\377\214\306>\215\307\77\211\214\306" \ + ">\3\215\305>\214\306>\305\342\240\215\377\377\377\4\252\324p\214\306" \ + ">\215\305>\214\305@\207\214\306>\3\214\305@\214\306>\214\305@\232\377" \ + "\377\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306>\3\214\305" \ + "@\214\306>\214\305@\232\377\377\377\7\374\377\375\242\321a\216\306A\212" \ + "\307>\214\306>\215\307\77\212\307<\210\214\306>\16\215\307\77\214\307" \ + ";\213\304\77\216\306A\214\305B\215\307\77\215\305>\212\307>\320\345\254" \ + "\374\377\377\377\376\377\377\377\375\377\376\377\375\377\372\223\377" \ + "\377\377\1\376\376\376\203\377\377\377\3\376\376\376\377\377\377kkm\203" \ + "::<\3<<>::<\221\221\221\305\377\377\377\1\316\316\316\204::<\2;;=jjl" \ + "\217\377\377\377\16\316\316\316\300\300\300\234\234\234__a::<;;=::<;" \ + ";=::<99;;;=::<;;=\204\204\206\232\377\377\377\1\362\362\362\202;;=\202" \ + "::<\3""99;::<\235\235\235\212\377\377\377\12\376\376\376\377\377\377" \ + "\205\205\20799;;;=::<;;=::<GGI\376\376\376\230\377\377\377\1\234\234" \ + "\236\205::<\1\234\234\234\246\377\377\377\10EEG::<;;=::<99;;;=\234\234" \ + "\234\377\377\377\202\376\376\376\202\377\377\377\1\376\376\376\205\377" \ + "\377\377\1\234\234\234\205::<\2;;=99;\202;;=\2""99;;;=\221::<\1""99;" \ + "\203::<\3;;=::<\316\316\316\231\377\377\377\3\214\305@\214\306>\214\305" \ + "@\207\214\306>\4\214\305@\215\305>\214\306>\252\324p\251\377\377\377" \ + "\215\214\306>\1\250\325p\216\377\377\377\1\342\361\320\202\214\306>\1" \ + "\214\305@\210\214\306>\202\214\306<\32\342\361\322\377\377\377\377\377" \ + "\375\266\334\205\212\306B\215\307\77\212\306@\220\306=\214\306>\215\307" \ + "\77\214\305B\213\305=\216\306\77\215\307\77\215\305<\212\306B\215\306" \ + "A\215\305@\216\306=\232\315V\371\373\360\377\377\375\377\377\377\375" \ + "\376\377\377\375\377\376\376\377\202\377\377\377\2\214\305@\212\307>" \ + "\211\214\306>\3\215\305>\214\306>\305\342\240\215\377\377\377\4\252\324" \ + "p\214\306>\215\305>\214\305@\207\214\306>\3\214\305@\214\306>\214\305" \ + "@\232\377\377\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306>" \ + "\3\214\305@\214\306>\214\305@\233\377\377\377\5\347\365\334\211\306=" \ + "\215\305>\216\306=\214\305@\211\214\306>\2\215\304B\212\307>\202\214" \ + "\306>\14\215\306A\214\306<\215\305@\252\324p\374\377\377\377\377\377" \ + "\377\375\376\377\376\377\376\376\377\377\377\375\377\377\377\377\375" \ + "\377\222\377\377\377\1\376\376\376\203\377\377\377\4\376\376\376lln:" \ + ":<;;=\203::<\2\235\235\235\376\376\376\304\377\377\377\1\316\316\316" \ + "\205::<\202;;=\2::<;;=\202::<\1;;=\211::<\202;;=\204::<\1""99;\202::" \ + "<\5;;=::<;;=__a\376\376\376\224\377\377\377\1\376\376\376\205\377\377" \ + "\377\1\235\235\235\206::<\3\346\346\346\377\377\377\376\376\376\207\377" \ + "\377\377\5\376\376\376\377\377\377\376\376\376\346\346\350;;=\203::<" \ + "\3;;=::<\265\265\265\230\377\377\377\1\234\234\236\205::<\1\234\234\234" \ + "\246\377\377\377\1lln\202::<\4""99;;;=99;\234\234\234\213\377\377\377" \ + "\1\234\234\234\203::<\7;;=::<;;=::<;;=::<;;=\222::<\7;;=99;;;=::<;;=" \ + "::<\316\316\316\231\377\377\377\3\214\305@\214\306>\214\305@\207\214" \ + "\306>\4\214\305@\215\305>\214\306>\252\324p\251\377\377\377\215\214\306" \ + ">\1\250\325p\216\377\377\377\1\342\361\320\202\214\306>\1\214\305@\210" \ + "\214\306>\13\216\306A\213\310\77\343\361\320\377\377\375\375\377\376" \ + "\371\374\361\242\320c\213\310\77\216\306\77\214\306>\215\306A\202\214" \ + "\305@\2\216\306A\213\305=\204\214\306>\11\213\307A\216\306A\212\307>" \ + "\260\331y\377\376\377\376\377\375\377\377\373\376\377\377\377\377\377" \ + "\202\377\376\377\2\212\311=\215\306A\211\214\306>\3\215\305>\214\306" \ + ">\305\342\240\215\377\377\377\4\252\324p\214\306>\215\305>\214\305@\207" \ + "\214\306>\3\214\305@\214\306>\214\305@\232\377\377\377\4\252\324p\214" \ + "\306>\215\305>\214\305@\207\214\306>\3\214\305@\214\306>\214\305@\231" \ + "\377\377\377\6\377\376\377\377\377\373\377\376\377\305\342\240\212\310" \ + "\77\214\304=\202\215\305@\210\214\306>\4\215\305>\213\305=\212\306@\215" \ + "\306A\202\214\306>\10\222\312M\370\373\362\377\376\377\377\375\376\377" \ + "\376\377\377\377\377\376\377\375\377\377\377\202\377\376\377\221\377" \ + "\377\377\1\376\376\376\205\377\377\377\2::<;;=\202::<\202;;=\3\300\300" \ + "\300\377\377\377\376\376\376\235\377\377\377\1\376\376\376\245\377\377" \ + "\377\1\316\316\316\207::<\5;;=::<;;=::<;;=\210::<\202;;=\2""99;;;=\202" \ + "::<\3;;=::<;;=\202::<\3;;=xxz\363\363\363\225\377\377\377\3\376\376\376" \ + "\377\377\377\376\376\376\202\377\377\377\3\363\363\363FFH::<\202;;=\202" \ + "::<\1\204\204\206\205\377\377\377\1\376\376\376\205\377\377\377\1\376" \ + "\376\376\202\377\377\377\1kkm\202::<\1;;=\202::<\1SSU\230\377\377\377" \ + "\1\234\234\236\205::<\1\234\234\234\244\377\377\377\3\376\376\376\377" \ + "\377\377xxz\202::<\1;;=\202::<\3xxx\377\377\377\376\376\376\211\377\377" \ + "\377\1\234\234\234\203::<\1;;=\202::<\1;;=\224::<\5;;=99;;;=::<;;=\202" \ + "::<\1\316\316\316\231\377\377\377\3\214\305@\214\306>\214\305@\207\214" \ + "\306>\4\214\305@\215\305>\214\306>\252\324p\251\377\377\377\215\214\306" \ + ">\1\250\325p\216\377\377\377\1\342\361\320\202\214\306>\1\214\305@\210" \ + "\214\306>\3\214\305@\214\306<\343\361\316\202\377\377\377\26\377\376" \ + "\374\353\365\335\223\312K\211\305\77\215\307=\215\306C\211\306;\214\306" \ + ">\215\305@\215\307\77\214\305@\213\307A\214\306>\212\307<\216\306\77" \ + "\212\306B\215\305>\212\306@\304\341\236\377\376\377\375\377\376\377\377" \ + "\375\203\377\377\377\2\212\306@\214\306<\211\214\306>\3\215\305>\214" \ + "\306>\305\342\240\215\377\377\377\4\252\324p\214\306>\215\305>\214\305" \ + "@\207\214\306>\3\214\305@\214\306>\214\305@\232\377\377\377\4\252\324" \ + "p\214\306>\215\305>\214\305@\207\214\306>\3\214\305@\214\306>\214\305" \ + "@\231\377\377\377\2\377\377\373\376\377\377\202\377\377\377\4\241\321" \ + "c\215\306A\215\305>\213\310\77\210\214\306>\20\215\305@\215\307=\213" \ + "\310\77\214\304;\216\306\77\213\310\77\333\355\303\377\375\376\377\377" \ + "\375\377\376\377\377\377\377\375\377\374\376\377\377\377\377\377\377" \ + "\377\375\376\376\376\222\377\377\377\1\376\376\376\204\377\377\377\206" \ + "::<\2\316\316\316\376\376\376\234\377\377\377\1\376\376\376\247\377\377" \ + "\377\1\316\316\316\204::<\1;;=\205::<\1;;=\212::<\4""99;;;=::<;;=\203" \ + "::<\1;;=\202::<\1\233\233\233\234\377\377\377\3\235\235\23799;;;=\203" \ + "::<\2;;=\346\346\346\203\377\377\377\1\376\376\376\204\377\377\377\3" \ + "\376\376\376\377\377\377\376\376\376\203\377\377\377\4\316\316\320;;" \ + "=::<;;=\202::<\2;;=\264\264\264\227\377\377\377\1\234\234\236\205::<" \ + "\1\234\234\234\246\377\377\377\2\234\234\236;;=\203::<\2;;=kkk\213\377" \ + "\377\377\1\234\234\234\204::<\3;;=::<;;=\225::<\2;;=99;\202::<\3;;=:" \ + "::\316\316\316\231\377\377\377\3\214\305@\214\306>\214\305@\207\214\306" \ + ">\4\214\305@\215\305>\214\306>\252\324p\251\377\377\377\215\214\306>" \ + "\1\250\325p\216\377\377\377\1\342\361\320\202\214\306>\1\214\305@\210" \ + "\214\306>\14\215\307\77\215\305@\340\361\315\376\376\376\377\376\377" \ + "\377\377\375\377\377\377\323\353\267\212\307>\215\305@\214\305@\214\311" \ + "@\202\214\306>\22\212\307>\215\305@\214\306>\212\306@\214\305@\215\305" \ + ">\215\307=\214\306>\214\304=\215\307\77\341\362\316\377\376\377\377\377" \ + "\377\376\376\376\377\377\375\375\376\377\217\307@\212\306@\211\214\306" \ + ">\3\215\305>\214\306>\305\342\240\215\377\377\377\4\252\324p\214\306" \ + ">\215\305>\214\305@\207\214\306>\3\214\305@\214\306>\214\305@\232\377" \ + "\377\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306>\3\214\305" \ + "@\214\306>\214\305@\232\377\377\377\7\377\376\377\376\377\377\377\377" \ + "\377\352\364\331\212\307<\215\307=\212\307>\211\214\306>\13\212\306@" \ + "\214\306<\216\306A\214\305@\252\322q\376\376\377\376\377\373\377\376" \ + "\377\376\376\377\377\377\375\376\377\377\203\377\377\377\1\376\377\375" \ + "\227\377\377\377\202::<\202;;=\3::<;;=\316\316\316\233\377\377\377\1" \ + "\375\375\375\251\377\377\377\1\316\316\316\211::<\1;;=\213::<\3;;=::" \ + "<;;=\204::<\3""99;\205\205\207\346\346\346\233\377\377\377\4\376\376" \ + "\376\364\364\364FFH;;=\202::<\202;;=\1\204\204\204\215\377\377\377\1" \ + "\376\376\376\202\377\377\377\7kkm::<99;::<;;=99;TTV\227\377\377\377\1" \ + "\234\234\236\205::<\1\234\234\234\246\377\377\377\1\234\234\236\202:" \ + ":<\202;;=\2::<kkk\202\377\377\377\3\376\376\376\377\377\377\376\376\376" \ + "\206\377\377\377\1\234\234\234\203::<\1;;=\202::<\2;;=::<\202;;=\223" \ + "::<\2""99;;;=\202::<\2;;;\316\316\316\231\377\377\377\3\214\305@\214" \ + "\306>\214\305@\207\214\306>\4\214\305@\215\305>\214\306>\252\324p\251" \ + "\377\377\377\215\214\306>\1\250\325p\216\377\377\377\1\342\361\320\202" \ + "\214\306>\1\214\305@\210\214\306>\202\214\305@\15\341\362\316\377\377" \ + "\375\376\377\375\377\377\377\373\377\374\377\376\377\271\332\211\212" \ + "\307>\212\307<\214\305B\214\305@\216\306\77\212\307>\202\215\307\77\11" \ + "\214\305B\215\306A\212\311=\214\303A\214\306>\215\306A\212\307>\225\311" \ + "K\371\372\362\202\377\377\375\202\377\377\377\2\214\305@\215\306A\211" \ + "\214\306>\3\215\305>\214\306>\305\342\240\215\377\377\377\4\252\324p" \ + "\214\306>\215\305>\214\305@\207\214\306>\3\214\305@\214\306>\214\305" \ + "@\232\377\377\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306>" \ + "\3\214\305@\214\306>\214\305@\231\377\377\377\10\376\377\377\377\376" \ + "\377\377\377\375\377\375\376\331\356\303\214\306>\214\305B\215\307\77" \ + "\210\214\306>\12\215\305>\212\306B\215\304B\214\306>\215\307=\224\310" \ + "J\364\370\351\376\376\374\375\377\372\377\377\375\203\377\377\377\3\377" \ + "\376\377\377\377\377\376\377\375\221\377\377\377\3\376\376\376\377\377" \ + "\377\376\376\376\203\377\377\377\7::<;;=99;::<;;=::<\315\315\315\232" \ + "\377\377\377\1\376\376\376\203\377\377\377\1\376\376\376\246\377\377" \ + "\377\1\316\316\316\204::<\1;;=\202::<\1;;=\203::<\1;;=\210::<\1;;=\202" \ + "::<\1;;=\202::<\4``b\233\233\235\347\347\351\376\376\376\235\377\377" \ + "\377\2\265\265\265;;=\202::<\1;;=\202::<\1\332\332\332\216\377\377\377" \ + "\3\376\376\376\377\377\377\302\302\302\206::<\1\315\315\315\226\377\377" \ + "\377\1\234\234\236\205::<\1\234\234\234\245\377\377\377\2\376\376\376" \ + "\235\235\237\205::<\1jjj\203\377\377\377\3\376\376\376\377\377\377\376" \ + "\376\376\205\377\377\377\1\234\234\234\204::<\2;;=kkm\202\234\234\236" \ + "\1\233\233\235\223\234\234\234\202\235\235\235\1\233\233\233\203\234" \ + "\234\234\1\346\346\346\231\377\377\377\3\214\305@\214\306>\214\305@\207" \ + "\214\306>\4\214\305@\215\305>\214\306>\252\324p\251\377\377\377\215\214" \ + "\306>\1\250\325p\216\377\377\377\1\342\361\320\202\214\306>\1\214\305" \ + "@\210\214\306>\17\212\307>\216\306A\342\360\315\376\377\377\376\376\374" \ + "\375\377\376\377\376\377\377\376\374\377\377\375\242\320d\215\307=\214" \ + "\306>\214\305@\215\305@\212\306@\202\214\305@\17\215\305@\212\307>\215" \ + "\307\77\214\306<\215\306A\213\304\77\215\306A\215\307\77\252\324n\377" \ + "\377\377\375\377\376\377\376\377\377\377\375\212\307<\215\305@\211\214" \ + "\306>\3\215\305>\214\306>\305\342\240\215\377\377\377\4\252\324p\214" \ + "\306>\215\305>\214\305@\207\214\306>\3\214\305@\214\306>\214\305@\232" \ + "\377\377\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306>\3\214" \ + "\305@\214\306>\214\305@\232\377\377\377\6\376\377\375\377\375\377\367" \ + "\375\363\223\312H\216\306\77\215\305>\212\214\306>\2\215\305@\214\306" \ + ">\202\212\307>\3\214\305@\247\324o\377\376\377\202\377\377\377\2\377" \ + "\376\377\377\377\375\233\377\377\377\2::<;;=\204::<\2\316\316\316\376" \ + "\376\376\236\377\377\377\3\316\316\316;;;:::\230::<\213\377\377\377\1" \ + "\316\316\316\224::<\6kkmlln\205\205\207\234\234\236\301\301\303\363\363" \ + "\363\202\377\377\377\1\376\376\376\202\377\377\377\3\376\376\376\377" \ + "\377\377\376\376\376\231\377\377\377\1SSS\204::<\2;;=lln\213\377\377" \ + "\377\1\376\376\376\205\377\377\377\2\376\376\376TTV\205::<\1lll\226\377" \ + "\377\377\1\234\234\236\205::<\1\234\234\234\246\377\377\377\2\233\233" \ + "\235;;=\204::<\2kkk\376\376\376\203\377\377\377\1\376\376\376\206\377" \ + "\377\377\1\234\234\234\205::<\1\234\234\236\266\377\377\377\3\214\305" \ + "@\214\306>\214\305@\207\214\306>\4\214\305@\215\305>\214\306>\252\324" \ + "p\251\377\377\377\215\214\306>\1\250\325p\216\377\377\377\1\342\361\320" \ + "\202\214\306>\1\214\305@\210\214\306>\3\212\307>\215\305>\342\362\315" \ + "\202\377\377\377\22\377\376\377\376\377\377\377\377\375\376\377\377\363" \ + "\367\346\225\311K\211\307@\216\306\77\212\307>\215\305@\214\306<\212" \ + "\307>\214\305@\214\306>\212\306@\215\306C\214\304\77\215\307\77\202\214" \ + "\306>\7\212\306@\307\341\240\377\376\377\376\377\372\377\377\377\212" \ + "\307>\215\305>\211\214\306>\3\215\305>\214\306>\305\342\240\215\377\377" \ + "\377\4\252\324p\214\306>\215\305>\214\305@\207\214\306>\3\214\305@\214" \ + "\306>\214\305@\232\377\377\377\4\252\324p\214\306>\215\305>\214\305@" \ + "\207\214\306>\3\214\305@\214\306>\214\305@\231\377\377\377\4\377\376" \ + "\377\376\377\375\376\377\377\257\330z\202\214\305@\1\215\307\77\211\214" \ + "\306>\14\212\307>\215\307\77\214\305@\215\305@\212\307>\215\307=\214" \ + "\305B\313\347\252\377\377\377\377\375\377\377\376\377\376\376\376\202" \ + "\376\377\375\231\377\377\377\4GGI;;=::<;;=\202::<\1\233\233\235\237\377" \ + "\377\377\3\316\316\316::<;;=\230::<\213\377\377\377\1\316\316\316\205" \ + "::<\1kkm\202\377\377\377\2\376\376\376\250\250\250\206::<\2FFH\346\346" \ + "\346\210\377\377\377\1\376\376\376\237\377\377\377\1\264\264\266\203" \ + ";;=\4::<;;=;;;\316\316\316\222\377\377\377\1\265\265\265\204::<\3;;=" \ + "::<\316\316\316\203\377\377\377\1\376\376\376\221\377\377\377\1\234\234" \ + "\236\205::<\1\234\234\234\245\377\377\377\2\376\376\376\235\235\237\205" \ + "::<\1lll\213\377\377\377\1\234\234\234\205::<\1\234\234\236\266\377\377" \ + "\377\3\214\305@\214\306>\214\305@\207\214\306>\4\214\305@\215\305>\214" \ + "\306>\252\324p\251\377\377\377\215\214\306>\1\250\325p\216\377\377\377" \ + "\1\342\361\320\202\214\306>\1\214\305@\211\214\306>\2\214\305@\343\361" \ + "\316\205\377\377\377\10\376\377\375\377\377\377\333\355\303\215\305@" \ + "\214\306>\214\306<\214\305@\215\305>\202\214\305@\207\214\306>\6\212" \ + "\306@\214\307;\330\355\304\377\376\377\377\377\377\215\305>\212\214\306" \ + ">\3\215\305>\214\306>\305\342\240\215\377\377\377\17\251\323q\214\306" \ + ">\215\307\77\214\305B\215\307\77\213\305=\215\307\77\214\305@\212\307" \ + ">\215\305@\213\310\77\214\305@\215\305<\214\306>\376\377\377\230\377" \ + "\377\377\6\376\377\377\253\323p\215\305@\213\307A\214\306<\212\306B\202" \ + "\214\306>\4\214\305@\214\306>\212\307>\214\305@\202\214\306>\2\214\305" \ + "@\376\377\375\220\377\377\377\1\377\377\375\202\377\377\377\16\376\377" \ + "\375\377\376\377\377\375\376\374\377\377\377\377\375\376\377\375\377" \ + "\377\377\336\355\304\214\306>\215\306A\214\306>\215\306A\212\306@\216" \ + "\306A\202\214\305@\4\215\307\77\214\306>\215\307\77\214\306>\202\214" \ + "\305@\16\214\306>\215\307\77\214\306>\215\307\77\214\305@\214\305B\222" \ + "\313H\361\370\346\376\377\377\377\377\377\377\376\377\377\377\377\374" \ + "\377\377\377\376\377\230\377\377\377\1kkm\202::<\1""99;\202::<\1\235" \ + "\235\237\233\377\377\377\1\376\376\376\203\377\377\377\1\316\316\316" \ + "\224::<\1;;=\205::<\213\377\377\377\1\316\316\316\205::<\1kkm\204\377" \ + "\377\377\3wwy::<;;=\202::<\4""99;;;=``b\363\363\363\206\377\377\377\1" \ + "\376\376\376\235\377\377\377\4\376\376\376\377\377\377\376\376\376TT" \ + "V\205::<\1lln\223\377\377\377\10\376\376\376SSU;;=::<;;=99;::<lll\205" \ + "\377\377\377\1\376\376\376\217\377\377\377\1\234\234\236\205::<\1\234" \ + "\234\234\246\377\377\377\1\204\204\206\202::<\1;;=\202::<\3xxx\377\377" \ + "\377\376\376\376\211\377\377\377\1\234\234\234\205::<\1\234\234\236\266" \ + "\377\377\377\3\214\305@\214\306>\214\305@\207\214\306>\4\214\305@\215" \ + "\305>\214\306>\252\324p\251\377\377\377\215\214\306>\1\250\325p\216\377" \ + "\377\377\1\342\361\320\202\214\306>\1\214\305@\211\214\306>\2\214\305" \ + "@\343\361\316\205\377\377\377\7\377\375\377\377\377\375\376\377\377\276" \ + "\337\220\213\310\77\213\304A\216\306=\207\214\306>\3\215\307\77\214\306" \ + ">\212\307>\202\215\305>\5\223\312J\361\371\344\377\375\377\212\307<\214" \ + "\305@\211\214\306>\3\215\305>\214\306>\305\342\240\214\377\377\377\14" \ + "\376\376\374\252\324n\214\306>\213\305=\215\307\77\214\305@\215\306A" \ + "\214\306>\215\307\77\213\310\77\215\305@\212\307>\202\214\306>\1\214" \ + "\305@\232\377\377\377\3\247\324m\215\305>\214\305@\202\214\306>\1\215" \ + "\307=\202\214\305@\6\214\306<\215\307=\214\305B\215\307\77\214\306>\214" \ + "\305@\224\377\377\377\15\377\377\375\376\376\376\377\377\377\377\376" \ + "\377\376\377\375\377\377\375\372\373\366\222\312M\216\306A\215\305<\214" \ + "\306>\212\307>\215\305<\202\214\306>\2\215\307\77\213\305=\204\214\306" \ + ">\1\214\305@\203\214\306>\14\215\307\77\214\305@\213\304\77\214\305B" \ + "\253\324n\376\376\377\376\377\377\377\376\377\377\377\377\376\377\375" \ + "\377\377\375\376\377\375\227\377\377\377\3lln::<;;=\203::<\2kkm\376\376" \ + "\376\236\377\377\377\2\316\316\316;;=\226::<\3;;=::<kkm\213\377\377\377" \ + "\1\316\316\316\204::<\2;;=kkm\204\377\377\377\3\363\363\363__a;;=\203" \ + "::<\4;;=99;\205\205\207\376\376\376\202\377\377\377\1\376\376\376\203" \ + "\377\377\377\1\376\376\376\236\377\377\377\1\301\301\301\204::<\4;;=" \ + "::<wwy\235\235\237\223\234\234\236\1kkm\204::<\5;;=99;\345\345\345\377" \ + "\377\377\376\376\376\222\377\377\377\1\234\234\236\205::<\1\234\234\234" \ + "\246\377\377\377\1kkm\204::<\2;;=\234\234\234\213\377\377\377\1\234\234" \ + "\234\205::<\1\234\234\236\266\377\377\377\3\214\305@\214\306>\214\305" \ + "@\207\214\306>\4\214\305@\215\305>\214\306>\252\324p\251\377\377\377" \ + "\215\214\306>\1\250\325p\216\377\377\377\1\342\361\320\202\214\306>\1" \ + "\214\305@\211\214\306>\2\214\305@\343\361\316\205\377\377\377\2\377\377" \ + "\375\377\375\377\202\377\377\377\1\242\322b\202\214\305@\2\214\305B\215" \ + "\307\77\205\214\306>\12\215\307\77\214\306>\215\306A\214\306>\212\306" \ + "@\215\307=\241\321c\377\377\377\215\304B\212\307>\211\214\306>\3\215" \ + "\305>\214\306>\305\342\240\214\377\377\377\5\376\377\375\251\323o\215" \ + "\307\77\214\306>\215\307\77\202\214\305@\2\214\306>\215\307\77\202\214" \ + "\306>\5\213\310\77\215\305>\214\305@\214\306>\377\376\377\230\377\377" \ + "\377\12\377\376\377\247\326p\213\304\77\215\307\77\214\305B\214\306<" \ + "\214\306>\215\307\77\214\305@\214\306>\202\215\307\77\3\214\306>\215" \ + "\306A\216\306\77\223\377\377\377\5\376\377\372\377\377\375\376\376\376" \ + "\377\377\377\377\377\375\202\377\376\377\4\250\325p\212\307<\214\305" \ + "@\215\307\77\202\214\305@\3\214\307;\215\307=\214\306>\202\214\305@\202" \ + "\214\306>\1\215\307\77\207\214\306>\202\214\305@\5\212\307>\307\341\240" \ + "\376\376\374\377\377\377\377\376\377\202\377\377\377\1\376\376\374\227" \ + "\377\377\377\7\234\234\236;;=99;<<>99;::<;;=\237\377\377\377\1\316\316" \ + "\316\223::<\7;;=99;;;=99;::<;;=kkm\213\377\377\377\1\316\316\316\205" \ + "::<\2mmo\376\376\377\204\377\377\377\12\332\332\332FFH;;=::<;;=99;<<" \ + ">::<\266\266\270\376\376\376\203\377\377\377\1\376\376\376\202\377\377" \ + "\377\1\376\376\376\230\377\377\377\3\376\376\376\377\377\377\376\376" \ + "\376\202\377\377\377\1kkm\205::<\202;;=\224::<\10;;=::<;;=::<;;=88:;" \ + ";=\205\205\205\224\377\377\377\1\234\234\236\205::<\1\234\234\234\246" \ + "\377\377\377\3SSU;;=::<\203;;=\1\234\234\234\206\377\377\377\1\376\376" \ + "\376\204\377\377\377\1\234\234\234\205::<\1\234\234\236\266\377\377\377" \ + "\3\214\305@\214\306>\214\305@\207\214\306>\4\214\305@\215\305>\214\306" \ + ">\252\324p\251\377\377\377\215\214\306>\1\250\325p\216\377\377\377\1" \ + "\342\361\320\202\214\306>\1\214\305@\211\214\306>\2\214\305@\343\361" \ + "\316\205\377\377\377\10\376\376\374\376\377\375\377\375\377\377\377\377" \ + "\367\372\357\224\313L\214\305B\215\305<\203\214\306>\202\215\307\77\204" \ + "\214\306>\6\215\306A\213\307A\214\306>\212\306@\277\337\223\215\305>" \ + "\212\214\306>\3\215\305>\214\306>\305\342\240\214\377\377\377\2\376\377" \ + "\377\251\322r\202\215\307\77\1\214\305B\202\214\306>\202\215\307\77\7" \ + "\214\306>\215\307\77\214\306>\214\304\77\212\306@\215\307\77\377\376" \ + "\377\230\377\377\377\7\377\377\375\215\305@\214\306>\214\305@\214\306" \ + ">\216\306\77\214\306<\203\214\305@\6\215\306C\215\307=\214\305@\215\306" \ + "A\233\314V\377\377\375\220\377\377\377\5\376\376\376\377\377\377\377" \ + "\376\377\377\375\377\377\377\375\202\376\377\377\21\377\376\377\314\346" \ + "\251\212\306B\215\307=\212\307>\216\306\77\215\306C\212\307>\215\306" \ + "C\214\305@\215\307\77\213\304\77\215\306A\214\306>\214\305@\215\307\77" \ + "\215\306A\203\214\306>\1\215\307\77\202\214\306>\202\215\307\77\10\214" \ + "\306>\214\305@\350\364\334\377\377\375\377\376\377\377\377\377\376\376" \ + "\376\377\376\377\222\377\377\377\1\376\376\376\204\377\377\377\1\301" \ + "\301\301\202::<\2""99;;;=\202::<\1\316\316\316\233\377\377\377\1\376" \ + "\376\376\202\377\377\377\2\316\316\316;;;\222::<\7""99;;;=::<;;=::<9" \ + "9;\204\204\206\213\377\377\377\1\316\316\316\205::<\1jjl\202\377\377" \ + "\377\202\376\376\376\202\377\377\377\1\265\265\267\202::<\202;;=\202" \ + "::<\2FFH\332\332\332\205\377\377\377\1\376\376\376\234\377\377\377\2" \ + "\376\376\376\317\317\317\202::<\1;;=\204::<\3;;=::<;;=\222::<\2""99;" \ + ";;=\202::<\1;;=\203::<\3\346\346\346\377\377\377\376\376\376\221\377" \ + "\377\377\1\234\234\236\205::<\1\234\234\234\246\377\377\377\1;;=\203" \ + "::<\4;;=::<\316\316\316\376\376\376\203\377\377\377\1\376\376\376\206" \ + "\377\377\377\1\234\234\234\205::<\1\234\234\236\266\377\377\377\3\214" \ + "\305@\214\306>\214\305@\207\214\306>\4\214\305@\215\305>\214\306>\252" \ + "\324p\251\377\377\377\215\214\306>\1\250\325p\216\377\377\377\1\342\361" \ + "\320\202\214\306>\1\214\305@\211\214\306>\2\214\305@\343\361\316\205" \ + "\377\377\377\203\376\377\377\202\377\376\377\2\341\361\315\214\305@\203" \ + "\215\307\77\202\214\306>\1\215\307\77\203\214\306>\10\214\305@\215\307" \ + "\77\214\306>\212\307>\216\306A\213\305;\214\305@\215\305<\211\214\306" \ + ">\3\215\305>\214\306>\305\342\240\214\377\377\377\2\376\377\377\252\324" \ + "p\202\214\306>\3\214\305B\214\306<\215\307\77\203\214\306>\6\214\306" \ + "<\214\307;\217\307@\212\307>\214\305@\376\377\377\231\377\377\377\10" \ + "\215\307=\214\305B\213\304A\216\310@\214\304\77\215\307=\214\305@\215" \ + "\307\77\203\214\306>\3\215\307\77\214\306>\247\324o\222\377\377\377\3" \ + "\377\377\375\377\377\377\377\375\376\203\377\377\377\20\360\371\346\223" \ + "\312K\216\306\77\213\304A\215\306A\213\305=\215\305@\212\307>\215\305" \ + "<\214\305B\214\305@\214\306>\214\306<\214\306>\215\307\77\213\305=\204" \ + "\214\306>\202\215\307\77\203\214\306>\10\215\306A\212\307<\243\321d\377" \ + "\377\373\375\377\376\377\376\377\377\377\377\376\376\374\223\377\377" \ + "\377\5\375\375\375\377\377\377\376\376\376\377\377\377\346\346\346\202" \ + "::<\1;;=\203::<\1\221\221\221\235\377\377\377\3\376\376\376\377\377\377" \ + "\376\376\376\222\377\377\377\1__a\204::<\2;;=\234\234\234\213\377\377" \ + "\377\1\316\316\316\205::<\3jjl\377\377\377\376\376\376\205\377\377\377" \ + "\2\204\204\206;;=\204::<\3;;=RRT\363\363\363\237\377\377\377\1\376\376" \ + "\376\202\377\377\377\2jjl;;=\206::<\4;;=::<99;;;=\223::<\1;;=\205::<" \ + "\1\204\204\206\203\377\377\377\1\376\376\376\217\377\377\377\1\234\234" \ + "\236\205::<\1\234\234\234\245\377\377\377\3\315\315\315;;=99;\202::<" \ + "\5""99;;;=\346\346\346\377\377\377\376\376\376\211\377\377\377\1\234" \ + "\234\234\205::<\1\234\234\236\266\377\377\377\3\214\305@\214\306>\214" \ + "\305@\207\214\306>\4\214\305@\215\305>\214\306>\252\324p\251\377\377" \ + "\377\215\214\306>\1\250\325p\216\377\377\377\1\342\361\320\202\214\306" \ + ">\1\214\305@\211\214\306>\2\214\305@\343\361\316\207\377\377\377\202" \ + "\377\377\375\4\376\377\377\377\377\375\303\342\237\212\306@\202\214\305" \ + "@\206\214\306>\7\216\306\77\213\305;\214\305@\216\306A\214\306>\215\307" \ + "\77\213\307A\212\214\306>\3\215\305>\214\306>\305\342\240\215\377\377" \ + "\377\17\252\323k\215\306A\214\306>\215\307\77\214\306>\215\307\77\214" \ + "\305@\214\306>\213\304A\215\306C\214\305@\213\304A\213\310=\214\306<" \ + "\342\357\321\230\377\377\377\6\360\371\346\214\305B\212\307<\215\307" \ + "=\213\305=\215\307\77\202\214\305@\7\215\306A\214\306>\214\306<\214\305" \ + "@\214\306>\214\305@\252\324p\222\377\377\377\11\377\376\377\376\377\377" \ + "\377\377\377\377\377\375\376\376\374\377\377\377\253\323p\215\307\77" \ + "\211\306;\202\215\306A\6\214\306>\214\306<\215\305>\216\305C\215\307" \ + "\77\213\304\77\202\215\307\77\2\215\307=\213\305;\202\215\307\77\2\214" \ + "\306>\215\307\77\205\214\306>\5\215\307\77\212\306@\214\306>\215\307" \ + "\77\304\341\236\202\377\377\377\2\376\376\377\374\377\377\230\377\377" \ + "\377\7SSU;;=99;::<;;=::<FFH\232\377\377\377\1\376\376\376\205\377\377" \ + "\377\1\376\376\376\220\377\377\377\2\376\376\376;;=\202::<\1;;=\202:" \ + ":<\1\316\316\316\213\377\377\377\1\316\316\316\205::<\1kkm\210\377\377" \ + "\377\2__a;;=\204::<\2;;=xxz\202\377\377\377\1\376\376\376\233\377\377" \ + "\377\1\376\376\376\202\377\377\377\2\315\315\315;;=\206::<\2;;=99;\203" \ + ";;=\223::<\1;;=\205::<\6FFH\363\363\363\377\377\377\376\376\376\377\377" \ + "\377\376\376\376\216\377\377\377\1\234\234\236\205::<\1\234\234\234\244" \ + "\377\377\377\4\376\376\376\223\223\22399;;;=\202::<\4;;=EEG\377\377\377" \ + "\376\376\376\202\377\377\377\1\376\376\376\202\377\377\377\1\376\376" \ + "\376\204\377\377\377\1\234\234\234\205::<\1\234\234\236\266\377\377\377" \ + "\3\214\305@\214\306>\214\305@\207\214\306>\4\214\305@\215\305>\214\306" \ + ">\252\324p\251\377\377\377\215\214\306>\1\250\325p\216\377\377\377\1" \ + "\342\361\320\202\214\306>\1\214\305@\211\214\306>\2\214\305@\343\361" \ + "\316\206\377\377\377\13\377\376\377\377\377\377\376\377\375\377\377\377" \ + "\377\376\377\376\377\377\253\324l\214\305B\213\304\77\214\305@\215\307" \ + "\77\203\214\306>\11\214\305@\214\306<\216\306=\214\306>\212\306@\215" \ + "\306C\214\304;\212\307>\214\305@\211\214\306>\3\215\305>\214\306>\305" \ + "\342\240\215\377\377\377\1\261\330\177\202\214\306>\2\214\306<\215\306" \ + "A\203\214\306>\7\215\307\77\214\306>\214\306<\215\307=\214\306>\215\306" \ + "C\323\353\267\230\377\377\377\4\340\361\315\215\305@\215\306A\214\305" \ + "@\202\214\306>\2\213\305=\215\306A\202\214\305@\5\214\306>\215\307\77" \ + "\214\306>\214\305@\260\330x\221\377\377\377\3\376\376\376\377\377\373" \ + "\375\377\376\202\377\377\377\25\376\377\377\314\345\253\214\305@\213" \ + "\304\77\216\306\77\212\307>\215\305@\214\306>\214\305@\215\305>\214\305" \ + "@\214\306>\214\306<\214\305@\215\306A\214\305@\215\306C\214\306>\214" \ + "\305@\214\306>\215\307\77\207\214\306>\7\212\306@\220\306=\215\306C\350" \ + "\364\336\376\377\373\377\377\375\376\377\377\230\377\377\377\1\221\221" \ + "\223\203::<\1;;=\202::<\1\265\265\265\230\377\377\377\1\376\376\376\227" \ + "\377\377\377\1\316\316\316\202::<\1;;=\203::<\1\363\363\363\213\377\377" \ + "\377\1\316\316\316\205::<\1kkm\204\377\377\377\1\376\376\376\203\377" \ + "\377\377\2\346\346\346FFH\206::<\2\234\234\236\376\376\376\237\377\377" \ + "\377\1\205\205\205\206::<\3;;=::<;;=\223::<\1;;=\203::<\202;;=\204::" \ + "<\2\234\234\234\376\376\376\221\377\377\377\1\234\234\236\205::<\1\234" \ + "\234\234\245\377\377\377\1RRR\204::<\2""99;yy{\203\377\377\377\1\376" \ + "\376\376\202\377\377\377\202\376\376\376\204\377\377\377\1\234\234\234" \ + "\205::<\1\234\234\236\266\377\377\377\3\214\305@\214\306>\214\305@\207" \ + "\214\306>\4\214\305@\215\305>\214\306>\252\324p\251\377\377\377\215\214" \ + "\306>\1\250\325p\216\377\377\377\1\342\361\320\202\214\306>\1\214\305" \ + "@\211\214\306>\2\214\305@\343\361\316\205\377\377\377\30\377\377\375" \ + "\377\377\377\375\377\376\377\377\377\377\376\377\377\377\377\376\377" \ + "\377\371\372\365\222\313H\214\305B\214\305@\215\307\77\214\306>\215\307" \ + "\77\214\306>\214\305@\212\306B\214\305@\212\307>\216\306\77\212\307>" \ + "\215\307\77\214\306<\214\305@\211\214\306>\3\215\305>\214\306>\305\342" \ + "\240\214\377\377\377\20\377\376\377\301\345\237\215\305>\215\306A\213" \ + "\304\77\215\306C\214\306>\214\306<\216\306\77\214\306>\214\305B\215\307" \ + "\77\214\306>\215\307\77\214\305@\271\332\211\230\377\377\377\10\307\341" \ + "\240\215\305>\214\305@\214\306>\215\305<\212\307>\214\305B\214\306<\202" \ + "\214\306>\5\215\305<\214\305B\215\307\77\214\306>\303\344\235\222\377" \ + "\377\377\6\376\376\377\377\377\375\376\377\377\377\376\377\352\364\333" \ + "\215\305@\202\215\307\77\16\214\306>\215\307\77\214\306>\215\307\77\214" \ + "\306<\216\306A\213\310\77\214\305D\215\3108\214\305@\215\305>\223\312" \ + "K\236\323a\215\307\77\207\214\306>\202\214\305@\10\214\306>\215\307\77" \ + "\212\307>\212\307<\241\321c\377\376\377\377\375\376\377\375\377\230\377" \ + "\377\377\3\332\332\332:::;;=\204::<\1SSU\203\377\377\377\1\376\376\376" \ + "\247\377\377\377\1\376\376\376\204\377\377\377\1\221\221\221\202::<\1" \ + ";:\77\202::<\1RRT\214\377\377\377\1\316\316\316\205::<\1kkm\211\377\377" \ + "\377\2\316\316\316;;=\202::<\5;;=::<;;=::<\316\316\316\210\377\377\377" \ + "\1\376\376\376\215\377\377\377\1\376\376\376\207\377\377\377\2\346\346" \ + "\350::<\202;;=\202::<\2:::xxx\230\234\234\234\3\235\235\235\234\234\234" \ + "kkm\203::<\4;;=::<FFH\364\364\364\203\377\377\377\1\376\376\376\215\377" \ + "\377\377\1\234\234\236\205::<\1\234\234\234\241\377\377\377\1\376\376" \ + "\376\202\377\377\377\1\332\332\334\206::<\1\250\250\252\214\377\377\377" \ + "\1\234\234\234\205::<\1\234\234\236\266\377\377\377\3\214\305@\214\306" \ + ">\214\305@\204\214\306>\2\213\307A\213\310\77\204\214\306>\1\252\324" \ + "p\232\377\377\377\1\377\377\375\216\377\377\377\215\214\306>\1\250\325" \ + "p\216\377\377\377\1\342\361\320\202\214\306>\1\214\305@\211\214\306>" \ + "\2\214\305@\343\361\316\215\377\377\377\10\352\363\336\214\306>\212\306" \ + "B\215\307\77\212\307<\215\305>\214\305@\215\307\77\221\214\306>\3\215" \ + "\305>\214\306>\305\342\240\214\377\377\377\30\377\376\377\313\347\254" \ + "\215\307\77\214\304=\215\307\77\212\306@\215\307\77\215\306A\214\305" \ + "@\214\306>\215\307\77\214\306>\215\307\77\214\305@\214\305B\222\313H" \ + "\377\376\377\377\375\376\377\376\377\377\377\377\377\376\377\377\377" \ + "\373\376\377\377\377\376\377\211\377\377\377\26\377\377\375\377\376\377" \ + "\377\377\377\376\377\377\377\377\375\376\377\375\377\377\377\241\323" \ + "b\215\304D\214\307;\215\307\77\214\305B\215\307\77\214\306<\215\306A" \ + "\212\307>\215\305@\214\306>\213\310=\215\305@\215\306A\323\352\264\221" \ + "\377\377\377\11\376\377\377\376\376\374\376\377\377\377\376\374\377\376" \ + "\377\242\320c\215\307\77\215\306A\214\306>\202\214\305@\203\214\306>" \ + "\25\214\305@\215\306A\214\305@\215\307\77\214\306>\215\307=\315\345\253" \ + "\361\370\346\215\307\77\214\306>\212\306@\216\306A\214\306>\215\305>" \ + "\215\305@\214\305@\212\307>\215\305@\212\306@\215\305<\215\305@\202\214" \ + "\306>\12\277\337\223\377\377\377\376\377\375\377\376\377\377\377\375" \ + "\376\377\377\377\377\377\376\376\376\377\377\377\377\377\375\222\377" \ + "\377\377\1___\202::<\202;;=\202::<\1\266\266\266\250\377\377\377\1\376" \ + "\376\376\202\377\377\377\1\376\376\376\203\377\377\377\1SSU\203::<\3" \ + ";;=::<\221\221\223\214\377\377\377\1\316\316\316\205::<\1kkm\210\377" \ + "\377\377\3\376\376\376\377\377\377\233\233\233\203::<\5;;=::<;;=FFH\364" \ + "\364\364\210\377\377\377\1\376\376\376\213\377\377\377\2\376\376\376" \ + "\377\377\377\202\376\376\376\205\377\377\377\1\204\204\206\202::<\1;" \ + ";=\202::<\3FFF\363\363\363\376\376\376\231\377\377\377\3\346\346\346" \ + "::<;;=\204::<\3\234\234\234\377\377\377\376\376\376\217\377\377\377\1" \ + "\234\234\236\205::<\1\234\234\234\234\377\377\377\1\376\376\376\207\377" \ + "\377\377\3\205\205\207::<;;=\204::<\1\346\346\350\214\377\377\377\1\234" \ + "\234\234\205::<\1\234\234\236\266\377\377\377\3\214\305@\214\306>\214" \ + "\305@\205\214\306>\7\214\306<\214\306>\215\307\77\214\305@\214\306>\252" \ + "\324p\376\377\375\230\377\377\377\203\377\376\377\203\377\377\377\1\376" \ + "\376\377\211\377\377\377\215\214\306>\1\250\325p\216\377\377\377\1\342" \ + "\361\320\202\214\306>\1\214\305@\211\214\306>\2\214\305@\343\361\316" \ + "\215\377\377\377\2\376\377\375\313\347\254\203\214\306>\3\214\305@\216" \ + "\306\77\211\306=\221\214\306>\3\215\305>\214\306>\305\342\240\214\377" \ + "\377\377\11\375\376\377\343\361\316\215\305>\215\307\77\213\304A\215" \ + "\307\77\215\305>\214\306<\214\305@\203\214\306>\14\215\307\77\214\305" \ + "@\213\304\77\214\305B\322\353\264\377\377\377\377\377\375\377\377\377" \ + "\377\376\377\376\377\377\377\377\377\376\377\377\210\377\377\377\13\377" \ + "\377\375\377\377\377\376\377\375\377\376\377\376\376\374\377\377\375" \ + "\377\377\377\350\364\334\215\304D\215\305>\215\307\77\202\214\305@\202" \ + "\214\306>\10\214\305@\215\306A\214\306<\215\306C\214\304=\215\307=\212" \ + "\307<\351\366\332\222\377\377\377\14\377\377\375\377\377\377\377\377" \ + "\375\304\343\237\214\306>\212\307>\217\307@\214\305@\215\307\77\214\306" \ + ">\214\305@\215\306A\202\214\306>\5\214\306<\215\305>\211\307>\216\306" \ + "=\251\323o\202\376\377\377\31\304\341\241\212\306@\215\306A\212\307>" \ + "\215\307\77\214\306<\216\305C\212\307<\216\306A\214\306<\215\307\77\215" \ + "\305>\212\307>\216\306A\214\305@\216\306A\341\361\315\377\376\377\377" \ + "\377\375\376\377\377\377\376\377\376\376\376\377\377\377\377\376\377" \ + "\376\377\375\222\377\377\377\1\265\265\265\202;;=\204::<\2SSU\364\364" \ + "\364\203\377\377\377\1\376\376\376\245\377\377\377\1\376\376\376\203" \ + "\377\377\377\1\316\316\316\203::<\1;;=\202::<\1\302\302\302\214\377\377" \ + "\377\1\316\316\316\205::<\1kkm\213\377\377\377\1lln\204::<\3;;=::<__" \ + "a\202\377\377\377\1\376\376\376\206\377\377\377\1\376\376\376\213\377" \ + "\377\377\1\376\376\376\202\377\377\377\1\376\376\376\203\377\377\377" \ + "\3\346\346\346::<;;=\204::<\1\234\234\234\234\377\377\377\1\204\204\206" \ + "\202;;=\202::<\2;;=SSU\221\377\377\377\1\234\234\236\205::<\1\234\234" \ + "\234\235\377\377\377\1\376\376\376\202\377\377\377\1\376\376\376\202" \ + "\377\377\377\2\346\346\346::<\202;;=\4""99;;;=::<kkm\215\377\377\377" \ + "\1\234\234\234\205::<\1\234\234\236\266\377\377\377\3\214\305@\214\306" \ + ">\214\305@\204\214\306>\10\214\305@\215\306A\215\305@\213\305=\214\306" \ + ">\215\307\77\252\324p\376\377\377\230\377\377\377\1\376\376\376\205\377" \ + "\377\377\2\376\377\377\376\377\375\210\377\377\377\215\214\306>\1\250" \ + "\325p\216\377\377\377\1\342\361\320\202\214\306>\1\214\305@\211\214\306" \ + ">\2\214\305@\343\361\316\215\377\377\377\10\377\377\375\377\375\376\262" \ + "\331|\214\305@\215\306A\214\306>\214\305B\215\307\77\221\214\306>\3\215" \ + "\305>\214\306>\305\342\240\214\377\377\377\10\376\377\375\377\377\377" \ + "\214\304\77\212\307>\216\306A\214\306>\215\305@\215\307\77\206\214\306" \ + ">\202\214\305@\3\233\316X\376\376\377\376\377\373\202\377\377\377\3\377" \ + "\375\376\377\377\375\377\376\377\210\377\377\377\12\377\376\377\376\377" \ + "\375\377\375\376\376\376\374\377\377\377\377\377\375\377\377\377\257" \ + "\330x\214\307;\215\307\77\202\214\305@\2\215\307\77\213\305=\202\214" \ + "\306>\1\215\305>\202\214\306>\5\216\306\77\215\306A\215\305@\376\377" \ + "\375\377\376\377\220\377\377\377\11\377\377\375\377\377\377\376\377\377" \ + "\350\364\334\212\307>\213\310\77\216\306\77\212\307>\214\305@\202\214" \ + "\306>%\215\306A\214\306>\213\305=\214\306>\215\307\77\215\305@\211\307" \ + ">\223\311M\363\367\350\376\377\375\377\377\377\377\377\375\242\320d\212" \ + "\307<\215\306A\214\305@\212\306@\215\306A\214\306>\212\307>\215\307\77" \ + "\217\304@\211\310<\215\305>\213\310\77\212\307>\214\306>\234\315W\367" \ + "\372\363\376\377\377\377\376\377\377\377\375\377\377\377\376\376\376" \ + "\377\377\375\377\377\377\376\377\375\222\377\377\377\1RRR\202::<\203" \ + ";;=\2::<\234\234\236\204\377\377\377\1\376\376\376\246\377\377\377\3" \ + "\376\376\376\377\377\377kkk\202::<\4;;=99;;;=FFH\215\377\377\377\1\316" \ + "\316\316\205::<\1kkm\211\377\377\377\5\376\376\376\377\377\377\363\363" \ + "\363SSU;;=\202::<\202;;=\2""99;\222\222\222\207\377\377\377\3\376\376" \ + "\376\377\377\377\376\376\376\214\377\377\377\1\376\376\376\204\377\377" \ + "\377\3\204\204\204;;=99;\202;;=\3::<FFH\363\363\363\230\377\377\377\1" \ + "\376\376\376\202\377\377\377\2\376\376\376\317\317\317\203::<\4;;=::" \ + "<;;=\266\266\266\220\377\377\377\1\234\234\236\205::<\1\234\234\234\243" \ + "\377\377\377\2\204\204\204;;=\204::<\2""99;\264\264\264\215\377\377\377" \ + "\1\234\234\234\205::<\1\234\234\236\266\377\377\377\3\214\305@\214\306" \ + ">\214\305@\204\214\306>\2\214\305@\214\306>\203\215\306A\2\215\307\77" \ + "\251\323q\231\377\377\377\203\377\377\375\202\377\377\377\1\377\375\376" \ + "\202\377\376\377\210\377\377\377\215\214\306>\1\250\325p\216\377\377" \ + "\377\1\342\361\320\202\214\306>\1\214\305@\211\214\306>\2\214\305@\343" \ + "\361\316\215\377\377\377\7\376\376\376\377\377\375\366\373\364\233\316" \ + "X\215\305@\215\307=\215\305>\222\214\306>\3\215\305>\214\306>\305\342" \ + "\240\216\377\377\377\6\243\322b\214\306>\215\305@\215\307\77\215\305" \ + "@\215\306A\203\214\306>\1\215\307\77\202\214\306>\202\215\307\77\2\214" \ + "\306>\315\346\254\202\377\377\377\4\377\376\375\376\377\375\376\376\377" \ + "\377\376\377\212\377\377\377\7\377\377\375\377\376\377\377\377\373\377" \ + "\377\375\327\356\304\214\306>\215\307\77\202\214\305@\203\214\306>\12" \ + "\215\307\77\214\306>\214\305@\216\306\77\214\306<\214\304\77\212\307" \ + ">\260\331{\376\377\375\377\376\377\220\377\377\377\13\376\377\377\377" \ + "\377\375\370\373\362\233\315Z\216\306A\214\305@\212\307>\215\306A\214" \ + "\306>\214\305@\215\306A\202\214\306>\6\215\307\77\214\305@\214\305B\214" \ + "\306>\215\307=\313\347\254\202\377\377\377\23\377\376\377\377\377\375" \ + "\350\364\334\212\307>\220\306=\214\305@\216\306=\214\306>\214\305@\214" \ + "\306>\212\306@\215\305>\212\306@\215\307\77\212\307>\215\307\77\214\305" \ + "@\212\306@\277\340\221\202\377\377\377\1\377\377\375\203\377\377\377" \ + "\2\377\376\377\377\377\375\220\377\377\377\4\376\376\376\377\377\377" \ + "\265\265\265::<\202;;=\5""99;::<;;=99;\317\317\317\250\377\377\377\1" \ + "\376\376\376\202\377\377\377\2\316\316\31699;\202::<\202;;=\2::<\221" \ + "\221\223\215\377\377\377\1\316\316\316\205::<\1kkm\207\377\377\377\1" \ + "\376\376\376\204\377\377\377\1\332\332\334\203::<\5;;=::<;;=99;\302\302" \ + "\302\202\377\377\377\1\376\376\376\216\377\377\377\1\376\376\376\202" \ + "\377\377\377\1\376\376\376\204\377\377\377\4\362\362\362FFH::<;;=\202" \ + "::<\2;;=\221\221\223\204\377\377\377\202\376\376\376\224\377\377\377" \ + "\1\376\376\376\203\377\377\377\1kkm\202;;=\203::<\1SSU\220\377\377\377" \ + "\1\234\234\236\205::<\1\234\234\234\240\377\377\377\3\376\376\376\377" \ + "\377\377\315\315\315\203::<\1;;=\202::<\1SSU\216\377\377\377\1\234\234" \ + "\234\205::<\1\234\234\236\266\377\377\377\3\214\305@\214\306>\214\305" \ + "@\204\214\306>\3\215\306A\214\306<\215\307=\202\214\305@\3\214\306>\253" \ + "\324n\377\377\375\230\377\377\377\2\375\376\377\376\376\376\203\377\377" \ + "\377\1\377\377\375\212\377\377\377\215\214\306>\1\250\325p\216\377\377" \ + "\377\1\342\361\320\202\214\306>\1\214\305@\211\214\306>\2\214\305@\343" \ + "\361\316\220\377\377\377\5\350\365\333\214\306>\214\305@\214\306>\215" \ + "\306A\221\214\306>\3\215\305>\214\306>\305\342\240\215\377\377\377\7" \ + "\377\377\375\277\337\224\212\306@\215\305@\212\307>\215\306A\215\307" \ + "\77\203\214\306>\202\215\307\77\203\214\306>\3\214\306<\214\306>\351" \ + "\363\330\202\377\377\377\3\376\376\376\374\377\377\376\377\377\211\377" \ + "\377\377\1\376\377\377\202\377\377\377\7\375\376\377\351\365\337\223" \ + "\311M\215\307=\214\305B\214\305@\215\307\77\202\214\306>\12\215\306A" \ + "\214\305@\214\306>\212\307>\215\306A\214\306>\215\307=\213\310\77\316" \ + "\345\255\376\377\377\221\377\377\377\7\376\377\377\377\377\375\300\337" \ + "\223\216\306A\213\305=\215\307=\215\305>\202\214\306>\1\215\307\77\203" \ + "\214\306>\202\214\305@\5\215\307\77\213\307A\251\322r\377\377\377\377" \ + "\377\375\202\377\377\377\14\377\376\377\377\377\377\305\342\237\212\307" \ + "<\220\305\77\214\306>\212\306@\215\306A\214\306<\214\305@\214\306<\216" \ + "\305C\202\214\306>\7\215\305<\214\306>\215\305>\214\305@\342\362\316" \ + "\377\377\377\377\377\375\202\377\377\377\3\376\377\377\377\376\377\376" \ + "\376\376\221\377\377\377\3\376\376\376\377\377\377___\205::<\4;;=FFH" \ + "\363\363\363\377\377\377\202\376\376\376\246\377\377\377\3\363\363\363" \ + "SSU;;=\204::<\4;;=\345\345\345\377\377\377\376\376\376\213\377\377\377" \ + "\1\316\316\316\205::<\1kkm\211\377\377\377\1\376\376\376\203\377\377" \ + "\377\4\264\264\266;;=99;::<\202;;=\3::<GGI\332\332\332\206\377\377\377" \ + "\1\376\376\376\215\377\377\377\1\376\376\376\203\377\377\377\3\234\234" \ + "\236::<;;=\204::<\2\346\346\346\376\376\376\202\377\377\377\1\376\376" \ + "\376\202\377\377\377\202\376\376\376\220\377\377\377\1\376\376\376\204" \ + "\377\377\377\2\376\376\376\317\317\317\204::<\3;;=::<\265\265\265\217" \ + "\377\377\377\1\234\234\236\205::<\1\234\234\234\235\377\377\377\1\376" \ + "\376\376\203\377\377\377\2\363\363\363TTV\203::<\5;;=99;::<\235\235\235" \ + "\376\376\376\215\377\377\377\1\234\234\234\205::<\1\234\234\236\266\377" \ + "\377\377\3\214\305@\214\306>\214\305@\204\214\306>\2\212\306@\213\310" \ + "\77\202\214\305@\3\215\307\77\214\306<\251\323o\231\377\377\377\4\377" \ + "\376\377\377\377\375\377\377\377\376\376\377\214\377\377\377\215\214" \ + "\306>\1\250\325p\216\377\377\377\1\342\361\320\202\214\306>\1\214\305" \ + "@\211\214\306>\2\214\305@\343\361\316\215\377\377\377\1\377\377\375\203" \ + "\377\377\377\4\323\353\267\212\307<\214\306<\212\306B\221\214\306>\3" \ + "\215\305>\214\306>\305\342\240\214\377\377\377\7\376\377\377\377\376" \ + "\377\350\365\331\215\307\77\215\305>\214\306>\212\307>\202\214\306>\1" \ + "\215\307\77\205\214\306>\11\215\307\77\213\304A\212\307>\222\312M\343" \ + "\361\316\376\376\377\377\376\377\377\377\377\377\375\377\210\377\377" \ + "\377\1\377\376\377\202\377\377\375\12\377\376\377\350\364\334\220\313" \ + "K\216\306=\215\305<\215\307\77\214\306>\213\305=\214\306>\215\306A\202" \ + "\214\306>\1\214\305@\202\212\307>\6\214\305@\215\306C\215\305>\360\370" \ + "\351\377\377\373\376\377\377\221\377\377\377\7\345\360\322\215\305@\214" \ + "\305@\215\307=\214\304=\213\310=\215\305>\202\214\306>\2\213\305=\215" \ + "\307\77\202\214\305@\7\215\307\77\214\307;\214\305@\363\367\346\376\377" \ + "\377\377\377\373\377\376\377\202\377\377\377\30\376\377\375\377\376\377" \ + "\241\321a\216\306\77\212\306@\213\310=\215\305@\213\307A\217\304>\215" \ + "\305@\214\306<\216\306A\215\306A\212\307>\214\306<\214\306>\212\307<" \ + "\233\314W\366\373\365\377\377\375\377\377\377\377\376\377\373\377\377" \ + "\377\376\377\224\377\377\377\1\317\317\317\205::<\4;;=::<``b\362\362" \ + "\362\247\377\377\377\2\376\376\376\221\221\221\206::<\3\204\204\206\377" \ + "\377\377\376\376\376\214\377\377\377\1\316\316\316\205::<\1kkm\212\377" \ + "\377\377\6\376\376\376\377\377\377\376\376\376\377\377\377\203\203\203" \ + ";;=\205::<\3``b\363\363\363\376\376\376\216\377\377\377\1\376\376\376" \ + "\206\377\377\377\3\363\363\363FFH;;=\203::<\2;;=\203\203\203\203\377" \ + "\377\377\3\376\376\376\377\377\377\376\376\376\225\377\377\377\1\376" \ + "\376\376\204\377\377\377\3kkk::<<<>\202::<\2;;=kkm\217\377\377\377\1" \ + "\234\234\236\205::<\1\234\234\234\236\377\377\377\4\376\376\376\377\377" \ + "\377\376\376\376kkk\202::<\5;;=::<99;;;=TTV\202\377\377\377\1\376\376" \ + "\376\214\377\377\377\1\234\234\234\205::<\1\234\234\236\266\377\377\377" \ + "\3\214\305@\214\306>\214\305@\204\214\306>\10\214\306<\214\306>\214\305" \ + "@\214\306>\215\307\77\214\306>\252\324r\376\377\377\230\377\377\377\1" \ + "\377\377\375\202\377\377\377\2\377\377\375\376\376\374\203\377\376\377" \ + "\210\377\377\377\215\214\306>\1\250\325p\216\377\377\377\1\342\361\320" \ + "\202\214\306>\1\214\305@\211\214\306>\2\214\305@\343\361\316\215\377" \ + "\377\377\10\375\377\374\377\376\377\375\377\376\376\376\377\377\377\377" \ + "\270\333\207\214\305@\215\307\77\221\214\306>\3\215\305>\214\306>\305" \ + "\342\240\214\377\377\377\12\375\376\377\377\376\377\376\377\377\234\313" \ + "Y\215\306A\214\305@\212\307>\214\305@\214\306>\215\307\77\206\214\306" \ + ">\7\215\307\77\214\306>\215\305@\213\310\77\304\343\240\371\372\364\376" \ + "\377\377\212\377\377\377\10\376\377\377\377\376\377\315\345\251\223\311" \ + "M\214\306>\216\306\77\214\305B\214\306<\202\214\306>\15\215\306A\214" \ + "\305@\214\306>\215\307\77\214\305@\214\306<\214\305@\215\307\77\213\304" \ + "A\263\330{\377\377\377\376\376\376\377\377\375\220\377\377\377\7\370" \ + "\373\364\232\315V\216\306=\212\311=\214\306>\216\306A\213\307A\202\214" \ + "\305@\202\214\306>\202\214\305@\10\215\307\77\215\305>\215\304D\304\341" \ + "\237\376\377\377\377\376\377\376\376\377\377\377\375\202\377\376\377" \ + "\24\376\377\377\377\377\373\350\365\333\215\305>\214\306<\214\306>\212" \ + "\306@\215\307\77\213\305=\215\305@\215\307\77\214\306>\215\305>\215\306" \ + "A\211\305A\215\305@\214\305B\213\310=\262\327z\374\377\377\202\377\377" \ + "\377\2\377\377\375\373\377\376\225\377\377\377\1\221\221\223\203::<\6" \ + ";;=99;;;=::<``b\362\362\362\246\377\377\377\2\265\265\265:::\202::<\1" \ + ";;=\203::<\1\346\346\350\216\377\377\377\1\316\316\316\205::<\1kkm\216" \ + "\377\377\377\6\363\363\363__a::<;;=::<;;=\202::<\1\204\204\204\204\377" \ + "\377\377\1\376\376\376\221\377\377\377\1\234\234\234\204::<\3;;=::<\347" \ + "\347\347\202\377\377\377\1\376\376\376\205\377\377\377\1\376\376\376" \ + "\225\377\377\377\3\376\376\376\377\377\377\265\265\265\202::<\202;;=" \ + "\3::<;;=\316\316\316\216\377\377\377\1\234\234\236\205::<\1\234\234\234" \ + "\240\377\377\377\2\204\204\204:::\206::<\1\301\301\303\217\377\377\377" \ + "\1\234\234\234\205::<\1\234\234\236\266\377\377\377\3\214\305@\214\306" \ + ">\214\305@\205\214\306>\7\214\305@\216\306A\215\307=\213\304\77\213\307" \ + "A\242\321a\345\356\317\230\342\362\316\7\341\361\315\342\361\322\342" \ + "\361\320\343\361\315\345\360\322\365\373\357\376\377\377\211\377\377" \ + "\377\215\214\306>\1\250\325p\216\377\377\377\1\342\361\320\202\214\306" \ + ">\1\214\305@\211\214\306>\2\214\305@\343\361\316\216\377\377\377\7\376" \ + "\377\375\377\377\375\377\377\377\377\376\377\371\374\365\242\322d\215" \ + "\306A\221\214\306>\3\215\305>\214\306>\305\342\240\214\377\377\377\10" \ + "\377\377\375\377\377\377\377\377\373\312\346\253\215\307=\212\307>\214" \ + "\305B\216\306=\206\214\306>\202\214\305@\10\214\306>\212\307>\216\306" \ + "\77\214\306>\212\307>\233\316W\306\340\237\361\370\346\210\377\377\377" \ + "\12\361\370\350\314\345\253\233\314W\214\306>\213\310\77\215\305<\214" \ + "\305@\212\307<\215\306A\214\305@\203\214\306>\202\214\305@\202\214\306" \ + ">\4\216\306A\212\306@\213\310\77\333\356\301\202\377\377\377\1\377\377" \ + "\375\220\377\377\377\26\270\332\204\215\306A\212\306B\214\306>\213\307" \ + "A\215\305@\214\306<\214\306>\215\306A\214\306<\215\307\77\214\305B\215" \ + "\307\77\214\307;\215\304D\241\323b\377\377\375\376\377\377\377\377\377" \ + "\377\377\373\377\377\377\376\377\377\202\377\377\375\16\377\377\377\376" \ + "\377\377\277\337\224\214\305@\215\306A\214\306>\215\305>\212\310\77\214" \ + "\305@\215\307\77\212\307>\214\305B\216\306=\215\306A\202\214\306<\6\214" \ + "\306>\213\307C\331\356\305\377\376\377\377\377\373\376\376\376\227\377" \ + "\377\377\3__a::<;:\77\205::<\2__a\363\363\363\203\377\377\377\1\376\376" \ + "\376\213\377\377\377\1\376\376\376\203\377\377\377\3\376\376\376\377" \ + "\377\377\376\376\376\213\377\377\377\1\376\376\376\202\377\377\377\1" \ + "\265\265\267\205::<\3;;=:::\234\234\234\217\377\377\377\1\316\316\316" \ + "\205::<\1kkm\217\377\377\377\4\332\332\332GGI::<;;=\204::<\1\250\250" \ + "\252\225\377\377\377\1FFH\205::<\1\204\204\204\242\377\377\377\1TTV\205" \ + "::<\4lln\376\376\376\377\377\377\376\376\376\203\377\377\377\1\376\376" \ + "\376\207\377\377\377\1\234\234\236\205::<\1\235\235\237\221\377\377\377" \ + "\1\376\376\376\202\377\377\377\1\376\376\376\202\377\377\377\202\376" \ + "\376\376\205\377\377\377\3\363\363\365\204\204\206;;=\204::<\3;;=:::" \ + "xxx\220\377\377\377\1\234\234\234\203::<\3;;=::<\234\234\234\204\377" \ + "\377\377\1\376\376\376\261\377\377\377\3\214\305@\214\306>\214\305@\250" \ + "\214\306>\2\215\307\77\342\362\316\212\377\377\377\215\214\306>\1\250" \ + "\325p\216\377\377\377\1\342\361\320\202\214\306>\1\214\305@\211\214\306" \ + ">\2\214\305@\343\361\316\216\377\377\377\11\375\376\377\377\376\377\377" \ + "\377\375\376\377\377\377\376\377\351\365\335\223\311M\212\307<\214\306" \ + ">\202\216\306A\4\212\307<\215\306A\215\305>\215\307\77\211\214\306>\3" \ + "\215\305>\214\306>\305\342\240\214\377\377\377\20\377\376\377\377\377" \ + "\375\377\376\377\365\374\364\223\312J\217\304>\215\307\77\212\307;\215" \ + "\306A\214\305B\214\305@\215\307\77\214\306<\213\310\77\214\305@\215\305" \ + ">\210\214\306>\10\234\315Z\257\327~\304\343\235\306\340\237\307\341\240" \ + "\304\343\237\257\327\177\241\321a\210\214\306>\20\217\304>\215\306A\212" \ + "\306@\212\307>\213\305;\216\306A\213\305=\215\306C\211\310<\216\306A" \ + "\214\306>\234\314V\377\377\377\375\377\374\376\377\377\377\376\377\211" \ + "\377\377\377\7\377\376\377\376\377\375\376\377\377\376\377\375\377\376" \ + "\377\377\377\377\333\355\303\210\214\306>\10\215\306A\214\305@\216\306" \ + "=\214\306>\215\307\77\214\305@\215\307\77\352\364\334\211\377\377\377" \ + "\6\377\376\377\367\375\363\232\315V\215\307\77\214\306>\214\305@\212" \ + "\214\306>\6\212\307>\223\311M\366\373\364\377\376\377\377\377\377\376" \ + "\377\373\221\377\377\377\1\376\376\376\204\377\377\377\2\346\346\346" \ + "FFH\203::<\1""99;\203::<\2__a\332\332\332\211\377\377\377\1\376\376\376" \ + "\203\377\377\377\1\376\376\376\205\377\377\377\1\376\376\376\206\377" \ + "\377\377\1\376\376\376\207\377\377\377\1\265\265\267\202::<\1;;=\204" \ + "::<\2```\376\376\376\217\377\377\377\1\316\316\316\205::<\1kkm\216\377" \ + "\377\377\4\376\376\376\377\377\377\301\301\301;;=\205::<\2;;=\331\331" \ + "\331\202\377\377\377\3\376\376\376\377\377\377\376\376\376\216\377\377" \ + "\377\1\265\265\267\205::<\3;;=\332\332\332\376\376\376\241\377\377\377" \ + "\1\266\266\270\205::<\2""99;\316\316\320\215\377\377\377\1\234\234\236" \ + "\203::<\5;;=::<\234\234\234\377\377\377\376\376\376\220\377\377\377\1" \ + "\376\376\376\206\377\377\377\1\376\376\376\203\377\377\377\2\346\346" \ + "\346``b\202::<\2""99;;;=\203::<\4FFF\363\363\363\377\377\377\376\376" \ + "\376\216\377\377\377\1\234\234\234\204::<\3;;=\234\234\234\376\376\376" \ + "\265\377\377\377\3\214\305@\214\306>\214\305@\250\214\306>\2\215\307" \ + "\77\342\362\316\212\377\377\377\215\214\306>\1\250\325p\216\377\377\377" \ + "\1\342\361\320\202\214\306>\1\214\305@\211\214\306>\2\214\305@\343\361" \ + "\316\215\377\377\377\16\377\376\377\376\377\377\377\376\377\377\377\377" \ + "\376\377\377\377\376\377\375\377\374\323\353\267\215\305<\215\306C\215" \ + "\305<\213\306:\213\310\77\212\306@\202\214\305@\211\214\306>\3\215\305" \ + ">\214\306>\305\342\240\215\377\377\377\4\376\377\377\377\377\375\377" \ + "\376\377\305\342\242\202\214\305@\5\216\306A\214\306>\215\307=\215\307" \ + "\77\213\304A\202\214\305@\2\214\306>\212\306@\210\214\306>\7\214\306" \ + "<\215\307=\215\307\77\213\305=\214\306>\215\307\77\213\305=\211\214\306" \ + ">\11\215\306A\215\305>\212\307;\213\304\77\215\306A\211\306=\215\306" \ + "A\212\307<\216\306A\202\215\307\77\4\343\361\320\376\377\375\377\377" \ + "\375\376\376\377\212\377\377\377\1\377\376\377\202\377\377\377\4\377" \ + "\376\377\376\377\377\367\375\363\225\311J\210\214\306>\10\215\307=\213" \ + "\310\77\214\305@\216\306\77\214\305@\212\307>\307\341\240\376\377\375" \ + "\210\377\377\377\5\377\376\377\374\377\375\377\376\377\343\361\320\212" \ + "\306@\202\214\306>\1\213\310\77\210\214\306>\10\215\306A\215\305>\214" \ + "\305@\260\327z\377\376\374\374\377\377\377\377\377\377\376\377\226\377" \ + "\377\377\1\332\332\332\210::<\2GGI\250\250\250\223\377\377\377\3\376" \ + "\376\376\377\377\377\376\376\376\202\377\377\377\1\376\376\376\202\377" \ + "\377\377\1\376\376\376\204\377\377\377\2\250\250\252;;=\204::<\202;;" \ + "=\2EEG\331\331\331\220\377\377\377\1\316\316\316\205::<\1kkm\221\377" \ + "\377\377\5\222\222\224::<;;=::<;;=\202::<\5SSU\364\364\364\376\376\376" \ + "\377\377\377\376\376\376\216\377\377\377\2\376\376\376TTV\203::<\4;;" \ + "=99;lln\376\376\376\243\377\377\377\1TTV\204::<\5;;=\204\204\206\376" \ + "\376\376\377\377\377\376\376\376\212\377\377\377\1\234\234\236\202::" \ + "<\1;;=\202::<\1\234\234\234\215\377\377\377\1\376\376\376\202\377\377" \ + "\377\1\376\376\376\212\377\377\377\6\376\376\376\250\250\252FFH99;::" \ + "<;;=\205::<\1\316\316\316\221\377\377\377\1\234\234\234\203::<\3;;=:" \ + ":<\234\234\236\266\377\377\377\3\214\305@\214\306>\214\305@\250\214\306" \ + ">\2\215\307\77\342\362\316\212\377\377\377\215\214\306>\1\250\325p\216" \ + "\377\377\377\1\342\361\320\202\214\306>\1\214\305@\211\214\306>\2\214" \ + "\305@\343\361\316\215\377\377\377\3\377\376\377\376\377\375\376\377\377" \ + "\202\377\377\377\13\377\377\375\377\376\377\376\376\374\271\332\211\215" \ + "\306A\211\306;\216\306A\212\307>\213\307A\215\306A\212\307>\211\214\306" \ + ">\3\215\305>\214\306>\305\342\240\214\377\377\377\20\376\377\375\377" \ + "\377\377\377\377\375\377\377\377\371\370\364\233\316U\214\306>\214\305" \ + "@\215\306A\214\306>\214\305@\215\307=\214\306>\215\305@\215\304B\213" \ + "\310=\210\214\306>\3\215\305@\214\306>\213\305=\202\213\310\77\3\214" \ + "\306>\215\307\77\215\305@\210\214\306>\20\212\306@\212\307;\216\306\77" \ + "\215\307\77\212\306@\214\306<\215\305>\215\307\77\220\305\77\211\307" \ + ">\263\330{\377\376\377\377\377\375\376\377\377\377\377\377\376\376\376" \ + "\211\377\377\377\7\377\377\373\377\377\377\377\375\376\377\377\377\377" \ + "\377\375\257\330|\213\310\77\211\214\306>\6\215\306C\211\306=\214\305" \ + "@\214\306>\242\322e\377\377\375\212\377\377\377\7\376\377\377\377\377" \ + "\375\377\375\376\277\337\224\216\307B\212\307>\214\305@\210\214\306>" \ + "\2\214\305@\216\306\77\202\212\307>\4\332\360\302\376\376\374\376\376" \ + "\376\377\376\377\227\377\377\377\1\266\266\266\202::<\1;;=\202::<\2;" \ + ";=::<\202;;=\2kkm\346\346\350\202\377\377\377\1\376\376\376\207\377\377" \ + "\377\1\376\376\376\203\377\377\377\5\376\376\376\377\377\377\376\376" \ + "\376\377\377\377\376\376\376\202\377\377\377\3\376\376\376\377\377\377" \ + "\376\376\376\204\377\377\377\2\364\364\364yy{\203::<\2;;=99;\203::<\3" \ + "\265\265\267\377\377\377\376\376\376\217\377\377\377\1\316\316\316\205" \ + "::<\1kkm\222\377\377\377\1kkm\203::<\1;;=\202::<\5kkm\377\377\377\376" \ + "\376\376\377\377\377\376\376\376\212\377\377\377\5\376\376\376\377\377" \ + "\377\376\376\376\265\265\267;;=\204::<\2;;=\315\315\315\244\377\377\377" \ + "\11\234\234\234::<99;;;=::<;;=::<\347\347\347\376\376\376\213\377\377" \ + "\377\1\234\234\236\204::<\2;;=\233\233\233\217\377\377\377\1\376\376" \ + "\376\206\377\377\377\6\376\376\376\377\377\377\376\376\376\377\377\377" \ + "\265\265\265TTT\202::<\202;;=\203::<\3;;=::<\266\266\270\202\377\377" \ + "\377\1\376\376\376\217\377\377\377\1\234\234\234\204::<\4;;=\235\235" \ + "\237\377\377\377\376\376\376\224\377\377\377\1\376\376\376\203\377\377" \ + "\377\1\376\376\376\233\377\377\377\3\214\305@\214\306>\214\305@\250\214" \ + "\306>\2\215\307\77\342\362\316\212\377\377\377\215\214\306>\1\250\325" \ + "p\216\377\377\377\1\342\361\320\202\214\306>\1\214\305@\211\214\306>" \ + "\2\214\305@\343\361\316\215\377\377\377\202\377\377\375\16\377\377\377" \ + "\377\377\375\377\377\377\376\377\375\376\376\374\377\376\377\375\377" \ + "\376\241\322_\215\306A\212\306B\215\305>\215\307\77\214\306<\214\305" \ + "B\211\214\306>\3\215\305>\214\306>\305\342\240\214\377\377\377\1\377" \ + "\376\377\202\377\377\375\15\376\377\377\377\375\376\340\361\317\214\306" \ + ">\212\307>\214\306>\215\307\77\214\306>\212\307<\215\307\77\215\305>" \ + "\216\306=\213\305=\210\214\306>\1\212\307>\202\214\305@\202\214\306>" \ + "\3\214\305@\215\306A\212\307>\210\214\306>\20\212\307>\213\304\77\214" \ + "\306>\211\310<\214\306>\216\306A\212\306@\215\305@\214\306>\223\313N" \ + "\367\372\363\376\377\377\377\377\377\377\376\377\376\377\373\377\376" \ + "\377\212\377\377\377\202\376\377\377\3\377\375\376\324\353\265\215\306" \ + "A\211\214\306>\7\215\305>\213\305=\215\307\77\215\306A\212\307>\351\363" \ + "\333\377\377\375\211\377\377\377\10\377\376\377\375\377\376\376\377\377" \ + "\377\376\377\370\373\362\233\314W\215\307\77\215\305<\210\214\306>\1" \ + "\215\307\77\202\214\306>\4\214\306<\225\310O\360\366\350\377\376\377" \ + "\221\377\377\377\3\376\376\376\377\377\377\376\376\376\205\377\377\377" \ + "\1\266\266\266\202::<\4;;=99;::<;;=\202::<\4;;=::<\204\204\206\346\346" \ + "\350\207\377\377\377\1\376\376\376\206\377\377\377\202\376\376\376\202" \ + "\377\377\377\1\376\376\376\203\377\377\377\1\376\376\376\202\377\377" \ + "\377\3\251\251\251FFF99;\202::<\1""99;\202::<\5;;=::<\234\234\236\377" \ + "\377\377\376\376\376\220\377\377\377\1\316\316\316\205::<\1kkm\222\377" \ + "\377\377\11\363\363\363GGI99;::<99;;;=::<;;=\234\234\234\214\377\377" \ + "\377\1\376\376\376\203\377\377\377\1SSU\202::<\1;;=\202::<\1kkm\245\377" \ + "\377\377\5\362\362\362GGI;;=::<;;=\202::<\1\204\204\206\206\377\377\377" \ + "\1\376\376\376\205\377\377\377\1\234\234\236\203::<\3""99;::<\234\234" \ + "\234\223\377\377\377\1\376\376\376\203\377\377\377\3\331\331\331\222" \ + "\222\222SSU\203::<\2;;=::<\202;;=\4::<;;=::<\265\265\267\202\377\377" \ + "\377\1\376\376\376\203\377\377\377\1\376\376\376\214\377\377\377\1\234" \ + "\234\234\205::<\1\234\234\236\203\377\377\377\1\376\376\376\223\377\377" \ + "\377\1\376\376\376\236\377\377\377\3\214\305@\214\306>\214\305@\250\214" \ + "\306>\2\215\307\77\342\362\316\212\377\377\377\215\214\306>\1\250\325" \ + "p\216\377\377\377\1\342\361\320\202\214\306>\1\214\305@\211\214\306>" \ + "\2\214\305@\343\361\316\216\377\377\377\17\377\376\377\377\377\377\376" \ + "\376\376\377\376\377\377\377\375\376\377\377\375\377\376\377\377\377" \ + "\363\367\350\222\312K\214\305@\213\310\77\214\304\77\215\307\77\216\306" \ + "A\211\214\306>\3\215\305>\214\306>\305\342\240\214\377\377\377\14\377" \ + "\376\377\376\377\375\376\377\377\377\376\377\376\377\377\376\377\375" \ + "\307\342\237\214\305@\214\306<\215\304D\214\306>\214\305D\202\212\307" \ + "<\2\212\307>\213\307A\210\214\306>\3\215\307\77\214\306>\215\307\77\202" \ + "\214\305@\213\214\306>\12\213\305;\215\306A\212\306@\214\306>\213\307" \ + "C\212\307>\215\305>\212\307>\215\305>\333\356\301\202\377\377\377\3\377" \ + "\377\375\377\377\377\377\376\377\211\377\377\377\10\376\377\375\377\377" \ + "\375\376\377\375\374\377\375\362\371\347\225\311M\215\307\77\215\305" \ + "<\210\214\306>\2\214\305@\216\306=\202\212\306@\2\305\342\237\377\375" \ + "\376\212\377\377\377\1\376\376\374\203\377\377\377\4\376\376\376\337" \ + "\363\316\215\306C\215\305<\211\214\306>\1\215\307\77\202\214\305@\4\214" \ + "\306<\253\324n\375\377\374\377\377\375\224\377\377\377\1\376\376\376" \ + "\204\377\377\377\2\301\301\301FFH\202::<\2;;=99;\202;;=\2::<;;=\202:" \ + ":<\2\204\204\206\316\316\320\207\377\377\377\1\376\376\376\203\377\377" \ + "\377\1\376\376\376\206\377\377\377\6\376\376\376\377\377\377\364\364" \ + "\364\265\265\267SSU::<\202;;=\202::<\5;;=::<;;=::<\204\204\204\223\377" \ + "\377\377\1\316\316\316\205::<\1kkm\223\377\377\377\11\315\315\315;;=" \ + "::<;;=::<;;=::<99;\302\302\302\216\377\377\377\5\301\301\303::<;;=::" \ + "<;;=\202::<\2\316\316\316\377\377\377\202\376\376\376\241\377\377\377" \ + "\14\376\376\376\377\377\377\234\234\234;;=::<;;=::<;;=::<\347\347\351" \ + "\377\377\377\376\376\376\211\377\377\377\1\234\234\236\203::<\3;;=::" \ + "<\234\234\236\216\377\377\377\202\376\376\376\1\377\377\377\202\316\316" \ + "\316\6\250\250\250\234\234\234jjjFFF;;=99;\202;;=\2::<;;=\202::<\5<<" \ + ">99;;;=::<\265\265\267\204\377\377\377\1\376\376\376\217\377\377\377" \ + "\1\234\234\234\204::<\2;;=\234\234\236\202\377\377\377\1\376\376\376" \ + "\223\377\377\377\1\376\376\376\202\377\377\377\1\376\376\376\234\377" \ + "\377\377\3\214\305@\214\306>\214\305@\250\214\306>\2\215\307\77\342\362" \ + "\316\212\377\377\377\215\214\306>\1\250\325p\216\377\377\377\1\342\361" \ + "\320\202\214\306>\1\214\305@\211\214\306>\2\214\305@\343\361\316\215" \ + "\377\377\377\202\377\376\377\16\377\377\375\376\377\377\377\377\377\377" \ + "\377\375\377\376\377\376\376\376\377\376\377\377\377\377\333\354\302" \ + "\212\307>\213\310\77\214\306<\213\310=\215\305@\211\214\306>\3\215\305" \ + ">\214\306>\305\342\240\214\377\377\377\1\377\376\377\202\376\377\377" \ + "\202\377\377\375\13\376\377\377\377\375\376\271\333\205\215\305>\214" \ + "\306>\212\307>\214\306>\215\306A\214\306>\212\306@\214\305@\210\214\306" \ + ">\3\214\305@\215\307\77\214\306>\202\212\307>\3\214\306>\215\307\77\215" \ + "\306A\210\214\306>\4\216\306A\211\306=\214\306<\216\306A\202\212\307" \ + ">\202\215\306A\10\322\352\270\377\377\375\376\376\374\377\377\377\376" \ + "\377\377\377\376\377\377\377\375\376\377\377\210\377\377\377\10\377\377" \ + "\375\377\377\377\377\376\377\374\376\373\250\325n\216\306\77\212\307" \ + ">\214\305B\210\214\306>\202\212\307>\6\214\305@\242\322d\376\376\374" \ + "\377\377\375\375\377\376\377\376\377\210\377\377\377\10\376\377\377\377" \ + "\377\375\377\375\376\377\377\375\375\376\377\376\377\375\270\333\207" \ + "\211\310<\210\214\306>\10\214\304=\216\307B\214\306>\212\307>\216\306" \ + "A\215\307\77\313\350\250\376\376\377\221\377\377\377\1\376\376\376\203" \ + "\377\377\377\1\376\376\376\204\377\377\377\7\332\332\332RRT;;=::<;;=" \ + "::<;;=\202::<\1;;=\203::<\3RRT\221\221\223\317\317\321\214\377\377\377" \ + "\11\376\376\376\377\377\377\364\364\364\301\301\301\204\204\206EEG;;" \ + "=99;;;=\204::<\1""99;\202::<\1\251\251\251\207\377\377\377\1\376\376" \ + "\376\214\377\377\377\1\316\316\316\205::<\1kkm\224\377\377\377\1\247" \ + "\247\247\203::<\5;;=::<;;=FFH\345\345\345\214\377\377\377\2\376\376\376" \ + "kkm\205::<\1SSU\202\377\377\377\1\376\376\376\244\377\377\377\2\363\363" \ + "\363FFH\204::<\2;;=\221\221\223\213\377\377\377\1\234\234\236\204::<" \ + "\4;;=SSUkkmlln\213kkm\5;;=::<;;=::<;;=\204::<\2;;=99;\202;;=\2::<;;=" \ + "\202::<\7;;=99;::<FFH\301\301\301\377\377\377\376\376\376\223\377\377" \ + "\377\1\234\234\234\205::<\1SSU\202kkm\1lln\223kkm\1lln\205kkm\1\332\332" \ + "\334\231\377\377\377\3\214\305@\214\306>\214\305@\250\214\306>\2\215" \ + "\307\77\342\362\316\212\377\377\377\215\214\306>\1\250\325p\216\377\377" \ + "\377\1\342\361\320\202\214\306>\1\214\305@\211\214\306>\2\214\305@\343" \ + "\361\316\215\377\377\377\1\377\376\377\202\377\377\375\202\377\377\377" \ + "\202\377\376\377\11\377\377\375\377\377\377\376\377\377\377\376\377\276" \ + "\336\223\214\306<\213\310\77\214\304=\215\306A\211\214\306>\3\215\305" \ + ">\214\306>\305\342\240\214\377\377\377\20\377\377\375\376\377\375\376" \ + "\376\376\377\376\377\375\377\376\377\375\377\376\377\377\376\377\375" \ + "\270\333\207\217\305<\212\307>\214\305@\216\306\77\213\305=\214\305@" \ + "\216\306=\211\214\306>\2\215\306A\215\305@\202\216\306\77\3\215\305@" \ + "\214\305@\215\307\77\210\214\306>\13\213\305=\215\306A\215\305>\212\306" \ + "@\215\305>\215\306A\220\305A\323\352\266\376\377\375\377\376\377\377" \ + "\377\375\202\377\377\377\3\376\377\377\377\375\377\376\377\375\213\377" \ + "\377\377\5\316\347\256\212\307>\213\305;\216\306A\212\307<\210\214\306" \ + ">\10\212\307>\216\306\77\215\305>\350\364\336\377\376\377\376\376\374" \ + "\377\377\377\377\376\377\210\377\377\377\1\377\376\377\202\377\377\377" \ + "\5\377\376\377\376\377\375\377\376\377\370\373\360\225\311K\210\214\306" \ + ">\10\216\306=\214\305@\215\310<\212\307>\214\306>\214\305@\223\312J\356" \ + "\371\350\231\377\377\377\4\376\376\376\377\377\377\363\363\363xxz\202" \ + "::<\1""99;\202::<\1;;=\203::<\202;;=\203::<\4__a\205\205\205\234\234" \ + "\234\250\250\250\205\316\316\316\4\250\250\250\234\234\234xxx___\202" \ + "::<\3""99;;;=99;\203::<\1;;=\203::<\2FFH\265\265\265\205\377\377\377" \ + "\1\376\376\376\217\377\377\377\1\316\316\316\205::<\1kkm\225\377\377" \ + "\377\3xxx::<;;=\204::<\1```\213\377\377\377\4\376\376\376\317\317\317" \ + "::<;;=\204::<\1\266\266\270\203\377\377\377\1\376\376\376\241\377\377" \ + "\377\1\377\377\375\202\377\377\377\1\204\204\206\202::<\1;;=\202::<\2" \ + "GGI\363\363\363\212\377\377\377\1\234\234\236\203::<\1;;=\202::<\1;;" \ + "=\221::<\1;;=\207::<\1;;=\202::<\1;;=\202::<\2``b\346\346\350\210\377" \ + "\377\377\1\376\376\376\215\377\377\377\1\234\234\234\207::<\3;;=::<;" \ + ";=\221::<\1;;=\203::<\1;;=\202::<\1\316\316\320\231\377\377\377\3\214" \ + "\305@\214\306>\214\305@\250\214\306>\2\215\307\77\342\362\316\212\377" \ + "\377\377\215\214\306>\1\250\325p\216\377\377\377\1\342\361\320\202\214" \ + "\306>\1\214\305@\211\214\306>\2\214\305@\343\361\316\215\377\377\377" \ + "\7\377\377\375\376\377\375\377\377\377\377\376\377\376\376\374\376\377" \ + "\377\377\377\377\202\376\377\377\202\377\377\375\4\377\377\377\242\320" \ + "d\211\306=\215\305@\212\214\306>\3\215\305>\214\306>\305\342\240\214" \ + "\377\377\377\6\377\376\377\377\377\377\377\377\375\377\375\377\376\377" \ + "\372\375\376\377\202\377\377\377\10\376\377\377\304\343\240\215\305@" \ + "\214\306>\216\306A\215\307\77\212\307>\215\307\77\212\214\306>\3\215" \ + "\307\77\214\306>\214\305@\202\215\307\77\211\214\306>\12\215\306C\212" \ + "\307<\215\307\77\215\305@\213\310\77\215\306A\323\352\266\377\376\377" \ + "\377\377\377\376\377\377\204\377\377\377\2\377\377\375\377\376\377\210" \ + "\377\377\377\10\376\377\377\377\376\377\361\370\346\225\311K\212\307" \ + ">\215\306A\214\305@\215\305>\210\214\306>\3\214\305@\214\306>\307\341" \ + "\240\203\376\377\377\2\377\377\375\376\377\377\210\377\377\377\5\376" \ + "\377\377\377\376\372\376\377\375\376\376\376\377\377\377\202\377\376" \ + "\377\1\334\355\301\210\214\306>\10\215\306A\213\310\77\215\305@\214\306" \ + ">\214\306<\215\306A\214\306>\254\322o\232\377\377\377\6\376\376\376\377" \ + "\377\377\376\376\376\302\302\302FFH;;=\206::<\1;;=\202::<\202;;=\203" \ + "::<\1;;=\204::<\3;;=::<;;=\202::<\1;;=\202::<\1;;=\203::<\2;;=::<\202" \ + ";;=\2__a\332\332\332\226\377\377\377\3\316\316\316::<;;=\203::<\1kkm" \ + "\222\377\377\377\7\376\376\376\377\377\377\376\376\376\363\363\363__" \ + "a::<;;=\204::<\1\203\203\203\202\377\377\377\2\376\376\376\377\377\377" \ + "\202\376\376\376\205\377\377\377\1kkm\202::<\1;;=\202::<\5TTV\377\377" \ + "\377\376\376\376\377\377\377\376\376\376\245\377\377\377\2\347\347\347" \ + "99;\202::<\1;;=\202::<\1\235\235\237\206\377\377\377\1\376\376\376\202" \ + "\377\377\377\2\376\376\376\234\234\234\224::<\1;;=\202::<\3""99;::<;" \ + ";=\204::<\1;;=\204::<\3;;=GGI\250\250\252\230\377\377\377\2\234\234\236" \ + ";;=\232::<\10;;=99;;;=::<;;=::<:::\316\316\316\230\377\377\377\10\377" \ + "\376\377\212\306@\214\305@\213\310=\214\306<\215\306A\214\307;\215\306" \ + "A\240\214\306>\10\214\305@\212\307<\214\306<\214\305@\212\306@\342\360" \ + "\315\376\377\377\377\376\377\210\377\377\377\212\214\306>\4\216\306\77" \ + "\212\306B\214\306>\250\325n\202\377\376\377\210\377\377\377\1\377\376" \ + "\377\202\377\377\377\5\376\377\375\342\362\316\214\305B\215\305@\214" \ + "\306<\210\214\306>\202\212\307>\5\343\361\320\377\377\377\377\377\375" \ + "\376\377\377\377\376\377\223\377\377\377\6\377\376\377\377\377\375\371" \ + "\372\364\223\312J\212\306@\215\305@\210\214\306>\10\214\305@\215\305" \ + ">\212\307>\304\343\240\377\377\375\377\377\377\377\377\375\377\376\377" \ + "\220\377\377\377\11\376\377\377\377\377\377\333\355\303\226\310K\213" \ + "\310\77\214\306>\215\305@\215\306A\214\305@\203\214\306>\7\215\305>\215" \ + "\305@\214\305@\212\307>\215\305>\215\307\77\215\306A\202\214\306<\5\215" \ + "\306A\213\305=\215\305@\215\307\77\213\305;\202\215\305@\13\215\307\77" \ + "\213\310\77\214\305@\215\307\77\212\307>\215\305>\214\306>\212\306@\235" \ + "\315U\347\365\334\377\376\377\220\377\377\377\15\376\376\376\377\377" \ + "\375\377\377\377\244\317c\213\307A\214\306<\213\307A\215\305>\215\305" \ + "<\215\307\77\214\306<\215\307\77\214\305@\202\215\307\77\12\214\305@" \ + "\215\306A\215\305@\234\315W\367\375\363\377\376\377\376\377\377\377\377" \ + "\375\376\377\377\377\376\377\220\377\377\377\10\260\331{\215\307=\212" \ + "\307>\213\307A\214\306>\215\305@\215\307\77\215\305>\210\214\306>\3\314" \ + "\345\253\377\377\377\376\377\375\202\377\376\377\2\377\377\377\376\377" \ + "\377\222\377\377\377\3\376\376\376\377\377\377\376\376\376\202\377\377" \ + "\377\3\364\364\364\220\220\220;;=\211::<\2;;=::<\202;;=\2::<;;=\202:" \ + ":<\4;;=::<;;=99;\203::<\2;;=99;\206::<\2GGI\247\247\251\203\377\377\377" \ + "\1\376\376\376\222\377\377\377\6\376\376\376\377\377\377\316\316\316" \ + ";;=99;;;=\202::<\2lln\376\376\376\202\377\377\377\1\376\376\376\221\377" \ + "\377\377\4\376\376\376\333\333\333FFH;;=\202::<\1;;=\202::<\1\265\265" \ + "\265\202\377\377\377\1\376\376\376\202\377\377\377\5\376\376\376\377" \ + "\377\377\376\376\376\377\377\377\316\316\320\202::<\2;;=99;\202;;=\1" \ + "\264\264\266\202\377\377\377\1\376\376\376\244\377\377\377\1\376\376" \ + "\376\202\377\377\377\1\205\205\207\204::<\3;;=FFH\363\363\363\206\377" \ + "\377\377\1\376\376\376\202\377\377\377\3\233\233\233::<;;=\220::<\3""9" \ + "9;;;=99;\202::<\1;;=\203::<\1;;=\204::<\7;;=::<SSU\250\250\252\362\362" \ + "\364\377\377\377\376\376\376\225\377\377\377\3\376\376\376\377\377\377" \ + "\235\235\237\202::<\1;;=\231::<\2;;=99;\204::<\1\316\316\316\230\377" \ + "\377\377\10\377\377\373\212\311=\212\306@\216\306A\215\305>\215\307\77" \ + "\214\306>\215\306A\240\214\306>\7\214\306<\214\306>\216\306\77\214\306" \ + ">\214\305@\343\361\320\377\377\375\211\377\377\377\210\214\306>\10\213" \ + "\307A\212\306@\215\305@\212\307<\215\307\77\247\324o\375\377\376\376" \ + "\377\377\211\377\377\377\7\376\377\375\377\377\377\377\377\375\342\360" \ + "\315\214\305@\213\305=\215\307\77\210\214\306>\10\215\305>\215\307\77" \ + "\343\361\316\376\376\376\377\376\377\376\377\377\377\377\375\376\377" \ + "\372\220\377\377\377\10\376\377\377\377\376\377\377\377\375\377\376\374" \ + "\376\377\375\343\362\321\212\307>\214\307;\210\214\306>\4\215\307=\215" \ + "\304B\213\307A\305\342\240\203\377\377\377\1\376\377\377\222\377\377" \ + "\377\21\377\376\377\367\374\365\267\332\206\215\306A\212\306@\214\306" \ + "<\214\306>\215\306A\215\307\77\214\306>\214\305@\212\306B\212\306@\212" \ + "\307<\215\307\77\214\306>\214\305@\202\215\305@\5\214\305@\214\306>\214" \ + "\305@\212\307>\215\306A\202\214\305@\11\214\307;\214\306>\215\306A\214" \ + "\305@\215\305>\212\306@\222\311I\306\343\240\366\373\364\224\377\377" \ + "\377\6\303\342\237\217\304@\214\306<\214\306>\215\306C\212\306B\204\214" \ + "\305@\1\215\306A\202\214\305@\11\215\306A\214\306<\214\306>\341\361\314" \ + "\377\377\377\376\377\375\377\377\377\377\375\377\377\377\375\221\377" \ + "\377\377\10\370\373\364\224\307N\215\305@\215\305>\212\307<\215\306A" \ + "\212\307<\215\306A\210\214\306>\10\215\307=\346\364\332\376\377\375\376" \ + "\377\373\377\377\377\376\376\377\377\376\377\377\377\375\230\377\377" \ + "\377\5\346\346\350\204\204\206GGI::<;;=\202::<\5;;=::<;;=::<;;=\202:" \ + ":<\3;;=::<;;=\202::<\5;;=99;;;=::<;;=\207::<\3FFH\234\234\234\363\363" \ + "\363\203\377\377\377\1\376\376\376\222\377\377\377\1\376\376\376\202" \ + "\377\377\377\4\316\316\316::<;;=99;\202;;=\1kkm\202\377\377\377\1\376" \ + "\376\376\220\377\377\377\1\376\376\376\202\377\377\377\5\376\376\376" \ + "\266\266\26699;;;=::<\202;;=\3::<GGG\332\332\332\207\377\377\377\2\376" \ + "\376\376\204\204\206\202;;=\4::<;;=::<SSU\252\377\377\377\2\376\376\376" \ + "\346\346\350\202::<\5;;=::<99;;;;\266\266\266\203\377\377\377\1\376\376" \ + "\376\205\377\377\377\3\235\235\235::<99;\220::<\1;;=\205::<\203;;=\1" \ + "99;\203::<\3SSS\221\221\221\316\316\316\205\377\377\377\1\376\376\376" \ + "\222\377\377\377\1\376\376\376\203\377\377\377\3\234\234\236::<;;=\232" \ + "::<\7""99;::<;:\77::<;;=99;\317\317\321\230\377\377\377\7\377\375\377" \ + "\214\306<\213\307A\215\305>\215\307\77\212\307>\216\306\77\241\214\306" \ + ">\1\215\306C\202\215\305@\5\212\306@\215\307=\343\361\320\377\377\377" \ + "\377\376\377\210\377\377\377\210\214\306>\10\215\305<\215\307\77\216" \ + "\306\77\214\306>\216\305C\252\324r\377\377\377\377\377\373\211\377\377" \ + "\377\7\375\377\376\377\377\377\377\375\376\343\361\316\215\307=\212\307" \ + ">\215\305>\210\214\306>\10\214\305@\215\305<\342\362\316\377\377\375" \ + "\377\376\377\375\377\374\376\376\377\376\377\377\222\377\377\377\1\375" \ + "\377\372\202\377\377\377\3\377\376\377\304\341\237\215\307\77\210\214" \ + "\306>\10\212\307;\215\307\77\213\305=\305\342\240\377\377\377\377\376" \ + "\374\377\377\375\376\377\377\221\377\377\377\22\377\376\377\377\377\375" \ + "\376\377\377\377\375\376\361\367\351\270\334\204\214\306>\215\307\77" \ + "\214\305@\212\306@\213\307A\212\306@\213\310\77\214\306>\215\304B\214" \ + "\306>\212\307<\214\306>\202\216\306A\6\214\306>\213\310\77\214\305@\215" \ + "\305<\215\305>\215\307=\202\213\310\77\10\215\306A\214\306>\215\306A" \ + "\222\311I\300\336\226\361\370\346\376\376\376\377\377\377\202\377\376" \ + "\377\1\376\377\373\217\377\377\377\10\377\377\375\347\365\333\214\307" \ + ";\211\305A\213\304\77\215\307\77\215\305<\213\310\77\202\214\306>\1\215" \ + "\307\77\203\214\306>\4\215\307\77\214\306>\215\306A\275\337\223\202\377" \ + "\377\377\5\377\376\377\377\377\377\376\377\375\377\376\377\376\377\377" \ + "\220\377\377\377\10\375\377\376\331\357\301\215\307\77\215\305>\216\305" \ + "C\211\306=\220\305A\211\307@\210\214\306>\10\214\305@\246\321e\377\377" \ + "\377\377\376\377\376\377\377\377\377\375\376\377\377\377\376\377\227" \ + "\377\377\377\1\376\376\376\202\377\377\377\3\363\363\363\266\266\270" \ + "__a\207::<\202;;=\203::<\2;;=99;\202;;=\2""99;::<\202;;=\1::<\203;;=" \ + "\3^^^\250\250\250\363\363\363\203\377\377\377\1\376\376\376\202\377\377" \ + "\377\1\376\376\376\224\377\377\377\4\316\316\316999::<;;=\202::<\1ll" \ + "l\205\377\377\377\1\376\376\376\217\377\377\377\6\376\376\376\377\377" \ + "\377\376\376\376\204\204\204::<;;=\203::<\3:::TTT\363\363\363\206\377" \ + "\377\377\10\347\347\347;;;99;::<;;=::<:::\234\234\236\253\377\377\377" \ + "\3\376\376\376lln;;=\202::<\3;;=999SSS\202\377\377\377\1\376\376\376" \ + "\203\377\377\377\4\376\376\376\377\377\377\376\376\376\234\234\234\223" \ + "::<\1""99;\202::<\1;;=\203::<\5kkmxxz\235\235\237\301\301\301\346\346" \ + "\346\207\377\377\377\1\376\376\376\202\377\377\377\1\376\376\376\221" \ + "\377\377\377\1\376\376\376\202\377\377\377\3\235\235\235::<;;=\232::" \ + "<\2;;=99;\202::<\3;;=::<\316\316\316\230\377\377\377\10\373\377\376\216" \ + "\306A\214\306<\213\304A\212\306@\214\305@\214\304\77\215\307\77\240\214" \ + "\306>\6\214\306<\215\306A\215\305@\216\310@\217\304@\341\361\314\212" \ + "\377\377\377\210\214\306>\7\215\307\77\213\310\77\213\305=\215\307\77" \ + "\214\304\77\253\323r\374\377\373\211\377\377\377\1\377\376\377\203\377" \ + "\377\377\3\342\362\315\215\305@\215\307=\211\214\306>\10\214\306<\215" \ + "\304B\341\363\313\374\377\375\376\376\377\377\377\377\377\375\376\377" \ + "\377\375\221\377\377\377\7\376\377\375\376\376\377\377\377\377\375\377" \ + "\374\377\377\377\377\377\375\253\323p\210\214\306>\5\215\307\77\215\305" \ + ">\217\304@\305\342\237\376\377\375\202\377\377\377\1\377\377\375\220" \ + "\377\377\377\1\376\377\377\202\377\376\377\202\376\377\375\202\377\377" \ + "\377\5\360\370\351\311\347\247\245\320e\215\305>\212\307>\202\214\306" \ + ">\5\215\306A\212\307>\215\305@\214\306>\214\306<\202\214\306>\2\214\306" \ + "<\214\306>\202\216\306A\14\214\306>\215\306A\215\305<\214\306>\213\305" \ + "=\255\331x\323\353\267\366\374\362\377\377\377\377\377\375\377\377\377" \ + "\376\377\377\217\377\377\377\2\376\376\376\377\377\377\202\377\377\375" \ + "\11\244\317d\214\306>\213\307A\214\306>\214\305@\214\306>\215\306A\214" \ + "\306<\215\307\77\202\214\306>\202\214\305@\13\215\305<\215\305@\230\316" \ + "V\370\373\360\376\377\375\377\377\377\377\376\377\376\376\376\377\377" \ + "\375\377\376\377\376\377\377\220\377\377\377\10\376\376\376\377\376\377" \ + "\262\327x\214\306>\216\306A\215\307=\215\305<\215\306A\211\214\306>\6" \ + "\215\306C\307\341\240\376\377\373\376\377\377\376\377\375\376\376\374" \ + "\236\377\377\377\4\346\346\350\266\266\270\204\204\206SSU\202::<\1;;" \ + "=\202::<\1;;=\202::<\202;;=\3""99;::<;;=\203::<\4GGIxxz\247\247\247\347" \ + "\347\347\212\377\377\377\1\376\376\376\223\377\377\377\1\364\364\364" \ + "\205\316\316\316\1\332\332\332\203\377\377\377\202\376\376\376\221\377" \ + "\377\377\1\376\376\376\202\377\377\377\202\316\316\316\203\316\316\320" \ + "\3\316\316\316\317\317\317\346\346\346\206\377\377\377\5\346\346\346" \ + "\316\316\316\317\317\317\316\316\316\315\315\315\202\316\316\316\1\363" \ + "\363\363\250\377\377\377\1\376\376\376\203\377\377\377\3\346\346\346" \ + "\315\315\315\317\317\317\202\316\316\320\3\317\317\317\315\315\315\363" \ + "\363\363\202\377\377\377\202\376\376\376\204\377\377\377\3\346\346\346" \ + "\316\316\316\316\316\320\224\316\316\316\1\315\315\315\203\377\377\377" \ + "\1\376\376\376\215\377\377\377\1\376\376\376\225\377\377\377\2\346\346" \ + "\346\317\317\317\232\316\316\316\1\317\317\317\203\316\316\316\4\317" \ + "\317\317\315\315\315\316\316\316\363\363\363\231\377\377\377\3\340\361" \ + "\317\342\360\317\342\362\316\202\343\361\316\2\342\360\315\343\361\316" \ + "\240\342\361\320\10\342\362\316\342\361\320\343\363\317\341\360\317\342" \ + "\361\320\370\373\364\376\377\375\376\377\377\210\377\377\377\210\342" \ + "\361\320\7\341\360\317\342\362\316\343\361\316\342\360\314\342\361\320" \ + "\350\364\336\377\376\374\211\377\377\377\10\377\376\377\377\377\375\377" \ + "\377\377\377\377\375\370\373\362\341\360\321\340\357\316\342\362\316" \ + "\210\342\361\320\3\342\362\316\342\361\320\371\373\360\203\377\377\377" \ + "\202\377\376\377\220\377\377\377\4\377\377\375\376\376\376\377\376\377" \ + "\376\377\375\203\377\377\377\1\365\375\362\210\342\361\320\4\341\360" \ + "\321\342\361\322\343\363\317\360\367\345\224\377\377\377\7\376\377\377" \ + "\376\377\375\377\377\375\377\376\377\377\377\375\377\375\376\377\376" \ + "\377\202\377\377\377\30\376\376\377\364\370\351\333\354\277\277\337\224" \ + "\247\324k\224\313K\214\305@\214\306>\212\306@\214\306>\214\305B\215\306" \ + "C\215\307\77\212\306@\214\306>\215\307\77\241\321c\257\330|\304\342\242" \ + "\341\361\315\377\377\377\377\376\377\376\377\373\377\377\377\202\377" \ + "\377\375\1\377\376\377\203\377\377\377\1\376\377\377\212\377\377\377" \ + "\1\376\376\376\203\377\377\377\13\376\376\374\372\372\370\342\361\320" \ + "\343\361\316\342\362\316\341\360\317\342\361\320\341\360\317\342\362" \ + "\316\342\361\322\342\361\320\202\341\361\315\6\342\361\320\341\360\317" \ + "\343\361\315\343\361\320\356\371\350\377\376\377\203\377\377\377\1\376" \ + "\377\375\202\377\377\377\1\376\377\375\222\377\377\377\6\366\373\364" \ + "\342\361\320\342\362\316\342\360\317\341\362\316\343\361\320\210\342" \ + "\361\320\10\341\362\316\341\361\315\352\364\334\377\377\377\377\376\377" \ + "\377\377\377\376\377\377\376\377\375\222\377\377\377\202\376\376\376" \ + "\202\377\377\377\1\376\376\376\202\377\377\377\1\376\376\376\202\377" \ + "\377\377\3\376\376\376\377\377\377\375\375\375\202\377\377\377\5\363" \ + "\363\363\316\316\316\264\264\264\235\235\235\233\233\233\202kkk\202k" \ + "km\3llnkkmyy{\202\234\234\236\6\316\316\320\346\346\346\377\377\377\376" \ + "\376\376\377\377\377\376\376\376\204\377\377\377\1\376\376\376\204\377" \ + "\377\377\1\376\376\376\240\377\377\377\1\376\376\376\231\377\377\377" \ + "\1\375\375\375\203\377\377\377\1\376\376\376\214\377\377\377\1\376\376" \ + "\376\202\377\377\377\1\376\376\376\242\377\377\377\1\376\376\376\206" \ + "\377\377\377\3\376\376\376\377\377\377\376\376\376\204\377\377\377\1" \ + "\376\376\376\202\377\377\377\202\376\376\376\225\377\377\377\3\376\376" \ + "\376\377\377\377\376\376\376\202\377\377\377\3\376\376\376\377\377\377" \ + "\376\376\376\214\377\377\377\3\376\376\376\377\377\377\376\376\376\265" \ + "\377\377\377\1\375\375\375\234\377\377\377\7\376\377\377\377\376\377" \ + "\376\377\377\376\376\374\377\376\377\377\377\377\377\377\375\240\377" \ + "\377\377\1\377\377\375\202\377\377\377\5\377\376\377\376\376\376\377" \ + "\376\377\376\376\377\377\377\375\221\377\377\377\7\375\376\377\377\377" \ + "\377\377\376\377\377\377\375\376\377\377\377\377\373\377\376\377\210" \ + "\377\377\377\5\377\376\377\377\377\377\376\376\374\376\377\377\377\377" \ + "\377\202\377\377\375\1\376\377\377\210\377\377\377\6\376\377\377\375" \ + "\376\377\377\376\377\377\377\377\376\377\377\377\377\377\202\377\377" \ + "\375\224\377\377\377\202\377\376\377\2\374\377\377\377\376\377\210\377" \ + "\377\377\3\376\377\377\376\376\376\376\377\377\202\377\377\377\3\375" \ + "\377\376\377\377\377\377\376\377\220\377\377\377\202\377\376\377\2\376" \ + "\377\377\375\376\377\202\377\377\377\4\377\377\375\377\376\377\377\377" \ + "\377\377\377\375\202\376\377\377\7\377\377\377\377\376\377\377\377\377" \ + "\376\377\375\370\373\364\344\357\315\342\361\320\202\342\362\315\14\340" \ + "\357\316\345\360\316\376\377\373\376\376\376\377\377\377\377\375\376" \ + "\377\377\375\377\377\377\375\377\376\377\377\377\377\376\377\377\377" \ + "\375\202\376\377\375\5\376\377\377\377\377\377\377\377\375\376\376\376" \ + "\377\376\377\214\377\377\377\1\376\376\376\202\377\377\377\5\377\377" \ + "\375\376\375\377\377\377\377\376\376\377\377\377\375\204\377\377\377" \ + "\1\377\377\375\205\377\377\377\202\377\376\377\2\377\377\377\377\377" \ + "\375\202\377\377\377\202\376\377\377\222\377\377\377\5\377\377\375\377" \ + "\377\377\377\377\375\377\377\377\377\377\375\202\377\377\377\1\377\376" \ + "\372\212\377\377\377\1\377\375\377\202\377\377\377\3\377\376\377\377" \ + "\377\377\377\377\375\225\377\377\377\1\376\376\376\211\377\377\377\1" \ + "\376\376\376\204\377\377\377\1\376\376\376\205\377\377\377\1\376\376" \ + "\376\206\377\377\377\3\376\376\376\377\377\377\376\376\376\206\377\377" \ + "\377\1\376\376\376\233\377\377\377\1\376\376\376\203\377\377\377\5\376" \ + "\376\376\377\377\377\376\376\376\377\377\377\376\376\376\223\377\377" \ + "\377\3\376\376\376\377\377\377\376\376\376\205\377\377\377\3\376\376" \ + "\376\377\377\377\376\376\376\203\377\377\377\3\376\376\376\377\377\377" \ + "\376\376\376\203\377\377\377\1\376\376\376\205\377\377\377\1\376\376" \ + "\376\246\377\377\377\3\376\376\376\377\377\377\376\376\376\220\377\377" \ + "\377\1\376\376\376\246\377\377\377\1\376\376\376\225\377\377\377\1\376" \ + "\376\376\202\377\377\377\1\376\376\376\240\377\377\377\1\376\376\376" \ + "\230\377\377\377\6\377\377\375\377\377\377\377\376\377\376\377\375\374" \ + "\377\377\376\375\377\242\377\377\377\202\377\376\377\6\376\376\376\375" \ + "\376\377\377\377\377\377\377\375\377\377\377\376\377\375\220\377\377" \ + "\377\7\377\377\375\377\377\377\377\377\375\377\375\376\376\377\375\376" \ + "\377\377\376\376\376\212\377\377\377\4\377\376\377\377\377\375\377\377" \ + "\377\377\377\375\203\377\376\377\210\377\377\377\5\377\377\375\377\377" \ + "\377\377\375\376\377\376\377\377\377\375\202\377\377\377\1\376\377\377" \ + "\221\377\377\377\1\375\376\377\203\377\377\375\2\376\377\375\377\375" \ + "\376\211\377\377\377\204\377\376\377\4\377\377\377\376\377\375\377\377" \ + "\375\377\376\377\221\377\377\377\5\376\377\377\376\376\376\377\377\373" \ + "\376\376\377\376\377\377\202\377\377\377\2\377\376\377\377\377\375\202" \ + "\377\377\377\7\377\377\375\377\376\377\376\376\377\377\377\377\376\377" \ + "\377\376\377\375\376\377\377\202\377\377\377\203\376\377\377\2\377\377" \ + "\377\376\376\374\202\377\376\377\13\376\376\376\377\377\375\377\377\377" \ + "\377\375\376\376\377\377\377\377\377\376\376\377\377\376\377\376\376" \ + "\374\376\377\377\377\377\375\221\377\377\377\203\377\377\375\4\377\377" \ + "\377\377\377\375\377\376\377\376\376\376\210\377\377\377\1\377\377\373" \ + "\203\377\377\377\1\377\377\375\202\376\377\377\222\377\377\377\1\377" \ + "\377\375\202\377\376\377\3\377\377\377\377\376\377\377\376\374\202\376" \ + "\377\377\210\377\377\377\4\377\377\375\377\377\377\376\377\375\377\375" \ + "\377\202\376\377\377\1\377\376\375\227\377\377\377\1\376\376\376\207" \ + "\377\377\377\1\376\376\376\217\377\377\377\1\376\376\376\205\377\377" \ + "\377\1\376\376\376\204\377\377\377\1\376\376\376\233\377\377\377\1\376" \ + "\376\376\211\377\377\377\1\376\376\376\222\377\377\377\1\376\376\376" \ + "\206\377\377\377\1\376\376\376\207\377\377\377\1\376\376\376\262\377" \ + "\377\377\1\376\376\376\212\377\377\377\1\376\376\376\202\377\377\377" \ + "\1\376\376\376\202\377\377\377\1\376\376\376\225\377\377\377\1\376\376" \ + "\376\306\377\377\377\1\376\376\376\235\377\377\377\7\377\376\377\376" \ + "\377\377\377\377\377\377\377\375\376\375\377\377\377\375\377\376\377" \ + "\241\377\377\377\1\376\377\377\203\377\377\377\3\377\377\375\377\375" \ + "\376\377\376\377\221\377\377\377\202\376\377\377\5\377\377\377\377\377" \ + "\375\377\377\377\377\376\377\377\377\375\211\377\377\377\203\377\377" \ + "\375\202\377\377\377\202\376\377\377\1\377\377\375\212\377\377\377\202" \ + "\376\377\375\3\376\377\377\377\377\375\377\376\377\223\377\377\377\6" \ + "\377\377\375\377\376\377\374\377\377\377\377\377\377\376\377\376\377" \ + "\375\210\377\377\377\3\377\377\375\376\377\377\377\377\375\202\377\377" \ + "\377\1\377\377\375\223\377\377\377\4\376\376\376\377\377\375\376\376" \ + "\376\377\376\377\202\377\377\375\1\376\376\376\206\377\377\377\1\377" \ + "\377\375\215\377\377\377\1\377\377\375\202\377\377\377\5\376\377\377" \ + "\377\377\377\376\376\374\377\377\377\377\376\377\202\377\377\377\1\376" \ + "\376\376\221\377\377\377\7\376\377\375\377\375\377\377\377\377\376\377" \ + "\377\377\377\377\377\377\373\377\376\377\202\377\377\377\1\377\377\375" \ + "\202\377\377\377\1\377\377\375\204\377\377\377\6\376\376\377\377\377" \ + "\375\376\377\377\377\377\375\377\376\377\375\377\374\222\377\377\377" \ + "\3\376\377\375\377\377\377\376\377\375\203\376\377\377\1\377\376\377" \ + "\211\377\377\377\7\377\377\373\377\376\377\377\377\375\377\377\377\377" \ + "\376\377\376\376\376\376\377\377") + + diff --git a/meta-agl-profile-core/recipes-core/psplash/files/psplash-quit.service b/meta-agl-profile-core/recipes-core/psplash/files/psplash-quit.service new file mode 100644 index 000000000..14bd4994b --- /dev/null +++ b/meta-agl-profile-core/recipes-core/psplash/files/psplash-quit.service @@ -0,0 +1,11 @@ +[Unit] +Description=Terminate Psplash Boot Screen +After=psplash-start.service + +[Service] +Type=oneshot +ExecStart=/usr/bin/psplash-write QUIT +TimeoutSec=20 + +[Install] +WantedBy=multi-user.target diff --git a/meta-agl-profile-core/recipes-core/psplash/files/psplash-start.service b/meta-agl-profile-core/recipes-core/psplash/files/psplash-start.service new file mode 100644 index 000000000..d3b6940d0 --- /dev/null +++ b/meta-agl-profile-core/recipes-core/psplash/files/psplash-start.service @@ -0,0 +1,12 @@ +[Unit] +Description=Start Psplash Boot Screen +Wants=systemd-vconsole-setup.service +After=systemd-vconsole-setup.service systemd-udev-trigger.service systemd-udevd.service +DefaultDependencies=no + +[Service] +ExecStartPre=/bin/sh -c "if [ -e /sys/class/graphics/fbcon/cursor_blink ]; then echo 0 > /sys/class/graphics/fbcon/cursor_blink; fi" +ExecStart=/bin/bash -c "/usr/bin/psplash-anim -n -a 90" + +[Install] +WantedBy=sysinit.target diff --git a/meta-agl-profile-core/recipes-core/psplash/psplash_git.bbappend b/meta-agl-profile-core/recipes-core/psplash/psplash_git.bbappend new file mode 100644 index 000000000..bdc196b6f --- /dev/null +++ b/meta-agl-profile-core/recipes-core/psplash/psplash_git.bbappend @@ -0,0 +1,27 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/files:" + +SRC_URI += "file://psplash-colors.h \ + file://psplash-start.service \ + file://psplash-quit.service \ + file://psplash-anim \ + " + +SPLASH_IMAGES="file://psplash-poky-img.h;outsuffix=default" + +inherit systemd + +SYSTEMD_PACKAGES = "${@bb.utils.contains('DISTRO_FEATURES', 'systemd', '${PN}', '', d)}" +SYSTEMD_SERVICE_${PN} = "${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'psplash-start.service psplash-quit.service', '', d)}" + +do_configure_append () { + cd ${S} + cp ../psplash-colors.h ./ +} + +do_install_append () { + if ${@bb.utils.contains('DISTRO_FEATURES','systemd','true','false',d)}; then + install -d ${D}${systemd_unitdir}/system + install -m 644 ${WORKDIR}/*.service ${D}/${systemd_unitdir}/system + fi + install -m 755 ${WORKDIR}/psplash-anim ${D}/${bindir} +} diff --git a/meta-agl-profile-core/recipes-core/systemd/.appends.core b/meta-agl-profile-core/recipes-core/systemd/.appends.core new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/meta-agl-profile-core/recipes-core/systemd/.appends.core diff --git a/meta-agl-profile-core/recipes-core/systemd/systemd/0001-Switch-Smack-label-earlier.patch b/meta-agl-profile-core/recipes-core/systemd/systemd/0001-Switch-Smack-label-earlier.patch new file mode 100644 index 000000000..46445be73 --- /dev/null +++ b/meta-agl-profile-core/recipes-core/systemd/systemd/0001-Switch-Smack-label-earlier.patch @@ -0,0 +1,52 @@ +From 6cc74075797edb6f698cb7f312bb1c3d8cc6cb28 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jos=C3=A9=20Bollo?= <jose.bollo@iot.bzh> +Date: Thu, 12 Oct 2017 17:17:56 +0200 +Subject: [PATCH] Switch Smack label earlier +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Switching label after removing capability isn't +possible. + +Change-Id: Ib7dac8f071f36119520ed3205d743c1e3df3cd5e +Signed-off-by: José Bollo <jose.bollo@iot.bzh> +--- + src/core/execute.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/src/core/execute.c b/src/core/execute.c +index d72e5bf08..0abffd569 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -2707,6 +2707,13 @@ static int exec_child( + } + } + ++ r = setup_smack(context, command); ++ if (r < 0) { ++ *exit_status = EXIT_SMACK_PROCESS_LABEL; ++ *error_message = strdup("Failed to set SMACK process label"); ++ return r; ++ } ++ + if (!cap_test_all(context->capability_bounding_set)) { + r = capability_bounding_set_drop(context->capability_bounding_set, false); + if (r < 0) { +@@ -2775,13 +2782,6 @@ static int exec_child( + } + #endif + +- r = setup_smack(context, command); +- if (r < 0) { +- *exit_status = EXIT_SMACK_PROCESS_LABEL; +- *error_message = strdup("Failed to set SMACK process label"); +- return r; +- } +- + #ifdef HAVE_APPARMOR + if (context->apparmor_profile && mac_apparmor_use()) { + r = aa_change_onexec(context->apparmor_profile); +-- +2.14.3 + diff --git a/meta-agl-profile-core/recipes-core/systemd/systemd/e2fsck.conf b/meta-agl-profile-core/recipes-core/systemd/systemd/e2fsck.conf new file mode 100644 index 000000000..b774f9ebf --- /dev/null +++ b/meta-agl-profile-core/recipes-core/systemd/systemd/e2fsck.conf @@ -0,0 +1,3 @@ +[options] +# This will prevent e2fsck from stopping boot just because the clock is wrong +broken_system_clock = 1 diff --git a/meta-agl-profile-core/recipes-core/systemd/systemd/wired.network b/meta-agl-profile-core/recipes-core/systemd/systemd/wired.network new file mode 100644 index 000000000..3559b0155 --- /dev/null +++ b/meta-agl-profile-core/recipes-core/systemd/systemd/wired.network @@ -0,0 +1,5 @@ +[Match] +Name=eth* en* + +[Network] +DHCP=yes diff --git a/meta-agl-profile-core/recipes-core/systemd/systemd_%.bbappend b/meta-agl-profile-core/recipes-core/systemd/systemd_%.bbappend new file mode 100644 index 000000000..f64ca8c8a --- /dev/null +++ b/meta-agl-profile-core/recipes-core/systemd/systemd_%.bbappend @@ -0,0 +1,26 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += "\ + file://e2fsck.conf \ + ${@bb.utils.contains('VIRTUAL-RUNTIME_net_manager','systemd','file://wired.network','',d)} \ +" + +# enable networkd/resolved support +PACKAGECONFIG_append_pn-systemd = " \ + ${@bb.utils.contains('VIRTUAL-RUNTIME_net_manager','systemd','networkd resolved','',d)} \ +" + +do_install_append() { + # Install /etc/e2fsck.conf to avoid boot stuck by wrong clock time + install -m 644 -p -D ${WORKDIR}/e2fsck.conf ${D}${sysconfdir}/e2fsck.conf + + if ${@bb.utils.contains('VIRTUAL-RUNTIME_net_manager','systemd','true','false',d)}; then + # Install DHCP configuration for Ethernet adapters + install -m 644 ${WORKDIR}/wired.network ${D}${sysconfdir}/systemd/network + fi +} + +FILES_${PN} += "${sysconfdir}/e2fsck.conf " + +# SPEC-737: connmand also has a NTP client which races with systemd-timesyncd +PACKAGECONFIG_remove = "timesyncd" diff --git a/meta-agl-profile-core/recipes-core/systemd/systemd_234.bbappend b/meta-agl-profile-core/recipes-core/systemd/systemd_234.bbappend new file mode 100644 index 000000000..4df7684d0 --- /dev/null +++ b/meta-agl-profile-core/recipes-core/systemd/systemd_234.bbappend @@ -0,0 +1,6 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" + +SRC_URI += "\ + file://0001-Switch-Smack-label-earlier.patch \ +" + diff --git a/meta-agl-profile-core/recipes-devtools/gdb/gdb_%.bbappend b/meta-agl-profile-core/recipes-devtools/gdb/gdb_%.bbappend new file mode 100644 index 000000000..7cba933af --- /dev/null +++ b/meta-agl-profile-core/recipes-devtools/gdb/gdb_%.bbappend @@ -0,0 +1 @@ +PACKAGECONFIG_remove = "readline" diff --git a/meta-agl-profile-core/recipes-devtools/low-level-can-generator/low-level-can-generator_git.bb b/meta-agl-profile-core/recipes-devtools/low-level-can-generator/low-level-can-generator_git.bb new file mode 100644 index 000000000..d364939b5 --- /dev/null +++ b/meta-agl-profile-core/recipes-devtools/low-level-can-generator/low-level-can-generator_git.bb @@ -0,0 +1,16 @@ +SUMMARY = "Low level CAN generator" +DESCRIPTION = "Generator used to customize low level CAN service with customs signals" +SECTION = "devel" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10" + +inherit cmake pkgconfig +BBCLASSEXTEND = "nativesdk" + +SRC_URI = "gitsm://gerrit.automotivelinux.org/gerrit/src/low-level-can-generator;protocol=https;branch=${AGL_BRANCH}" +SRCREV = "92f95384ce4b4a198b1fea93272201421f7b9a39" + +PV = "4.0+git${SRCPV}" +S = "${WORKDIR}/git" + diff --git a/meta-agl-profile-core/recipes-devtools/packagegroups/nativesdk-packagegroup-sdk-host.bbappend b/meta-agl-profile-core/recipes-devtools/packagegroups/nativesdk-packagegroup-sdk-host.bbappend new file mode 100644 index 000000000..504a019b4 --- /dev/null +++ b/meta-agl-profile-core/recipes-devtools/packagegroups/nativesdk-packagegroup-sdk-host.bbappend @@ -0,0 +1 @@ +RDEPENDS_${PN} += "nativesdk-low-level-can-generator" diff --git a/meta-agl-profile-core/recipes-devtools/packagegroups/packagegroup-agl-devel.bb b/meta-agl-profile-core/recipes-devtools/packagegroups/packagegroup-agl-devel.bb new file mode 100644 index 000000000..ade8560ab --- /dev/null +++ b/meta-agl-profile-core/recipes-devtools/packagegroups/packagegroup-agl-devel.bb @@ -0,0 +1,24 @@ +SUMMARY = "Provides a set of tools for development for AGL DISTRO" +LICENSE = "MIT" + +inherit packagegroup + +RDEPENDS_${PN} = "\ + strace \ + ldd \ + less \ + vim \ + lsof \ + gdb \ + valgrind \ + perf \ + htop \ + powertop \ + latencytop \ + systemtap \ + screen \ + usbutils \ + rsync \ + tree \ + pstree \ + " diff --git a/meta-agl-profile-core/recipes-devtools/run-agl-postinsts/run-agl-postinsts/run-agl-postinsts b/meta-agl-profile-core/recipes-devtools/run-agl-postinsts/run-agl-postinsts/run-agl-postinsts new file mode 100755 index 000000000..1d1a5a059 --- /dev/null +++ b/meta-agl-profile-core/recipes-devtools/run-agl-postinsts/run-agl-postinsts/run-agl-postinsts @@ -0,0 +1,48 @@ +#!/bin/sh +# +# Copyright 2017 IoT.bzh. + +# Author: Ronan Le Martret <ronan.lemartret@iot.bzh> +# + +# The following script will run all the scriptlets found in #SYSCONFDIR#/agl-postinsts. + +agl_pi_dir="#SYSCONFDIR#/agl-postinsts" + +POSTINST_LOGGING=1 +LOGFILE=/var/log/agl-postinstall.log + +[ -e $LOGFILE ] && mv ${LOGFILE} ${LOGFILE}.old.$(date +%F--%H%M.%S) + +append_log=">>$LOGFILE 2>&1" + +exec_postinst_scriptlets() { + for i in `ls $agl_pi_dir`; do + i=$agl_pi_dir/$i + echo "Running postinst $i..." + [ "$POSTINST_LOGGING" = "1" ] && eval echo "Running postinst $i..." $append_log + if [ -x $i ]; then + eval sh -c $i $append_log + if [ $? -eq 0 ]; then + rm $i + else + echo "ERROR: postinst $i failed." + [ "$POSTINST_LOGGING" = "1" ] && eval echo "ERROR: postinst $i failed." $append_log + remove_agl_pi_dir=0 + fi + else + echo "ERROR: postinst $i do not exists or do not have execute permission." + [ "$POSTINST_LOGGING" = "1" ] && eval echo "ERROR: postinst $i do not exists or do not have execute permission." $append_log + remove_agl_pi_dir=0 + fi + done +} + +remove_agl_pi_dir=1 +exec_postinst_scriptlets +systemctl daemon-reload + +# since all postinstalls executed successfully, remove the postinstalls directory +if [ $remove_agl_pi_dir = 1 ]; then + rm -rf $agl_pi_dir +fi diff --git a/meta-agl-profile-core/recipes-devtools/run-agl-postinsts/run-agl-postinsts/run-agl-postinsts.service b/meta-agl-profile-core/recipes-devtools/run-agl-postinsts/run-agl-postinsts/run-agl-postinsts.service new file mode 100644 index 000000000..8f8667db6 --- /dev/null +++ b/meta-agl-profile-core/recipes-devtools/run-agl-postinsts/run-agl-postinsts/run-agl-postinsts.service @@ -0,0 +1,17 @@ +[Unit] +Description=Run pending agl postinsts +DefaultDependencies=no +After=#SYSTEMD_SERVICE_AFTER# +Before=#SYSTEMD_SERVICE_BEFORE# +ConditionPathExists=#SYSCONFDIR#/agl-postinsts + +[Service] +Type=oneshot +StandardOutput=journal+console +ExecStart=#SBINDIR#/run-agl-postinsts +ExecStartPost=#BASE_BINDIR#/systemctl disable run-agl-postinsts.service +RemainAfterExit=No +TimeoutSec=0 + +[Install] +WantedBy=multi-user.target diff --git a/meta-agl-profile-core/recipes-devtools/run-agl-postinsts/run-agl-postinsts_1.0.bb b/meta-agl-profile-core/recipes-devtools/run-agl-postinsts/run-agl-postinsts_1.0.bb new file mode 100644 index 000000000..b1ecccf85 --- /dev/null +++ b/meta-agl-profile-core/recipes-devtools/run-agl-postinsts/run-agl-postinsts_1.0.bb @@ -0,0 +1,46 @@ +SUMMARY = "Runs AGL postinstall scripts on first boot of the target device" +SECTION = "devel" + +LICENSE = "MIT" +LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" + +SRC_URI = "file://run-agl-postinsts \ + file://run-agl-postinsts.service" + +S = "${WORKDIR}" + +inherit allarch systemd + +SYSTEMD_SERVICE_${PN} = "run-agl-postinsts.service" + +SYSTEMD_SERVICE_AFTER ?= "dbus.service cynara.service" + +SYSTEMD_SERVICE_BEFORE ?= "systemd-user-sessions.service" + +do_configure() { + : +} + +do_compile () { + : +} + +do_install() { + install -d ${D}${sbindir} + install -m 0755 ${WORKDIR}/run-agl-postinsts ${D}${sbindir}/ + + install -d ${D}${systemd_unitdir}/system/ + install -m 0644 ${WORKDIR}/run-agl-postinsts.service ${D}${systemd_unitdir}/system/ + + sed -i -e 's:#SYSCONFDIR#:${sysconfdir}:g' \ + -e 's:#SBINDIR#:${sbindir}:g' \ + -e 's:#BASE_BINDIR#:${base_bindir}:g' \ + -e 's:#LOCALSTATEDIR#:${localstatedir}:g' \ + ${D}${sbindir}/run-agl-postinsts \ + ${D}${systemd_unitdir}/system/run-agl-postinsts.service + + sed -i -e 's:#SYSTEMD_SERVICE_AFTER#:${SYSTEMD_SERVICE_AFTER}:g' \ + -e 's:#SYSTEMD_SERVICE_BEFORE#:${SYSTEMD_SERVICE_BEFORE}:g' \ + ${D}${systemd_unitdir}/system/run-agl-postinsts.service +} + diff --git a/meta-agl-profile-core/recipes-devtools/run-postinsts/run-postinsts_%.bbappend b/meta-agl-profile-core/recipes-devtools/run-postinsts/run-postinsts_%.bbappend new file mode 100644 index 000000000..fc327b6ef --- /dev/null +++ b/meta-agl-profile-core/recipes-devtools/run-postinsts/run-postinsts_%.bbappend @@ -0,0 +1,5 @@ +do_configure_append() { + if ! grep -q StandardOutput= ${WORKDIR}/run-postinsts.service; then + sed -i '/ExecStart=/iStandardOutput=journal+console' ${WORKDIR}/run-postinsts.service + fi +} diff --git a/meta-agl-profile-core/recipes-ivi/images/agl-image-ivi-crosssdk.bb b/meta-agl-profile-core/recipes-ivi/images/agl-image-ivi-crosssdk.bb new file mode 100644 index 000000000..0303d051d --- /dev/null +++ b/meta-agl-profile-core/recipes-ivi/images/agl-image-ivi-crosssdk.bb @@ -0,0 +1,19 @@ +SUMMARY = "Cross SDK of AGL Distribution for IVI profile" + +DESCRIPTION = "Basic image for baseline of AGL Distribution for IVI profile. \ +It includes the full meta-toolchain, plus developement headers and libraries \ +to form a standalone cross SDK." + +require agl-image-ivi.bb + +LICENSE = "MIT" + +IMAGE_FEATURES += "dev-pkgs" +IMAGE_INSTALL += "kernel-dev" + +inherit populate_sdk + +# Task do_populate_sdk and do_rootfs can't be exec simultaneously. +# Both exec "createrepo" on the same directory, and so one of them +# can failed (randomly). +addtask do_populate_sdk after do_rootfs diff --git a/meta-agl-profile-core/recipes-ivi/images/agl-image-ivi-qa.bb b/meta-agl-profile-core/recipes-ivi/images/agl-image-ivi-qa.bb new file mode 100644 index 000000000..017439454 --- /dev/null +++ b/meta-agl-profile-core/recipes-ivi/images/agl-image-ivi-qa.bb @@ -0,0 +1,14 @@ +SUMMARY = "A basic system of AGL distribution of IVI profile for Quality Assurance(QA)" + +DESCRIPTION = "A basic set of AGL Distribution. This image also has additional \ +packages (e.g. commandline tools) for Quality Assurance(QA)." + +require agl-image-ivi.bb + +LICENSE = "MIT" + +IMAGE_INSTALL_append = " \ + packagegroup-agl-test \ + packagegroup-ivi-common-test \ + " + diff --git a/meta-agl-profile-core/recipes-ivi/images/agl-image-ivi.bb b/meta-agl-profile-core/recipes-ivi/images/agl-image-ivi.bb new file mode 100644 index 000000000..dd4f89b15 --- /dev/null +++ b/meta-agl-profile-core/recipes-ivi/images/agl-image-ivi.bb @@ -0,0 +1,17 @@ +SUMMARY = "A basic system of AGL distribution of IVI profile" + +DESCRIPTION = "Basic image for baseline of AGL Distribution for IVI profile." + +require agl-image-ivi.inc + +LICENSE = "MIT" + +IMAGE_INSTALL_append = "\ + packagegroup-agl-image-ivi \ + " + +DISTRO_FEATURES_append = " agl-core-image-profile" + +IMAGE_INSTALL += "\ + agl-desktop-config \ + " diff --git a/meta-agl-profile-core/recipes-ivi/images/agl-image-ivi.inc b/meta-agl-profile-core/recipes-ivi/images/agl-image-ivi.inc new file mode 100644 index 000000000..0b564840b --- /dev/null +++ b/meta-agl-profile-core/recipes-ivi/images/agl-image-ivi.inc @@ -0,0 +1,3 @@ +require recipes-core/images/agl-image-minimal.inc + +IMAGE_FEATURES += "splash package-management ssh-server-dropbear" diff --git a/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-image-ivi.bb b/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-image-ivi.bb new file mode 100644 index 000000000..075af913a --- /dev/null +++ b/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-image-ivi.bb @@ -0,0 +1,31 @@ +SUMMARY = "The middlewares for AGL IVI profile" +DESCRIPTION = "The set of packages required for AGL Distribution" +LICENSE = "MIT" + +inherit packagegroup + +PACKAGES = "\ + packagegroup-agl-image-ivi \ + " + +ALLOW_EMPTY_${PN} = "1" + +RDEPENDS_${PN} += "\ + packagegroup-agl-image-minimal \ +" + +RDEPENDS_${PN} += "\ + packagegroup-agl-ivi-automotive \ + packagegroup-agl-ivi-connectivity \ + packagegroup-agl-ivi-graphics \ + packagegroup-agl-ivi-multimedia \ + packagegroup-agl-ivi-navi-lbs \ + packagegroup-agl-ivi-os-commonlibs \ + packagegroup-agl-ivi-speech-services \ + packagegroup-agl-ivi-security \ + packagegroup-agl-ivi-kernel \ + " + +RDEPENDS_${PN} += "\ + agl-login-manager \ + " diff --git a/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-automotive.bb b/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-automotive.bb new file mode 100644 index 000000000..f7221517f --- /dev/null +++ b/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-automotive.bb @@ -0,0 +1,14 @@ +SUMMARY = "The middlewares for AGL IVI profile" +DESCRIPTION = "The set of packages required by Automotive Subsystem" +LICENSE = "MIT" + +inherit packagegroup + +PACKAGES = "\ + packagegroup-agl-ivi-automotive \ + " + +ALLOW_EMPTY_${PN} = "1" + +RDEPENDS_${PN} += "\ + " diff --git a/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-connectivity.bb b/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-connectivity.bb new file mode 100644 index 000000000..664180d55 --- /dev/null +++ b/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-connectivity.bb @@ -0,0 +1,19 @@ +SUMMARY = "The middlewares for AGL IVI profile" +DESCRIPTION = "The set of packages required by Connectivity Subsystem" +LICENSE = "MIT" + +inherit packagegroup + +PACKAGES = "\ + packagegroup-agl-ivi-connectivity \ + " + +ALLOW_EMPTY_${PN} = "1" + +RDEPENDS_${PN} += "\ + ofono \ + rtl-sdr \ + rygel \ + rygel-plugin-media-export \ + rygel-plugin-lms \ + " diff --git a/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-graphics.bb b/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-graphics.bb new file mode 100644 index 000000000..d7650564b --- /dev/null +++ b/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-graphics.bb @@ -0,0 +1,14 @@ +SUMMARY = "The middlewares for AGL IVI profile" +DESCRIPTION = "The set of packages required by Graphics Subsystem" +LICENSE = "MIT" + +inherit packagegroup + +PACKAGES = "\ + packagegroup-agl-ivi-graphics \ + " + +ALLOW_EMPTY_${PN} = "1" + +RDEPENDS_${PN} += "\ + " diff --git a/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-kernel.bb b/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-kernel.bb new file mode 100644 index 000000000..be51817b7 --- /dev/null +++ b/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-kernel.bb @@ -0,0 +1,14 @@ +SUMMARY = "The middlewares for AGL IVI profile" +DESCRIPTION = "The set of packages required by Kernel Subsystem" +LICENSE = "MIT" + +inherit packagegroup + +PACKAGES = "\ + packagegroup-agl-ivi-kernel \ + " + +ALLOW_EMPTY_${PN} = "1" + +RDEPENDS_${PN} += "\ + " diff --git a/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-multimedia.bb b/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-multimedia.bb new file mode 100644 index 000000000..11536405e --- /dev/null +++ b/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-multimedia.bb @@ -0,0 +1,17 @@ +SUMMARY = "The middlewares for AGL IVI profile" +DESCRIPTION = "The set of packages required by Multimedia Subsystem" +LICENSE = "MIT" + +inherit packagegroup + +PACKAGES = "\ + packagegroup-agl-ivi-multimedia \ + " + +ALLOW_EMPTY_${PN} = "1" + +RDEPENDS_${PN} += "\ + gstreamer1.0-plugins-base-meta \ + gstreamer1.0-plugins-good-meta \ + lightmediascanner-meta \ + " diff --git a/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-navi-lbs.bb b/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-navi-lbs.bb new file mode 100644 index 000000000..b7f47eecc --- /dev/null +++ b/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-navi-lbs.bb @@ -0,0 +1,14 @@ +SUMMARY = "The packages of middlewares for AGL IVI profile" +DESCRIPTION = "The set of packages required by Navigation and Location Based Services Subsystem" +LICENSE = "MIT" + +inherit packagegroup + +PACKAGES = "\ + packagegroup-agl-ivi-navi-lbs \ + " + +RDEPENDS_${PN} += "\ + gpsd \ + geoclue \ + " diff --git a/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-os-commonlibs.bb b/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-os-commonlibs.bb new file mode 100644 index 000000000..0a9de8d5f --- /dev/null +++ b/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-os-commonlibs.bb @@ -0,0 +1,14 @@ +SUMMARY = "The packages of middlewares for AGL IVI profile" +DESCRIPTION = "The set of packages required by Operating System and Common libraries Subsystem" +LICENSE = "MIT" + +inherit packagegroup + +PACKAGES = "\ + packagegroup-agl-ivi-os-commonlibs \ + " + +ALLOW_EMPTY_${PN} = "1" + +RDEPENDS_${PN} += "\ + " diff --git a/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-security.bb b/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-security.bb new file mode 100644 index 000000000..f651c50cd --- /dev/null +++ b/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-security.bb @@ -0,0 +1,14 @@ +SUMMARY = "The packages of middlewares for AGL IVI profile" +DESCRIPTION = "The set of packages required by Security Subsystem" +LICENSE = "MIT" + +inherit packagegroup + +PACKAGES = "\ + packagegroup-agl-ivi-security \ + " + +ALLOW_EMPTY_${PN} = "1" + +RDEPENDS_${PN} += "\ + " diff --git a/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-speech-services.bb b/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-speech-services.bb new file mode 100644 index 000000000..eccebee9f --- /dev/null +++ b/meta-agl-profile-core/recipes-ivi/packagegroups/packagegroup-agl-ivi-speech-services.bb @@ -0,0 +1,14 @@ +SUMMARY = "The packages of middlewares for AGL IVI profile" +DESCRIPTION = "The set of packages required by Speech Services Subsystem" +LICENSE = "MIT" + +inherit packagegroup + +PACKAGES = "\ + packagegroup-agl-ivi-speech-services \ + " + +ALLOW_EMPTY_${PN} = "1" + +RDEPENDS_${PN} += "\ + " diff --git a/meta-agl-profile-core/recipes-multimedia/gstreamer1.0-plugins-good/gstreamer1.0-plugins-good_%.bbappend b/meta-agl-profile-core/recipes-multimedia/gstreamer1.0-plugins-good/gstreamer1.0-plugins-good_%.bbappend new file mode 100644 index 000000000..86a181fbb --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/gstreamer1.0-plugins-good/gstreamer1.0-plugins-good_%.bbappend @@ -0,0 +1,2 @@ +# libv4l2 is useful for making more efficient use of cameras via v4l2src. +PACKAGECONFIG_append = " libv4l2" diff --git a/meta-agl-profile-core/recipes-multimedia/lightmediascanner/.appends.meta-efl b/meta-agl-profile-core/recipes-multimedia/lightmediascanner/.appends.meta-efl new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/lightmediascanner/.appends.meta-efl diff --git a/meta-agl-profile-core/recipes-multimedia/lightmediascanner/files/0001-Define-comparison_fn_t-for-non-glibc-systems.patch b/meta-agl-profile-core/recipes-multimedia/lightmediascanner/files/0001-Define-comparison_fn_t-for-non-glibc-systems.patch new file mode 100644 index 000000000..15d4b3f0e --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/lightmediascanner/files/0001-Define-comparison_fn_t-for-non-glibc-systems.patch @@ -0,0 +1,33 @@ +From 5bc5b8c5dad3edec6736fd7e7ce61250c4ce3725 Mon Sep 17 00:00:00 2001 +From: Khem Raj <raj.khem@gmail.com> +Date: Wed, 12 Jul 2017 17:13:19 -0700 +Subject: [PATCH] Define comparison_fn_t for non-glibc systems + +lightmediascanner.c:324:12: error: 'comparison_fn_t' undeclared (first use in this function) + (comparison_fn_t)_plugin_sort); + ^~~~~~~~~~~~~~~ + +Signed-off-by: Khem Raj <raj.khem@gmail.com> +--- + src/lib/lightmediascanner.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/lib/lightmediascanner.c b/src/lib/lightmediascanner.c +index 344b247..b866883 100644 +--- a/src/lib/lightmediascanner.c ++++ b/src/lib/lightmediascanner.c +@@ -37,6 +37,11 @@ + #define DEFAULT_SLAVE_TIMEOUT 1000 + #define DEFAULT_COMMIT_INTERVAL 100 + ++#if !defined(__GLIBC__) ++typedef int (*__compar_fn_t) (const void*, const void*); ++typedef __compar_fn_t comparison_fn_t; ++#endif ++ + #ifdef HAVE_MAGIC_H + static magic_t _magic_handle; + +-- +2.13.2 + diff --git a/meta-agl-profile-core/recipes-multimedia/lightmediascanner/files/dbus-lightmediascanner.conf b/meta-agl-profile-core/recipes-multimedia/lightmediascanner/files/dbus-lightmediascanner.conf new file mode 100644 index 000000000..9cb321ba9 --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/lightmediascanner/files/dbus-lightmediascanner.conf @@ -0,0 +1,7 @@ +<?xml version="1.0"?> <!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> +<busconfig> + <policy context="default"> + <allow send_destination="org.lightmediascanner"/> + <allow receive_type="signal" receive_sender="org.lightmediascanner" receive_interface="org.freedesktop.DBus.Properties"/> + </policy> +</busconfig> diff --git a/meta-agl-profile-core/recipes-multimedia/lightmediascanner/files/id3-plugin-support-out-of-tree-build.patch b/meta-agl-profile-core/recipes-multimedia/lightmediascanner/files/id3-plugin-support-out-of-tree-build.patch new file mode 100644 index 000000000..9528bec79 --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/lightmediascanner/files/id3-plugin-support-out-of-tree-build.patch @@ -0,0 +1,11 @@ +--- a/src/plugins/Makefile.am 2015-10-25 16:12:29.331415823 +0000 ++++ b/src/plugins/Makefile.am 2015-10-25 16:14:37.593415808 +0000 +@@ -93,7 +93,7 @@ + id3_id3_la_SOURCES = id3/id3.c id3/id3v1_genres.c + id3_id3_la_LIBADD = $(PLUGINS_LIBADD) + +-id3/id3v1_genres.c: $(srcdir)/id3/id3v1_genres.def $(srcdir)/id3/id3v1_genres_gen.awk ++$(srcdir)/id3/id3v1_genres.c: $(srcdir)/id3/id3v1_genres.def $(srcdir)/id3/id3v1_genres_gen.awk + $(AWK) -f $(srcdir)/id3/id3v1_genres_gen.awk $(srcdir)/id3/id3v1_genres.def > $@ + + EXTRA_DIST += id3/id3v1_genres.def id3/id3v1_genres_gen.awk diff --git a/meta-agl-profile-core/recipes-multimedia/lightmediascanner/files/lightmediascanner.service b/meta-agl-profile-core/recipes-multimedia/lightmediascanner/files/lightmediascanner.service new file mode 100644 index 000000000..33cf27ed0 --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/lightmediascanner/files/lightmediascanner.service @@ -0,0 +1,11 @@ +[Unit] +Description=Lightmediascanner (LMS) + +[Service] +Type=dbus +BusName=org.lightmediascanner +ExecStart=/usr/bin/lightmediascannerd --startup-scan --directory=/media --directory=${HOME}/Music --directory=${HOME}/Videos + +[Install] +WantedBy=default.target +Alias=dbus-org.lightmediascanner.service diff --git a/meta-agl-profile-core/recipes-multimedia/lightmediascanner/files/plugin-ogg-fix-chucksize-issue.patch b/meta-agl-profile-core/recipes-multimedia/lightmediascanner/files/plugin-ogg-fix-chucksize-issue.patch new file mode 100644 index 000000000..6a0b8ff93 --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/lightmediascanner/files/plugin-ogg-fix-chucksize-issue.patch @@ -0,0 +1,53 @@ +From 3e66b97221440b17a184feb48692dce7e0561cac Mon Sep 17 00:00:00 2001 +From: Matt Ranostay <matt.ranostay@konsulko.com> +Date: Wed, 8 Mar 2017 16:30:01 -0800 +Subject: [PATCH] plugin: ogg: fix chucksize issue + +There are some OGG files that have metadata chucks that go over the +hardcoded 10 * 4096 size due to album art. This patchset just parses +each chuck and continues till it runs out of valid chunks. + +Signed-off-by: Matt Ranostay <matt.ranostay@konsulko.com> +--- + src/plugins/ogg/ogg.c | 11 ++--------- + 1 file changed, 2 insertions(+), 9 deletions(-) + +diff --git a/src/plugins/ogg/ogg.c b/src/plugins/ogg/ogg.c +index 1c0818e..c94dc38 100644 +--- a/src/plugins/ogg/ogg.c ++++ b/src/plugins/ogg/ogg.c +@@ -47,8 +47,6 @@ + int CHUNKSIZE = 4096; + #endif + +-#define MAX_CHUNKS_PER_PAGE 10 +- + struct stream { + struct lms_stream base; + int serial; +@@ -122,10 +120,8 @@ _set_lms_info(struct lms_string_size *info, const char *tag) + + static bool _ogg_read_page(FILE *fp, ogg_sync_state *osync, ogg_page *page) + { +- int i; +- +- for (i = 0; i < MAX_CHUNKS_PER_PAGE && ogg_sync_pageout(osync, page) != 1; +- i++) { ++ while(ogg_sync_pageout(osync, page) != 1) ++ { + lms_ogg_buffer_t buffer = lms_get_ogg_sync_buffer(osync, CHUNKSIZE); + int bytes = fread(buffer, 1, CHUNKSIZE, fp); + +@@ -136,9 +132,6 @@ static bool _ogg_read_page(FILE *fp, ogg_sync_state *osync, ogg_page *page) + ogg_sync_wrote(osync, bytes); + } + +- if (i > MAX_CHUNKS_PER_PAGE) +- return false; +- + return true; + } + +-- +2.7.4 + diff --git a/meta-agl-profile-core/recipes-multimedia/lightmediascanner/lightmediascanner_%.bbappend b/meta-agl-profile-core/recipes-multimedia/lightmediascanner/lightmediascanner_%.bbappend new file mode 100644 index 000000000..cf248d3fd --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/lightmediascanner/lightmediascanner_%.bbappend @@ -0,0 +1,33 @@ +# Disable everything but the roygalty-free formats +PACKAGECONFIG = "ogg flac wave m3u pls jpeg png" + +FILESEXTRAPATHS_prepend := "${THISDIR}/files:" + +SRC_URI += "file://lightmediascanner.service \ + file://plugin-ogg-fix-chucksize-issue.patch \ + file://dbus-lightmediascanner.conf \ + " + +CFLAGS_append = " -D_FILE_OFFSET_BITS=64" + +inherit systemd + +do_install_append() { + # Install LMS systemd service + if ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'true', 'false', d)}; then + install -m 644 -p -D ${WORKDIR}/lightmediascanner.service ${D}${systemd_user_unitdir}/lightmediascanner.service + + # Execute these manually on behalf of systemctl script (from systemd-systemctl-native.bb) + # because it does not support systemd's user mode. + mkdir -p ${D}/etc/systemd/user/default.target.wants/ + ln -sf ${systemd_user_unitdir}/lightmediascanner.service ${D}/etc/systemd/user/dbus-org.lightmediascanner.service + ln -sf ${systemd_user_unitdir}/lightmediascanner.service ${D}/etc/systemd/user/default.target.wants/lightmediascanner.service + fi + + install -d ${D}/etc/dbus-1/session.d + install -m 0644 ${WORKDIR}/dbus-lightmediascanner.conf ${D}/etc/dbus-1/session.d/lightmediascanner.conf +} + +FILES_${PN} += " \ + ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', '${systemd_user_unitdir}/lightmediascanner.service', '', d)} \ + " diff --git a/meta-agl-profile-core/recipes-multimedia/lightmediascanner/lightmediascanner_0.5.1.bb b/meta-agl-profile-core/recipes-multimedia/lightmediascanner/lightmediascanner_0.5.1.bb new file mode 100644 index 000000000..f2158760f --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/lightmediascanner/lightmediascanner_0.5.1.bb @@ -0,0 +1,63 @@ +SUMMARY = "Lightweight media scanner" +DESCRIPTION = "Lightweight media scanner meant to be used in not-so-powerful devices, like embedded systems or old machines." +SECTION = "libs/multimedia" + +LICENSE = "LGPLv2.1+" +LIC_FILES_CHKSUM = "file://COPYING;md5=a6f89e2100d9b6cdffcea4f398e37343 \ + file://src/lib/lightmediascanner.c;endline=21;md5=6d8889bccb4c6c27e8b786342a3eb267" + +DEPENDS = "file gawk glib-2.0 sqlite3" + +PV = "0.5.1+git${SRCPV}" +SRCREV = "adfddb3486276a5ed2f5008c9e43a811e1271cc9" +SRC_URI = "git://github.com/profusion/lightmediascanner.git \ + file://id3-plugin-support-out-of-tree-build.patch \ + file://0001-Define-comparison_fn_t-for-non-glibc-systems.patch \ + " + +S = "${WORKDIR}/git" + +inherit autotools pkgconfig + +EXTRA_OECONF = "--enable-static --disable-mp4" + +PACKAGECONFIG ??= "ogg flac wave id3 m3u pls asf rm jpeg png" +PACKAGECONFIG[generic] = "--enable-generic,--disable-generic,libav" +PACKAGECONFIG[ogg] = "--enable-ogg,--disable-ogg,libogg libvorbis libtheora" +PACKAGECONFIG[flac] = "--enable-flac,--disable-flac,flac" +PACKAGECONFIG[wave] = "--enable-wave,--disable-wave" +PACKAGECONFIG[id3] = "--enable-id3,--disable-id3" +PACKAGECONFIG[m3u] = "--enable-m3u,--disable-m3u" +PACKAGECONFIG[pls] = "--enable-pls,--disable-pls" +PACKAGECONFIG[asf] = "--enable-asf,--disable-asf" +PACKAGECONFIG[rm] = "--enable-rm,--disable-rm" +PACKAGECONFIG[jpeg] = "--enable-jpeg,--disable-jpeg" +PACKAGECONFIG[png] = "--enable-png,--disable-png" + +do_install_append() { + # Install "test" binary for corresponding package + install -d ${D}/${bindir} + install -m 755 ${B}/src/bin/.libs/test ${D}/${bindir}/test-lms + # Remove .la files for loadable modules + rm -f ${D}/${libdir}/${PN}/plugins/*.la +} + +FILES_${PN} += "${datadir}/dbus-1" +FILES_${PN}-dbg += "${libdir}/${PN}/plugins/.debug" + +PACKAGES_prepend = "${PN}-test " +FILES_${PN}-test_prepend = "${bindir}/test-lms " + +PACKAGES += "${PN}-meta" +ALLOW_EMPTY_${PN}-meta = "1" + +PACKAGES_DYNAMIC = "${PN}-plugin-*" + +python populate_packages_prepend () { + lms_libdir = d.expand('${libdir}/${PN}') + pkgs = [] + + pkgs += do_split_packages(d, oe.path.join(lms_libdir, "plugins"), '^(.*)\.so$', d.expand('${PN}-plugin-%s'), 'LightMediaScanner plugin for %s', prepend=True, extra_depends=d.expand('${PN}')) + metapkg = d.getVar('PN') + '-meta' + d.setVar('RDEPENDS_' + metapkg, ' '.join(pkgs)) +} diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/agl-audio-plugin_0.1.bb b/meta-agl-profile-core/recipes-multimedia/pulseaudio/agl-audio-plugin_0.1.bb new file mode 100644 index 000000000..633a3e248 --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/pulseaudio/agl-audio-plugin_0.1.bb @@ -0,0 +1,28 @@ +SUMMARY = "AGL Audio Policy Plugin" +DESCRIPTION = "AGL PulseAudio Routing plugin, forked from the Tizen IVI \ +PulseAudio Routing plugin, also known as module-murphy-ivi. This is a \ +stripped-down version of the former, not needing Murphy anymore and using \ +either a JSON configuration file or its own embedded configuration." +HOMEPAGE = "http://www.iot.bzh" + +LICENSE = "LGPL-2.1" +LIC_FILES_CHKSUM = "file://COPYING;md5=2d5025d4aa3495befef8f17206a5b0a1" + +DEPENDS = "json-c pulseaudio" +RDEPENDS_${PN} = "pulseaudio-server pulseaudio-module-null-sink pulseaudio-module-loopback" + +SRCREV = "952d404e87ca6001e546fe9105bdb6760c468760" +SRC_URI = "git://gerrit.automotivelinux.org/gerrit/staging/agl-audio-plugin;protocol=https;branch=${AGL_BRANCH}" + +S = "${WORKDIR}/git" + +inherit cmake pkgconfig + +FULL_OPTIMIZATION = "-O1 -pipe ${DEBUG_FLAGS}" + +PULSE_PV="9.0" + +EXTRA_OECMAKE_append = " -DPULSE_PV:STRING=${PULSE_PV}" + +FILES_${PN} += "${libdir}/pulse-${PULSE_PV}/modules/* ${sysconfdir}/pulse/*" +FILES_${PN}-dbg += "${libdir}/pulse-${PULSE_PV}/modules/.debug/*" diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio-10.0/0001-install-files-for-a-module-development.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio-10.0/0001-install-files-for-a-module-development.patch new file mode 100644 index 000000000..8c5f9efd4 --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio-10.0/0001-install-files-for-a-module-development.patch @@ -0,0 +1,78 @@ +From 53281e2d11f84e2dae0704e0167369710ee2cb30 Mon Sep 17 00:00:00 2001 +From: Yannick Gicquel <yannick.gicquel@iot.bzh> +Date: Fri, 23 Sep 2016 14:26:03 +0200 +Subject: [PATCH 1/6] install files for a module development + +Signed-off-by: Yannick Gicquel <yannick.gicquel@iot.bzh> +--- + Makefile.am | 14 +++++++++++++- + configure.ac | 1 + + pulseaudio-module-devel.pc.in | 12 ++++++++++++ + 3 files changed, 26 insertions(+), 1 deletion(-) + create mode 100644 pulseaudio-module-devel.pc.in + +diff --git a/Makefile.am b/Makefile.am +index 13bc469..f0d68a2 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -53,7 +53,16 @@ dist_vapi_DATA = \ + vala/libpulse-simple.deps vala/libpulse-simple.vapi + + pkgconfigdir = $(libdir)/pkgconfig +-pkgconfig_DATA = libpulse.pc libpulse-simple.pc ++pkgconfig_DATA = libpulse.pc libpulse-simple.pc pulseaudio-module-devel.pc ++ ++moduledev_DATA = pulsecore-config.h $(top_srcdir)/src/pulsecore/*.h ++moduledevdir = $(includedir)/pulsemodule/pulsecore ++ ++moduledevfilter_DATA = $(top_srcdir)/src/pulsecore/filter/*.h ++moduledevfilterdir = $(includedir)/pulsemodule/pulsecore/filter ++ ++moduledevinternal_DATA = src/pulse/internal.h src/pulse/client-conf.h src/pulse/fork-detect.h ++moduledevinternaldir = $(includedir)/pulsemodule/pulse + + if HAVE_GLIB20 + pkgconfig_DATA += \ +@@ -107,6 +116,9 @@ dist-hook: + check-daemon: + $(MAKE) -C src check-daemon + ++pulsecore-config.h: config.h ++ cp $< $@ ++ + .PHONY: homepage distcleancheck doxygen + + # see git-version-gen +diff --git a/configure.ac b/configure.ac +index 9250c05..f9201ee 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1502,6 +1502,7 @@ man/pulse-client.conf.5.xml + man/default.pa.5.xml + man/pulse-cli-syntax.5.xml + man/start-pulseaudio-x11.1.xml ++pulseaudio-module-devel.pc + ]) + + AC_CONFIG_FILES([src/esdcompat:src/daemon/esdcompat.in], [chmod +x src/esdcompat]) +diff --git a/pulseaudio-module-devel.pc.in b/pulseaudio-module-devel.pc.in +new file mode 100644 +index 0000000..85aadbc +--- /dev/null ++++ b/pulseaudio-module-devel.pc.in +@@ -0,0 +1,12 @@ ++prefix=@prefix@ ++exec_prefix=@exec_prefix@ ++libdir=@libdir@ ++includedir=@includedir@ ++modlibexecdir=@modlibexecdir@ ++ ++Name: pulseaudio-module-devel ++Description: PulseAudio Module Development Interface ++Version: @PACKAGE_VERSION@ ++Libs: -L${libdir} -L${libdir}/pulseaudio -L${modlibexecdir} -lpulsecommon-@PA_MAJORMINOR@ -lpulsecore-@PA_MAJORMINOR@ -lprotocol-native ++Libs.private: ++Cflags: -I${includedir}/pulsemodule -D_REENTRANT +-- +1.9.1 + diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio-10.0/0002-volume-ramp-additions-to-the-low-level-infra.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio-10.0/0002-volume-ramp-additions-to-the-low-level-infra.patch new file mode 100644 index 000000000..9cee6f5de --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio-10.0/0002-volume-ramp-additions-to-the-low-level-infra.patch @@ -0,0 +1,566 @@ +From 7757059ffc6e63ea20ba9013682d72d619e7aefc Mon Sep 17 00:00:00 2001 +From: Sangchul Lee <sangchul1011@gmail.com> +Date: Sat, 27 Aug 2016 21:33:16 +0900 +Subject: [PATCH 2/6] volume ramp: additions to the low level infra + +The original patch is + - https://review.tizen.org/git/?p=platform/upstream/pulseaudio.git;a=commit;h=df1c4275ed79e0b708c75b92f9d247e0492bc1f0 + - by Jaska Uimonen <jaska.uimonen <at> helsinki.fi> + +Signed-off-by: Sangchul Lee <sc11.lee@samsung.com> +--- + src/map-file | 4 + + src/pulse/def.h | 13 ++- + src/pulse/volume.c | 74 ++++++++++++- + src/pulse/volume.h | 33 ++++++ + src/pulsecore/mix.c | 310 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + src/pulsecore/mix.h | 27 +++++ + 6 files changed, 459 insertions(+), 2 deletions(-) + +diff --git a/src/map-file b/src/map-file +index 93a62b8..ef9b57d 100644 +--- a/src/map-file ++++ b/src/map-file +@@ -138,6 +138,10 @@ pa_cvolume_max_mask; + pa_cvolume_merge; + pa_cvolume_min; + pa_cvolume_min_mask; ++pa_cvolume_ramp_equal; ++pa_cvolume_ramp_init; ++pa_cvolume_ramp_set; ++pa_cvolume_ramp_channel_ramp_set; + pa_cvolume_remap; + pa_cvolume_scale; + pa_cvolume_scale_mask; +diff --git a/src/pulse/def.h b/src/pulse/def.h +index 680bdc9..bc3cedd 100644 +--- a/src/pulse/def.h ++++ b/src/pulse/def.h +@@ -347,11 +347,15 @@ typedef enum pa_stream_flags { + * consider absolute when the sink is in flat volume mode, + * relative otherwise. \since 0.9.20 */ + +- PA_STREAM_PASSTHROUGH = 0x80000U ++ PA_STREAM_PASSTHROUGH = 0x80000U, + /**< Used to tag content that will be rendered by passthrough sinks. + * The data will be left as is and not reformatted, resampled. + * \since 1.0 */ + ++ PA_STREAM_START_RAMP_MUTED = 0x100000U ++ /**< Used to tag content that the stream will be started ramp volume ++ * muted so that you can nicely fade it in */ ++ + } pa_stream_flags_t; + + /** \cond fulldocs */ +@@ -380,6 +384,7 @@ typedef enum pa_stream_flags { + #define PA_STREAM_FAIL_ON_SUSPEND PA_STREAM_FAIL_ON_SUSPEND + #define PA_STREAM_RELATIVE_VOLUME PA_STREAM_RELATIVE_VOLUME + #define PA_STREAM_PASSTHROUGH PA_STREAM_PASSTHROUGH ++#define PA_STREAM_START_RAMP_MUTED PA_STREAM_START_RAMP_MUTED + + /** \endcond */ + +@@ -1047,6 +1052,12 @@ typedef enum pa_port_available { + /** \endcond */ + #endif + ++/** \cond fulldocs */ ++#define PA_VOLUMER_RAMP_TYPE_LINEAR PA_VOLUMER_RAMP_TYPE_LINEAR ++#define PA_VOLUMER_RAMP_TYPE_LOGARITHMIC PA_VOLUMER_RAMP_TYPE_LOGARITHMIC ++#define PA_VOLUMER_RAMP_TYPE_CUBIC PA_VOLUMER_RAMP_TYPE_CUBIC ++/** \endcond */ ++ + PA_C_DECL_END + + #endif +diff --git a/src/pulse/volume.c b/src/pulse/volume.c +index 1667b94..85072c1 100644 +--- a/src/pulse/volume.c ++++ b/src/pulse/volume.c +@@ -445,7 +445,10 @@ int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) { + unsigned c; + pa_assert(a); + +- pa_return_val_if_fail(pa_cvolume_valid(a), 0); ++ if (pa_cvolume_valid(a) == 0) ++ abort(); ++ ++ /* pa_return_val_if_fail(pa_cvolume_valid(a), 0); */ + pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), 0); + + for (c = 0; c < a->channels; c++) +@@ -977,3 +980,72 @@ pa_cvolume* pa_cvolume_dec(pa_cvolume *v, pa_volume_t dec) { + + return pa_cvolume_scale(v, m); + } ++ ++int pa_cvolume_ramp_equal(const pa_cvolume_ramp *a, const pa_cvolume_ramp *b) { ++ int i; ++ pa_assert(a); ++ pa_assert(b); ++ ++ if (PA_UNLIKELY(a == b)) ++ return 1; ++ ++ if (a->channels != b->channels) ++ return 0; ++ ++ for (i = 0; i < a->channels; i++) { ++ if (a->ramps[i].type != b->ramps[i].type || ++ a->ramps[i].length != b->ramps[i].length || ++ a->ramps[i].target != b->ramps[i].target) ++ return 0; ++ } ++ ++ return 1; ++} ++ ++pa_cvolume_ramp* pa_cvolume_ramp_init(pa_cvolume_ramp *ramp) { ++ unsigned c; ++ ++ pa_assert(ramp); ++ ++ ramp->channels = 0; ++ ++ for (c = 0; c < PA_CHANNELS_MAX; c++) { ++ ramp->ramps[c].type = PA_VOLUME_RAMP_TYPE_LINEAR; ++ ramp->ramps[c].length = 0; ++ ramp->ramps[c].target = PA_VOLUME_INVALID; ++ } ++ ++ return ramp; ++} ++ ++pa_cvolume_ramp* pa_cvolume_ramp_set(pa_cvolume_ramp *ramp, unsigned channels, pa_volume_ramp_type_t type, long time, pa_volume_t vol) { ++ int i; ++ ++ pa_assert(ramp); ++ pa_assert(channels > 0); ++ pa_assert(time >= 0); ++ pa_assert(channels <= PA_CHANNELS_MAX); ++ ++ ramp->channels = (uint8_t) channels; ++ ++ for (i = 0; i < ramp->channels; i++) { ++ ramp->ramps[i].type = type; ++ ramp->ramps[i].length = time; ++ ramp->ramps[i].target = PA_CLAMP_VOLUME(vol); ++ } ++ ++ return ramp; ++} ++ ++pa_cvolume_ramp* pa_cvolume_ramp_channel_ramp_set(pa_cvolume_ramp *ramp, unsigned channel, pa_volume_ramp_type_t type, long time, pa_volume_t vol) { ++ ++ pa_assert(ramp); ++ pa_assert(channel <= ramp->channels); ++ pa_assert(time >= 0); ++ ++ ramp->ramps[channel].type = type; ++ ramp->ramps[channel].length = time; ++ ramp->ramps[channel].target = PA_CLAMP_VOLUME(vol); ++ ++ return ramp; ++} +diff --git a/src/pulse/volume.h b/src/pulse/volume.h +index 8cf4fa4..2ae3451 100644 +--- a/src/pulse/volume.h ++++ b/src/pulse/volume.h +@@ -431,6 +431,39 @@ pa_cvolume* pa_cvolume_inc(pa_cvolume *v, pa_volume_t inc); + * the channels are kept. \since 0.9.16 */ + pa_cvolume* pa_cvolume_dec(pa_cvolume *v, pa_volume_t dec); + ++/** Volume ramp type ++*/ ++typedef enum pa_volume_ramp_type { ++ PA_VOLUME_RAMP_TYPE_LINEAR = 0, /**< linear */ ++ PA_VOLUME_RAMP_TYPE_LOGARITHMIC = 1, /**< logarithmic */ ++ PA_VOLUME_RAMP_TYPE_CUBIC = 2, ++} pa_volume_ramp_type_t; ++ ++/** A structure encapsulating a volume ramp */ ++typedef struct pa_volume_ramp_t { ++ pa_volume_ramp_type_t type; ++ long length; ++ pa_volume_t target; ++} pa_volume_ramp_t; ++ ++/** A structure encapsulating a multichannel volume ramp */ ++typedef struct pa_cvolume_ramp { ++ uint8_t channels; ++ pa_volume_ramp_t ramps[PA_CHANNELS_MAX]; ++} pa_cvolume_ramp; ++ ++/** Return non-zero when *a == *b */ ++int pa_cvolume_ramp_equal(const pa_cvolume_ramp *a, const pa_cvolume_ramp *b); ++ ++/** Init volume ramp struct */ ++pa_cvolume_ramp* pa_cvolume_ramp_init(pa_cvolume_ramp *ramp); ++ ++/** Set first n channels of ramp struct to certain value */ ++pa_cvolume_ramp* pa_cvolume_ramp_set(pa_cvolume_ramp *ramp, unsigned channel, pa_volume_ramp_type_t type, long time, pa_volume_t vol); ++ ++/** Set individual channel in the channel struct */ ++pa_cvolume_ramp* pa_cvolume_ramp_channel_ramp_set(pa_cvolume_ramp *ramp, unsigned channel, pa_volume_ramp_type_t type, long time, pa_volume_t vol); ++ + PA_C_DECL_END + + #endif +diff --git a/src/pulsecore/mix.c b/src/pulsecore/mix.c +index 59622d7..1e4cc1e 100644 +--- a/src/pulsecore/mix.c ++++ b/src/pulsecore/mix.c +@@ -724,3 +724,313 @@ void pa_volume_memchunk( + + pa_memblock_release(c->memblock); + } ++ ++static void calc_linear_integer_volume_no_mapping(int32_t linear[], float volume[], unsigned nchannels) { ++ unsigned channel, padding; ++ ++ pa_assert(linear); ++ pa_assert(volume); ++ ++ for (channel = 0; channel < nchannels; channel++) ++ linear[channel] = (int32_t) lrint(volume[channel] * 0x10000U); ++ ++ for (padding = 0; padding < VOLUME_PADDING; padding++, channel++) ++ linear[channel] = linear[padding]; ++} ++ ++static void calc_linear_float_volume_no_mapping(float linear[], float volume[], unsigned nchannels) { ++ unsigned channel, padding; ++ ++ pa_assert(linear); ++ pa_assert(volume); ++ ++ for (channel = 0; channel < nchannels; channel++) ++ linear[channel] = volume[channel]; ++ ++ for (padding = 0; padding < VOLUME_PADDING; padding++, channel++) ++ linear[channel] = linear[padding]; ++} ++ ++typedef void (*pa_calc_volume_no_mapping_func_t) (void *volumes, float *volume, int channels); ++ ++static const pa_calc_volume_no_mapping_func_t calc_volume_table_no_mapping[] = { ++ [PA_SAMPLE_U8] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping, ++ [PA_SAMPLE_ALAW] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping, ++ [PA_SAMPLE_ULAW] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping, ++ [PA_SAMPLE_S16LE] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping, ++ [PA_SAMPLE_S16BE] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping, ++ [PA_SAMPLE_FLOAT32LE] = (pa_calc_volume_no_mapping_func_t) calc_linear_float_volume_no_mapping, ++ [PA_SAMPLE_FLOAT32BE] = (pa_calc_volume_no_mapping_func_t) calc_linear_float_volume_no_mapping, ++ [PA_SAMPLE_S32LE] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping, ++ [PA_SAMPLE_S32BE] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping, ++ [PA_SAMPLE_S24LE] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping, ++ [PA_SAMPLE_S24BE] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping, ++ [PA_SAMPLE_S24_32LE] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping, ++ [PA_SAMPLE_S24_32BE] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping ++}; ++ ++static const unsigned format_sample_size_table[] = { ++ [PA_SAMPLE_U8] = 1, ++ [PA_SAMPLE_ALAW] = 1, ++ [PA_SAMPLE_ULAW] = 1, ++ [PA_SAMPLE_S16LE] = 2, ++ [PA_SAMPLE_S16BE] = 2, ++ [PA_SAMPLE_FLOAT32LE] = 4, ++ [PA_SAMPLE_FLOAT32BE] = 4, ++ [PA_SAMPLE_S32LE] = 4, ++ [PA_SAMPLE_S32BE] = 4, ++ [PA_SAMPLE_S24LE] = 3, ++ [PA_SAMPLE_S24BE] = 3, ++ [PA_SAMPLE_S24_32LE] = 4, ++ [PA_SAMPLE_S24_32BE] = 4 ++}; ++ ++static float calc_volume_ramp_linear(pa_volume_ramp_int_t *ramp) { ++ pa_assert(ramp); ++ pa_assert(ramp->length > 0); ++ ++ /* basic linear interpolation */ ++ return ramp->start + (ramp->length - ramp->left) * (ramp->end - ramp->start) / (float) ramp->length; ++} ++ ++static float calc_volume_ramp_logarithmic(pa_volume_ramp_int_t *ramp) { ++ float x_val, s, e; ++ long temp; ++ ++ pa_assert(ramp); ++ pa_assert(ramp->length > 0); ++ ++ if (ramp->end > ramp->start) { ++ temp = ramp->left; ++ s = ramp->end; ++ e = ramp->start; ++ } else { ++ temp = ramp->length - ramp->left; ++ s = ramp->start; ++ e = ramp->end; ++ } ++ ++ x_val = temp == 0 ? 0.0 : powf(temp, 10); ++ ++ /* base 10 logarithmic interpolation */ ++ return s + x_val * (e - s) / powf(ramp->length, 10); ++} ++ ++static float calc_volume_ramp_cubic(pa_volume_ramp_int_t *ramp) { ++ float x_val, s, e; ++ long temp; ++ ++ pa_assert(ramp); ++ pa_assert(ramp->length > 0); ++ ++ if (ramp->end > ramp->start) { ++ temp = ramp->left; ++ s = ramp->end; ++ e = ramp->start; ++ } else { ++ temp = ramp->length - ramp->left; ++ s = ramp->start; ++ e = ramp->end; ++ } ++ ++ x_val = temp == 0 ? 0.0 : cbrtf(temp); ++ ++ /* cubic interpolation */ ++ return s + x_val * (e - s) / cbrtf(ramp->length); ++} ++ ++typedef float (*pa_calc_volume_ramp_func_t) (pa_volume_ramp_int_t *); ++ ++static const pa_calc_volume_ramp_func_t calc_volume_ramp_table[] = { ++ [PA_VOLUME_RAMP_TYPE_LINEAR] = (pa_calc_volume_ramp_func_t) calc_volume_ramp_linear, ++ [PA_VOLUME_RAMP_TYPE_LOGARITHMIC] = (pa_calc_volume_ramp_func_t) calc_volume_ramp_logarithmic, ++ [PA_VOLUME_RAMP_TYPE_CUBIC] = (pa_calc_volume_ramp_func_t) calc_volume_ramp_cubic ++}; ++ ++static void calc_volume_ramps(pa_cvolume_ramp_int *ram, float *vol) ++{ ++ int i; ++ ++ for (i = 0; i < ram->channels; i++) { ++ if (ram->ramps[i].left <= 0) { ++ if (ram->ramps[i].target == PA_VOLUME_NORM) { ++ vol[i] = 1.0; ++ } ++ } else { ++ vol[i] = ram->ramps[i].curr = calc_volume_ramp_table[ram->ramps[i].type] (&ram->ramps[i]); ++ ram->ramps[i].left--; ++ } ++ } ++} ++ ++void pa_volume_ramp_memchunk( ++ pa_memchunk *c, ++ const pa_sample_spec *spec, ++ pa_cvolume_ramp_int *ramp) { ++ ++ void *ptr; ++ volume_val linear[PA_CHANNELS_MAX + VOLUME_PADDING]; ++ float vol[PA_CHANNELS_MAX + VOLUME_PADDING]; ++ pa_do_volume_func_t do_volume; ++ long length_in_frames; ++ int i; ++ ++ pa_assert(c); ++ pa_assert(spec); ++ pa_assert(pa_frame_aligned(c->length, spec)); ++ pa_assert(ramp); ++ ++ length_in_frames = c->length / format_sample_size_table[spec->format] / spec->channels; ++ ++ if (pa_memblock_is_silence(c->memblock)) { ++ for (i = 0; i < ramp->channels; i++) { ++ if (ramp->ramps[i].length > 0) ++ ramp->ramps[i].length -= length_in_frames; ++ } ++ return; ++ } ++ ++ if (spec->format < 0 || spec->format >= PA_SAMPLE_MAX) { ++ pa_log_warn("Unable to change volume of format"); ++ return; ++ } ++ ++ do_volume = pa_get_volume_func(spec->format); ++ pa_assert(do_volume); ++ ++ ptr = (uint8_t*) pa_memblock_acquire(c->memblock) + c->index; ++ ++ for (i = 0; i < length_in_frames; i++) { ++ calc_volume_ramps(ramp, vol); ++ calc_volume_table_no_mapping[spec->format] ((void *)linear, vol, spec->channels); ++ ++ /* we only process one frame per iteration */ ++ do_volume (ptr, (void *)linear, spec->channels, format_sample_size_table[spec->format] * spec->channels); ++ ++ /* pa_log_debug("1: %d 2: %d", linear[0], linear[1]); */ ++ ++ ptr = (uint8_t*)ptr + format_sample_size_table[spec->format] * spec->channels; ++ } ++ ++ pa_memblock_release(c->memblock); ++} ++ ++pa_cvolume_ramp_int* pa_cvolume_ramp_convert(const pa_cvolume_ramp *src, pa_cvolume_ramp_int *dst, int sample_rate) { ++ ++ int i, j, channels, remaining_channels; ++ float temp; ++ ++ if (dst->channels < src->channels) { ++ channels = dst->channels; ++ remaining_channels = 0; ++ } ++ else { ++ channels = src->channels; ++ remaining_channels = dst->channels; ++ } ++ ++ for (i = 0; i < channels; i++) { ++ dst->ramps[i].type = src->ramps[i].type; ++ /* ms to samples */ ++ dst->ramps[i].length = src->ramps[i].length * sample_rate / 1000; ++ dst->ramps[i].left = dst->ramps[i].length; ++ dst->ramps[i].start = dst->ramps[i].end; ++ dst->ramps[i].target = src->ramps[i].target; ++ /* scale to pulse internal mapping so that when ramp is over there's no glitch in volume */ ++ temp = src->ramps[i].target / (float)0x10000U; ++ dst->ramps[i].end = temp * temp * temp; ++ } ++ ++ j = i; ++ ++ for (i--; j < remaining_channels; j++) { ++ dst->ramps[j].type = dst->ramps[i].type; ++ dst->ramps[j].length = dst->ramps[i].length; ++ dst->ramps[j].left = dst->ramps[i].left; ++ dst->ramps[j].start = dst->ramps[i].start; ++ dst->ramps[j].target = dst->ramps[i].target; ++ dst->ramps[j].end = dst->ramps[i].end; ++ } ++ ++ return dst; ++} ++ ++bool pa_cvolume_ramp_active(pa_cvolume_ramp_int *ramp) { ++ int i; ++ ++ for (i = 0; i < ramp->channels; i++) { ++ if (ramp->ramps[i].left > 0) ++ return true; ++ } ++ ++ return false; ++} ++ ++bool pa_cvolume_ramp_target_active(pa_cvolume_ramp_int *ramp) { ++ int i; ++ ++ for (i = 0; i < ramp->channels; i++) { ++ if (ramp->ramps[i].target != PA_VOLUME_NORM) ++ return true; ++ } ++ ++ return false; ++} ++ ++pa_cvolume * pa_cvolume_ramp_get_targets(pa_cvolume_ramp_int *ramp, pa_cvolume *volume) { ++ int i = 0; ++ ++ volume->channels = ramp->channels; ++ ++ for (i = 0; i < ramp->channels; i++) ++ volume->values[i] = ramp->ramps[i].target; ++ ++ return volume; ++} ++ ++pa_cvolume_ramp_int* pa_cvolume_ramp_start_from(pa_cvolume_ramp_int *src, pa_cvolume_ramp_int *dst) { ++ int i; ++ ++ for (i = 0; i < src->channels; i++) { ++ /* if new vols are invalid, copy old ramp i.e. no effect */ ++ if (dst->ramps[i].target == PA_VOLUME_INVALID) ++ dst->ramps[i] = src->ramps[i]; ++ /* if there's some old ramp still left */ ++ else if (src->ramps[i].left > 0) ++ dst->ramps[i].start = src->ramps[i].curr; ++ } ++ ++ return dst; ++} ++ ++pa_cvolume_ramp_int* pa_cvolume_ramp_int_init(pa_cvolume_ramp_int *src, pa_volume_t vol, int channels) { ++ int i; ++ float temp; ++ ++ src->channels = channels; ++ ++ for (i = 0; i < channels; i++) { ++ src->ramps[i].type = PA_VOLUME_RAMP_TYPE_LINEAR; ++ src->ramps[i].length = 0; ++ src->ramps[i].left = 0; ++ if (vol == PA_VOLUME_NORM) { ++ src->ramps[i].start = 1.0; ++ src->ramps[i].end = 1.0; ++ src->ramps[i].curr = 1.0; ++ } ++ else if (vol == PA_VOLUME_MUTED) { ++ src->ramps[i].start = 0.0; ++ src->ramps[i].end = 0.0; ++ src->ramps[i].curr = 0.0; ++ } ++ else { ++ temp = vol / (float)0x10000U; ++ src->ramps[i].start = temp * temp * temp; ++ src->ramps[i].end = src->ramps[i].start; ++ src->ramps[i].curr = src->ramps[i].start; ++ } ++ src->ramps[i].target = vol; ++ } ++ ++ return src; ++} +diff --git a/src/pulsecore/mix.h b/src/pulsecore/mix.h +index 8102bcd..0f86b6f 100644 +--- a/src/pulsecore/mix.h ++++ b/src/pulsecore/mix.h +@@ -59,4 +59,31 @@ void pa_volume_memchunk( + const pa_sample_spec *spec, + const pa_cvolume *volume); + ++typedef struct pa_volume_ramp_int_t { ++ pa_volume_ramp_type_t type; ++ long length; ++ long left; ++ float start; ++ float end; ++ float curr; ++ pa_volume_t target; ++} pa_volume_ramp_int_t; ++ ++typedef struct pa_cvolume_ramp_int { ++ uint8_t channels; ++ pa_volume_ramp_int_t ramps[PA_CHANNELS_MAX]; ++} pa_cvolume_ramp_int; ++ ++pa_cvolume_ramp_int* pa_cvolume_ramp_convert(const pa_cvolume_ramp *src, pa_cvolume_ramp_int *dst, int sample_rate); ++bool pa_cvolume_ramp_active(pa_cvolume_ramp_int *ramp); ++bool pa_cvolume_ramp_target_active(pa_cvolume_ramp_int *ramp); ++pa_cvolume_ramp_int* pa_cvolume_ramp_start_from(pa_cvolume_ramp_int *src, pa_cvolume_ramp_int *dst); ++pa_cvolume_ramp_int* pa_cvolume_ramp_int_init(pa_cvolume_ramp_int *src, pa_volume_t vol, int channels); ++pa_cvolume * pa_cvolume_ramp_get_targets(pa_cvolume_ramp_int *ramp, pa_cvolume *volume); ++ ++void pa_volume_ramp_memchunk( ++ pa_memchunk *c, ++ const pa_sample_spec *spec, ++ pa_cvolume_ramp_int *ramp); ++ + #endif +-- +1.9.1 + diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio-10.0/0003-volume-ramp-adding-volume-ramping-to-sink-input.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio-10.0/0003-volume-ramp-adding-volume-ramping-to-sink-input.patch new file mode 100644 index 000000000..eb485ca7c --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio-10.0/0003-volume-ramp-adding-volume-ramping-to-sink-input.patch @@ -0,0 +1,189 @@ +From e4469df7c69316b49cad93dd288badc98fa1cad5 Mon Sep 17 00:00:00 2001 +From: Sangchul Lee <sangchul1011@gmail.com> +Date: Sat, 27 Aug 2016 21:33:17 +0900 +Subject: [PATCH 3/6] volume ramp: adding volume ramping to sink-input + +The original patch is + - https://review.tizen.org/git/?p=platform/upstream/pulseaudio.git;a=commit;h=98042248fd67ce0ab3807c5c472c0d5d8b0f99d3 + - by Jaska Uimonen <jaska.uimonen <at> helsinki.fi> + +Signed-off-by: Sangchul Lee <sc11.lee@samsung.com> +--- + src/pulsecore/sink-input.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++ + src/pulsecore/sink-input.h | 11 ++++++++- + 2 files changed, 71 insertions(+), 1 deletion(-) + +diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c +index 8ec63b5..cc8953f 100644 +--- a/src/pulsecore/sink-input.c ++++ b/src/pulsecore/sink-input.c +@@ -526,6 +526,11 @@ int pa_sink_input_new( + reset_callbacks(i); + i->userdata = NULL; + ++ if (data->flags & PA_SINK_INPUT_START_RAMP_MUTED) ++ pa_cvolume_ramp_int_init(&i->ramp, PA_VOLUME_MUTED, data->sample_spec.channels); ++ else ++ pa_cvolume_ramp_int_init(&i->ramp, PA_VOLUME_NORM, data->sample_spec.channels); ++ + i->thread_info.state = i->state; + i->thread_info.attached = false; + pa_atomic_store(&i->thread_info.drained, 1); +@@ -542,6 +547,8 @@ int pa_sink_input_new( + i->thread_info.playing_for = 0; + i->thread_info.direct_outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + ++ i->thread_info.ramp = i->ramp; ++ + pa_assert_se(pa_idxset_put(core->sink_inputs, i, &i->index) == 0); + pa_assert_se(pa_idxset_put(i->sink->inputs, pa_sink_input_ref(i), NULL) == 0); + +@@ -923,6 +930,8 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink bytes */, pa + while (tchunk.length > 0) { + pa_memchunk wchunk; + bool nvfs = need_volume_factor_sink; ++ pa_cvolume target; ++ pa_bool_t tmp; + + wchunk = tchunk; + pa_memblock_ref(wchunk.memblock); +@@ -959,6 +968,16 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink bytes */, pa + pa_volume_memchunk(&wchunk, &i->sink->sample_spec, &i->volume_factor_sink); + } + ++ /* check for possible volume ramp */ ++ if (pa_cvolume_ramp_active(&i->thread_info.ramp)) { ++ pa_memchunk_make_writable(&wchunk, 0); ++ pa_volume_ramp_memchunk(&wchunk, &i->sink->sample_spec, &(i->thread_info.ramp)); ++ } else if ((tmp = pa_cvolume_ramp_target_active(&(i->thread_info.ramp)))) { ++ pa_memchunk_make_writable(&wchunk, 0); ++ pa_cvolume_ramp_get_targets(&i->thread_info.ramp, &target); ++ pa_volume_memchunk(&wchunk, &i->sink->sample_spec, &target); ++ } ++ + pa_memblockq_push_align(i->thread_info.render_memblockq, &wchunk); + } else { + pa_memchunk rchunk; +@@ -975,6 +994,16 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink bytes */, pa + pa_volume_memchunk(&rchunk, &i->sink->sample_spec, &i->volume_factor_sink); + } + ++ /* check for possible volume ramp */ ++ if (pa_cvolume_ramp_active(&(i->thread_info.ramp))) { ++ pa_memchunk_make_writable(&rchunk, 0); ++ pa_volume_ramp_memchunk(&rchunk, &i->sink->sample_spec, &(i->thread_info.ramp)); ++ } else if (pa_cvolume_ramp_target_active(&(i->thread_info.ramp))) { ++ pa_memchunk_make_writable(&rchunk, 0); ++ pa_cvolume_ramp_get_targets(&i->thread_info.ramp, &target); ++ pa_volume_memchunk(&rchunk, &i->sink->sample_spec, &target); ++ } ++ + pa_memblockq_push_align(i->thread_info.render_memblockq, &rchunk); + pa_memblock_unref(rchunk.memblock); + } +@@ -1339,6 +1368,31 @@ int pa_sink_input_remove_volume_factor(pa_sink_input *i, const char *key) { + return 0; + } + ++/* Called from main thread */ ++void pa_sink_input_set_volume_ramp( ++ pa_sink_input *i, ++ const pa_cvolume_ramp *ramp, ++ pa_bool_t send_msg, ++ pa_bool_t save) { ++ ++ pa_sink_input_assert_ref(i); ++ pa_assert_ctl_context(); ++ pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); ++ pa_assert(ramp); ++ ++ pa_cvolume_ramp_convert(ramp, &i->ramp, i->sample_spec.rate); ++ ++ pa_log_debug("setting volume ramp with target vol:%d and length:%ld", ++ i->ramp.ramps[0].target, ++ i->ramp.ramps[0].length); ++ ++ ++ /* This tells the sink that volume ramp changed */ ++ if (send_msg) ++ pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_VOLUME_RAMP, ++ NULL, 0, NULL) == 0); ++} ++ + /* Called from main context */ + static void set_real_ratio(pa_sink_input *i, const pa_cvolume *v) { + pa_sink_input_assert_ref(i); +@@ -1932,6 +1986,13 @@ int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t + } + return 0; + ++ case PA_SINK_INPUT_MESSAGE_SET_VOLUME_RAMP: ++ /* we have ongoing ramp where we take current start values */ ++ pa_cvolume_ramp_start_from(&i->thread_info.ramp, &i->ramp); ++ i->thread_info.ramp = i->ramp; ++ pa_sink_input_request_rewind(i, 0, true, false, false); ++ return 0; ++ + case PA_SINK_INPUT_MESSAGE_SET_SOFT_MUTE: + if (i->thread_info.muted != i->muted) { + i->thread_info.muted = i->muted; +diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h +index 86deab2..6e1b211 100644 +--- a/src/pulsecore/sink-input.h ++++ b/src/pulsecore/sink-input.h +@@ -32,6 +32,7 @@ + #include <pulsecore/client.h> + #include <pulsecore/sink.h> + #include <pulsecore/core.h> ++#include <pulsecore/mix.h> + + typedef enum pa_sink_input_state { + PA_SINK_INPUT_INIT, /*< The stream is not active yet, because pa_sink_input_put() has not been called yet */ +@@ -58,7 +59,8 @@ typedef enum pa_sink_input_flags { + PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND = 256, + PA_SINK_INPUT_NO_CREATE_ON_SUSPEND = 512, + PA_SINK_INPUT_KILL_ON_SUSPEND = 1024, +- PA_SINK_INPUT_PASSTHROUGH = 2048 ++ PA_SINK_INPUT_PASSTHROUGH = 2048, ++ PA_SINK_INPUT_START_RAMP_MUTED = 4096, + } pa_sink_input_flags_t; + + struct pa_sink_input { +@@ -121,6 +123,9 @@ struct pa_sink_input { + * this.*/ + bool save_sink:1, save_volume:1, save_muted:1; + ++ /* for volume ramps */ ++ pa_cvolume_ramp_int ramp; ++ + pa_resample_method_t requested_resample_method, actual_resample_method; + + /* Returns the chunk of audio data and drops it from the +@@ -249,6 +254,8 @@ struct pa_sink_input { + pa_usec_t requested_sink_latency; + + pa_hashmap *direct_outputs; ++ ++ pa_cvolume_ramp_int ramp; + } thread_info; + + void *userdata; +@@ -265,6 +272,7 @@ enum { + PA_SINK_INPUT_MESSAGE_SET_STATE, + PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY, + PA_SINK_INPUT_MESSAGE_GET_REQUESTED_LATENCY, ++ PA_SINK_INPUT_MESSAGE_SET_VOLUME_RAMP, + PA_SINK_INPUT_MESSAGE_MAX + }; + +@@ -370,6 +378,7 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, bool s + void pa_sink_input_add_volume_factor(pa_sink_input *i, const char *key, const pa_cvolume *volume_factor); + int pa_sink_input_remove_volume_factor(pa_sink_input *i, const char *key); + pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, bool absolute); ++void pa_sink_input_set_volume_ramp(pa_sink_input *i, const pa_cvolume_ramp *ramp, pa_bool_t send_msg, pa_bool_t save); + + void pa_sink_input_set_mute(pa_sink_input *i, bool mute, bool save); + +-- +1.9.1 + diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio-10.0/0004-sink-input-Code-cleanup-regarding-volume-ramping.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio-10.0/0004-sink-input-Code-cleanup-regarding-volume-ramping.patch new file mode 100644 index 000000000..64d7b141d --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio-10.0/0004-sink-input-Code-cleanup-regarding-volume-ramping.patch @@ -0,0 +1,62 @@ +From 49d8943b151a73be3dd726561a720c0f4bfdccac Mon Sep 17 00:00:00 2001 +From: Sangchul Lee <sangchul1011@gmail.com> +Date: Sat, 27 Aug 2016 21:33:18 +0900 +Subject: [PATCH 4/6] sink-input: Code cleanup regarding volume ramping + +Remove unused parameter of pa_sink_input_set_volume_ramp(). +Use bool instead of pa_bool_t. + +Signed-off-by: Sangchul Lee <sc11.lee@samsung.com> +--- + src/pulsecore/sink-input.c | 7 ++----- + src/pulsecore/sink-input.h | 2 +- + 2 files changed, 3 insertions(+), 6 deletions(-) + +diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c +index cc8953f..e1968e0 100644 +--- a/src/pulsecore/sink-input.c ++++ b/src/pulsecore/sink-input.c +@@ -931,7 +931,6 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink bytes */, pa + pa_memchunk wchunk; + bool nvfs = need_volume_factor_sink; + pa_cvolume target; +- pa_bool_t tmp; + + wchunk = tchunk; + pa_memblock_ref(wchunk.memblock); +@@ -972,7 +971,7 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink bytes */, pa + if (pa_cvolume_ramp_active(&i->thread_info.ramp)) { + pa_memchunk_make_writable(&wchunk, 0); + pa_volume_ramp_memchunk(&wchunk, &i->sink->sample_spec, &(i->thread_info.ramp)); +- } else if ((tmp = pa_cvolume_ramp_target_active(&(i->thread_info.ramp)))) { ++ } else if ((pa_cvolume_ramp_target_active(&(i->thread_info.ramp)))) { + pa_memchunk_make_writable(&wchunk, 0); + pa_cvolume_ramp_get_targets(&i->thread_info.ramp, &target); + pa_volume_memchunk(&wchunk, &i->sink->sample_spec, &target); +@@ -1372,9 +1371,7 @@ int pa_sink_input_remove_volume_factor(pa_sink_input *i, const char *key) { + void pa_sink_input_set_volume_ramp( + pa_sink_input *i, + const pa_cvolume_ramp *ramp, +- pa_bool_t send_msg, +- pa_bool_t save) { +- ++ bool send_msg) { + pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); + pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); +diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h +index 6e1b211..92f61c3 100644 +--- a/src/pulsecore/sink-input.h ++++ b/src/pulsecore/sink-input.h +@@ -378,7 +378,7 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, bool s + void pa_sink_input_add_volume_factor(pa_sink_input *i, const char *key, const pa_cvolume *volume_factor); + int pa_sink_input_remove_volume_factor(pa_sink_input *i, const char *key); + pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, bool absolute); +-void pa_sink_input_set_volume_ramp(pa_sink_input *i, const pa_cvolume_ramp *ramp, pa_bool_t send_msg, pa_bool_t save); ++void pa_sink_input_set_volume_ramp(pa_sink_input *i, const pa_cvolume_ramp *ramp, bool send_msg); + + void pa_sink_input_set_mute(pa_sink_input *i, bool mute, bool save); + +-- +1.9.1 + diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio-10.0/0005-sink-input-volume-Add-support-for-volume-ramp-factor.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio-10.0/0005-sink-input-volume-Add-support-for-volume-ramp-factor.patch new file mode 100644 index 000000000..e371b7ec5 --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio-10.0/0005-sink-input-volume-Add-support-for-volume-ramp-factor.patch @@ -0,0 +1,299 @@ +From a98e78ccc4f12d6efad2832a09202651e2a8b6cd Mon Sep 17 00:00:00 2001 +From: Sangchul Lee <sangchul1011@gmail.com> +Date: Sat, 27 Aug 2016 21:33:19 +0900 +Subject: [PATCH 5/6] sink-input, volume: Add support for volume ramp factor + +Previously, using pa_sink_input_set_volume_ramp() is hard to manage +if there are several callers. These new volume ramp factor APIs make it +easy for caller to use and to set more than one volume ramp factor. +New volume ramp factor will be applied by the multiplication of the other +ramp factors that have been already set. + +APIs are added as below. + - pa_sink_input_add_volume_ramp_factor() + - pa_sink_input_remove_volume_ramp_factor() + - pa_cvolume_ramp_compatible() + - pa_sw_cvolume_ramp_multiply() + - pa_cvolume_ramp_valid() + +Signed-off-by: Sangchul Lee <sc11.lee@samsung.com> +--- + src/map-file | 3 ++ + src/pulse/volume.c | 44 ++++++++++++++++++ + src/pulse/volume.h | 9 ++++ + src/pulsecore/sink-input.c | 108 +++++++++++++++++++++++++++++++++++++++++++++ + src/pulsecore/sink-input.h | 5 +++ + 5 files changed, 169 insertions(+) + +diff --git a/src/map-file b/src/map-file +index ef9b57d..7577c14 100644 +--- a/src/map-file ++++ b/src/map-file +@@ -142,6 +142,8 @@ pa_cvolume_ramp_equal; + pa_cvolume_ramp_init; + pa_cvolume_ramp_set; + pa_cvolume_ramp_channel_ramp_set; ++pa_cvolume_ramp_compatible; ++pa_cvolume_ramp_valid; + pa_cvolume_remap; + pa_cvolume_scale; + pa_cvolume_scale_mask; +@@ -344,6 +346,7 @@ pa_sw_cvolume_divide_scalar; + pa_sw_cvolume_multiply; + pa_sw_cvolume_multiply_scalar; + pa_sw_cvolume_snprint_dB; ++pa_sw_cvolume_ramp_multiply; + pa_sw_volume_divide; + pa_sw_volume_from_dB; + pa_sw_volume_from_linear; +diff --git a/src/pulse/volume.c b/src/pulse/volume.c +index 85072c1..8d99150 100644 +--- a/src/pulse/volume.c ++++ b/src/pulse/volume.c +@@ -1049,3 +1049,47 @@ pa_cvolume_ramp* pa_cvolume_ramp_channel_ramp_set(pa_cvolume_ramp *ramp, unsigne + + return ramp; + } ++ ++int pa_cvolume_ramp_compatible(const pa_cvolume_ramp *ramp, const pa_sample_spec *ss) { ++ ++ pa_assert(ramp); ++ pa_assert(ss); ++ ++ pa_return_val_if_fail(pa_cvolume_ramp_valid(ramp), 0); ++ pa_return_val_if_fail(pa_sample_spec_valid(ss), 0); ++ ++ return ramp->channels == ss->channels; ++} ++ ++pa_cvolume_ramp *pa_sw_cvolume_ramp_multiply(pa_cvolume_ramp *dest, const pa_cvolume_ramp *a, const pa_cvolume_ramp *b) { ++ unsigned i; ++ ++ pa_assert(dest); ++ pa_assert(a); ++ pa_assert(b); ++ ++ pa_return_val_if_fail(pa_cvolume_ramp_valid(a), NULL); ++ pa_return_val_if_fail(pa_cvolume_ramp_valid(b), NULL); ++ ++ for (i = 0; i < a->channels && i < b->channels; i++) ++ dest->ramps[i].target = pa_sw_volume_multiply(a->ramps[i].target, b->ramps[i].target); ++ ++ dest->channels = (uint8_t) i; ++ ++ return dest; ++} ++ ++int pa_cvolume_ramp_valid(const pa_cvolume_ramp *ramp) { ++ unsigned c; ++ ++ pa_assert(ramp); ++ ++ if (!pa_channels_valid(ramp->channels)) ++ return 0; ++ ++ for (c = 0; c < ramp->channels; c++) ++ if (!PA_VOLUME_IS_VALID(ramp->ramps[c].target)) ++ return 0; ++ ++ return 1; ++} +diff --git a/src/pulse/volume.h b/src/pulse/volume.h +index 2ae3451..65fcb08 100644 +--- a/src/pulse/volume.h ++++ b/src/pulse/volume.h +@@ -458,12 +458,21 @@ int pa_cvolume_ramp_equal(const pa_cvolume_ramp *a, const pa_cvolume_ramp *b); + /** Init volume ramp struct */ + pa_cvolume_ramp* pa_cvolume_ramp_init(pa_cvolume_ramp *ramp); + ++/** Set the volume ramp of the first n channels to PA_VOLUME_NORM */ ++#define pa_cvolume_ramp_reset(a, n, t, l) pa_cvolume_ramp_set((a), (n), (t), (l), PA_VOLUME_NORM) ++ + /** Set first n channels of ramp struct to certain value */ + pa_cvolume_ramp* pa_cvolume_ramp_set(pa_cvolume_ramp *ramp, unsigned channel, pa_volume_ramp_type_t type, long time, pa_volume_t vol); + + /** Set individual channel in the channel struct */ + pa_cvolume_ramp* pa_cvolume_ramp_channel_ramp_set(pa_cvolume_ramp *ramp, unsigned channel, pa_volume_ramp_type_t type, long time, pa_volume_t vol); + ++int pa_cvolume_ramp_compatible(const pa_cvolume_ramp *ramp, const pa_sample_spec *ss); ++ ++int pa_cvolume_ramp_valid(const pa_cvolume_ramp *ramp); ++ ++pa_cvolume_ramp *pa_sw_cvolume_ramp_multiply(pa_cvolume_ramp *dest, const pa_cvolume_ramp *a, const pa_cvolume_ramp *b); ++ + PA_C_DECL_END + + #endif +diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c +index e1968e0..6f89aa1 100644 +--- a/src/pulsecore/sink-input.c ++++ b/src/pulsecore/sink-input.c +@@ -53,6 +53,11 @@ struct volume_factor_entry { + pa_cvolume volume; + }; + ++struct volume_ramp_factor_entry { ++ char *key; ++ pa_cvolume_ramp ramp; ++}; ++ + static struct volume_factor_entry *volume_factor_entry_new(const char *key, const pa_cvolume *volume) { + struct volume_factor_entry *entry; + +@@ -83,6 +88,37 @@ static void volume_factor_from_hashmap(pa_cvolume *v, pa_hashmap *items, uint8_t + pa_sw_cvolume_multiply(v, v, &entry->volume); + } + ++static struct volume_ramp_factor_entry *volume_ramp_factor_entry_new(const char *key, const pa_cvolume_ramp *ramp) { ++ struct volume_ramp_factor_entry *entry; ++ ++ pa_assert(key); ++ pa_assert(ramp); ++ ++ entry = pa_xnew(struct volume_ramp_factor_entry, 1); ++ entry->key = pa_xstrdup(key); ++ ++ entry->ramp = *ramp; ++ ++ return entry; ++} ++ ++static void volume_ramp_factor_entry_free(struct volume_ramp_factor_entry *ramp_entry) { ++ pa_assert(ramp_entry); ++ ++ pa_xfree(ramp_entry->key); ++ pa_xfree(ramp_entry); ++} ++ ++static void volume_ramp_factor_from_hashmap(pa_cvolume_ramp *r, pa_hashmap *items, uint8_t channels, pa_volume_ramp_type_t type, long length) { ++ struct volume_ramp_factor_entry *entry; ++ void *state = NULL; ++ ++ pa_cvolume_ramp_reset(r, channels, type, length); ++ PA_HASHMAP_FOREACH(entry, items, state) ++ pa_sw_cvolume_ramp_multiply(r, r, &entry->ramp); ++ ++} ++ + static void sink_input_free(pa_object *o); + static void set_real_ratio(pa_sink_input *i, const pa_cvolume *v); + +@@ -500,6 +536,8 @@ int pa_sink_input_new( + i->volume_factor_sink_items = data->volume_factor_sink_items; + data->volume_factor_sink_items = NULL; + volume_factor_from_hashmap(&i->volume_factor_sink, i->volume_factor_sink_items, i->sink->sample_spec.channels); ++ i->ramp_factor_items = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, ++ (pa_free_cb_t) volume_ramp_factor_entry_free); + + i->real_ratio = i->reference_ratio = data->volume; + pa_cvolume_reset(&i->soft_volume, i->sample_spec.channels); +@@ -764,6 +802,9 @@ static void sink_input_free(pa_object *o) { + if (i->volume_factor_sink_items) + pa_hashmap_free(i->volume_factor_sink_items); + ++ if (i->ramp_factor_items) ++ pa_hashmap_free(i->ramp_factor_items); ++ + pa_xfree(i->driver); + pa_xfree(i); + } +@@ -1367,6 +1408,73 @@ int pa_sink_input_remove_volume_factor(pa_sink_input *i, const char *key) { + return 0; + } + ++void pa_sink_input_add_volume_ramp_factor(pa_sink_input *i, const char *key, const pa_cvolume_ramp *ramp_factor, bool send_msg) { ++ struct volume_ramp_factor_entry *r; ++ ++ pa_sink_input_assert_ref(i); ++ pa_assert_ctl_context(); ++ pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); ++ pa_assert(ramp_factor); ++ pa_assert(key); ++ pa_assert(pa_cvolume_ramp_valid(ramp_factor)); ++ pa_assert(ramp_factor->channels == 1 || pa_cvolume_ramp_compatible(ramp_factor, &i->sample_spec)); ++ ++ r = volume_ramp_factor_entry_new(key, ramp_factor); ++ if (!pa_cvolume_ramp_compatible(ramp_factor, &i->sample_spec)) ++ pa_cvolume_ramp_set(&r->ramp, i->sample_spec.channels, ramp_factor->ramps[0].type, ramp_factor->ramps[0].length, ramp_factor->ramps[0].target); ++ ++ pa_assert_se(pa_hashmap_put(i->ramp_factor_items, r->key, r) >= 0); ++ if (pa_hashmap_size(i->ramp_factor_items) == 1) ++ pa_cvolume_ramp_set(&i->ramp_factor, i->sample_spec.channels, r->ramp.ramps[0].type, r->ramp.ramps[0].length, r->ramp.ramps[0].target); ++ else ++ pa_sw_cvolume_ramp_multiply(&i->ramp_factor, &i->ramp_factor, &r->ramp); ++ ++ pa_cvolume_ramp_convert(&i->ramp_factor, &i->ramp, i->sample_spec.rate); ++ ++ if (send_msg) ++ pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_VOLUME_RAMP, NULL, 0, NULL) == 0); ++ ++ return 0; ++} ++ ++/* Returns 0 if an entry was removed and -1 if no entry for the given key was ++ * found. */ ++int pa_sink_input_remove_volume_ramp_factor(pa_sink_input *i, const char *key, bool send_msg) { ++ struct volume_ramp_factor_entry *r; ++ ++ pa_sink_input_assert_ref(i); ++ pa_assert(key); ++ pa_assert_ctl_context(); ++ pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); ++ ++ r = pa_hashmap_remove(i->ramp_factor_items, key); ++ if (!r) ++ return -1; ++ ++ switch (pa_hashmap_size(i->ramp_factor_items)) { ++ case 0: ++ pa_cvolume_ramp_reset(&i->ramp_factor, i->sample_spec.channels, r->ramp.ramps[0].type, r->ramp.ramps[0].length); ++ break; ++ case 1: { ++ struct volume_ramp_factor_entry *rf; ++ rf = pa_hashmap_first(i->ramp_factor_items); ++ pa_cvolume_ramp_set(&i->ramp_factor, i->sample_spec.channels, r->ramp.ramps[0].type, r->ramp.ramps[0].length, rf->ramp.ramps[0].target); ++ break; ++ } ++ default: ++ volume_ramp_factor_from_hashmap(&i->ramp_factor, i->ramp_factor_items, i->ramp_factor.channels, i->ramp_factor.ramps[0].type, i->ramp_factor.ramps[0].length); ++ } ++ ++ volume_ramp_factor_entry_free(r); ++ ++ pa_cvolume_ramp_convert(&i->ramp_factor, &i->ramp, i->sample_spec.rate); ++ ++ if (send_msg) ++ pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_VOLUME_RAMP, NULL, 0, NULL) == 0); ++ ++ return 0; ++} ++ + /* Called from main thread */ + void pa_sink_input_set_volume_ramp( + pa_sink_input *i, +diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h +index 92f61c3..5430d53 100644 +--- a/src/pulsecore/sink-input.h ++++ b/src/pulsecore/sink-input.h +@@ -113,6 +113,9 @@ struct pa_sink_input { + pa_cvolume volume_factor_sink; /* A second volume factor in format of the sink this stream is connected to. */ + pa_hashmap *volume_factor_sink_items; + ++ pa_cvolume_ramp ramp_factor; ++ pa_hashmap *ramp_factor_items; ++ + bool volume_writable:1; + + bool muted:1; +@@ -379,6 +382,8 @@ void pa_sink_input_add_volume_factor(pa_sink_input *i, const char *key, const pa + int pa_sink_input_remove_volume_factor(pa_sink_input *i, const char *key); + pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, bool absolute); + void pa_sink_input_set_volume_ramp(pa_sink_input *i, const pa_cvolume_ramp *ramp, bool send_msg); ++void pa_sink_input_add_volume_ramp_factor(pa_sink_input *i, const char *key, const pa_cvolume_ramp *ramp_factor, bool send_msg); ++int pa_sink_input_remove_volume_ramp_factor(pa_sink_input *i, const char *key, bool send_msg); + + void pa_sink_input_set_mute(pa_sink_input *i, bool mute, bool save); + +-- +1.9.1 + diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio-10.0/0006-sink-input-Remove-pa_sink_input_set_volume_ramp.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio-10.0/0006-sink-input-Remove-pa_sink_input_set_volume_ramp.patch new file mode 100644 index 000000000..50110bd14 --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio-10.0/0006-sink-input-Remove-pa_sink_input_set_volume_ramp.patch @@ -0,0 +1,63 @@ +From ac9a99505fd768b66dd92e9091e80b576cabc00d Mon Sep 17 00:00:00 2001 +From: Sangchul Lee <sangchul1011@gmail.com> +Date: Sat, 27 Aug 2016 21:33:20 +0900 +Subject: [PATCH 6/6] sink-input: Remove pa_sink_input_set_volume_ramp() + +Please use pa_sink_input_add_volume_ramp_factor() or +pa_sink_input_remove_volume_ramp_factor() instead of it. + +Signed-off-by: Sangchul Lee <sc11.lee@samsung.com> +--- + src/pulsecore/sink-input.c | 23 ----------------------- + src/pulsecore/sink-input.h | 1 - + 2 files changed, 24 deletions(-) + +diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c +index 6f89aa1..4c7c568 100644 +--- a/src/pulsecore/sink-input.c ++++ b/src/pulsecore/sink-input.c +@@ -1475,29 +1475,6 @@ int pa_sink_input_remove_volume_ramp_factor(pa_sink_input *i, const char *key, b + return 0; + } + +-/* Called from main thread */ +-void pa_sink_input_set_volume_ramp( +- pa_sink_input *i, +- const pa_cvolume_ramp *ramp, +- bool send_msg) { +- pa_sink_input_assert_ref(i); +- pa_assert_ctl_context(); +- pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); +- pa_assert(ramp); +- +- pa_cvolume_ramp_convert(ramp, &i->ramp, i->sample_spec.rate); +- +- pa_log_debug("setting volume ramp with target vol:%d and length:%ld", +- i->ramp.ramps[0].target, +- i->ramp.ramps[0].length); +- +- +- /* This tells the sink that volume ramp changed */ +- if (send_msg) +- pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_VOLUME_RAMP, +- NULL, 0, NULL) == 0); +-} +- + /* Called from main context */ + static void set_real_ratio(pa_sink_input *i, const pa_cvolume *v) { + pa_sink_input_assert_ref(i); +diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h +index 5430d53..5fef3d5 100644 +--- a/src/pulsecore/sink-input.h ++++ b/src/pulsecore/sink-input.h +@@ -381,7 +381,6 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, bool s + void pa_sink_input_add_volume_factor(pa_sink_input *i, const char *key, const pa_cvolume *volume_factor); + int pa_sink_input_remove_volume_factor(pa_sink_input *i, const char *key); + pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, bool absolute); +-void pa_sink_input_set_volume_ramp(pa_sink_input *i, const pa_cvolume_ramp *ramp, bool send_msg); + void pa_sink_input_add_volume_ramp_factor(pa_sink_input *i, const char *key, const pa_cvolume_ramp *ramp_factor, bool send_msg); + int pa_sink_input_remove_volume_ramp_factor(pa_sink_input *i, const char *key, bool send_msg); + +-- +1.9.1 + diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio-10.0/enable-ofono-hfp-backend.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio-10.0/enable-ofono-hfp-backend.patch new file mode 100644 index 000000000..85b1ae03d --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio-10.0/enable-ofono-hfp-backend.patch @@ -0,0 +1,11 @@ +--- pulseaudio-9.0/src/daemon/default.pa.in.orig 2017-05-17 17:26:20.415369638 +0000 ++++ pulseaudio-9.0/src/daemon/default.pa.in 2017-05-17 17:26:49.995316383 +0000 +@@ -82,7 +82,7 @@ + .endif + + .ifexists module-bluetooth-discover@PA_SOEXT@ +-load-module module-bluetooth-discover ++load-module module-bluetooth-discover headset=ofono + .endif + ])dnl + diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0008-install-files-for-a-module-development.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0008-install-files-for-a-module-development.patch new file mode 100644 index 000000000..ac164d643 --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0008-install-files-for-a-module-development.patch @@ -0,0 +1,53 @@ +--- a/Makefile.am 2016-04-12 11:28:10.832997230 +0200 ++++ b/Makefile.am 2016-04-12 11:32:41.868996777 +0200 +@@ -49,7 +49,13 @@ + vala/libpulse-simple.deps vala/libpulse-simple.vapi + + pkgconfigdir = $(libdir)/pkgconfig +-pkgconfig_DATA = libpulse.pc libpulse-simple.pc ++pkgconfig_DATA = libpulse.pc libpulse-simple.pc pulseaudio-module-devel.pc ++ ++moduledev_DATA = pulsecore-config.h $(top_srcdir)/src/pulsecore/*.h ++moduledevdir = $(includedir)/pulsemodule/pulsecore ++ ++moduledevinternal_DATA = src/pulse/internal.h src/pulse/client-conf.h src/pulse/fork-detect.h ++moduledevinternaldir = $(includedir)/pulsemodule/pulse + + if HAVE_GLIB20 + pkgconfig_DATA += \ +@@ -103,6 +109,9 @@ + check-daemon: + $(MAKE) -C src check-daemon + ++pulsecore-config.h: config.h ++ cp $< $@ ++ + .PHONY: homepage distcleancheck doxygen + + # see git-version-gen +--- a/configure.ac 2016-04-12 11:34:10.605996629 +0200 ++++ b/configure.ac 2016-04-12 11:37:43.502996274 +0200 +@@ -1464,6 +1464,7 @@ + man/default.pa.5.xml + man/pulse-cli-syntax.5.xml + man/start-pulseaudio-x11.1.xml ++pulseaudio-module-devel.pc + ]) + + AC_CONFIG_FILES([src/esdcompat:src/daemon/esdcompat.in], [chmod +x src/esdcompat]) +--- /dev/null 2016-03-15 16:08:23.302999643 +0100 ++++ b/pulseaudio-module-devel.pc.in 2016-03-17 16:16:58.427977484 +0100 +@@ -0,0 +1,12 @@ ++prefix=@prefix@ ++exec_prefix=@exec_prefix@ ++libdir=@libdir@ ++includedir=@includedir@ ++modlibexecdir=@modlibexecdir@ ++ ++Name: pulseaudio-module-devel ++Description: PulseAudio Module Development Interface ++Version: @PACKAGE_VERSION@ ++Libs: -L${libdir} -L${libdir}/pulseaudio -L${modlibexecdir} -lpulsecommon-@PA_MAJORMINOR@ -lpulsecore-@PA_MAJORMINOR@ -lprotocol-native ++Libs.private: ++Cflags: -I${includedir}/pulsemodule -D_REENTRANT + diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0010-volume-ramp-additions-to-the-low-level-infra.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0010-volume-ramp-additions-to-the-low-level-infra.patch new file mode 100644 index 000000000..e249bc438 --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0010-volume-ramp-additions-to-the-low-level-infra.patch @@ -0,0 +1,503 @@ +--- a/src/map-file 2016-04-12 15:03:17.009975690 +0200 ++++ b/src/map-file 2016-04-12 15:03:52.389975631 +0200 +@@ -136,6 +136,9 @@ + pa_cvolume_merge; + pa_cvolume_min; + pa_cvolume_min_mask; ++pa_cvolume_ramp_init; ++pa_cvolume_ramp_set; ++pa_cvolume_ramp_channel_ramp_set; + pa_cvolume_remap; + pa_cvolume_scale; + pa_cvolume_scale_mask; +--- a/src/pulse/def.h 2016-04-12 15:05:58.245975421 +0200 ++++ b/src/pulse/def.h 2016-04-12 15:13:19.424974685 +0200 +@@ -347,11 +347,15 @@ + * consider absolute when the sink is in flat volume mode, + * relative otherwise. \since 0.9.20 */ + +- PA_STREAM_PASSTHROUGH = 0x80000U ++ PA_STREAM_PASSTHROUGH = 0x80000U, + /**< Used to tag content that will be rendered by passthrough sinks. + * The data will be left as is and not reformatted, resampled. + * \since 1.0 */ + ++ PA_STREAM_START_RAMP_MUTED = 0x100000U ++ /**< Used to tag content that the stream will be started ramp volume ++ * muted so that you can nicely fade it in */ ++ + } pa_stream_flags_t; + + /** \cond fulldocs */ +@@ -380,6 +384,7 @@ + #define PA_STREAM_FAIL_ON_SUSPEND PA_STREAM_FAIL_ON_SUSPEND + #define PA_STREAM_RELATIVE_VOLUME PA_STREAM_RELATIVE_VOLUME + #define PA_STREAM_PASSTHROUGH PA_STREAM_PASSTHROUGH ++#define PA_STREAM_START_RAMP_MUTED PA_STREAM_START_RAMP_MUTED + + /** \endcond */ + +@@ -1047,6 +1052,13 @@ + /** \endcond */ + #endif + ++/** \cond fulldocs */ ++#define PA_VOLUMER_RAMP_TYPE_LINEAR PA_VOLUMER_RAMP_TYPE_LINEAR ++#define PA_VOLUMER_RAMP_TYPE_LOGARITHMIC PA_VOLUMER_RAMP_TYPE_LOGARITHMIC ++#define PA_VOLUMER_RAMP_TYPE_CUBIC PA_VOLUMER_RAMP_TYPE_CUBIC ++ ++/** \endcond */ ++ + PA_C_DECL_END + + #endif +--- a/src/pulse/volume.c 2016-04-12 15:13:38.598974653 +0200 ++++ b/src/pulse/volume.c 2016-04-12 15:27:57.729973219 +0200 +@@ -445,7 +445,10 @@ + unsigned c; + pa_assert(a); + +- pa_return_val_if_fail(pa_cvolume_valid(a), 0); ++ if (pa_cvolume_valid(a) == 0) ++ abort(); ++ ++ /* pa_return_val_if_fail(pa_cvolume_valid(a), 0); */ + pa_return_val_if_fail(PA_VOLUME_IS_VALID(v), 0); + + for (c = 0; c < a->channels; c++) +@@ -986,3 +989,51 @@ + + return pa_cvolume_scale(v, m); + } ++ ++pa_cvolume_ramp* pa_cvolume_ramp_init(pa_cvolume_ramp *ramp) { ++ unsigned c; ++ ++ pa_assert(ramp); ++ ++ ramp->channels = 0; ++ ++ for (c = 0; c < PA_CHANNELS_MAX; c++) { ++ ramp->ramps[c].type = PA_VOLUME_RAMP_TYPE_LINEAR; ++ ramp->ramps[c].length = 0; ++ ramp->ramps[c].target = PA_VOLUME_INVALID; ++ } ++ ++ return ramp; ++} ++ ++pa_cvolume_ramp* pa_cvolume_ramp_set(pa_cvolume_ramp *ramp, unsigned channels, pa_volume_ramp_type_t type, long time, pa_volume_t vol) { ++ int i; ++ ++ pa_assert(ramp); ++ pa_assert(channels > 0); ++ pa_assert(time >= 0); ++ pa_assert(channels <= PA_CHANNELS_MAX); ++ ++ ramp->channels = (uint8_t) channels; ++ ++ for (i = 0; i < ramp->channels; i++) { ++ ramp->ramps[i].type = type; ++ ramp->ramps[i].length = time; ++ ramp->ramps[i].target = PA_CLAMP_VOLUME(vol); ++ } ++ ++ return ramp; ++} ++ ++pa_cvolume_ramp* pa_cvolume_ramp_channel_ramp_set(pa_cvolume_ramp *ramp, unsigned channel, pa_volume_ramp_type_t type, long time, pa_volume_t vol) { ++ ++ pa_assert(ramp); ++ pa_assert(channel <= ramp->channels); ++ pa_assert(time >= 0); ++ ++ ramp->ramps[channel].type = type; ++ ramp->ramps[channel].length = time; ++ ramp->ramps[channel].target = PA_CLAMP_VOLUME(vol); ++ ++ return ramp; ++} +--- a/src/pulse/volume.h 2016-04-12 15:40:34.989971955 +0200 ++++ b/src/pulse/volume.h 2016-04-12 15:38:50.708972129 +0200 +@@ -413,6 +413,36 @@ + * the channels are kept. \since 0.9.16 */ + pa_cvolume* pa_cvolume_dec(pa_cvolume *v, pa_volume_t dec); + ++/** Volume ramp type ++*/ ++typedef enum pa_volume_ramp_type { ++ PA_VOLUME_RAMP_TYPE_LINEAR = 0, /**< linear */ ++ PA_VOLUME_RAMP_TYPE_LOGARITHMIC = 1, /**< logarithmic */ ++ PA_VOLUME_RAMP_TYPE_CUBIC = 2, ++} pa_volume_ramp_type_t; ++ ++/** A structure encapsulating a volume ramp */ ++typedef struct pa_volume_ramp_t { ++ pa_volume_ramp_type_t type; ++ long length; ++ pa_volume_t target; ++} pa_volume_ramp_t; ++ ++/** A structure encapsulating a multichannel volume ramp */ ++typedef struct pam_cvolume_ramp { ++ uint8_t channels; ++ pa_volume_ramp_t ramps[PA_CHANNELS_MAX]; ++} pa_cvolume_ramp; ++ ++/** Init volume ramp struct */ ++pa_cvolume_ramp* pa_cvolume_ramp_init(pa_cvolume_ramp *ramp); ++ ++/** Set first n channels of ramp struct to certain value */ ++pa_cvolume_ramp* pa_cvolume_ramp_set(pa_cvolume_ramp *ramp, unsigned channel, pa_volume_ramp_type_t type, long time, pa_volume_t vol); ++ ++/** Set individual channel in the channel struct */ ++pa_cvolume_ramp* pa_cvolume_ramp_channel_ramp_set(pa_cvolume_ramp *ramp, unsigned channel, pa_volume_ramp_type_t type, long time, pa_volume_t vol); ++ + PA_C_DECL_END + + #endif +--- a/src/pulsecore/sample-util.c 2016-04-12 15:41:51.812971827 +0200 ++++ b/src/pulsecore/sample-util.c 2016-04-12 16:31:56.795966812 +0200 +@@ -41,6 +41,13 @@ + + #define PA_SILENCE_MAX (PA_PAGE_SIZE*16) + ++#define VOLUME_PADDING 32 ++ ++typedef union { ++ float f; ++ uint32_t i; ++} volume_val; ++ + pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) { + void *data; + +@@ -403,3 +410,292 @@ + usec = pa_bytes_to_usec_round_up(size, from); + return pa_usec_to_bytes_round_up(usec, to); + } ++ ++static void calc_linear_integer_volume_no_mapping(int32_t linear[], float volume[], unsigned nchannels) { ++ unsigned channel, padding; ++ ++ pa_assert(linear); ++ pa_assert(volume); ++ ++ for (channel = 0; channel < nchannels; channel++) ++ linear[channel] = (int32_t) lrint(volume[channel] * 0x10000U); ++ ++ for (padding = 0; padding < VOLUME_PADDING; padding++, channel++) ++ linear[channel] = linear[padding]; ++} ++ ++static void calc_linear_float_volume_no_mapping(float linear[], float volume[], unsigned nchannels) { ++ unsigned channel, padding; ++ ++ pa_assert(linear); ++ pa_assert(volume); ++ ++ for (channel = 0; channel < nchannels; channel++) ++ linear[channel] = volume[channel]; ++ ++ for (padding = 0; padding < VOLUME_PADDING; padding++, channel++) ++ linear[channel] = linear[padding]; ++} ++ ++typedef void (*pa_calc_volume_no_mapping_func_t) (void *volumes, float *volume, int channels); ++ ++static const pa_calc_volume_no_mapping_func_t calc_volume_table_no_mapping[] = { ++ [PA_SAMPLE_U8] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping, ++ [PA_SAMPLE_ALAW] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping, ++ [PA_SAMPLE_ULAW] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping, ++ [PA_SAMPLE_S16LE] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping, ++ [PA_SAMPLE_S16BE] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping, ++ [PA_SAMPLE_FLOAT32LE] = (pa_calc_volume_no_mapping_func_t) calc_linear_float_volume_no_mapping, ++ [PA_SAMPLE_FLOAT32BE] = (pa_calc_volume_no_mapping_func_t) calc_linear_float_volume_no_mapping, ++ [PA_SAMPLE_S32LE] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping, ++ [PA_SAMPLE_S32BE] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping, ++ [PA_SAMPLE_S24LE] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping, ++ [PA_SAMPLE_S24BE] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping, ++ [PA_SAMPLE_S24_32LE] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping, ++ [PA_SAMPLE_S24_32BE] = (pa_calc_volume_no_mapping_func_t) calc_linear_integer_volume_no_mapping ++}; ++ ++static const unsigned format_sample_size_table[] = { ++ [PA_SAMPLE_U8] = 1, ++ [PA_SAMPLE_ALAW] = 1, ++ [PA_SAMPLE_ULAW] = 1, ++ [PA_SAMPLE_S16LE] = 2, ++ [PA_SAMPLE_S16BE] = 2, ++ [PA_SAMPLE_FLOAT32LE] = 4, ++ [PA_SAMPLE_FLOAT32BE] = 4, ++ [PA_SAMPLE_S32LE] = 4, ++ [PA_SAMPLE_S32BE] = 4, ++ [PA_SAMPLE_S24LE] = 3, ++ [PA_SAMPLE_S24BE] = 3, ++ [PA_SAMPLE_S24_32LE] = 4, ++ [PA_SAMPLE_S24_32BE] = 4 ++}; ++ ++static float calc_volume_ramp_linear(pa_volume_ramp_int_t *ramp) { ++ pa_assert(ramp); ++ pa_assert(ramp->length > 0); ++ ++ /* basic linear interpolation */ ++ return ramp->start + (ramp->length - ramp->left) * (ramp->end - ramp->start) / (float) ramp->length; ++} ++ ++static float calc_volume_ramp_logarithmic(pa_volume_ramp_int_t *ramp) { ++ float x_val, s, e; ++ long temp; ++ ++ pa_assert(ramp); ++ pa_assert(ramp->length > 0); ++ ++ if (ramp->end > ramp->start) { ++ temp = ramp->left; ++ s = ramp->end; ++ e = ramp->start; ++ } else { ++ temp = ramp->length - ramp->left; ++ s = ramp->start; ++ e = ramp->end; ++ } ++ ++ x_val = temp == 0 ? 0.0 : powf(temp, 10); ++ ++ /* base 10 logarithmic interpolation */ ++ return s + x_val * (e - s) / powf(ramp->length, 10); ++} ++ ++static float calc_volume_ramp_cubic(pa_volume_ramp_int_t *ramp) { ++ float x_val, s, e; ++ long temp; ++ ++ pa_assert(ramp); ++ pa_assert(ramp->length > 0); ++ ++ if (ramp->end > ramp->start) { ++ temp = ramp->left; ++ s = ramp->end; ++ e = ramp->start; ++ } else { ++ temp = ramp->length - ramp->left; ++ s = ramp->start; ++ e = ramp->end; ++ } ++ ++ x_val = temp == 0 ? 0.0 : cbrtf(temp); ++ ++ /* cubic interpolation */ ++ return s + x_val * (e - s) / cbrtf(ramp->length); ++} ++ ++typedef float (*pa_calc_volume_ramp_func_t) (pa_volume_ramp_int_t *); ++ ++static const pa_calc_volume_ramp_func_t calc_volume_ramp_table[] = { ++ [PA_VOLUME_RAMP_TYPE_LINEAR] = (pa_calc_volume_ramp_func_t) calc_volume_ramp_linear, ++ [PA_VOLUME_RAMP_TYPE_LOGARITHMIC] = (pa_calc_volume_ramp_func_t) calc_volume_ramp_logarithmic, ++ [PA_VOLUME_RAMP_TYPE_CUBIC] = (pa_calc_volume_ramp_func_t) calc_volume_ramp_cubic ++}; ++ ++static void calc_volume_ramps(pa_cvolume_ramp_int *ram, float *vol) ++{ ++ int i; ++ ++ for (i = 0; i < ram->channels; i++) { ++ if (ram->ramps[i].left <= 0) { ++ if (ram->ramps[i].target == PA_VOLUME_NORM) { ++ vol[i] = 1.0; ++ } ++ } else { ++ vol[i] = ram->ramps[i].curr = calc_volume_ramp_table[ram->ramps[i].type] (&ram->ramps[i]); ++ ram->ramps[i].left--; ++ } ++ } ++} ++ ++void pa_volume_ramp_memchunk( ++ pa_memchunk *c, ++ const pa_sample_spec *spec, ++ pa_cvolume_ramp_int *ramp) { ++ ++ void *ptr; ++ volume_val linear[PA_CHANNELS_MAX + VOLUME_PADDING]; ++ float vol[PA_CHANNELS_MAX + VOLUME_PADDING]; ++ pa_do_volume_func_t do_volume; ++ long length_in_frames; ++ int i; ++ ++ pa_assert(c); ++ pa_assert(spec); ++ pa_assert(pa_frame_aligned(c->length, spec)); ++ pa_assert(ramp); ++ ++ length_in_frames = c->length / format_sample_size_table[spec->format] / spec->channels; ++ ++ if (pa_memblock_is_silence(c->memblock)) { ++ for (i = 0; i < ramp->channels; i++) { ++ if (ramp->ramps[i].length > 0) ++ ramp->ramps[i].length -= length_in_frames; ++ } ++ return; ++ } ++ ++ if (spec->format < 0 || spec->format >= PA_SAMPLE_MAX) { ++ pa_log_warn("Unable to change volume of format"); ++ return; ++ } ++ ++ do_volume = pa_get_volume_func(spec->format); ++ pa_assert(do_volume); ++ ++ ptr = (uint8_t*) pa_memblock_acquire(c->memblock) + c->index; ++ ++ for (i = 0; i < length_in_frames; i++) { ++ calc_volume_ramps(ramp, vol); ++ calc_volume_table_no_mapping[spec->format] ((void *)linear, vol, spec->channels); ++ ++ /* we only process one frame per iteration */ ++ do_volume (ptr, (void *)linear, spec->channels, format_sample_size_table[spec->format] * spec->channels); ++ ++ /* pa_log_debug("1: %d 2: %d", linear[0], linear[1]); */ ++ ++ ptr = (uint8_t*)ptr + format_sample_size_table[spec->format] * spec->channels; ++ } ++ ++ pa_memblock_release(c->memblock); ++} ++ ++pa_cvolume_ramp_int* pa_cvolume_ramp_convert(const pa_cvolume_ramp *src, pa_cvolume_ramp_int *dst, int sample_rate) { ++ int i; ++ float temp; ++ ++ for (i = 0; i < dst->channels; i++) { ++ dst->ramps[i].type = src->ramps[i].type; ++ /* ms to samples */ ++ dst->ramps[i].length = src->ramps[i].length * sample_rate / 1000; ++ dst->ramps[i].left = dst->ramps[i].length; ++ dst->ramps[i].start = dst->ramps[i].end; ++ dst->ramps[i].target = src->ramps[i].target; ++ /* scale to pulse internal mapping so that when ramp is over there's no glitch in volume */ ++ temp = src->ramps[i].target / (float)0x10000U; ++ dst->ramps[i].end = temp * temp * temp; ++ } ++ ++ return dst; ++} ++ ++bool pa_cvolume_ramp_active(pa_cvolume_ramp_int *ramp) { ++ int i; ++ ++ for (i = 0; i < ramp->channels; i++) { ++ if (ramp->ramps[i].left > 0) ++ return true; ++ } ++ ++ return false; ++} ++ ++bool pa_cvolume_ramp_target_active(pa_cvolume_ramp_int *ramp) { ++ int i; ++ ++ for (i = 0; i < ramp->channels; i++) { ++ if (ramp->ramps[i].target != PA_VOLUME_NORM) ++ return true; ++ } ++ ++ return false; ++} ++ ++pa_cvolume * pa_cvolume_ramp_get_targets(pa_cvolume_ramp_int *ramp, pa_cvolume *volume) { ++ int i = 0; ++ ++ volume->channels = ramp->channels; ++ ++ for (i = 0; i < ramp->channels; i++) ++ volume->values[i] = ramp->ramps[i].target; ++ ++ return volume; ++} ++ ++pa_cvolume_ramp_int* pa_cvolume_ramp_start_from(pa_cvolume_ramp_int *src, pa_cvolume_ramp_int *dst) { ++ int i; ++ ++ for (i = 0; i < src->channels; i++) { ++ /* if new vols are invalid, copy old ramp i.e. no effect */ ++ if (dst->ramps[i].target == PA_VOLUME_INVALID) ++ dst->ramps[i] = src->ramps[i]; ++ /* if there's some old ramp still left */ ++ else if (src->ramps[i].left > 0) ++ dst->ramps[i].start = src->ramps[i].curr; ++ } ++ ++ return dst; ++} ++ ++pa_cvolume_ramp_int* pa_cvolume_ramp_int_init(pa_cvolume_ramp_int *src, pa_volume_t vol, int channels) { ++ int i; ++ float temp; ++ ++ src->channels = channels; ++ ++ for (i = 0; i < channels; i++) { ++ src->ramps[i].type = PA_VOLUME_RAMP_TYPE_LINEAR; ++ src->ramps[i].length = 0; ++ src->ramps[i].left = 0; ++ if (vol == PA_VOLUME_NORM) { ++ src->ramps[i].start = 1.0; ++ src->ramps[i].end = 1.0; ++ src->ramps[i].curr = 1.0; ++ } ++ else if (vol == PA_VOLUME_MUTED) { ++ src->ramps[i].start = 0.0; ++ src->ramps[i].end = 0.0; ++ src->ramps[i].curr = 0.0; ++ } ++ else { ++ temp = vol / (float)0x10000U; ++ src->ramps[i].start = temp * temp * temp; ++ src->ramps[i].end = src->ramps[i].start; ++ src->ramps[i].curr = src->ramps[i].start; ++ } ++ src->ramps[i].target = vol; ++ } ++ ++ return src; ++} +--- a/src/pulsecore/sample-util.h 2016-04-12 15:53:06.327970701 +0200 ++++ b/src/pulsecore/sample-util.h 2016-04-12 16:24:16.356967580 +0200 +@@ -45,6 +45,33 @@ + + pa_memchunk* pa_silence_memchunk_get(pa_silence_cache *cache, pa_mempool *pool, pa_memchunk* ret, const pa_sample_spec *spec, size_t length); + ++typedef struct pa_volume_ramp_int_t { ++ pa_volume_ramp_type_t type; ++ long length; ++ long left; ++ float start; ++ float end; ++ float curr; ++ pa_volume_t target; ++} pa_volume_ramp_int_t; ++ ++typedef struct pa_cvolume_ramp_int { ++ uint8_t channels; ++ pa_volume_ramp_int_t ramps[PA_CHANNELS_MAX]; ++} pa_cvolume_ramp_int; ++ ++pa_cvolume_ramp_int* pa_cvolume_ramp_convert(const pa_cvolume_ramp *src, pa_cvolume_ramp_int *dst, int sample_rate); ++bool pa_cvolume_ramp_active(pa_cvolume_ramp_int *ramp); ++bool pa_cvolume_ramp_target_active(pa_cvolume_ramp_int *ramp); ++pa_cvolume_ramp_int* pa_cvolume_ramp_start_from(pa_cvolume_ramp_int *src, pa_cvolume_ramp_int *dst); ++pa_cvolume_ramp_int* pa_cvolume_ramp_int_init(pa_cvolume_ramp_int *src, pa_volume_t vol, int channels); ++pa_cvolume * pa_cvolume_ramp_get_targets(pa_cvolume_ramp_int *ramp, pa_cvolume *volume); ++ ++void pa_volume_ramp_memchunk( ++ pa_memchunk *c, ++ const pa_sample_spec *spec, ++ pa_cvolume_ramp_int *ramp); ++ + size_t pa_frame_align(size_t l, const pa_sample_spec *ss) PA_GCC_PURE; + + bool pa_frame_aligned(size_t l, const pa_sample_spec *ss) PA_GCC_PURE; diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0011-volume-ramp-adding-volume-ramping-to-sink-input.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0011-volume-ramp-adding-volume-ramping-to-sink-input.patch new file mode 100644 index 000000000..08fb79248 --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0011-volume-ramp-adding-volume-ramping-to-sink-input.patch @@ -0,0 +1,159 @@ +--- a/src/pulsecore/sink-input.c 2016-04-12 16:50:41.311964935 +0200 ++++ b/src/pulsecore/sink-input.c 2016-04-12 17:22:40.420961732 +0200 +@@ -525,6 +525,11 @@ + reset_callbacks(i); + i->userdata = NULL; + ++ if (data->flags & PA_SINK_INPUT_START_RAMP_MUTED) ++ pa_cvolume_ramp_int_init(&i->ramp, PA_VOLUME_MUTED, data->sample_spec.channels); ++ else ++ pa_cvolume_ramp_int_init(&i->ramp, PA_VOLUME_NORM, data->sample_spec.channels); ++ + i->thread_info.state = i->state; + i->thread_info.attached = false; + pa_atomic_store(&i->thread_info.drained, 1); +@@ -541,6 +546,8 @@ + i->thread_info.playing_for = 0; + i->thread_info.direct_outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + ++ i->thread_info.ramp = i->ramp; ++ + pa_assert_se(pa_idxset_put(core->sink_inputs, i, &i->index) == 0); + pa_assert_se(pa_idxset_put(i->sink->inputs, pa_sink_input_ref(i), NULL) == 0); + +@@ -922,6 +929,8 @@ + while (tchunk.length > 0) { + pa_memchunk wchunk; + bool nvfs = need_volume_factor_sink; ++ pa_cvolume target; ++ bool tmp; + + wchunk = tchunk; + pa_memblock_ref(wchunk.memblock); +@@ -958,6 +967,16 @@ + pa_volume_memchunk(&wchunk, &i->sink->sample_spec, &i->volume_factor_sink); + } + ++ /* check for possible volume ramp */ ++ if (pa_cvolume_ramp_active(&i->thread_info.ramp)) { ++ pa_memchunk_make_writable(&wchunk, 0); ++ pa_volume_ramp_memchunk(&wchunk, &i->sink->sample_spec, &(i->thread_info.ramp)); ++ } else if ((tmp = pa_cvolume_ramp_target_active(&(i->thread_info.ramp)))) { ++ pa_memchunk_make_writable(&wchunk, 0); ++ pa_cvolume_ramp_get_targets(&i->thread_info.ramp, &target); ++ pa_volume_memchunk(&wchunk, &i->sink->sample_spec, &target); ++ } ++ + pa_memblockq_push_align(i->thread_info.render_memblockq, &wchunk); + } else { + pa_memchunk rchunk; +@@ -974,6 +993,16 @@ + pa_volume_memchunk(&rchunk, &i->sink->sample_spec, &i->volume_factor_sink); + } + ++ /* check for possible volume ramp */ ++ if (pa_cvolume_ramp_active(&i->thread_info.ramp)) { ++ pa_memchunk_make_writable(&wchunk, 0); ++ pa_volume_ramp_memchunk(&wchunk, &i->sink->sample_spec, &(i->thread_info.ramp)); ++ } else if ((tmp = pa_cvolume_ramp_target_active(&(i->thread_info.ramp)))) { ++ pa_memchunk_make_writable(&wchunk, 0); ++ pa_cvolume_ramp_get_targets(&i->thread_info.ramp, &target); ++ pa_volume_memchunk(&wchunk, &i->sink->sample_spec, &target); ++ } ++ + pa_memblockq_push_align(i->thread_info.render_memblockq, &rchunk); + pa_memblock_unref(rchunk.memblock); + } +@@ -1338,6 +1367,31 @@ + return 0; + } + ++/* Called from main thread */ ++void pa_sink_input_set_volume_ramp( ++ pa_sink_input *i, ++ const pa_cvolume_ramp *ramp, ++ bool send_msg, ++ bool save) { ++ ++ pa_sink_input_assert_ref(i); ++ pa_assert_ctl_context(); ++ pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); ++ pa_assert(ramp); ++ ++ pa_cvolume_ramp_convert(ramp, &i->ramp, i->sample_spec.rate); ++ ++ pa_log_debug("setting volume ramp with target vol:%d and length:%ld", ++ i->ramp.ramps[0].target, ++ i->ramp.ramps[0].length); ++ ++ ++ /* This tells the sink that volume ramp changed */ ++ if (send_msg) ++ pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_VOLUME_RAMP, ++ NULL, 0, NULL) == 0); ++} ++ + /* Called from main context */ + static void set_real_ratio(pa_sink_input *i, const pa_cvolume *v) { + pa_sink_input_assert_ref(i); +@@ -1929,6 +1983,12 @@ + } + return 0; + ++ case PA_SINK_INPUT_MESSAGE_SET_VOLUME_RAMP: ++ /* we have ongoing ramp where we take current start values */ ++ pa_cvolume_ramp_start_from(&i->thread_info.ramp, &i->ramp); ++ i->thread_info.ramp = i->ramp; ++ return 0; ++ + case PA_SINK_INPUT_MESSAGE_SET_SOFT_MUTE: + if (i->thread_info.muted != i->muted) { + i->thread_info.muted = i->muted; +--- a/src/pulsecore/sink-input.h 2016-04-12 16:50:46.712964926 +0200 ++++ b/src/pulsecore/sink-input.h 2016-04-12 17:30:24.289960958 +0200 +@@ -59,7 +59,8 @@ + PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND = 256, + PA_SINK_INPUT_NO_CREATE_ON_SUSPEND = 512, + PA_SINK_INPUT_KILL_ON_SUSPEND = 1024, +- PA_SINK_INPUT_PASSTHROUGH = 2048 ++ PA_SINK_INPUT_PASSTHROUGH = 2048, ++ PA_SINK_INPUT_START_RAMP_MUTED = 4096, + } pa_sink_input_flags_t; + + struct pa_sink_input { +@@ -122,6 +123,9 @@ + * this.*/ + bool save_sink:1, save_volume:1, save_muted:1; + ++ /* for volume ramps */ ++ pa_cvolume_ramp_int ramp; ++ + pa_resample_method_t requested_resample_method, actual_resample_method; + + /* Returns the chunk of audio data and drops it from the +@@ -250,6 +254,8 @@ + pa_usec_t requested_sink_latency; + + pa_hashmap *direct_outputs; ++ ++ pa_cvolume_ramp_int ramp; + } thread_info; + + void *userdata; +@@ -266,6 +272,7 @@ + PA_SINK_INPUT_MESSAGE_SET_STATE, + PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY, + PA_SINK_INPUT_MESSAGE_GET_REQUESTED_LATENCY, ++ PA_SINK_INPUT_MESSAGE_SET_VOLUME_RAMP, + PA_SINK_INPUT_MESSAGE_MAX + }; + +@@ -374,6 +381,8 @@ + + void pa_sink_input_set_mute(pa_sink_input *i, bool mute, bool save); + ++void pa_sink_input_set_volume_ramp(pa_sink_input *i, const pa_cvolume_ramp *ramp, bool send_msg, bool save); ++ + void pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_proplist *p); + + pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i); diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0012-volume-ramp-add-volume-ramping-to-sink.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0012-volume-ramp-add-volume-ramping-to-sink.patch new file mode 100644 index 000000000..43e8283ef --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0012-volume-ramp-add-volume-ramping-to-sink.patch @@ -0,0 +1,159 @@ +--- a/src/pulsecore/sink.c 2016-04-12 18:01:23.403957855 +0200 ++++ b/src/pulsecore/sink.c 2016-04-12 18:44:49.677953506 +0200 +@@ -324,6 +324,8 @@ + &s->sample_spec, + 0); + ++ pa_cvolume_ramp_int_init(&s->ramp, PA_VOLUME_NORM, data->sample_spec.channels); ++ + s->thread_info.rtpoll = NULL; + s->thread_info.inputs = pa_hashmap_new_full(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func, NULL, + (pa_free_cb_t) pa_sink_input_unref); +@@ -347,6 +349,8 @@ + s->thread_info.volume_change_extra_delay = core->deferred_volume_extra_delay_usec; + s->thread_info.latency_offset = s->latency_offset; + ++ s->thread_info.ramp = s->ramp; ++ + /* FIXME: This should probably be moved to pa_sink_put() */ + pa_assert_se(pa_idxset_put(core->sinks, s, &s->index) >= 0); + +@@ -1182,6 +1186,7 @@ + + } else if (n == 1) { + pa_cvolume volume; ++ pa_cvolume target; + + *result = info[0].chunk; + pa_memblock_ref(result->memblock); +@@ -1198,9 +1203,20 @@ + result, + &s->sample_spec, + result->length); +- } else if (!pa_cvolume_is_norm(&volume)) { ++ } else if (!pa_cvolume_is_norm(&volume) || pa_cvolume_ramp_target_active(&s->thread_info.ramp) || pa_cvolume_ramp_active(&s->thread_info.ramp)) { + pa_memchunk_make_writable(result, 0); +- pa_volume_memchunk(result, &s->sample_spec, &volume); ++ if (!pa_cvolume_ramp_active(&s->thread_info.ramp)) { ++ if (!pa_cvolume_is_norm(&volume)) ++ pa_volume_memchunk(result, &s->sample_spec, &volume); ++ pa_volume_ramp_memchunk(result, &s->sample_spec, &(s->thread_info.ramp)); ++ } ++ else { ++ if (pa_cvolume_ramp_target_active(&s->thread_info.ramp)) { ++ pa_cvolume_ramp_get_targets(&s->thread_info.ramp, &target); ++ pa_sw_cvolume_multiply(&volume, &volume, &target); ++ } ++ pa_volume_memchunk(result, &s->sample_spec, &volume); ++ } + } + } else { + void *ptr; +@@ -1290,6 +1306,7 @@ + + } else { + void *ptr; ++ pa_cvolume target_vol; + + ptr = pa_memblock_acquire(target->memblock); + +@@ -1299,6 +1316,15 @@ + &s->thread_info.soft_volume, + s->thread_info.soft_muted); + ++ if (pa_cvolume_ramp_target_active(&s->thread_info.ramp) || pa_cvolume_ramp_active(&s->thread_info.ramp)) { ++ if (pa_cvolume_ramp_active(&s->thread_info.ramp)) ++ pa_volume_ramp_memchunk(target, &s->sample_spec, &(s->thread_info.ramp)); ++ else { ++ pa_cvolume_ramp_get_targets(&s->thread_info.ramp, &target_vol); ++ pa_volume_memchunk(target, &s->sample_spec, &target_vol); ++ } ++ } ++ + pa_memblock_release(target->memblock); + } + +@@ -2058,6 +2084,32 @@ + pa_assert_se(pa_asyncmsgq_send(root_sink->asyncmsgq, PA_MSGOBJECT(root_sink), PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL) == 0); + } + ++/* Called from main thread */ ++void pa_sink_set_volume_ramp( ++ pa_sink *s, ++ const pa_cvolume_ramp *ramp, ++ bool send_msg, ++ bool save) { ++ ++ pa_sink_assert_ref(s); ++ pa_assert_ctl_context(); ++ pa_assert(PA_SINK_IS_LINKED(s->state)); ++ pa_assert(ramp); ++ ++ /* make sure we don't change the volume when a PASSTHROUGH input is connected ... ++ * ... *except* if we're being invoked to reset the volume to ensure 0 dB gain */ ++ if (pa_sink_is_passthrough(s)) { ++ pa_log_warn("Cannot do volume ramp, Sink is connected to PASSTHROUGH input"); ++ return; ++ } ++ ++ pa_cvolume_ramp_convert(ramp, &s->ramp, s->sample_spec.rate); ++ ++ /* This tells the sink that volume ramp changed */ ++ if (send_msg) ++ pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME_RAMP, NULL, 0, NULL) == 0); ++} ++ + /* Called from the io thread if sync volume is used, otherwise from the main thread. + * Only to be called by sink implementor */ + void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) { +@@ -2713,6 +2765,12 @@ + sync_input_volumes_within_thread(s); + return 0; + ++ case PA_SINK_MESSAGE_SET_VOLUME_RAMP: ++ /* if we have ongoing ramp where we take current start values */ ++ pa_cvolume_ramp_start_from(&s->thread_info.ramp, &s->ramp); ++ s->thread_info.ramp = s->ramp; ++ return 0; ++ + case PA_SINK_MESSAGE_GET_VOLUME: + + if ((s->flags & PA_SINK_DEFERRED_VOLUME) && s->get_volume) { +--- a/src/pulsecore/sink.h 2016-04-12 18:01:42.117957824 +0200 ++++ b/src/pulsecore/sink.h 2016-04-12 18:23:29.394955642 +0200 +@@ -105,6 +105,9 @@ + pa_cvolume saved_volume; + bool saved_save_volume:1; + ++ /* for volume ramps */ ++ pa_cvolume_ramp_int ramp; ++ + pa_asyncmsgq *asyncmsgq; + + pa_memchunk silence; +@@ -300,6 +303,8 @@ + uint32_t volume_change_safety_margin; + /* Usec delay added to all volume change events, may be negative. */ + int32_t volume_change_extra_delay; ++ ++ pa_cvolume_ramp_int ramp; + } thread_info; + + void *userdata; +@@ -333,6 +338,7 @@ + PA_SINK_MESSAGE_SET_MAX_REQUEST, + PA_SINK_MESSAGE_SET_PORT, + PA_SINK_MESSAGE_UPDATE_VOLUME_AND_MUTE, ++ PA_SINK_MESSAGE_SET_VOLUME_RAMP, + PA_SINK_MESSAGE_SET_LATENCY_OFFSET, + PA_SINK_MESSAGE_MAX + } pa_sink_message_t; +@@ -453,6 +459,8 @@ + void pa_sink_set_mute(pa_sink *sink, bool mute, bool save); + bool pa_sink_get_mute(pa_sink *sink, bool force_refresh); + ++void pa_sink_set_volume_ramp(pa_sink *s, const pa_cvolume_ramp *ramp, bool send_msg, bool save); ++ + bool pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p); + + int pa_sink_set_port(pa_sink *s, const char *name, bool save); diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0013-add-internal-corking-state-for-sink-input.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0013-add-internal-corking-state-for-sink-input.patch new file mode 100644 index 000000000..cb68e26af --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0013-add-internal-corking-state-for-sink-input.patch @@ -0,0 +1,72 @@ +--- a/src/pulsecore/sink-input.c 2016-04-13 11:44:04.389999429 +0200 ++++ b/src/pulsecore/sink-input.c 2016-04-13 11:52:45.167998560 +0200 +@@ -786,6 +786,9 @@ + update_n_corked(i, state); + i->state = state; + ++ i->corked = false; ++ i->corked_internal = false; ++ + /* We might need to update the sink's volume if we are in flat volume mode. */ + if (pa_sink_flat_volume_enabled(i->sink)) + pa_sink_set_volume(i->sink, NULL, false, i->save_volume); +@@ -1493,13 +1496,38 @@ + } + } + ++static void pa_sink_input_cork_really(pa_sink_input *i, bool b) { ++ pa_sink_input_assert_ref(i); ++ pa_assert_ctl_context(); ++ pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); ++ ++ if (i->corked_internal == false && i->corked == false) ++ b = false; ++ else ++ b = true; ++ ++ sink_input_set_state(i, b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING); ++} ++ + /* Called from main context */ + void pa_sink_input_cork(pa_sink_input *i, bool b) { + pa_sink_input_assert_ref(i); + pa_assert_ctl_context(); + pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); + +- sink_input_set_state(i, b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING); ++ i->corked = b; ++ ++ pa_sink_input_cork_really(i, b); ++} ++ ++void pa_sink_input_cork_internal(pa_sink_input *i, bool b) { ++ pa_sink_input_assert_ref(i); ++ pa_assert_ctl_context(); ++ pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); ++ ++ i->corked_internal = b; ++ ++ pa_sink_input_cork_really(i, b); + } + + /* Called from main context */ +--- a/src/pulsecore/sink-input.h 2016-04-13 11:44:28.035999390 +0200 ++++ b/src/pulsecore/sink-input.h 2016-04-13 11:53:56.325998441 +0200 +@@ -126,6 +126,9 @@ + /* for volume ramps */ + pa_cvolume_ramp_int ramp; + ++ bool corked; ++ bool corked_internal; ++ + pa_resample_method_t requested_resample_method, actual_resample_method; + + /* Returns the chunk of audio data and drops it from the +@@ -357,6 +360,7 @@ + void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes, bool rewrite, bool flush, bool dont_rewind_render); + + void pa_sink_input_cork(pa_sink_input *i, bool b); ++void pa_sink_input_cork_internal(pa_sink_input *i, bool b); + + int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate); + int pa_sink_input_update_rate(pa_sink_input *i); diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0020-core-util-Add-pa_join.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0020-core-util-Add-pa_join.patch new file mode 100644 index 000000000..891a5b83a --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0020-core-util-Add-pa_join.patch @@ -0,0 +1,37 @@ +--- a/src/pulsecore/core-util.c 2016-04-13 16:17:33.314016929 +0200 ++++ b/src/pulsecore/core-util.c 2016-04-13 16:18:31.186016833 +0200 +@@ -1104,6 +1104,24 @@ + return pa_xstrndup(current, l); + } + ++char *pa_join(const char * const *strings, unsigned n_strings, const char *delimiter) { ++ pa_strbuf *buf; ++ unsigned i; ++ ++ pa_assert(strings || n_strings == 0); ++ ++ buf = pa_strbuf_new(); ++ ++ for (i = 0; i < n_strings; i++) { ++ if (i > 0 && delimiter) ++ pa_strbuf_puts(buf, delimiter); ++ ++ pa_strbuf_puts(buf, strings[i]); ++ } ++ ++ return pa_strbuf_tostring_free(buf); ++} ++ + PA_STATIC_TLS_DECLARE(signame, pa_xfree); + + /* Return the name of an UNIX signal. Similar to Solaris sig2str() */ +--- a/src/pulsecore/core-util.h 2016-04-13 16:17:39.177016919 +0200 ++++ b/src/pulsecore/core-util.h 2016-04-13 16:19:09.141016769 +0200 +@@ -108,6 +108,7 @@ + char *pa_split(const char *c, const char*delimiters, const char **state); + const char *pa_split_in_place(const char *c, const char*delimiters, int *n, const char **state); + char *pa_split_spaces(const char *c, const char **state); ++char *pa_join(const char * const *strings, unsigned n_strings, const char *delimiter); + + char *pa_strip_nl(char *s); + char *pa_strip(char *s); diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0021-dynarray-Add-pa_dynarray_get_raw_array.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0021-dynarray-Add-pa_dynarray_get_raw_array.patch new file mode 100644 index 000000000..040913c8f --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0021-dynarray-Add-pa_dynarray_get_raw_array.patch @@ -0,0 +1,21 @@ +--- a/src/pulsecore/dynarray.c 2016-04-13 16:25:38.628016119 +0200 ++++ b/src/pulsecore/dynarray.c 2016-04-13 16:26:54.694015992 +0200 +@@ -91,3 +91,9 @@ + + return array->n_entries; + } ++ ++void * const *pa_dynarray_get_raw_array(pa_dynarray *array) { ++ pa_assert(array); ++ ++ return array->data; ++} +--- a/src/pulsecore/dynarray.h 2016-04-13 16:25:43.225016112 +0200 ++++ b/src/pulsecore/dynarray.h 2016-04-13 16:27:47.414015904 +0200 +@@ -52,5 +52,5 @@ + void *pa_dynarray_steal_last(pa_dynarray *array); + + unsigned pa_dynarray_size(pa_dynarray *array); +- ++void * const *pa_dynarray_get_raw_array(pa_dynarray *array); + #endif diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0022-device-port-Add-pa_device_port.active.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0022-device-port-Add-pa_device_port.active.patch new file mode 100644 index 000000000..4a8143f61 --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0022-device-port-Add-pa_device_port.active.patch @@ -0,0 +1,198 @@ +--- a/src/pulsecore/core.h 2016-04-13 16:38:56.392014788 +0200 ++++ b/src/pulsecore/core.h 2016-04-13 16:41:50.331014498 +0200 +@@ -125,6 +125,7 @@ + PA_CORE_HOOK_CARD_PROFILE_ADDED, + PA_CORE_HOOK_CARD_PROFILE_AVAILABLE_CHANGED, + PA_CORE_HOOK_PORT_AVAILABLE_CHANGED, ++ PA_CORE_HOOK_PORT_ACTIVE_CHANGED, + PA_CORE_HOOK_PORT_LATENCY_OFFSET_CHANGED, + PA_CORE_HOOK_MAX + } pa_core_hook_t; +--- a/src/pulsecore/device-port.c 2016-04-13 16:39:37.411014719 +0200 ++++ b/src/pulsecore/device-port.c 2016-04-13 17:06:47.393011999 +0200 +@@ -175,6 +175,21 @@ + pa_hook_fire(&core->hooks[PA_CORE_HOOK_PORT_LATENCY_OFFSET_CHANGED], p); + } + ++void pa_device_port_active_changed(pa_device_port *port, bool new_active) { ++ bool old_active; ++ ++ pa_assert(port); ++ ++ old_active = port->active; ++ ++ if (new_active == old_active) ++ return; ++ ++ port->active = new_active; ++ pa_log_debug("Port %s %s.", port->name, new_active ? "activated" : "deactivated"); ++ pa_hook_fire(&port->core->hooks[PA_CORE_HOOK_PORT_ACTIVE_CHANGED], port); ++} ++ + pa_device_port *pa_device_port_find_best(pa_hashmap *ports) + { + void *state; +--- a/src/pulsecore/device-port.h 2016-04-13 16:39:51.603014696 +0200 ++++ b/src/pulsecore/device-port.h 2016-04-13 17:07:12.649011957 +0200 +@@ -46,6 +46,7 @@ + + unsigned priority; + pa_available_t available; /* PA_AVAILABLE_UNKNOWN, PA_AVAILABLE_NO or PA_AVAILABLE_YES */ ++ bool active; + + pa_proplist *proplist; + pa_hashmap *profiles; /* Does not own the profiles */ +--- a/src/pulsecore/sink.c 2016-04-13 16:40:11.131014663 +0200 ++++ b/src/pulsecore/sink.c 2016-04-13 17:14:30.963011225 +0200 +@@ -658,6 +658,9 @@ + else + pa_assert_se(sink_set_state(s, PA_SINK_IDLE) == 0); + ++ if (s->active_port) ++ pa_device_port_active_changed(s->active_port, true); ++ + pa_source_put(s->monitor_source); + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index); +@@ -685,6 +688,9 @@ + if (linked) + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK], s); + ++ if (s->active_port) ++ pa_device_port_active_changed(s->active_port, false); ++ + if (s->state != PA_SINK_UNLINKED) + pa_namereg_unregister(s->core, s->name); + pa_idxset_remove_by_data(s->core->sinks, s, NULL); +@@ -3297,6 +3303,7 @@ + /* Called from main context */ + int pa_sink_set_port(pa_sink *s, const char *name, bool save) { + pa_device_port *port; ++ pa_device_port *old_port; + int ret; + + pa_sink_assert_ref(s); +@@ -3313,11 +3320,15 @@ + if (!(port = pa_hashmap_get(s->ports, name))) + return -PA_ERR_NOENTITY; + +- if (s->active_port == port) { ++ old_port = s->active_port; ++ ++ if (port == old_port) { + s->save_port = s->save_port || save; + return 0; + } + ++ pa_device_port_active_changed(old_port, false); ++ + if (s->flags & PA_SINK_DEFERRED_VOLUME) { + struct sink_message_set_port msg = { .port = port, .ret = 0 }; + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_PORT, &msg, 0, NULL) == 0); +@@ -3326,17 +3337,26 @@ + else + ret = s->set_port(s, port); + +- if (ret < 0) +- return -PA_ERR_NOENTITY; ++ if (ret < 0) { ++ pa_log("Failed to set the port of sink %s from %s to %s.", s->name, old_port->name, port->name); ++ ++ /* We don't know the real state of the device, but let's assume that ++ * the old port is still active, because s->active_port is left to ++ * point to the old port anyway. */ ++ pa_device_port_active_changed(old_port, true); ++ ++ return ret; ++ } + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + +- pa_log_info("Changed port of sink %u \"%s\" to %s", s->index, s->name, port->name); ++ pa_log_info("Changed port of sink %u \"%s\" from %s to %s", s->index, s->name, old_port->name, port->name); + + s->active_port = port; + s->save_port = save; + + pa_sink_set_latency_offset(s, s->active_port->latency_offset); ++ pa_device_port_active_changed(port, true); + + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PORT_CHANGED], s); + +--- a/src/pulsecore/source.c 2016-04-13 16:40:25.290014640 +0200 ++++ b/src/pulsecore/source.c 2016-04-13 17:21:26.051010533 +0200 +@@ -603,6 +603,9 @@ + else + pa_assert_se(source_set_state(s, PA_SOURCE_IDLE) == 0); + ++ if (s->active_port) ++ pa_device_port_active_changed(s->active_port, true); ++ + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index); + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PUT], s); + } +@@ -623,6 +626,9 @@ + if (linked) + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], s); + ++ if (s->active_port) ++ pa_device_port_active_changed(s->active_port, false); ++ + if (s->state != PA_SOURCE_UNLINKED) + pa_namereg_unregister(s->core, s->name); + pa_idxset_remove_by_data(s->core->sources, s, NULL); +@@ -2576,6 +2582,7 @@ + /* Called from main context */ + int pa_source_set_port(pa_source *s, const char *name, bool save) { + pa_device_port *port; ++ pa_device_port *old_port; + int ret; + + pa_source_assert_ref(s); +@@ -2592,11 +2599,15 @@ + if (!(port = pa_hashmap_get(s->ports, name))) + return -PA_ERR_NOENTITY; + +- if (s->active_port == port) { ++ old_port = s->active_port; ++ ++ if (port == old_port) { + s->save_port = s->save_port || save; + return 0; + } + ++ pa_device_port_active_changed(old_port, false); ++ + if (s->flags & PA_SOURCE_DEFERRED_VOLUME) { + struct source_message_set_port msg = { .port = port, .ret = 0 }; + pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_PORT, &msg, 0, NULL) == 0); +@@ -2605,16 +2616,26 @@ + else + ret = s->set_port(s, port); + +- if (ret < 0) +- return -PA_ERR_NOENTITY; ++ if (ret < 0) { ++ pa_log("Failed to set the port of sink %s from %s to %s.", s->name, old_port->name, port->name); ++ ++ /* We don't know the real state of the device, but let's assume that ++ * the old port is still active, because s->active_port is left to ++ * point to the old port anyway. */ ++ pa_device_port_active_changed(old_port, true); ++ ++ return ret; ++ } + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); + +- pa_log_info("Changed port of source %u \"%s\" to %s", s->index, s->name, port->name); ++ pa_log_info("Changed port of source %u \"%s\" from %s to %s", s->index, s->name, old_port->name, port->name); + + s->active_port = port; + s->save_port = save; + ++ pa_device_port_active_changed(port, true); ++ + pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PORT_CHANGED], s); + + return 0; diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0030-volume-api-Add-libvolume-api.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0030-volume-api-Add-libvolume-api.patch new file mode 100644 index 000000000..b904ac315 --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0030-volume-api-Add-libvolume-api.patch @@ -0,0 +1,6118 @@ +From 0223ac3e092249c792bedcab2bf5dbaec443f960 Mon Sep 17 00:00:00 2001 +From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com> +Date: Wed, 21 May 2014 11:51:27 +0300 +Subject: [PATCH 1/1] volume-api: Add libvolume-api.so + +This library implements the "core" of the new volume system, which +will be used by several modules. + +Change-Id: Ib25ada1392e83237a3908e6064ee0ad6dff7afaf +Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com> +--- + Makefile.am | 3 + + src/Makefile.am | 19 +- + src/map-file | 15 + + src/modules/volume-api/audio-group.c | 448 +++++++++++++ + src/modules/volume-api/audio-group.h | 85 +++ + src/modules/volume-api/binding.c | 386 +++++++++++ + src/modules/volume-api/binding.h | 128 ++++ + src/modules/volume-api/bvolume.h | 43 ++ + src/modules/volume-api/device-creator.c | 1108 +++++++++++++++++++++++++++++++ + src/modules/volume-api/device-creator.h | 32 + + src/modules/volume-api/device.c | 293 ++++++++ + src/modules/volume-api/device.h | 76 +++ + src/modules/volume-api/mute-control.c | 306 +++++++++ + src/modules/volume-api/mute-control.h | 102 +++ + src/modules/volume-api/sstream.c | 366 ++++++++++ + src/modules/volume-api/sstream.h | 108 +++ + src/modules/volume-api/stream-creator.c | 691 +++++++++++++++++++ + src/modules/volume-api/stream-creator.h | 32 + + src/modules/volume-api/volume-api.c | 647 ++++++++++++++++++ + src/modules/volume-api/volume-api.h | 163 +++++ + src/modules/volume-api/volume-control.c | 363 ++++++++++ + src/modules/volume-api/volume-control.h | 112 ++++ + src/pulse/ext-volume-api.c | 275 ++++++++ + src/pulse/ext-volume-api.h | 68 ++ + 24 files changed, 5868 insertions(+), 1 deletion(-) + create mode 100644 src/modules/volume-api/audio-group.c + create mode 100644 src/modules/volume-api/audio-group.h + create mode 100644 src/modules/volume-api/binding.c + create mode 100644 src/modules/volume-api/binding.h + create mode 100644 src/modules/volume-api/bvolume.h + create mode 100644 src/modules/volume-api/device-creator.c + create mode 100644 src/modules/volume-api/device-creator.h + create mode 100644 src/modules/volume-api/device.c + create mode 100644 src/modules/volume-api/device.h + create mode 100644 src/modules/volume-api/mute-control.c + create mode 100644 src/modules/volume-api/mute-control.h + create mode 100644 src/modules/volume-api/sstream.c + create mode 100644 src/modules/volume-api/sstream.h + create mode 100644 src/modules/volume-api/stream-creator.c + create mode 100644 src/modules/volume-api/stream-creator.h + create mode 100644 src/modules/volume-api/volume-api.c + create mode 100644 src/modules/volume-api/volume-api.h + create mode 100644 src/modules/volume-api/volume-control.c + create mode 100644 src/modules/volume-api/volume-control.h + create mode 100644 src/pulse/ext-volume-api.c + create mode 100644 src/pulse/ext-volume-api.h + +diff --git a/Makefile.am b/Makefile.am +index 9431d4a..cf4a648 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -57,6 +57,9 @@ + moduledevinternal_DATA = src/pulse/internal.h src/pulse/client-conf.h src/pulse/fork-detect.h + moduledevinternaldir = $(includedir)/pulsemodule/pulse + ++moduledevvolumeapi_DATA = $(top_srcdir)/src/modules/volume-api/*.h ++moduledevvolumeapidir = $(includedir)/pulsemodule/modules/volume-api ++ + if HAVE_GLIB20 + pkgconfig_DATA += \ + libpulse-mainloop-glib.pc +diff --git a/src/Makefile.am b/src/Makefile.am +index 22b9b81..bc41dca 100644 +--- a/src/Makefile.am 2016-04-13 15:51:34.439019531 +0200 ++++ b/src/Makefile.am 2016-04-13 15:53:03.721019382 +0200 +@@ -792,6 +792,7 @@ + pulse/ext-device-manager.h \ + pulse/ext-device-restore.h \ + pulse/ext-stream-restore.h \ ++ pulse/ext-volume-api.h \ + pulse/format.h \ + pulse/gccmacro.h \ + pulse/introspect.h \ +@@ -838,6 +839,7 @@ + pulse/ext-device-manager.c pulse/ext-device-manager.h \ + pulse/ext-device-restore.c pulse/ext-device-restore.h \ + pulse/ext-stream-restore.c pulse/ext-stream-restore.h \ ++ pulse/ext-volume-api.c pulse/ext-volume-api.h \ + pulse/format.c pulse/format.h \ + pulse/gccmacro.h \ + pulse/internal.h \ +@@ -1018,7 +1020,8 @@ modlibexec_LTLIBRARIES = \ + libprotocol-cli.la \ + libprotocol-simple.la \ + libprotocol-http.la \ +- libprotocol-native.la ++ libprotocol-native.la \ ++ libvolume-api.la + + if HAVE_WEBRTC + modlibexec_LTLIBRARIES += libwebrtc-util.la +@@ -1065,6 +1068,20 @@ libprotocol_native_la_CFLAGS += $(DBUS_CFLAGS) + libprotocol_native_la_LIBADD += $(DBUS_LIBS) + endif + ++libvolume_api_la_SOURCES = \ ++ modules/volume-api/audio-group.c modules/volume-api/audio-group.h \ ++ modules/volume-api/binding.c modules/volume-api/binding.h \ ++ modules/volume-api/bvolume.h \ ++ modules/volume-api/device.c modules/volume-api/device.h \ ++ modules/volume-api/device-creator.c modules/volume-api/device-creator.h \ ++ modules/volume-api/mute-control.c modules/volume-api/mute-control.h \ ++ modules/volume-api/sstream.c modules/volume-api/sstream.h \ ++ modules/volume-api/stream-creator.c modules/volume-api/stream-creator.h \ ++ modules/volume-api/volume-api.c modules/volume-api/volume-api.h \ ++ modules/volume-api/volume-control.c modules/volume-api/volume-control.h ++libvolume_api_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version ++libvolume_api_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINOR@.la libpulsecommon-@PA_MAJORMINOR@.la libpulse.la ++ + if HAVE_ESOUND + libprotocol_esound_la_SOURCES = pulsecore/protocol-esound.c pulsecore/protocol-esound.h pulsecore/esound.h + libprotocol_esound_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version +diff --git a/src/map-file b/src/map-file +index fbf3f22..1f64a2f 100644 +--- a/src/map-file ++++ b/src/map-file +@@ -172,6 +172,21 @@ + pa_ext_stream_restore_subscribe; + pa_ext_stream_restore_test; + pa_ext_stream_restore_write; ++pa_ext_volume_api_balance_valid; ++pa_ext_volume_api_bvolume_copy_balance; ++pa_ext_volume_api_bvolume_get_left_right_balance; ++pa_ext_volume_api_bvolume_get_rear_front_balance; ++pa_ext_volume_api_bvolume_equal; ++pa_ext_volume_api_bvolume_from_cvolume; ++pa_ext_volume_api_bvolume_init_invalid; ++pa_ext_volume_api_bvolume_init_mono; ++pa_ext_volume_api_bvolume_remap; ++pa_ext_volume_api_bvolume_reset_balance; ++pa_ext_volume_api_bvolume_set_left_right_balance; ++pa_ext_volume_api_bvolume_set_rear_front_balance; ++pa_ext_volume_api_bvolume_snprint_balance; ++pa_ext_volume_api_bvolume_to_cvolume; ++pa_ext_volume_api_bvolume_valid; + pa_format_info_copy; + pa_format_info_free; + pa_format_info_from_string; +diff --git a/src/modules/volume-api/audio-group.c b/src/modules/volume-api/audio-group.c +new file mode 100644 +index 0000000..76bfa69 +--- /dev/null ++++ b/src/modules/volume-api/audio-group.c +@@ -0,0 +1,448 @@ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#ifdef HAVE_CONFIG_H ++#include <config.h> ++#endif ++ ++#include "audio-group.h" ++ ++#include <modules/volume-api/sstream.h> ++ ++#include <pulsecore/core-util.h> ++ ++int pa_audio_group_new(pa_volume_api *api, const char *name, const char *description, pa_audio_group **group) { ++ pa_audio_group *group_local; ++ int r; ++ ++ pa_assert(api); ++ pa_assert(name); ++ pa_assert(description); ++ pa_assert(group); ++ ++ group_local = pa_xnew0(pa_audio_group, 1); ++ group_local->volume_api = api; ++ group_local->index = pa_volume_api_allocate_audio_group_index(api); ++ ++ r = pa_volume_api_register_name(api, name, true, &group_local->name); ++ if (r < 0) ++ goto fail; ++ ++ group_local->description = pa_xstrdup(description); ++ group_local->proplist = pa_proplist_new(); ++ group_local->volume_streams = pa_hashmap_new(NULL, NULL); ++ group_local->mute_streams = pa_hashmap_new(NULL, NULL); ++ ++ *group = group_local; ++ ++ return 0; ++ ++fail: ++ pa_audio_group_free(group_local); ++ ++ return r; ++} ++ ++void pa_audio_group_put(pa_audio_group *group) { ++ const char *prop_key; ++ void *state = NULL; ++ ++ pa_assert(group); ++ ++ pa_volume_api_add_audio_group(group->volume_api, group); ++ ++ group->linked = true; ++ ++ pa_log_debug("Created audio group #%u.", group->index); ++ pa_log_debug(" Name: %s", group->name); ++ pa_log_debug(" Description: %s", group->description); ++ pa_log_debug(" Volume control: %s", group->volume_control ? group->volume_control->name : "(unset)"); ++ pa_log_debug(" Mute control: %s", group->mute_control ? group->mute_control->name : "(unset)"); ++ pa_log_debug(" Properties:"); ++ ++ while ((prop_key = pa_proplist_iterate(group->proplist, &state))) ++ pa_log_debug(" %s = %s", prop_key, pa_strnull(pa_proplist_gets(group->proplist, prop_key))); ++ ++ pa_hook_fire(&group->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_PUT], group); ++} ++ ++void pa_audio_group_unlink(pa_audio_group *group) { ++ pas_stream *stream; ++ ++ pa_assert(group); ++ ++ if (group->unlinked) { ++ pa_log_debug("Unlinking audio group %s (already unlinked, this is a no-op).", group->name); ++ return; ++ } ++ ++ group->unlinked = true; ++ ++ pa_log_debug("Unlinking audio group %s.", group->name); ++ ++ if (group->linked) ++ pa_hook_fire(&group->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_UNLINK], group); ++ ++ pa_volume_api_remove_audio_group(group->volume_api, group); ++ ++ while ((stream = pa_hashmap_first(group->mute_streams))) ++ pas_stream_set_audio_group_for_mute(stream, NULL); ++ ++ while ((stream = pa_hashmap_first(group->volume_streams))) ++ pas_stream_set_audio_group_for_volume(stream, NULL); ++ ++ if (group->mute_control_binding) { ++ pa_binding_free(group->mute_control_binding); ++ group->mute_control_binding = NULL; ++ } ++ ++ if (group->volume_control_binding) { ++ pa_binding_free(group->volume_control_binding); ++ group->volume_control_binding = NULL; ++ } ++ ++ pa_audio_group_set_have_own_mute_control(group, false); ++ pa_audio_group_set_have_own_volume_control(group, false); ++ ++ if (group->mute_control) { ++ pa_mute_control_remove_audio_group(group->mute_control, group); ++ group->mute_control = NULL; ++ } ++ ++ if (group->volume_control) { ++ pa_volume_control_remove_audio_group(group->volume_control, group); ++ group->volume_control = NULL; ++ } ++} ++ ++void pa_audio_group_free(pa_audio_group *group) { ++ pa_assert(group); ++ ++ if (!group->unlinked) ++ pa_audio_group_unlink(group); ++ ++ if (group->mute_streams) ++ pa_hashmap_free(group->mute_streams); ++ ++ if (group->volume_streams) ++ pa_hashmap_free(group->volume_streams); ++ ++ if (group->proplist) ++ pa_proplist_free(group->proplist); ++ ++ pa_xfree(group->description); ++ ++ if (group->name) ++ pa_volume_api_unregister_name(group->volume_api, group->name); ++ ++ pa_xfree(group); ++} ++ ++const char *pa_audio_group_get_name(pa_audio_group *group) { ++ pa_assert(group); ++ ++ return group->name; ++} ++ ++static int volume_control_set_volume_cb(pa_volume_control *control, const pa_bvolume *volume, bool set_volume, ++ bool set_balance) { ++ pa_audio_group *group; ++ pas_stream *stream; ++ void *state; ++ ++ pa_assert(control); ++ pa_assert(volume); ++ ++ group = control->userdata; ++ ++ PA_HASHMAP_FOREACH(stream, group->volume_streams, state) { ++ if (stream->own_volume_control) ++ pa_volume_control_set_volume(stream->own_volume_control, volume, set_volume, set_balance); ++ } ++ ++ return 0; ++} ++ ++static void volume_control_set_initial_volume_cb(pa_volume_control *control) { ++ pa_audio_group *group; ++ pas_stream *stream; ++ void *state; ++ ++ pa_assert(control); ++ ++ group = control->userdata; ++ ++ PA_HASHMAP_FOREACH(stream, group->volume_streams, state) { ++ if (stream->own_volume_control) ++ pa_volume_control_set_volume(stream->own_volume_control, &control->volume, true, true); ++ } ++} ++ ++void pa_audio_group_set_have_own_volume_control(pa_audio_group *group, bool have) { ++ pa_assert(group); ++ ++ if (have == group->have_own_volume_control) ++ return; ++ ++ if (have) { ++ pa_bvolume initial_volume; ++ ++ if (group->volume_api->core->flat_volumes) ++ /* Usually the initial volume should get overridden by some module ++ * that manages audio group volume levels, but if there's no such ++ * module, let's try to avoid too high volume in flat volume ++ * mode. */ ++ pa_bvolume_init_mono(&initial_volume, 0.3 * PA_VOLUME_NORM); ++ else ++ pa_bvolume_init_mono(&initial_volume, PA_VOLUME_NORM); ++ ++ pa_assert(!group->own_volume_control); ++ group->own_volume_control = pa_volume_control_new(group->volume_api, "audio-group-volume-control", ++ group->description, false, false); ++ pa_volume_control_set_owner_audio_group(group->own_volume_control, group); ++ group->own_volume_control->set_volume = volume_control_set_volume_cb; ++ group->own_volume_control->userdata = group; ++ pa_volume_control_put(group->own_volume_control, &initial_volume, volume_control_set_initial_volume_cb); ++ } else { ++ pa_volume_control_free(group->own_volume_control); ++ group->own_volume_control = NULL; ++ } ++ ++ group->have_own_volume_control = have; ++} ++ ++static int mute_control_set_mute_cb(pa_mute_control *control, bool mute) { ++ pa_audio_group *group; ++ pas_stream *stream; ++ void *state; ++ ++ pa_assert(control); ++ ++ group = control->userdata; ++ ++ PA_HASHMAP_FOREACH(stream, group->mute_streams, state) { ++ if (stream->own_mute_control) ++ pa_mute_control_set_mute(stream->own_mute_control, mute); ++ } ++ ++ return 0; ++} ++ ++static void mute_control_set_initial_mute_cb(pa_mute_control *control) { ++ pa_audio_group *group; ++ pas_stream *stream; ++ void *state; ++ ++ pa_assert(control); ++ ++ group = control->userdata; ++ ++ PA_HASHMAP_FOREACH(stream, group->mute_streams, state) { ++ if (stream->own_mute_control) ++ pa_mute_control_set_mute(stream->own_mute_control, control->mute); ++ } ++} ++ ++void pa_audio_group_set_have_own_mute_control(pa_audio_group *group, bool have) { ++ pa_assert(group); ++ ++ if (have == group->have_own_mute_control) ++ return; ++ ++ group->have_own_mute_control = have; ++ ++ if (have) { ++ pa_assert(!group->own_mute_control); ++ group->own_mute_control = pa_mute_control_new(group->volume_api, "audio-group-mute-control", group->description); ++ pa_mute_control_set_owner_audio_group(group->own_mute_control, group); ++ group->own_mute_control->set_mute = mute_control_set_mute_cb; ++ group->own_mute_control->userdata = group; ++ pa_mute_control_put(group->own_mute_control, false, true, mute_control_set_initial_mute_cb); ++ } else { ++ pa_mute_control_free(group->own_mute_control); ++ group->own_mute_control = NULL; ++ } ++} ++ ++static void set_volume_control_internal(pa_audio_group *group, pa_volume_control *control) { ++ pa_volume_control *old_control; ++ ++ pa_assert(group); ++ ++ old_control = group->volume_control; ++ ++ if (control == old_control) ++ return; ++ ++ if (old_control) ++ pa_volume_control_remove_audio_group(old_control, group); ++ ++ group->volume_control = control; ++ ++ if (control) ++ pa_volume_control_add_audio_group(control, group); ++ ++ if (!group->linked || group->unlinked) ++ return; ++ ++ pa_log_debug("The volume control of audio group %s changed from %s to %s.", group->name, ++ old_control ? old_control->name : "(unset)", control ? control->name : "(unset)"); ++ ++ pa_hook_fire(&group->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_VOLUME_CONTROL_CHANGED], group); ++} ++ ++void pa_audio_group_set_volume_control(pa_audio_group *group, pa_volume_control *control) { ++ pa_assert(group); ++ ++ if (group->volume_control_binding) { ++ pa_binding_free(group->volume_control_binding); ++ group->volume_control_binding = NULL; ++ } ++ ++ set_volume_control_internal(group, control); ++} ++ ++static void set_mute_control_internal(pa_audio_group *group, pa_mute_control *control) { ++ pa_mute_control *old_control; ++ ++ pa_assert(group); ++ ++ old_control = group->mute_control; ++ ++ if (control == old_control) ++ return; ++ ++ if (old_control) ++ pa_mute_control_remove_audio_group(old_control, group); ++ ++ group->mute_control = control; ++ ++ if (control) ++ pa_mute_control_add_audio_group(control, group); ++ ++ if (!group->linked || group->unlinked) ++ return; ++ ++ pa_log_debug("The mute control of audio group %s changed from %s to %s.", group->name, ++ old_control ? old_control->name : "(unset)", control ? control->name : "(unset)"); ++ ++ pa_hook_fire(&group->volume_api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_MUTE_CONTROL_CHANGED], group); ++} ++ ++void pa_audio_group_set_mute_control(pa_audio_group *group, pa_mute_control *control) { ++ pa_assert(group); ++ ++ if (group->mute_control_binding) { ++ pa_binding_free(group->mute_control_binding); ++ group->mute_control_binding = NULL; ++ } ++ ++ set_mute_control_internal(group, control); ++} ++ ++void pa_audio_group_bind_volume_control(pa_audio_group *group, pa_binding_target_info *target_info) { ++ pa_binding_owner_info owner_info = { ++ .userdata = group, ++ .set_value = (pa_binding_set_value_cb_t) set_volume_control_internal, ++ }; ++ ++ pa_assert(group); ++ pa_assert(target_info); ++ ++ if (group->volume_control_binding) ++ pa_binding_free(group->volume_control_binding); ++ ++ group->volume_control_binding = pa_binding_new(group->volume_api, &owner_info, target_info); ++} ++ ++void pa_audio_group_bind_mute_control(pa_audio_group *group, pa_binding_target_info *target_info) { ++ pa_binding_owner_info owner_info = { ++ .userdata = group, ++ .set_value = (pa_binding_set_value_cb_t) set_mute_control_internal, ++ }; ++ ++ pa_assert(group); ++ pa_assert(target_info); ++ ++ if (group->mute_control_binding) ++ pa_binding_free(group->mute_control_binding); ++ ++ group->mute_control_binding = pa_binding_new(group->volume_api, &owner_info, target_info); ++} ++ ++void pa_audio_group_add_volume_stream(pa_audio_group *group, pas_stream *stream) { ++ pa_assert(group); ++ pa_assert(stream); ++ ++ pa_assert_se(pa_hashmap_put(group->volume_streams, stream, stream) >= 0); ++ ++ if (stream->own_volume_control && group->own_volume_control) ++ pa_volume_control_set_volume(stream->own_volume_control, &group->own_volume_control->volume, true, true); ++ ++ pa_log_debug("Stream %s added to audio group %s (volume).", stream->name, group->name); ++} ++ ++void pa_audio_group_remove_volume_stream(pa_audio_group *group, pas_stream *stream) { ++ pa_assert(group); ++ pa_assert(stream); ++ ++ pa_assert_se(pa_hashmap_remove(group->volume_streams, stream)); ++ ++ pa_log_debug("Stream %s removed from audio group %s (volume).", stream->name, group->name); ++} ++ ++void pa_audio_group_add_mute_stream(pa_audio_group *group, pas_stream *stream) { ++ pa_assert(group); ++ pa_assert(stream); ++ ++ pa_assert_se(pa_hashmap_put(group->mute_streams, stream, stream) >= 0); ++ ++ if (stream->own_mute_control && group->own_mute_control) ++ pa_mute_control_set_mute(stream->own_mute_control, group->own_mute_control->mute); ++ ++ pa_log_debug("Stream %s added to audio group %s (mute).", stream->name, group->name); ++} ++ ++void pa_audio_group_remove_mute_stream(pa_audio_group *group, pas_stream *stream) { ++ pa_assert(group); ++ pa_assert(stream); ++ ++ pa_assert_se(pa_hashmap_remove(group->mute_streams, stream)); ++ ++ pa_log_debug("Stream %s removed from audio group %s (mute).", stream->name, group->name); ++} ++ ++pa_binding_target_type *pa_audio_group_create_binding_target_type(pa_volume_api *api) { ++ pa_binding_target_type *type; ++ ++ pa_assert(api); ++ ++ type = pa_binding_target_type_new(PA_AUDIO_GROUP_BINDING_TARGET_TYPE, api->audio_groups, ++ &api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_PUT], ++ &api->hooks[PA_VOLUME_API_HOOK_AUDIO_GROUP_UNLINK], ++ (pa_binding_target_type_get_name_cb_t) pa_audio_group_get_name); ++ pa_binding_target_type_add_field(type, PA_AUDIO_GROUP_BINDING_TARGET_FIELD_VOLUME_CONTROL, ++ PA_BINDING_CALCULATE_FIELD_OFFSET(pa_audio_group, volume_control)); ++ pa_binding_target_type_add_field(type, PA_AUDIO_GROUP_BINDING_TARGET_FIELD_MUTE_CONTROL, ++ PA_BINDING_CALCULATE_FIELD_OFFSET(pa_audio_group, mute_control)); ++ ++ return type; ++} +diff --git a/src/modules/volume-api/audio-group.h b/src/modules/volume-api/audio-group.h +new file mode 100644 +index 0000000..41591ba +--- /dev/null ++++ b/src/modules/volume-api/audio-group.h +@@ -0,0 +1,85 @@ ++#ifndef fooaudiogrouphfoo ++#define fooaudiogrouphfoo ++ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#include <modules/volume-api/binding.h> ++#include <modules/volume-api/mute-control.h> ++#include <modules/volume-api/volume-control.h> ++ ++#include <pulse/proplist.h> ++ ++#include <inttypes.h> ++ ++typedef struct pa_audio_group pa_audio_group; ++ ++#define PA_AUDIO_GROUP_BINDING_TARGET_TYPE "AudioGroup" ++#define PA_AUDIO_GROUP_BINDING_TARGET_FIELD_VOLUME_CONTROL "volume_control" ++#define PA_AUDIO_GROUP_BINDING_TARGET_FIELD_MUTE_CONTROL "mute_control" ++ ++struct pa_audio_group { ++ pa_volume_api *volume_api; ++ uint32_t index; ++ const char *name; ++ char *description; ++ pa_proplist *proplist; ++ pa_volume_control *volume_control; ++ pa_mute_control *mute_control; ++ bool have_own_volume_control; ++ bool have_own_mute_control; ++ pa_volume_control *own_volume_control; ++ pa_mute_control *own_mute_control; ++ ++ pa_binding *volume_control_binding; ++ pa_binding *mute_control_binding; ++ pa_hashmap *volume_streams; /* pas_stream -> pas_stream (hashmap-as-a-set) */ ++ pa_hashmap *mute_streams; /* pas_stream -> pas_stream (hashmap-as-a-set) */ ++ ++ bool linked; ++ bool unlinked; ++}; ++ ++int pa_audio_group_new(pa_volume_api *api, const char *name, const char *description, pa_audio_group **group); ++void pa_audio_group_put(pa_audio_group *group); ++void pa_audio_group_unlink(pa_audio_group *group); ++void pa_audio_group_free(pa_audio_group *group); ++ ++const char *pa_audio_group_get_name(pa_audio_group *group); ++ ++/* Called by policy modules. */ ++void pa_audio_group_set_have_own_volume_control(pa_audio_group *group, bool have); ++void pa_audio_group_set_have_own_mute_control(pa_audio_group *group, bool have); ++void pa_audio_group_set_volume_control(pa_audio_group *group, pa_volume_control *control); ++void pa_audio_group_set_mute_control(pa_audio_group *group, pa_mute_control *control); ++void pa_audio_group_bind_volume_control(pa_audio_group *group, pa_binding_target_info *target_info); ++void pa_audio_group_bind_mute_control(pa_audio_group *group, pa_binding_target_info *target_info); ++ ++/* Called from sstream.c only. */ ++void pa_audio_group_add_volume_stream(pa_audio_group *group, pas_stream *stream); ++void pa_audio_group_remove_volume_stream(pa_audio_group *group, pas_stream *stream); ++void pa_audio_group_add_mute_stream(pa_audio_group *group, pas_stream *stream); ++void pa_audio_group_remove_mute_stream(pa_audio_group *group, pas_stream *stream); ++ ++/* Called from volume-api.c only. */ ++pa_binding_target_type *pa_audio_group_create_binding_target_type(pa_volume_api *api); ++ ++#endif +diff --git a/src/modules/volume-api/binding.c b/src/modules/volume-api/binding.c +new file mode 100644 +index 0000000..6e73119 +--- /dev/null ++++ b/src/modules/volume-api/binding.c +@@ -0,0 +1,386 @@ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#ifdef HAVE_CONFIG_H ++#include <config.h> ++#endif ++ ++#include "binding.h" ++ ++#include <pulse/def.h> ++#include <pulse/xmalloc.h> ++ ++#include <pulsecore/core-util.h> ++#include <pulsecore/macro.h> ++ ++struct field_entry { ++ char *name; ++ size_t offset; ++}; ++ ++static void set_target_type(pa_binding *binding, pa_binding_target_type *type); ++static void set_target_object(pa_binding *binding, void *object); ++ ++pa_binding_owner_info *pa_binding_owner_info_new(pa_binding_set_value_cb_t set_value, void *userdata) { ++ pa_binding_owner_info *info; ++ ++ pa_assert(set_value); ++ ++ info = pa_xnew0(pa_binding_owner_info, 1); ++ info->set_value = set_value; ++ info->userdata = userdata; ++ ++ return info; ++} ++ ++pa_binding_owner_info *pa_binding_owner_info_copy(const pa_binding_owner_info *info) { ++ pa_assert(info); ++ ++ return pa_binding_owner_info_new(info->set_value, info->userdata); ++} ++ ++void pa_binding_owner_info_free(pa_binding_owner_info *info) { ++ pa_assert(info); ++ ++ pa_xfree(info); ++} ++ ++pa_binding_target_info *pa_binding_target_info_new(const char *type, const char *name, const char *field) { ++ pa_binding_target_info *info; ++ ++ pa_assert(type); ++ pa_assert(name); ++ pa_assert(field); ++ ++ info = pa_xnew0(pa_binding_target_info, 1); ++ info->type = pa_xstrdup(type); ++ info->name = pa_xstrdup(name); ++ info->field = pa_xstrdup(field); ++ ++ return info; ++} ++ ++int pa_binding_target_info_new_from_string(const char *str, const char *field, pa_binding_target_info **info) { ++ const char *colon; ++ char *type = NULL; ++ char *name = NULL; ++ ++ pa_assert(str); ++ pa_assert(field); ++ pa_assert(info); ++ ++ if (!pa_startswith(str, "bind:")) ++ goto fail; ++ ++ colon = strchr(str + 5, ':'); ++ if (!colon) ++ goto fail; ++ ++ type = pa_xstrndup(str + 5, colon - (str + 5)); ++ ++ if (!*type) ++ goto fail; ++ ++ name = pa_xstrdup(colon + 1); ++ ++ if (!*name) ++ goto fail; ++ ++ *info = pa_binding_target_info_new(type, name, field); ++ pa_xfree(name); ++ pa_xfree(type); ++ ++ return 0; ++ ++fail: ++ pa_log("Invalid binding target: %s", str); ++ pa_xfree(name); ++ pa_xfree(type); ++ ++ return -PA_ERR_INVALID; ++} ++ ++pa_binding_target_info *pa_binding_target_info_copy(const pa_binding_target_info *info) { ++ pa_assert(info); ++ ++ return pa_binding_target_info_new(info->type, info->name, info->field); ++} ++ ++void pa_binding_target_info_free(pa_binding_target_info *info) { ++ pa_assert(info); ++ ++ pa_xfree(info->field); ++ pa_xfree(info->name); ++ pa_xfree(info->type); ++ pa_xfree(info); ++} ++ ++static void field_entry_free(struct field_entry *entry) { ++ pa_assert(entry); ++ ++ pa_xfree(entry->name); ++ pa_xfree(entry); ++} ++ ++pa_binding_target_type *pa_binding_target_type_new(const char *name, pa_hashmap *objects, pa_hook *put_hook, ++ pa_hook *unlink_hook, pa_binding_target_type_get_name_cb_t get_name) { ++ pa_binding_target_type *type; ++ ++ pa_assert(name); ++ pa_assert(objects); ++ pa_assert(put_hook); ++ pa_assert(unlink_hook); ++ pa_assert(get_name); ++ ++ type = pa_xnew0(pa_binding_target_type, 1); ++ type->name = pa_xstrdup(name); ++ type->objects = objects; ++ type->put_hook = put_hook; ++ type->unlink_hook = unlink_hook; ++ type->get_name = get_name; ++ type->fields = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, (pa_free_cb_t) field_entry_free); ++ ++ return type; ++} ++ ++void pa_binding_target_type_free(pa_binding_target_type *type) { ++ pa_assert(type); ++ ++ if (type->fields) ++ pa_hashmap_free(type->fields); ++ ++ pa_xfree(type->name); ++ pa_xfree(type); ++} ++ ++void pa_binding_target_type_add_field(pa_binding_target_type *type, const char *name, size_t offset) { ++ struct field_entry *entry; ++ ++ pa_assert(type); ++ pa_assert(name); ++ ++ entry = pa_xnew0(struct field_entry, 1); ++ entry->name = pa_xstrdup(name); ++ entry->offset = offset; ++ ++ pa_assert_se(pa_hashmap_put(type->fields, entry->name, entry) >= 0); ++} ++ ++int pa_binding_target_type_get_field_offset(pa_binding_target_type *type, const char *field, size_t *offset) { ++ struct field_entry *entry; ++ ++ pa_assert(type); ++ pa_assert(field); ++ pa_assert(offset); ++ ++ entry = pa_hashmap_get(type->fields, field); ++ if (!entry) ++ return -PA_ERR_NOENTITY; ++ ++ *offset = entry->offset; ++ ++ return 0; ++} ++ ++static pa_hook_result_t target_type_added_cb(void *hook_data, void *call_data, void *userdata) { ++ pa_binding_target_type *type = call_data; ++ pa_binding *binding = userdata; ++ ++ pa_assert(type); ++ pa_assert(binding); ++ ++ if (!pa_streq(type->name, binding->target_info->type)) ++ return PA_HOOK_OK; ++ ++ set_target_type(binding, type); ++ ++ return PA_HOOK_OK; ++} ++ ++static pa_hook_result_t target_type_removed_cb(void *hook_data, void *call_data, void *userdata) { ++ pa_binding_target_type *type = call_data; ++ pa_binding *binding = userdata; ++ ++ pa_assert(type); ++ pa_assert(binding); ++ ++ if (type != binding->target_type) ++ return PA_HOOK_OK; ++ ++ set_target_type(binding, NULL); ++ ++ return PA_HOOK_OK; ++} ++ ++static pa_hook_result_t target_put_cb(void *hook_data, void *call_data, void *userdata) { ++ pa_binding *binding = userdata; ++ ++ pa_assert(call_data); ++ pa_assert(binding); ++ ++ if (!pa_streq(binding->target_type->get_name(call_data), binding->target_info->name)) ++ return PA_HOOK_OK; ++ ++ set_target_object(binding, call_data); ++ ++ return PA_HOOK_OK; ++} ++ ++static pa_hook_result_t target_unlink_cb(void *hook_data, void *call_data, void *userdata) { ++ pa_binding *binding = userdata; ++ ++ pa_assert(call_data); ++ pa_assert(binding); ++ ++ if (call_data != binding->target_object) ++ return PA_HOOK_OK; ++ ++ set_target_object(binding, NULL); ++ ++ return PA_HOOK_OK; ++} ++ ++static void set_target_object(pa_binding *binding, void *object) { ++ pa_assert(binding); ++ ++ binding->target_object = object; ++ ++ if (object) { ++ if (binding->target_put_slot) { ++ pa_hook_slot_free(binding->target_put_slot); ++ binding->target_put_slot = NULL; ++ } ++ ++ if (!binding->target_unlink_slot) ++ binding->target_unlink_slot = pa_hook_connect(binding->target_type->unlink_hook, PA_HOOK_NORMAL, target_unlink_cb, ++ binding); ++ ++ if (binding->target_field_offset_valid) ++ binding->owner_info->set_value(binding->owner_info->userdata, ++ *((void **) (((uint8_t *) object) + binding->target_field_offset))); ++ else ++ binding->owner_info->set_value(binding->owner_info->userdata, NULL); ++ } else { ++ if (binding->target_unlink_slot) { ++ pa_hook_slot_free(binding->target_unlink_slot); ++ binding->target_unlink_slot = NULL; ++ } ++ ++ if (binding->target_type) { ++ if (!binding->target_put_slot) ++ binding->target_put_slot = pa_hook_connect(binding->target_type->put_hook, PA_HOOK_NORMAL, target_put_cb, binding); ++ } else { ++ if (binding->target_put_slot) { ++ pa_hook_slot_free(binding->target_put_slot); ++ binding->target_put_slot = NULL; ++ } ++ } ++ ++ binding->owner_info->set_value(binding->owner_info->userdata, NULL); ++ } ++} ++ ++static void set_target_type(pa_binding *binding, pa_binding_target_type *type) { ++ pa_assert(binding); ++ ++ binding->target_type = type; ++ ++ if (type) { ++ int r; ++ ++ if (binding->target_type_added_slot) { ++ pa_hook_slot_free(binding->target_type_added_slot); ++ binding->target_type_added_slot = NULL; ++ } ++ ++ if (!binding->target_type_removed_slot) ++ binding->target_type_removed_slot = ++ pa_hook_connect(&binding->volume_api->hooks[PA_VOLUME_API_HOOK_BINDING_TARGET_TYPE_REMOVED], ++ PA_HOOK_NORMAL, target_type_removed_cb, binding); ++ ++ r = pa_binding_target_type_get_field_offset(type, binding->target_info->field, &binding->target_field_offset); ++ if (r >= 0) ++ binding->target_field_offset_valid = true; ++ else { ++ pa_log_warn("Reference to non-existing field \"%s\" in binding target type \"%s\".", binding->target_info->field, ++ type->name); ++ binding->target_field_offset_valid = false; ++ } ++ ++ set_target_object(binding, pa_hashmap_get(type->objects, binding->target_info->name)); ++ } else { ++ if (binding->target_type_removed_slot) { ++ pa_hook_slot_free(binding->target_type_removed_slot); ++ binding->target_type_removed_slot = NULL; ++ } ++ ++ if (!binding->target_type_added_slot) ++ binding->target_type_added_slot = ++ pa_hook_connect(&binding->volume_api->hooks[PA_VOLUME_API_HOOK_BINDING_TARGET_TYPE_ADDED], ++ PA_HOOK_NORMAL, target_type_added_cb, binding); ++ ++ binding->target_field_offset_valid = false; ++ ++ set_target_object(binding, NULL); ++ } ++} ++ ++pa_binding *pa_binding_new(pa_volume_api *api, const pa_binding_owner_info *owner_info, ++ const pa_binding_target_info *target_info) { ++ pa_binding *binding; ++ ++ pa_assert(api); ++ pa_assert(owner_info); ++ pa_assert(target_info); ++ ++ binding = pa_xnew0(pa_binding, 1); ++ binding->volume_api = api; ++ binding->owner_info = pa_binding_owner_info_copy(owner_info); ++ binding->target_info = pa_binding_target_info_copy(target_info); ++ ++ set_target_type(binding, pa_hashmap_get(api->binding_target_types, target_info->type)); ++ ++ return binding; ++} ++ ++void pa_binding_free(pa_binding *binding) { ++ pa_assert(binding); ++ ++ if (binding->target_unlink_slot) ++ pa_hook_slot_free(binding->target_unlink_slot); ++ ++ if (binding->target_put_slot) ++ pa_hook_slot_free(binding->target_put_slot); ++ ++ if (binding->target_type_removed_slot) ++ pa_hook_slot_free(binding->target_type_removed_slot); ++ ++ if (binding->target_type_added_slot) ++ pa_hook_slot_free(binding->target_type_added_slot); ++ ++ if (binding->target_info) ++ pa_binding_target_info_free(binding->target_info); ++ ++ if (binding->owner_info) ++ pa_binding_owner_info_free(binding->owner_info); ++ ++ pa_xfree(binding); ++} +diff --git a/src/modules/volume-api/binding.h b/src/modules/volume-api/binding.h +new file mode 100644 +index 0000000..ba4dea8 +--- /dev/null ++++ b/src/modules/volume-api/binding.h +@@ -0,0 +1,128 @@ ++#ifndef foobindinghfoo ++#define foobindinghfoo ++ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#include <modules/volume-api/volume-api.h> ++ ++typedef struct pa_binding pa_binding; ++typedef struct pa_binding_owner_info pa_binding_owner_info; ++typedef struct pa_binding_target_info pa_binding_target_info; ++typedef struct pa_binding_target_type pa_binding_target_type; ++ ++typedef void (*pa_binding_set_value_cb_t)(void *userdata, void *value); ++ ++struct pa_binding_owner_info { ++ /* This is the object that has the variable that the binding is created ++ * for. */ ++ void *userdata; ++ ++ /* Called when the owner object's value needs to be updated. The userdata ++ * parameter of the callback is the same as the userdata field in this ++ * struct, and the value parameter is the new value for whatever variable ++ * the binding was created for. */ ++ pa_binding_set_value_cb_t set_value; ++}; ++ ++pa_binding_owner_info *pa_binding_owner_info_new(pa_binding_set_value_cb_t set_value, void *userdata); ++pa_binding_owner_info *pa_binding_owner_info_copy(const pa_binding_owner_info *info); ++void pa_binding_owner_info_free(pa_binding_owner_info *info); ++ ++struct pa_binding_target_info { ++ /* The target type name as registered with ++ * pa_binding_target_type_register(). */ ++ char *type; ++ ++ /* The target object name as returned by the get_name callback of ++ * pa_binding_target_type. */ ++ char *name; ++ ++ /* The target field of the target object. */ ++ char *field; ++}; ++ ++pa_binding_target_info *pa_binding_target_info_new(const char *type, const char *name, const char *field); ++ ++/* The string format is "bind:TYPE:NAME". */ ++int pa_binding_target_info_new_from_string(const char *str, const char *field, pa_binding_target_info **info); ++ ++pa_binding_target_info *pa_binding_target_info_copy(const pa_binding_target_info *info); ++void pa_binding_target_info_free(pa_binding_target_info *info); ++ ++typedef const char *(*pa_binding_target_type_get_name_cb_t)(void *object); ++ ++struct pa_binding_target_type { ++ /* Identifier for this target type. */ ++ char *name; ++ ++ /* name -> object. Points directly to some "master" object hashmap, so the ++ * hashmap is not owned by pa_binding_target_type. */ ++ pa_hashmap *objects; ++ ++ /* The hook that notifies of new objects if this target type. The call data ++ * of the hook must be a pointer to the new object (this should be true for ++ * all PUT hooks, so don't worry too much). */ ++ pa_hook *put_hook; ++ ++ /* The hook that notifies of unlinked objects of this target type. The call ++ * data of the hook must be a pointer to the removed object (this should be ++ * true for all UNLINK hooks, so don't worry too much). */ ++ pa_hook *unlink_hook; ++ ++ /* Function for getting the name of an object of this target type. */ ++ pa_binding_target_type_get_name_cb_t get_name; ++ ++ pa_hashmap *fields; ++}; ++ ++pa_binding_target_type *pa_binding_target_type_new(const char *name, pa_hashmap *objects, pa_hook *put_hook, ++ pa_hook *unlink_hook, pa_binding_target_type_get_name_cb_t get_name); ++void pa_binding_target_type_free(pa_binding_target_type *type); ++ ++/* Useful when calling pa_binding_target_type_add_field(). */ ++#define PA_BINDING_CALCULATE_FIELD_OFFSET(type, field) ((size_t) &(((type *) 0)->field)) ++ ++/* Called during the type initialization (right after ++ * pa_binding_target_type_new()). */ ++void pa_binding_target_type_add_field(pa_binding_target_type *type, const char *name, size_t offset); ++ ++int pa_binding_target_type_get_field_offset(pa_binding_target_type *type, const char *field, size_t *offset); ++ ++struct pa_binding { ++ pa_volume_api *volume_api; ++ pa_binding_owner_info *owner_info; ++ pa_binding_target_info *target_info; ++ pa_binding_target_type *target_type; ++ void *target_object; ++ size_t target_field_offset; ++ bool target_field_offset_valid; ++ pa_hook_slot *target_type_added_slot; ++ pa_hook_slot *target_type_removed_slot; ++ pa_hook_slot *target_put_slot; ++ pa_hook_slot *target_unlink_slot; ++}; ++ ++pa_binding *pa_binding_new(pa_volume_api *api, const pa_binding_owner_info *owner_info, ++ const pa_binding_target_info *target_info); ++void pa_binding_free(pa_binding *binding); ++ ++#endif +diff --git a/src/modules/volume-api/bvolume.h b/src/modules/volume-api/bvolume.h +new file mode 100644 +index 0000000..0317fb6 +--- /dev/null ++++ b/src/modules/volume-api/bvolume.h +@@ -0,0 +1,43 @@ ++#ifndef foobvolumehfoo ++#define foobvolumehfoo ++ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#include <pulse/ext-volume-api.h> ++ ++typedef pa_ext_volume_api_bvolume pa_bvolume; ++ ++#define pa_balance_valid pa_ext_volume_api_balance_valid ++#define pa_bvolume_valid pa_ext_volume_api_bvolume_valid ++#define pa_bvolume_init_invalid pa_ext_volume_api_bvolume_init_invalid ++#define pa_bvolume_init_mono pa_ext_volume_api_bvolume_init_mono ++#define pa_bvolume_equal pa_ext_volume_api_bvolume_equal ++#define pa_bvolume_from_cvolume pa_ext_volume_api_bvolume_from_cvolume ++#define pa_bvolume_to_cvolume pa_ext_volume_api_bvolume_to_cvolume ++#define pa_bvolume_copy_balance pa_ext_volume_api_bvolume_copy_balance ++#define pa_bvolume_reset_balance pa_ext_volume_api_bvolume_reset_balance ++#define pa_bvolume_remap pa_ext_volume_api_bvolume_remap ++ ++#define PA_BVOLUME_SNPRINT_BALANCE_MAX PA_EXT_VOLUME_API_BVOLUME_SNPRINT_BALANCE_MAX ++#define pa_bvolume_snprint_balance pa_ext_volume_api_bvolume_snprint_balance ++ ++#endif +diff --git a/src/modules/volume-api/device-creator.c b/src/modules/volume-api/device-creator.c +new file mode 100644 +index 0000000..1d912ba +--- /dev/null ++++ b/src/modules/volume-api/device-creator.c +@@ -0,0 +1,1108 @@ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#ifdef HAVE_CONFIG_H ++#include <config.h> ++#endif ++ ++#include "device-creator.h" ++ ++#include <modules/volume-api/device.h> ++#include <modules/volume-api/mute-control.h> ++#include <modules/volume-api/volume-control.h> ++ ++#include <pulsecore/core-util.h> ++#include <pulsecore/i18n.h> ++ ++struct pa_device_creator { ++ pa_volume_api *volume_api; ++ pa_hashmap *devices; /* pa_device_port/pa_sink/pa_source -> struct device */ ++ pa_hook_slot *card_put_slot; ++ pa_hook_slot *card_unlink_slot; ++ pa_hook_slot *sink_put_slot; ++ pa_hook_slot *sink_unlink_slot; ++ pa_hook_slot *source_put_slot; ++ pa_hook_slot *source_unlink_slot; ++}; ++ ++enum device_type { ++ DEVICE_TYPE_PORT, ++ DEVICE_TYPE_PORT_MONITOR, ++ DEVICE_TYPE_SINK, ++ DEVICE_TYPE_SOURCE, ++}; ++ ++struct device_volume_control { ++ struct device *device; ++ pa_volume_control *volume_control; ++ ++ bool unlinked; ++ ++ pa_hook_slot *volume_changed_slot; ++}; ++ ++struct device_mute_control { ++ struct device *device; ++ pa_mute_control *mute_control; ++ ++ bool unlinked; ++ ++ pa_hook_slot *mute_changed_slot; ++}; ++ ++struct device { ++ pa_device_creator *creator; ++ enum device_type type; ++ pa_device_port *port; ++ pa_sink *sink; ++ pa_source *source; ++ pa_device *device; ++ struct device_volume_control *volume_control; ++ struct device_mute_control *mute_control; ++ ++ bool unlinked; ++ ++ pa_hook_slot *proplist_changed_slot; ++ pa_hook_slot *port_active_changed_slot; ++ struct device *monitor; ++}; ++ ++static const char *device_type_from_icon_name(const char *icon_name) { ++ if (!icon_name) ++ return NULL; ++ ++ if (pa_streq(icon_name, "audio-input-microphone")) ++ return "microphone"; ++ ++ if (pa_streq(icon_name, "audio-speakers")) ++ return "speakers"; ++ ++ if (pa_streq(icon_name, "audio-headphones")) ++ return "headphones"; ++ ++ return NULL; ++} ++ ++static const char *device_type_from_port_name(pa_device_port *port) { ++ pa_assert(port); ++ ++ if (strstr(port->name, "analog")) { ++ if (port->direction == PA_DIRECTION_INPUT) ++ return "analog-input"; ++ else ++ return "analog-output"; ++ } ++ ++ if (strstr(port->name, "hdmi")) { ++ if (port->direction == PA_DIRECTION_INPUT) ++ return "hdmi-input"; ++ else ++ return "hdmi-output"; ++ } ++ ++ if (strstr(port->name, "iec958")) { ++ if (port->direction == PA_DIRECTION_INPUT) ++ return "spdif-input"; ++ else ++ return "spdif-output"; ++ } ++ ++ return NULL; ++} ++ ++static const char *device_type_from_port(pa_device_port *port) { ++ const char *device_type; ++ ++ pa_assert(port); ++ ++ device_type = device_type_from_icon_name(pa_proplist_gets(port->proplist, PA_PROP_DEVICE_ICON_NAME)); ++ if (device_type) ++ return device_type; ++ ++ device_type = device_type_from_port_name(port); ++ if (device_type) ++ return device_type; ++ ++ return NULL; ++} ++ ++static const char *get_sink_description(pa_sink *sink) { ++ const char *description; ++ ++ pa_assert(sink); ++ ++ description = pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION); ++ if (description) ++ return description; ++ ++ return sink->name; ++} ++ ++static const char *get_source_description(pa_source *source) { ++ const char *description; ++ ++ pa_assert(source); ++ ++ description = pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION); ++ if (description) ++ return description; ++ ++ return source->name; ++} ++ ++static int volume_control_set_volume_cb(pa_volume_control *c, const pa_bvolume *volume, bool set_volume, bool set_balance) { ++ struct device_volume_control *control; ++ struct device *device; ++ pa_bvolume bvolume; ++ pa_cvolume cvolume; ++ ++ pa_assert(c); ++ pa_assert(volume); ++ ++ control = c->userdata; ++ device = control->device; ++ ++ switch (device->type) { ++ case DEVICE_TYPE_PORT: ++ if (device->port->direction == PA_DIRECTION_OUTPUT) ++ pa_bvolume_from_cvolume(&bvolume, &device->sink->reference_volume, &device->sink->channel_map); ++ else ++ pa_bvolume_from_cvolume(&bvolume, &device->source->reference_volume, &device->source->channel_map); ++ break; ++ ++ case DEVICE_TYPE_SINK: ++ pa_bvolume_from_cvolume(&bvolume, &device->sink->reference_volume, &device->sink->channel_map); ++ break; ++ ++ case DEVICE_TYPE_PORT_MONITOR: ++ case DEVICE_TYPE_SOURCE: ++ pa_bvolume_from_cvolume(&bvolume, &device->source->reference_volume, &device->source->channel_map); ++ break; ++ } ++ ++ if (set_volume) ++ bvolume.volume = volume->volume; ++ ++ if (set_balance) ++ pa_bvolume_copy_balance(&bvolume, volume); ++ ++ pa_bvolume_to_cvolume(&bvolume, &cvolume); ++ ++ switch (device->type) { ++ case DEVICE_TYPE_PORT: ++ if (device->port->direction == PA_DIRECTION_OUTPUT) ++ pa_sink_set_volume(device->sink, &cvolume, true, true); ++ else ++ pa_source_set_volume(device->source, &cvolume, true, true); ++ break; ++ ++ case DEVICE_TYPE_PORT_MONITOR: ++ case DEVICE_TYPE_SOURCE: ++ pa_source_set_volume(device->source, &cvolume, true, true); ++ break; ++ ++ case DEVICE_TYPE_SINK: ++ pa_sink_set_volume(device->sink, &cvolume, true, true); ++ break; ++ } ++ ++ return 0; ++} ++ ++static struct device_volume_control *device_volume_control_new(struct device *device) { ++ struct device_volume_control *control; ++ const char *name = NULL; ++ bool convertible_to_dB = false; ++ bool channel_map_is_writable; ++ ++ pa_assert(device); ++ ++ control = pa_xnew0(struct device_volume_control, 1); ++ control->device = device; ++ ++ switch (device->type) { ++ case DEVICE_TYPE_PORT: ++ name = "port-volume-control"; ++ ++ if (device->port->direction == PA_DIRECTION_OUTPUT) ++ convertible_to_dB = device->sink->flags & PA_SINK_DECIBEL_VOLUME; ++ else ++ convertible_to_dB = device->source->flags & PA_SOURCE_DECIBEL_VOLUME; ++ ++ break; ++ ++ case DEVICE_TYPE_PORT_MONITOR: ++ name = "port-monitor-volume-control"; ++ convertible_to_dB = device->source->flags & PA_SOURCE_DECIBEL_VOLUME; ++ break; ++ ++ case DEVICE_TYPE_SINK: ++ name = "sink-volume-control"; ++ convertible_to_dB = device->sink->flags & PA_SINK_DECIBEL_VOLUME; ++ break; ++ ++ case DEVICE_TYPE_SOURCE: ++ name = "source-volume-control"; ++ convertible_to_dB = device->source->flags & PA_SOURCE_DECIBEL_VOLUME; ++ break; ++ } ++ ++ channel_map_is_writable = false; ++ control->volume_control = pa_volume_control_new(device->creator->volume_api, name, device->device->description, ++ convertible_to_dB, channel_map_is_writable); ++ control->volume_control->set_volume = volume_control_set_volume_cb; ++ control->volume_control->userdata = control; ++ ++ return control; ++} ++ ++static pa_hook_result_t sink_or_source_volume_changed_cb(void *hook_data, void *call_data, void *userdata) { ++ struct device_volume_control *control = userdata; ++ struct device *device; ++ pa_sink *sink = NULL; ++ pa_source *source = NULL; ++ pa_bvolume bvolume; ++ ++ pa_assert(control); ++ pa_assert(call_data); ++ ++ device = control->device; ++ ++ switch (device->type) { ++ case DEVICE_TYPE_PORT: ++ if (device->port->direction == PA_DIRECTION_OUTPUT) ++ sink = call_data; ++ else ++ source = call_data; ++ break; ++ ++ case DEVICE_TYPE_PORT_MONITOR: ++ case DEVICE_TYPE_SOURCE: ++ source = call_data; ++ break; ++ ++ case DEVICE_TYPE_SINK: ++ sink = call_data; ++ break; ++ } ++ ++ if ((sink && sink != device->sink) || (source && source != device->source)) ++ return PA_HOOK_OK; ++ ++ if (sink) ++ pa_bvolume_from_cvolume(&bvolume, &sink->reference_volume, &sink->channel_map); ++ else ++ pa_bvolume_from_cvolume(&bvolume, &source->reference_volume, &source->channel_map); ++ ++ pa_volume_control_volume_changed(control->volume_control, &bvolume, true, true); ++ ++ return PA_HOOK_OK; ++} ++ ++static void volume_control_set_initial_volume_cb(pa_volume_control *c) { ++ struct device_volume_control *control; ++ struct device *device; ++ pa_cvolume cvolume; ++ ++ pa_assert(c); ++ ++ control = c->userdata; ++ device = control->device; ++ pa_bvolume_to_cvolume(&control->volume_control->volume, &cvolume); ++ ++ switch (device->type) { ++ case DEVICE_TYPE_PORT: ++ if (device->port->direction == PA_DIRECTION_OUTPUT) ++ pa_sink_set_volume(device->sink, &cvolume, true, true); ++ else ++ pa_source_set_volume(device->source, &cvolume, true, true); ++ break; ++ ++ case DEVICE_TYPE_PORT_MONITOR: ++ case DEVICE_TYPE_SOURCE: ++ pa_source_set_volume(device->source, &cvolume, true, true); ++ break; ++ ++ case DEVICE_TYPE_SINK: ++ pa_sink_set_volume(device->sink, &cvolume, true, true); ++ break; ++ } ++} ++ ++static void device_volume_control_put(struct device_volume_control *control) { ++ struct device *device; ++ pa_bvolume volume; ++ ++ pa_assert(control); ++ ++ device = control->device; ++ ++ switch (device->type) { ++ case DEVICE_TYPE_PORT: ++ if (device->port->direction == PA_DIRECTION_OUTPUT) { ++ control->volume_changed_slot = pa_hook_connect(&device->port->core->hooks[PA_CORE_HOOK_SINK_VOLUME_CHANGED], ++ PA_HOOK_NORMAL, sink_or_source_volume_changed_cb, control); ++ pa_bvolume_from_cvolume(&volume, &device->sink->reference_volume, &device->sink->channel_map); ++ } else { ++ control->volume_changed_slot = pa_hook_connect(&device->port->core->hooks[PA_CORE_HOOK_SOURCE_VOLUME_CHANGED], ++ PA_HOOK_NORMAL, sink_or_source_volume_changed_cb, control); ++ pa_bvolume_from_cvolume(&volume, &device->source->reference_volume, &device->source->channel_map); ++ } ++ break; ++ ++ case DEVICE_TYPE_PORT_MONITOR: ++ case DEVICE_TYPE_SOURCE: ++ control->volume_changed_slot = pa_hook_connect(&device->source->core->hooks[PA_CORE_HOOK_SOURCE_VOLUME_CHANGED], ++ PA_HOOK_NORMAL, sink_or_source_volume_changed_cb, control); ++ pa_bvolume_from_cvolume(&volume, &device->source->reference_volume, &device->source->channel_map); ++ break; ++ ++ case DEVICE_TYPE_SINK: ++ control->volume_changed_slot = pa_hook_connect(&device->sink->core->hooks[PA_CORE_HOOK_SINK_VOLUME_CHANGED], ++ PA_HOOK_NORMAL, sink_or_source_volume_changed_cb, control); ++ pa_bvolume_from_cvolume(&volume, &device->sink->reference_volume, &device->sink->channel_map); ++ break; ++ } ++ ++ pa_volume_control_put(control->volume_control, &volume, volume_control_set_initial_volume_cb); ++} ++ ++static void device_volume_control_unlink(struct device_volume_control *control) { ++ pa_assert(control); ++ ++ if (control->unlinked) ++ return; ++ ++ control->unlinked = true; ++ ++ if (control->volume_control) ++ pa_volume_control_unlink(control->volume_control); ++ ++ if (control->volume_changed_slot) { ++ pa_hook_slot_free(control->volume_changed_slot); ++ control->volume_changed_slot = NULL; ++ } ++} ++ ++static void device_volume_control_free(struct device_volume_control *control) { ++ pa_assert(control); ++ ++ if (!control->unlinked) ++ device_volume_control_unlink(control); ++ ++ if (control->volume_control) ++ pa_volume_control_free(control->volume_control); ++ ++ pa_xfree(control); ++} ++ ++static int mute_control_set_mute_cb(pa_mute_control *c, bool mute) { ++ struct device_mute_control *control; ++ struct device *device; ++ ++ pa_assert(c); ++ ++ control = c->userdata; ++ device = control->device; ++ ++ switch (device->type) { ++ case DEVICE_TYPE_PORT: ++ if (device->port->direction == PA_DIRECTION_OUTPUT) ++ pa_sink_set_mute(device->sink, mute, true); ++ else ++ pa_source_set_mute(device->source, mute, true); ++ break; ++ ++ case DEVICE_TYPE_PORT_MONITOR: ++ case DEVICE_TYPE_SOURCE: ++ pa_source_set_mute(device->source, mute, true); ++ break; ++ ++ case DEVICE_TYPE_SINK: ++ pa_sink_set_mute(device->sink, mute, true); ++ break; ++ } ++ ++ return 0; ++} ++ ++static struct device_mute_control *device_mute_control_new(struct device *device) { ++ struct device_mute_control *control; ++ const char *name = NULL; ++ ++ pa_assert(device); ++ ++ control = pa_xnew0(struct device_mute_control, 1); ++ control->device = device; ++ ++ switch (device->type) { ++ case DEVICE_TYPE_PORT: ++ name = "port-mute-control"; ++ break; ++ ++ case DEVICE_TYPE_PORT_MONITOR: ++ name = "port-monitor-mute-control"; ++ break; ++ ++ case DEVICE_TYPE_SINK: ++ name = "sink-mute-control"; ++ break; ++ ++ case DEVICE_TYPE_SOURCE: ++ name = "source-mute-control"; ++ break; ++ } ++ ++ control->mute_control = pa_mute_control_new(device->creator->volume_api, name, device->device->description); ++ control->mute_control->set_mute = mute_control_set_mute_cb; ++ control->mute_control->userdata = control; ++ ++ return control; ++} ++ ++static pa_hook_result_t sink_or_source_mute_changed_cb(void *hook_data, void *call_data, void *userdata) { ++ struct device_mute_control *control = userdata; ++ struct device *device; ++ pa_sink *sink = NULL; ++ pa_source *source = NULL; ++ bool mute; ++ ++ pa_assert(control); ++ pa_assert(call_data); ++ ++ device = control->device; ++ ++ switch (device->type) { ++ case DEVICE_TYPE_PORT: ++ if (device->port->direction == PA_DIRECTION_OUTPUT) ++ sink = call_data; ++ else ++ source = call_data; ++ break; ++ ++ case DEVICE_TYPE_PORT_MONITOR: ++ case DEVICE_TYPE_SOURCE: ++ source = call_data; ++ break; ++ ++ case DEVICE_TYPE_SINK: ++ sink = call_data; ++ break; ++ } ++ ++ if ((sink && sink != device->sink) || (source && source != device->source)) ++ return PA_HOOK_OK; ++ ++ if (sink) ++ mute = sink->muted; ++ else ++ mute = source->muted; ++ ++ pa_mute_control_mute_changed(control->mute_control, mute); ++ ++ return PA_HOOK_OK; ++} ++ ++static void mute_control_set_initial_mute_cb(pa_mute_control *c) { ++ struct device_volume_control *control; ++ struct device *device; ++ ++ pa_assert(c); ++ ++ control = c->userdata; ++ device = control->device; ++ ++ switch (device->type) { ++ case DEVICE_TYPE_PORT: ++ if (device->port->direction == PA_DIRECTION_OUTPUT) ++ pa_sink_set_mute(device->sink, c->mute, true); ++ else ++ pa_source_set_mute(device->source, c->mute, true); ++ break; ++ ++ case DEVICE_TYPE_PORT_MONITOR: ++ case DEVICE_TYPE_SOURCE: ++ pa_source_set_mute(device->source, c->mute, true); ++ break; ++ ++ case DEVICE_TYPE_SINK: ++ pa_sink_set_mute(device->sink, c->mute, true); ++ break; ++ } ++} ++ ++static void device_mute_control_put(struct device_mute_control *control) { ++ struct device *device; ++ bool mute = false; ++ ++ pa_assert(control); ++ ++ device = control->device; ++ ++ switch (device->type) { ++ case DEVICE_TYPE_PORT: ++ if (device->port->direction == PA_DIRECTION_OUTPUT) { ++ control->mute_changed_slot = pa_hook_connect(&device->port->core->hooks[PA_CORE_HOOK_SINK_MUTE_CHANGED], ++ PA_HOOK_NORMAL, sink_or_source_mute_changed_cb, control); ++ mute = device->sink->muted; ++ } else { ++ control->mute_changed_slot = pa_hook_connect(&device->port->core->hooks[PA_CORE_HOOK_SOURCE_MUTE_CHANGED], ++ PA_HOOK_NORMAL, sink_or_source_mute_changed_cb, control); ++ mute = device->source->muted; ++ } ++ break; ++ ++ case DEVICE_TYPE_PORT_MONITOR: ++ case DEVICE_TYPE_SOURCE: ++ control->mute_changed_slot = pa_hook_connect(&device->source->core->hooks[PA_CORE_HOOK_SOURCE_MUTE_CHANGED], ++ PA_HOOK_NORMAL, sink_or_source_mute_changed_cb, control); ++ mute = device->source->muted; ++ break; ++ ++ case DEVICE_TYPE_SINK: ++ control->mute_changed_slot = pa_hook_connect(&device->sink->core->hooks[PA_CORE_HOOK_SINK_MUTE_CHANGED], ++ PA_HOOK_NORMAL, sink_or_source_mute_changed_cb, control); ++ mute = device->sink->muted; ++ break; ++ } ++ ++ pa_mute_control_put(control->mute_control, mute, true, mute_control_set_initial_mute_cb); ++} ++ ++static void device_mute_control_unlink(struct device_mute_control *control) { ++ pa_assert(control); ++ ++ if (control->unlinked) ++ return; ++ ++ control->unlinked = true; ++ ++ if (control->mute_control) ++ pa_mute_control_unlink(control->mute_control); ++ ++ if (control->mute_changed_slot) { ++ pa_hook_slot_free(control->mute_changed_slot); ++ control->mute_changed_slot = NULL; ++ } ++} ++ ++static void device_mute_control_free(struct device_mute_control *control) { ++ pa_assert(control); ++ ++ if (!control->unlinked) ++ device_mute_control_unlink(control); ++ ++ if (control->mute_control) ++ pa_mute_control_free(control->mute_control); ++ ++ pa_xfree(control); ++} ++ ++static void device_set_sink_and_source_from_port(struct device *device) { ++ pa_sink *sink; ++ pa_source *source; ++ uint32_t idx; ++ ++ pa_assert(device); ++ ++ device->sink = NULL; ++ device->source = NULL; ++ ++ if (!device->port->active) ++ return; ++ ++ switch (device->type) { ++ case DEVICE_TYPE_PORT: ++ if (device->port->direction == PA_DIRECTION_OUTPUT) { ++ PA_IDXSET_FOREACH(sink, device->port->card->sinks, idx) { ++ if (sink->active_port == device->port) { ++ device->sink = sink; ++ break; ++ } ++ } ++ ++ pa_assert(device->sink); ++ } else { ++ PA_IDXSET_FOREACH(source, device->port->card->sources, idx) { ++ if (source->active_port == device->port) { ++ device->source = source; ++ break; ++ } ++ } ++ ++ pa_assert(device->source); ++ } ++ break; ++ ++ case DEVICE_TYPE_PORT_MONITOR: { ++ PA_IDXSET_FOREACH(sink, device->port->card->sinks, idx) { ++ if (sink->active_port == device->port) { ++ device->sink = sink; ++ device->source = sink->monitor_source; ++ break; ++ } ++ } ++ ++ pa_assert(device->sink); ++ break; ++ } ++ ++ case DEVICE_TYPE_SINK: ++ case DEVICE_TYPE_SOURCE: ++ pa_assert_not_reached(); ++ } ++} ++ ++static pa_hook_result_t sink_or_source_proplist_changed_cb(void *hook_data, void *call_data, void *userdata) { ++ struct device *device = userdata; ++ pa_sink *sink = NULL; ++ pa_source *source = NULL; ++ const char *description = NULL; ++ ++ pa_assert(device); ++ pa_assert(call_data); ++ ++ switch (device->type) { ++ case DEVICE_TYPE_PORT: ++ case DEVICE_TYPE_PORT_MONITOR: ++ pa_assert_not_reached(); ++ ++ case DEVICE_TYPE_SINK: ++ sink = call_data; ++ ++ if (sink != device->sink) ++ return PA_HOOK_OK; ++ ++ description = get_sink_description(sink); ++ break; ++ ++ case DEVICE_TYPE_SOURCE: ++ source = call_data; ++ ++ if (source != device->source) ++ return PA_HOOK_OK; ++ ++ description = get_source_description(source); ++ break; ++ } ++ ++ pa_device_description_changed(device->device, description); ++ pa_volume_control_description_changed(device->volume_control->volume_control, description); ++ pa_mute_control_description_changed(device->mute_control->mute_control, description); ++ ++ return PA_HOOK_OK; ++} ++ ++static struct device *device_new(pa_device_creator *creator, enum device_type type, void *core_device) { ++ struct device *device = NULL; ++ const char *name = NULL; ++ char *description = NULL; ++ pa_direction_t direction = PA_DIRECTION_OUTPUT; ++ const char *device_type = NULL; ++ bool create_volume_and_mute_controls = true; ++ ++ pa_assert(creator); ++ pa_assert(core_device); ++ ++ device = pa_xnew0(struct device, 1); ++ device->creator = creator; ++ device->type = type; ++ ++ switch (type) { ++ case DEVICE_TYPE_PORT: ++ device->port = core_device; ++ device_set_sink_and_source_from_port(device); ++ name = "port-device"; ++ description = pa_xstrdup(device->port->description); ++ direction = device->port->direction; ++ device_type = device_type_from_port(device->port); ++ ++ if (!device->sink && !device->source) ++ create_volume_and_mute_controls = false; ++ break; ++ ++ case DEVICE_TYPE_PORT_MONITOR: ++ device->port = core_device; ++ device_set_sink_and_source_from_port(device); ++ name = "port-monitor-device"; ++ description = pa_sprintf_malloc(_("Monitor of %s"), device->port->description); ++ direction = PA_DIRECTION_INPUT; ++ ++ if (!device->source) ++ create_volume_and_mute_controls = false; ++ break; ++ ++ case DEVICE_TYPE_SINK: ++ device->sink = core_device; ++ name = "sink-device"; ++ description = pa_xstrdup(get_sink_description(device->sink)); ++ direction = PA_DIRECTION_OUTPUT; ++ break; ++ ++ case DEVICE_TYPE_SOURCE: ++ device->source = core_device; ++ name = "source-device"; ++ description = pa_xstrdup(get_source_description(device->source)); ++ direction = PA_DIRECTION_INPUT; ++ break; ++ } ++ ++ device->device = pa_device_new(creator->volume_api, name, description, direction, &device_type, device_type ? 1 : 0); ++ pa_xfree(description); ++ ++ if (create_volume_and_mute_controls) { ++ device->volume_control = device_volume_control_new(device); ++ device->mute_control = device_mute_control_new(device); ++ } ++ ++ switch (type) { ++ case DEVICE_TYPE_PORT: ++ if (device->port->direction == PA_DIRECTION_OUTPUT) ++ device->monitor = device_new(creator, DEVICE_TYPE_PORT_MONITOR, device->port); ++ break; ++ ++ case DEVICE_TYPE_PORT_MONITOR: ++ break; ++ ++ case DEVICE_TYPE_SINK: ++ device->proplist_changed_slot = pa_hook_connect(&device->sink->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], ++ PA_HOOK_NORMAL, sink_or_source_proplist_changed_cb, device); ++ break; ++ ++ case DEVICE_TYPE_SOURCE: ++ device->proplist_changed_slot = pa_hook_connect(&device->source->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], ++ PA_HOOK_NORMAL, sink_or_source_proplist_changed_cb, device); ++ break; ++ } ++ ++ return device; ++} ++ ++static pa_hook_result_t port_active_changed_cb(void *hook_data, void *call_data, void *userdata) { ++ struct device *device = userdata; ++ pa_device_port *port = call_data; ++ bool should_have_volume_and_mute_controls = false; ++ ++ pa_assert(device); ++ pa_assert(port); ++ ++ if (port != device->port) ++ return PA_HOOK_OK; ++ ++ device_set_sink_and_source_from_port(device); ++ ++ switch (device->type) { ++ case DEVICE_TYPE_PORT: ++ should_have_volume_and_mute_controls = device->sink || device->source; ++ break; ++ ++ case DEVICE_TYPE_PORT_MONITOR: ++ should_have_volume_and_mute_controls = !!device->source; ++ break; ++ ++ case DEVICE_TYPE_SINK: ++ case DEVICE_TYPE_SOURCE: ++ pa_assert_not_reached(); ++ } ++ ++ if (should_have_volume_and_mute_controls && !device->volume_control) { ++ pa_assert(!device->mute_control); ++ ++ device->volume_control = device_volume_control_new(device); ++ device_volume_control_put(device->volume_control); ++ pa_device_set_default_volume_control(device->device, device->volume_control->volume_control); ++ ++ device->mute_control = device_mute_control_new(device); ++ device_mute_control_put(device->mute_control); ++ pa_device_set_default_mute_control(device->device, device->mute_control->mute_control); ++ } ++ ++ if (!should_have_volume_and_mute_controls && device->volume_control) { ++ pa_assert(device->mute_control); ++ ++ device_mute_control_free(device->mute_control); ++ device->mute_control = NULL; ++ device_volume_control_free(device->volume_control); ++ device->volume_control = NULL; ++ } ++ ++ return PA_HOOK_OK; ++} ++ ++static void device_put(struct device *device) { ++ pa_assert(device); ++ ++ switch (device->type) { ++ case DEVICE_TYPE_PORT: ++ case DEVICE_TYPE_PORT_MONITOR: ++ device->port_active_changed_slot = pa_hook_connect(&device->port->core->hooks[PA_CORE_HOOK_PORT_ACTIVE_CHANGED], ++ PA_HOOK_NORMAL, port_active_changed_cb, device); ++ ++ case DEVICE_TYPE_SINK: ++ case DEVICE_TYPE_SOURCE: ++ break; ++ } ++ ++ if (device->volume_control) ++ device_volume_control_put(device->volume_control); ++ ++ if (device->mute_control) ++ device_mute_control_put(device->mute_control); ++ ++ pa_device_put(device->device, device->volume_control ? device->volume_control->volume_control : NULL, ++ device->mute_control ? device->mute_control->mute_control : NULL); ++ ++ if (device->monitor) ++ device_put(device->monitor); ++} ++ ++static void device_unlink(struct device *device) { ++ pa_assert(device); ++ ++ if (device->unlinked) ++ return; ++ ++ device->unlinked = true; ++ ++ if (device->monitor) ++ device_unlink(device->monitor); ++ ++ if (device->device) ++ pa_device_unlink(device->device); ++ ++ if (device->mute_control) ++ device_mute_control_unlink(device->mute_control); ++ ++ if (device->volume_control) ++ device_volume_control_unlink(device->volume_control); ++ ++ if (device->port_active_changed_slot) { ++ pa_hook_slot_free(device->port_active_changed_slot); ++ device->port_active_changed_slot = NULL; ++ } ++} ++ ++static void device_free(struct device *device) { ++ pa_assert(device); ++ ++ if (!device->unlinked) ++ device_unlink(device); ++ ++ if (device->monitor) ++ device_free(device->monitor); ++ ++ if (device->proplist_changed_slot) ++ pa_hook_slot_free(device->proplist_changed_slot); ++ ++ if (device->mute_control) ++ device_mute_control_free(device->mute_control); ++ ++ if (device->volume_control) ++ device_volume_control_free(device->volume_control); ++ ++ if (device->device) ++ pa_device_free(device->device); ++ ++ pa_xfree(device); ++} ++ ++static void create_device(pa_device_creator *creator, enum device_type type, void *core_device) { ++ struct device *device; ++ ++ pa_assert(creator); ++ pa_assert(core_device); ++ ++ switch (type) { ++ case DEVICE_TYPE_PORT: ++ break; ++ ++ case DEVICE_TYPE_PORT_MONITOR: ++ pa_assert_not_reached(); ++ ++ case DEVICE_TYPE_SINK: ++ if (!pa_hashmap_isempty(((pa_sink *) core_device)->ports)) ++ return; ++ break; ++ ++ case DEVICE_TYPE_SOURCE: { ++ pa_source *source = core_device; ++ ++ if (source->monitor_of && !pa_hashmap_isempty(source->monitor_of->ports)) ++ return; ++ ++ if (!pa_hashmap_isempty(((pa_source *) core_device)->ports)) ++ return; ++ break; ++ } ++ } ++ ++ device = device_new(creator, type, core_device); ++ pa_hashmap_put(creator->devices, core_device, device); ++ device_put(device); ++} ++ ++static pa_hook_result_t card_put_cb(void *hook_data, void *call_data, void *userdata) { ++ pa_device_creator *creator = userdata; ++ pa_card *card = call_data; ++ pa_device_port *port; ++ void *state; ++ ++ pa_assert(creator); ++ pa_assert(card); ++ ++ PA_HASHMAP_FOREACH(port, card->ports, state) ++ create_device(creator, DEVICE_TYPE_PORT, port); ++ ++ return PA_HOOK_OK; ++} ++ ++static pa_hook_result_t card_unlink_cb(void *hook_data, void *call_data, void *userdata) { ++ pa_device_creator *creator = userdata; ++ pa_card *card = call_data; ++ pa_device_port *port; ++ void *state; ++ ++ pa_assert(creator); ++ pa_assert(card); ++ ++ PA_HASHMAP_FOREACH(port, card->ports, state) ++ pa_hashmap_remove_and_free(creator->devices, port); ++ ++ return PA_HOOK_OK; ++} ++ ++static pa_hook_result_t sink_put_cb(void *hook_data, void *call_data, void *userdata) { ++ pa_device_creator *creator = userdata; ++ pa_sink *sink = call_data; ++ ++ pa_assert(creator); ++ pa_assert(sink); ++ ++ create_device(creator, DEVICE_TYPE_SINK, sink); ++ ++ return PA_HOOK_OK; ++} ++ ++static pa_hook_result_t sink_unlink_cb(void *hook_data, void *call_data, void *userdata) { ++ pa_device_creator *creator = userdata; ++ pa_sink *sink = call_data; ++ ++ pa_assert(creator); ++ pa_assert(sink); ++ ++ pa_hashmap_remove_and_free(creator->devices, sink); ++ ++ return PA_HOOK_OK; ++} ++ ++static pa_hook_result_t source_put_cb(void *hook_data, void *call_data, void *userdata) { ++ pa_device_creator *creator = userdata; ++ pa_source *source = call_data; ++ ++ pa_assert(creator); ++ pa_assert(source); ++ ++ create_device(creator, DEVICE_TYPE_SOURCE, source); ++ ++ return PA_HOOK_OK; ++} ++ ++static pa_hook_result_t source_unlink_cb(void *hook_data, void *call_data, void *userdata) { ++ pa_device_creator *creator = userdata; ++ pa_source *source = call_data; ++ ++ pa_assert(creator); ++ pa_assert(source); ++ ++ pa_hashmap_remove_and_free(creator->devices, source); ++ ++ return PA_HOOK_OK; ++} ++ ++pa_device_creator *pa_device_creator_new(pa_volume_api *api) { ++ pa_device_creator *creator; ++ pa_card *card; ++ uint32_t idx; ++ pa_sink *sink; ++ pa_source *source; ++ ++ pa_assert(api); ++ ++ creator = pa_xnew0(pa_device_creator, 1); ++ creator->volume_api = api; ++ creator->devices = pa_hashmap_new_full(NULL, NULL, NULL, (pa_free_cb_t) device_free); ++ creator->card_put_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_CARD_PUT], PA_HOOK_NORMAL, card_put_cb, creator); ++ creator->card_unlink_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_CARD_UNLINK], PA_HOOK_NORMAL, card_unlink_cb, ++ creator); ++ creator->sink_put_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_NORMAL, sink_put_cb, creator); ++ creator->sink_unlink_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_NORMAL, sink_unlink_cb, ++ creator); ++ creator->source_put_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_NORMAL, source_put_cb, ++ creator); ++ creator->source_unlink_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_NORMAL, ++ source_unlink_cb, creator); ++ ++ PA_IDXSET_FOREACH(card, api->core->cards, idx) { ++ pa_device_port *port; ++ void *state; ++ ++ PA_HASHMAP_FOREACH(port, card->ports, state) ++ create_device(creator, DEVICE_TYPE_PORT, port); ++ } ++ ++ PA_IDXSET_FOREACH(sink, api->core->sinks, idx) ++ create_device(creator, DEVICE_TYPE_SINK, sink); ++ ++ PA_IDXSET_FOREACH(source, api->core->sources, idx) ++ create_device(creator, DEVICE_TYPE_SOURCE, source); ++ ++ return creator; ++} ++ ++void pa_device_creator_free(pa_device_creator *creator) { ++ pa_assert(creator); ++ ++ if (creator->devices) ++ pa_hashmap_remove_all(creator->devices); ++ ++ if (creator->source_unlink_slot) ++ pa_hook_slot_free(creator->source_unlink_slot); ++ ++ if (creator->source_put_slot) ++ pa_hook_slot_free(creator->source_put_slot); ++ ++ if (creator->sink_unlink_slot) ++ pa_hook_slot_free(creator->sink_unlink_slot); ++ ++ if (creator->sink_put_slot) ++ pa_hook_slot_free(creator->sink_put_slot); ++ ++ if (creator->card_unlink_slot) ++ pa_hook_slot_free(creator->card_unlink_slot); ++ ++ if (creator->card_put_slot) ++ pa_hook_slot_free(creator->card_put_slot); ++ ++ if (creator->devices) ++ pa_hashmap_free(creator->devices); ++ ++ pa_xfree(creator); ++} +diff --git a/src/modules/volume-api/device-creator.h b/src/modules/volume-api/device-creator.h +new file mode 100644 +index 0000000..bcec8d9 +--- /dev/null ++++ b/src/modules/volume-api/device-creator.h +@@ -0,0 +1,32 @@ ++#ifndef foodevicecreatorhfoo ++#define foodevicecreatorhfoo ++ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#include <modules/volume-api/volume-api.h> ++ ++typedef struct pa_device_creator pa_device_creator; ++ ++pa_device_creator *pa_device_creator_new(pa_volume_api *api); ++void pa_device_creator_free(pa_device_creator *creator); ++ ++#endif +diff --git a/src/modules/volume-api/device.c b/src/modules/volume-api/device.c +new file mode 100644 +index 0000000..ea496ba +--- /dev/null ++++ b/src/modules/volume-api/device.c +@@ -0,0 +1,293 @@ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#ifdef HAVE_CONFIG_H ++#include <config.h> ++#endif ++ ++#include "device.h" ++ ++#include <modules/volume-api/mute-control.h> ++#include <modules/volume-api/volume-control.h> ++ ++#include <pulse/direction.h> ++ ++#include <pulsecore/core-util.h> ++ ++pa_device *pa_device_new(pa_volume_api *api, const char *name, const char *description, pa_direction_t direction, ++ const char * const *device_types, unsigned n_device_types) { ++ pa_device *device; ++ unsigned i; ++ ++ pa_assert(api); ++ pa_assert(name); ++ pa_assert(description); ++ pa_assert(device_types || n_device_types == 0); ++ ++ device = pa_xnew0(pa_device, 1); ++ device->volume_api = api; ++ device->index = pa_volume_api_allocate_device_index(api); ++ pa_assert_se(pa_volume_api_register_name(api, name, false, &device->name) >= 0); ++ device->description = pa_xstrdup(description); ++ device->direction = direction; ++ device->device_types = pa_dynarray_new(pa_xfree); ++ ++ for (i = 0; i < n_device_types; i++) ++ pa_dynarray_append(device->device_types, pa_xstrdup(device_types[i])); ++ ++ device->proplist = pa_proplist_new(); ++ device->use_default_volume_control = true; ++ device->use_default_mute_control = true; ++ ++ return device; ++} ++ ++void pa_device_put(pa_device *device, pa_volume_control *default_volume_control, pa_mute_control *default_mute_control) { ++ char *device_types_str; ++ const char *prop_key; ++ void *state = NULL; ++ ++ pa_assert(device); ++ ++ if (default_volume_control) { ++ device->default_volume_control = default_volume_control; ++ pa_volume_control_add_default_for_device(default_volume_control, device); ++ ++ device->volume_control = default_volume_control; ++ pa_volume_control_add_device(default_volume_control, device); ++ } ++ ++ if (default_mute_control) { ++ device->default_mute_control = default_mute_control; ++ pa_mute_control_add_default_for_device(default_mute_control, device); ++ ++ device->mute_control = default_mute_control; ++ pa_mute_control_add_device(default_mute_control, device); ++ } ++ ++ pa_volume_api_add_device(device->volume_api, device); ++ ++ device->linked = true; ++ ++ device_types_str = pa_join((const char * const *) pa_dynarray_get_raw_array(device->device_types), ++ pa_dynarray_size(device->device_types), ", "); ++ ++ pa_log_debug("Created device #%u.", device->index); ++ pa_log_debug(" Name: %s", device->name); ++ pa_log_debug(" Description: %s", device->description); ++ pa_log_debug(" Direction: %s", pa_direction_to_string(device->direction)); ++ pa_log_debug(" Device Types: %s", *device_types_str ? device_types_str : "(none)"); ++ pa_log_debug(" Volume control: %s", device->volume_control ? device->volume_control->name : "(unset)"); ++ pa_log_debug(" Mute control: %s", device->mute_control ? device->mute_control->name : "(unset)"); ++ pa_log_debug(" Properties:"); ++ ++ while ((prop_key = pa_proplist_iterate(device->proplist, &state))) ++ pa_log_debug(" %s = %s", prop_key, pa_strnull(pa_proplist_gets(device->proplist, prop_key))); ++ ++ pa_xfree(device_types_str); ++ ++ pa_hook_fire(&device->volume_api->hooks[PA_VOLUME_API_HOOK_DEVICE_PUT], device); ++} ++ ++void pa_device_unlink(pa_device *device) { ++ pa_assert(device); ++ ++ if (device->unlinked) { ++ pa_log_debug("Unlinking device %s (already unlinked, this is a no-op).", device->name); ++ return; ++ } ++ ++ device->unlinked = true; ++ ++ pa_log_debug("Unlinking device %s.", device->name); ++ ++ if (device->linked) ++ pa_hook_fire(&device->volume_api->hooks[PA_VOLUME_API_HOOK_DEVICE_UNLINK], device); ++ ++ pa_volume_api_remove_device(device->volume_api, device); ++ ++ if (device->mute_control) { ++ pa_mute_control_remove_device(device->mute_control, device); ++ device->mute_control = NULL; ++ } ++ ++ if (device->default_mute_control) { ++ pa_mute_control_remove_default_for_device(device->default_mute_control, device); ++ device->default_mute_control = NULL; ++ } ++ ++ if (device->volume_control) { ++ pa_volume_control_remove_device(device->volume_control, device); ++ device->volume_control = NULL; ++ } ++ ++ if (device->default_volume_control) { ++ pa_volume_control_remove_default_for_device(device->default_volume_control, device); ++ device->default_volume_control = NULL; ++ } ++} ++ ++void pa_device_free(pa_device *device) { ++ pa_assert(device); ++ ++ if (!device->unlinked) ++ pa_device_unlink(device); ++ ++ if (device->proplist) ++ pa_proplist_free(device->proplist); ++ ++ if (device->device_types) ++ pa_dynarray_free(device->device_types); ++ ++ pa_xfree(device->description); ++ ++ if (device->name) ++ pa_volume_api_unregister_name(device->volume_api, device->name); ++ ++ pa_xfree(device); ++} ++ ++static void set_volume_control_internal(pa_device *device, pa_volume_control *control) { ++ pa_volume_control *old_control; ++ ++ pa_assert(device); ++ ++ old_control = device->volume_control; ++ ++ if (control == old_control) ++ return; ++ ++ if (old_control) ++ pa_volume_control_remove_device(old_control, device); ++ ++ device->volume_control = control; ++ ++ if (control) ++ pa_volume_control_add_device(control, device); ++ ++ if (!device->linked || device->unlinked) ++ return; ++ ++ pa_log_debug("The volume control of device %s changed from %s to %s.", device->name, ++ old_control ? old_control->name : "(unset)", control ? control->name : "(unset)"); ++ ++ pa_hook_fire(&device->volume_api->hooks[PA_VOLUME_API_HOOK_DEVICE_VOLUME_CONTROL_CHANGED], device); ++} ++ ++void pa_device_set_volume_control(pa_device *device, pa_volume_control *control) { ++ pa_assert(device); ++ ++ device->use_default_volume_control = false; ++ set_volume_control_internal(device, control); ++} ++ ++static void set_mute_control_internal(pa_device *device, pa_mute_control *control) { ++ pa_mute_control *old_control; ++ ++ pa_assert(device); ++ ++ old_control = device->mute_control; ++ ++ if (control == old_control) ++ return; ++ ++ if (old_control) ++ pa_mute_control_remove_device(old_control, device); ++ ++ device->mute_control = control; ++ ++ if (control) ++ pa_mute_control_add_device(control, device); ++ ++ pa_log_debug("The mute control of device %s changed from %s to %s.", device->name, ++ old_control ? old_control->name : "(unset)", control ? control->name : "(unset)"); ++ ++ pa_hook_fire(&device->volume_api->hooks[PA_VOLUME_API_HOOK_DEVICE_MUTE_CONTROL_CHANGED], device); ++} ++ ++void pa_device_set_mute_control(pa_device *device, pa_mute_control *control) { ++ pa_assert(device); ++ ++ device->use_default_mute_control = false; ++ set_mute_control_internal(device, control); ++} ++ ++void pa_device_description_changed(pa_device *device, const char *new_description) { ++ char *old_description; ++ ++ pa_assert(device); ++ pa_assert(new_description); ++ ++ old_description = device->description; ++ ++ if (pa_streq(new_description, old_description)) ++ return; ++ ++ device->description = pa_xstrdup(new_description); ++ pa_log_debug("The description of device %s changed from \"%s\" to \"%s\".", device->name, old_description, ++ new_description); ++ pa_xfree(old_description); ++ pa_hook_fire(&device->volume_api->hooks[PA_VOLUME_API_HOOK_DEVICE_DESCRIPTION_CHANGED], device); ++} ++ ++void pa_device_set_default_volume_control(pa_device *device, pa_volume_control *control) { ++ pa_volume_control *old_control; ++ ++ pa_assert(device); ++ ++ old_control = device->default_volume_control; ++ ++ if (control == old_control) ++ return; ++ ++ if (old_control) ++ pa_volume_control_remove_default_for_device(old_control, device); ++ ++ device->default_volume_control = control; ++ ++ if (control) ++ pa_volume_control_add_default_for_device(control, device); ++ ++ if (device->use_default_volume_control) ++ set_volume_control_internal(device, control); ++} ++ ++void pa_device_set_default_mute_control(pa_device *device, pa_mute_control *control) { ++ pa_mute_control *old_control; ++ ++ pa_assert(device); ++ ++ old_control = device->default_mute_control; ++ ++ if (control == old_control) ++ return; ++ ++ if (old_control) ++ pa_mute_control_remove_default_for_device(old_control, device); ++ ++ device->default_mute_control = control; ++ ++ if (control) ++ pa_mute_control_add_default_for_device(control, device); ++ ++ if (device->use_default_mute_control) ++ set_mute_control_internal(device, control); ++} +diff --git a/src/modules/volume-api/device.h b/src/modules/volume-api/device.h +new file mode 100644 +index 0000000..9eac7e9 +--- /dev/null ++++ b/src/modules/volume-api/device.h +@@ -0,0 +1,76 @@ ++#ifndef foodevicehfoo ++#define foodevicehfoo ++ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#include <modules/volume-api/volume-api.h> ++ ++#include <pulsecore/dynarray.h> ++ ++typedef struct pa_device pa_device; ++ ++struct pa_device { ++ pa_volume_api *volume_api; ++ uint32_t index; ++ const char *name; ++ char *description; ++ pa_direction_t direction; ++ pa_dynarray *device_types; ++ pa_proplist *proplist; ++ pa_volume_control *volume_control; ++ pa_mute_control *mute_control; ++ ++ /* The device implementation can provide default volume and mute controls, ++ * which are used in case there's no policy module that wants to override ++ * the defaults. */ ++ pa_volume_control *default_volume_control; ++ bool use_default_volume_control; ++ pa_mute_control *default_mute_control; ++ bool use_default_mute_control; ++ ++ bool linked; ++ bool unlinked; ++}; ++ ++pa_device *pa_device_new(pa_volume_api *api, const char *name, const char *description, pa_direction_t direction, ++ const char * const *device_types, unsigned n_device_types); ++void pa_device_put(pa_device *device, pa_volume_control *default_volume_control, pa_mute_control *default_mute_control); ++void pa_device_unlink(pa_device *device); ++void pa_device_free(pa_device *device); ++ ++/* Called by policy modules. */ ++void pa_device_set_volume_control(pa_device *device, pa_volume_control *control); ++void pa_device_set_mute_control(pa_device *device, pa_mute_control *control); ++ ++/* Called by policy modules. Note that pa_device_set_volume_control() and ++ * pa_device_set_mute_control() automatically disable the corresponding ++ * use_default flags, so these functions are mainly useful for re-enabling the ++ * flags. */ ++void pa_device_set_use_default_volume_control(pa_device *device, bool use); ++void pa_device_set_use_default_mute_control(pa_device *device, bool use); ++ ++/* Called by the device implementation. */ ++void pa_device_description_changed(pa_device *device, const char *new_description); ++void pa_device_set_default_volume_control(pa_device *device, pa_volume_control *control); ++void pa_device_set_default_mute_control(pa_device *device, pa_mute_control *control); ++ ++#endif +diff --git a/src/modules/volume-api/mute-control.c b/src/modules/volume-api/mute-control.c +new file mode 100644 +index 0000000..adc008e +--- /dev/null ++++ b/src/modules/volume-api/mute-control.c +@@ -0,0 +1,306 @@ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#ifdef HAVE_CONFIG_H ++#include <config.h> ++#endif ++ ++#include "mute-control.h" ++ ++#include <modules/volume-api/audio-group.h> ++#include <modules/volume-api/device.h> ++#include <modules/volume-api/sstream.h> ++ ++#include <pulsecore/core-util.h> ++ ++pa_mute_control *pa_mute_control_new(pa_volume_api *api, const char *name, const char *description) { ++ pa_mute_control *control; ++ ++ pa_assert(api); ++ pa_assert(name); ++ pa_assert(description); ++ ++ control = pa_xnew0(pa_mute_control, 1); ++ control->volume_api = api; ++ control->index = pa_volume_api_allocate_mute_control_index(api); ++ pa_assert_se(pa_volume_api_register_name(api, name, false, &control->name) >= 0); ++ control->description = pa_xstrdup(description); ++ control->proplist = pa_proplist_new(); ++ control->devices = pa_hashmap_new(NULL, NULL); ++ control->default_for_devices = pa_hashmap_new(NULL, NULL); ++ control->streams = pa_hashmap_new(NULL, NULL); ++ control->audio_groups = pa_hashmap_new(NULL, NULL); ++ ++ return control; ++} ++ ++void pa_mute_control_put(pa_mute_control *control, bool initial_mute, bool initial_mute_is_set, ++ pa_mute_control_set_initial_mute_cb_t set_initial_mute_cb) { ++ const char *prop_key; ++ void *state = NULL; ++ ++ pa_assert(control); ++ pa_assert(initial_mute_is_set || control->set_mute); ++ pa_assert(set_initial_mute_cb || !control->set_mute); ++ ++ if (initial_mute_is_set) ++ control->mute = initial_mute; ++ else ++ control->mute = false; ++ ++ if (set_initial_mute_cb) ++ set_initial_mute_cb(control); ++ ++ pa_volume_api_add_mute_control(control->volume_api, control); ++ ++ control->linked = true; ++ ++ pa_log_debug("Created mute control #%u.", control->index); ++ pa_log_debug(" Name: %s", control->name); ++ pa_log_debug(" Description: %s", control->description); ++ pa_log_debug(" Mute: %s", pa_yes_no(control->mute)); ++ pa_log_debug(" Properties:"); ++ ++ while ((prop_key = pa_proplist_iterate(control->proplist, &state))) ++ pa_log_debug(" %s = %s", prop_key, pa_strnull(pa_proplist_gets(control->proplist, prop_key))); ++ ++ pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_PUT], control); ++} ++ ++void pa_mute_control_unlink(pa_mute_control *control) { ++ pa_audio_group *group; ++ pa_device *device; ++ pas_stream *stream; ++ ++ pa_assert(control); ++ ++ if (control->unlinked) { ++ pa_log_debug("Unlinking mute control %s (already unlinked, this is a no-op).", control->name); ++ return; ++ } ++ ++ control->unlinked = true; ++ ++ pa_log_debug("Unlinking mute control %s.", control->name); ++ ++ if (control->linked) ++ pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_UNLINK], control); ++ ++ pa_volume_api_remove_mute_control(control->volume_api, control); ++ ++ while ((group = pa_hashmap_first(control->audio_groups))) ++ pa_audio_group_set_mute_control(group, NULL); ++ ++ while ((stream = pa_hashmap_first(control->streams))) ++ pas_stream_set_mute_control(stream, NULL); ++ ++ while ((device = pa_hashmap_first(control->default_for_devices))) ++ pa_device_set_default_mute_control(device, NULL); ++ ++ while ((device = pa_hashmap_first(control->devices))) { ++ /* Why do we have this assertion here? The concern is that if we call ++ * pa_device_set_mute_control() for some device that has the ++ * use_default_mute_control flag set, then that flag will be unset as ++ * a side effect, and we don't want that side effect. This assertion ++ * should be safe, because we just called ++ * pa_device_set_default_mute_control(NULL) for each device that this ++ * control was the default for, and that should ensure that we don't ++ * any more hold any references to devices that used to use this ++ * control as the default. */ ++ pa_assert(!device->use_default_mute_control); ++ pa_device_set_mute_control(device, NULL); ++ } ++} ++ ++void pa_mute_control_free(pa_mute_control *control) { ++ pa_assert(control); ++ ++ if (!control->unlinked) ++ pa_mute_control_unlink(control); ++ ++ if (control->audio_groups) { ++ pa_assert(pa_hashmap_isempty(control->audio_groups)); ++ pa_hashmap_free(control->audio_groups); ++ } ++ ++ if (control->streams) { ++ pa_assert(pa_hashmap_isempty(control->streams)); ++ pa_hashmap_free(control->streams); ++ } ++ ++ if (control->default_for_devices) { ++ pa_assert(pa_hashmap_isempty(control->default_for_devices)); ++ pa_hashmap_free(control->default_for_devices); ++ } ++ ++ if (control->devices) { ++ pa_assert(pa_hashmap_isempty(control->devices)); ++ pa_hashmap_free(control->devices); ++ } ++ ++ if (control->proplist) ++ pa_proplist_free(control->proplist); ++ ++ pa_xfree(control->description); ++ ++ if (control->name) ++ pa_volume_api_unregister_name(control->volume_api, control->name); ++ ++ pa_xfree(control); ++} ++ ++void pa_mute_control_set_owner_audio_group(pa_mute_control *control, pa_audio_group *group) { ++ pa_assert(control); ++ pa_assert(group); ++ ++ control->owner_audio_group = group; ++} ++ ++static void set_mute_internal(pa_mute_control *control, bool mute) { ++ bool old_mute; ++ ++ pa_assert(control); ++ ++ old_mute = control->mute; ++ ++ if (mute == old_mute) ++ return; ++ ++ control->mute = mute; ++ ++ if (!control->linked || control->unlinked) ++ return; ++ ++ pa_log_debug("The mute of mute control %s changed from %s to %s.", control->name, pa_yes_no(old_mute), ++ pa_yes_no(control->mute)); ++ ++ pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_MUTE_CHANGED], control); ++} ++ ++int pa_mute_control_set_mute(pa_mute_control *control, bool mute) { ++ int r; ++ ++ pa_assert(control); ++ ++ if (!control->set_mute) { ++ pa_log_info("Tried to set the mute of mute control %s, but the mute control doesn't support the operation.", ++ control->name); ++ return -PA_ERR_NOTSUPPORTED; ++ } ++ ++ if (mute == control->mute) ++ return 0; ++ ++ control->set_mute_in_progress = true; ++ r = control->set_mute(control, mute); ++ control->set_mute_in_progress = false; ++ ++ if (r >= 0) ++ set_mute_internal(control, mute); ++ ++ return r; ++} ++ ++void pa_mute_control_description_changed(pa_mute_control *control, const char *new_description) { ++ char *old_description; ++ ++ pa_assert(control); ++ pa_assert(new_description); ++ ++ old_description = control->description; ++ ++ if (pa_streq(new_description, old_description)) ++ return; ++ ++ control->description = pa_xstrdup(new_description); ++ pa_log_debug("The description of mute control %s changed from \"%s\" to \"%s\".", control->name, old_description, ++ new_description); ++ pa_xfree(old_description); ++ pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_MUTE_CONTROL_DESCRIPTION_CHANGED], control); ++} ++ ++void pa_mute_control_mute_changed(pa_mute_control *control, bool new_mute) { ++ pa_assert(control); ++ ++ if (!control->linked) ++ return; ++ ++ if (control->set_mute_in_progress) ++ return; ++ ++ set_mute_internal(control, new_mute); ++} ++ ++void pa_mute_control_add_device(pa_mute_control *control, pa_device *device) { ++ pa_assert(control); ++ pa_assert(device); ++ ++ pa_assert_se(pa_hashmap_put(control->devices, device, device) >= 0); ++} ++ ++void pa_mute_control_remove_device(pa_mute_control *control, pa_device *device) { ++ pa_assert(control); ++ pa_assert(device); ++ ++ pa_assert_se(pa_hashmap_remove(control->devices, device)); ++} ++ ++void pa_mute_control_add_default_for_device(pa_mute_control *control, pa_device *device) { ++ pa_assert(control); ++ pa_assert(device); ++ ++ pa_assert_se(pa_hashmap_put(control->default_for_devices, device, device) >= 0); ++} ++ ++void pa_mute_control_remove_default_for_device(pa_mute_control *control, pa_device *device) { ++ pa_assert(control); ++ pa_assert(device); ++ ++ pa_assert_se(pa_hashmap_remove(control->default_for_devices, device)); ++} ++ ++void pa_mute_control_add_stream(pa_mute_control *control, pas_stream *stream) { ++ pa_assert(control); ++ pa_assert(stream); ++ ++ pa_assert_se(pa_hashmap_put(control->streams, stream, stream) >= 0); ++} ++ ++void pa_mute_control_remove_stream(pa_mute_control *control, pas_stream *stream) { ++ pa_assert(control); ++ pa_assert(stream); ++ ++ pa_assert_se(pa_hashmap_remove(control->streams, stream)); ++} ++ ++void pa_mute_control_add_audio_group(pa_mute_control *control, pa_audio_group *group) { ++ pa_assert(control); ++ pa_assert(group); ++ ++ pa_assert_se(pa_hashmap_put(control->audio_groups, group, group) >= 0); ++} ++ ++void pa_mute_control_remove_audio_group(pa_mute_control *control, pa_audio_group *group) { ++ pa_assert(control); ++ pa_assert(group); ++ ++ pa_assert_se(pa_hashmap_remove(control->audio_groups, group)); ++} +diff --git a/src/modules/volume-api/mute-control.h b/src/modules/volume-api/mute-control.h +new file mode 100644 +index 0000000..1f70a43 +--- /dev/null ++++ b/src/modules/volume-api/mute-control.h +@@ -0,0 +1,102 @@ ++#ifndef foomutecontrolhfoo ++#define foomutecontrolhfoo ++ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#include <modules/volume-api/volume-api.h> ++ ++typedef struct pa_mute_control pa_mute_control; ++ ++struct pa_mute_control { ++ pa_volume_api *volume_api; ++ uint32_t index; ++ const char *name; ++ char *description; ++ pa_proplist *proplist; ++ bool mute; ++ ++ /* If this mute control is the "own mute control" of an audio group, this ++ * is set to point to that group, otherwise this is NULL. */ ++ pa_audio_group *owner_audio_group; ++ ++ pa_hashmap *devices; /* pa_device -> pa_device (hashmap-as-a-set) */ ++ pa_hashmap *default_for_devices; /* pa_device -> pa_device (hashmap-as-a-set) */ ++ pa_hashmap *streams; /* pas_stream -> pas_stream (hashmap-as-a-set) */ ++ pa_hashmap *audio_groups; /* pa_audio_group -> pa_audio_group (hashmap-as-a-set) */ ++ ++ bool linked; ++ bool unlinked; ++ bool set_mute_in_progress; ++ ++ /* Called from pa_mute_control_set_mute(). The implementation is expected ++ * to return a negative error code on failure. May be NULL, if the mute ++ * control is read-only. */ ++ int (*set_mute)(pa_mute_control *control, bool mute); ++ ++ void *userdata; ++}; ++ ++pa_mute_control *pa_mute_control_new(pa_volume_api *api, const char *name, const char *description); ++ ++typedef void (*pa_mute_control_set_initial_mute_cb_t)(pa_mute_control *control); ++ ++/* initial_mute is the preferred initial mute of the mute control ++ * implementation. It may be unset, if the implementation doesn't care about ++ * the initial state of the mute control. Read-only mute controls, however, ++ * must always set initial_mute. ++ * ++ * The implementation's initial mute preference may be overridden by policy, if ++ * the mute control isn't read-only. When the final initial mute is known, the ++ * the implementation is notified via set_initial_mute_cb (the mute can be read ++ * from control->mute). set_initial_mute_cb may be NULL, if the mute control is ++ * read-only. */ ++void pa_mute_control_put(pa_mute_control *control, bool initial_mute, bool initial_mute_is_set, ++ pa_mute_control_set_initial_mute_cb_t set_initial_mute_cb); ++ ++void pa_mute_control_unlink(pa_mute_control *control); ++void pa_mute_control_free(pa_mute_control *control); ++ ++/* Called by audio-group.c only. */ ++void pa_mute_control_set_owner_audio_group(pa_mute_control *control, pa_audio_group *group); ++ ++/* Called by clients and policy modules. */ ++int pa_mute_control_set_mute(pa_mute_control *control, bool mute); ++ ++/* Called by the mute control implementation. */ ++void pa_mute_control_description_changed(pa_mute_control *control, const char *new_description); ++void pa_mute_control_mute_changed(pa_mute_control *control, bool new_mute); ++ ++/* Called from device.c only. */ ++void pa_mute_control_add_device(pa_mute_control *control, pa_device *device); ++void pa_mute_control_remove_device(pa_mute_control *control, pa_device *device); ++void pa_mute_control_add_default_for_device(pa_mute_control *control, pa_device *device); ++void pa_mute_control_remove_default_for_device(pa_mute_control *control, pa_device *device); ++ ++/* Called from sstream.c only. */ ++void pa_mute_control_add_stream(pa_mute_control *control, pas_stream *stream); ++void pa_mute_control_remove_stream(pa_mute_control *control, pas_stream *stream); ++ ++/* Called from audio-group.c only. */ ++void pa_mute_control_add_audio_group(pa_mute_control *control, pa_audio_group *group); ++void pa_mute_control_remove_audio_group(pa_mute_control *control, pa_audio_group *group); ++ ++#endif +diff --git a/src/modules/volume-api/sstream.c b/src/modules/volume-api/sstream.c +new file mode 100644 +index 0000000..e3531a8 +--- /dev/null ++++ b/src/modules/volume-api/sstream.c +@@ -0,0 +1,366 @@ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#ifdef HAVE_CONFIG_H ++#include <config.h> ++#endif ++ ++#include "sstream.h" ++ ++#include <modules/volume-api/audio-group.h> ++#include <modules/volume-api/binding.h> ++#include <modules/volume-api/mute-control.h> ++#include <modules/volume-api/volume-control.h> ++ ++#include <pulse/direction.h> ++ ++#include <pulsecore/core-util.h> ++ ++pas_stream *pas_stream_new(pa_volume_api *api, const char *name, const char *description, pa_direction_t direction) { ++ pas_stream *stream; ++ ++ pa_assert(api); ++ pa_assert(name); ++ pa_assert(description); ++ ++ stream = pa_xnew0(pas_stream, 1); ++ stream->volume_api = api; ++ stream->index = pa_volume_api_allocate_stream_index(api); ++ pa_assert_se(pa_volume_api_register_name(api, name, false, &stream->name) >= 0); ++ stream->description = pa_xstrdup(description); ++ stream->direction = direction; ++ stream->proplist = pa_proplist_new(); ++ stream->use_default_volume_control = true; ++ stream->use_default_mute_control = true; ++ ++ return stream; ++} ++ ++static void set_volume_control_internal(pas_stream *stream, pa_volume_control *control) { ++ pa_volume_control *old_control; ++ ++ pa_assert(stream); ++ ++ old_control = stream->volume_control; ++ ++ if (control == old_control) ++ return; ++ ++ if (old_control) { ++ /* If the old control pointed to the own volume control of an audio ++ * group, then the stream's audio group for volume needs to be ++ * updated. We set it to NULL here, and if it should be non-NULL, that ++ * will be fixed very soon (a few lines down). */ ++ pas_stream_set_audio_group_for_volume(stream, NULL); ++ ++ pa_volume_control_remove_stream(old_control, stream); ++ } ++ ++ stream->volume_control = control; ++ ++ if (control) { ++ pa_volume_control_add_stream(control, stream); ++ pas_stream_set_audio_group_for_volume(stream, control->owner_audio_group); ++ } ++ ++ if (!stream->linked || stream->unlinked) ++ return; ++ ++ pa_log_debug("The volume control of stream %s changed from %s to %s.", stream->name, ++ old_control ? old_control->name : "(unset)", control ? control->name : "(unset)"); ++ ++ pa_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_VOLUME_CONTROL_CHANGED], stream); ++} ++ ++static void set_mute_control_internal(pas_stream *stream, pa_mute_control *control) { ++ pa_mute_control *old_control; ++ ++ pa_assert(stream); ++ ++ old_control = stream->mute_control; ++ ++ if (control == old_control) ++ return; ++ ++ if (old_control) { ++ /* If the old control pointed to the own mute control of an audio ++ * group, then the stream's audio group for mute needs to be updated. ++ * We set it to NULL here, and if it should be non-NULL, that will be ++ * fixed very soon (a few lines down). */ ++ pas_stream_set_audio_group_for_mute(stream, NULL); ++ ++ pa_mute_control_remove_stream(old_control, stream); ++ } ++ ++ stream->mute_control = control; ++ ++ if (control) { ++ pa_mute_control_add_stream(control, stream); ++ pas_stream_set_audio_group_for_mute(stream, control->owner_audio_group); ++ } ++ ++ if (!stream->linked || stream->unlinked) ++ return; ++ ++ pa_log_debug("The mute control of stream %s changed from %s to %s.", stream->name, ++ old_control ? old_control->name : "(unset)", control ? control->name : "(unset)"); ++ ++ pa_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_MUTE_CONTROL_CHANGED], stream); ++} ++ ++void pas_stream_put(pas_stream *stream, pa_proplist *initial_properties) { ++ const char *prop_key; ++ void *state = NULL; ++ ++ pa_assert(stream); ++ pa_assert(!stream->create_own_volume_control || stream->delete_own_volume_control); ++ pa_assert(!stream->create_own_mute_control || stream->delete_own_mute_control); ++ ++ if (initial_properties) ++ pa_proplist_update(stream->proplist, PA_UPDATE_REPLACE, initial_properties); ++ ++ pa_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_SET_INITIAL_VOLUME_CONTROL], stream); ++ ++ if (stream->use_default_volume_control) ++ set_volume_control_internal(stream, stream->own_volume_control); ++ ++ pa_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_SET_INITIAL_MUTE_CONTROL], stream); ++ ++ if (stream->use_default_mute_control) ++ set_mute_control_internal(stream, stream->own_mute_control); ++ ++ pa_volume_api_add_stream(stream->volume_api, stream); ++ ++ stream->linked = true; ++ ++ pa_log_debug("Created stream #%u.", stream->index); ++ pa_log_debug(" Name: %s", stream->name); ++ pa_log_debug(" Description: %s", stream->description); ++ pa_log_debug(" Direction: %s", pa_direction_to_string(stream->direction)); ++ pa_log_debug(" Volume control: %s", stream->volume_control ? stream->volume_control->name : "(unset)"); ++ pa_log_debug(" Mute control: %s", stream->mute_control ? stream->mute_control->name : "(unset)"); ++ pa_log_debug(" Properties:"); ++ ++ while ((prop_key = pa_proplist_iterate(stream->proplist, &state))) ++ pa_log_debug(" %s = %s", prop_key, pa_strnull(pa_proplist_gets(stream->proplist, prop_key))); ++ ++ pa_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_PUT], stream); ++} ++ ++void pas_stream_unlink(pas_stream *stream) { ++ pa_assert(stream); ++ ++ if (stream->unlinked) { ++ pa_log_debug("Unlinking stream %s (already unlinked, this is a no-op).", stream->name); ++ return; ++ } ++ ++ stream->unlinked = true; ++ ++ pa_log_debug("Unlinking stream %s.", stream->name); ++ ++ if (stream->linked) ++ pa_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_UNLINK], stream); ++ ++ pa_volume_api_remove_stream(stream->volume_api, stream); ++ ++ pas_stream_set_audio_group_for_mute(stream, NULL); ++ pas_stream_set_audio_group_for_volume(stream, NULL); ++ pas_stream_set_mute_control(stream, NULL); ++ pas_stream_set_volume_control(stream, NULL); ++ pas_stream_set_have_own_mute_control(stream, false); ++ pas_stream_set_have_own_volume_control(stream, false); ++} ++ ++void pas_stream_free(pas_stream *stream) { ++ pa_assert(stream); ++ ++ if (!stream->unlinked) ++ pas_stream_unlink(stream); ++ ++ if (stream->proplist) ++ pa_proplist_free(stream->proplist); ++ ++ pa_xfree(stream->description); ++ ++ if (stream->name) ++ pa_volume_api_unregister_name(stream->volume_api, stream->name); ++ ++ pa_xfree(stream); ++} ++ ++int pas_stream_set_have_own_volume_control(pas_stream *stream, bool have) { ++ pa_assert(stream); ++ ++ if (have == stream->have_own_volume_control) ++ return 0; ++ ++ if (have) { ++ pa_assert(!stream->own_volume_control); ++ ++ if (!stream->create_own_volume_control) { ++ pa_log_debug("Stream %s doesn't support own volume control.", stream->name); ++ return -PA_ERR_NOTSUPPORTED; ++ } ++ ++ stream->own_volume_control = stream->create_own_volume_control(stream); ++ } else { ++ stream->delete_own_volume_control(stream); ++ stream->own_volume_control = NULL; ++ } ++ ++ stream->have_own_volume_control = have; ++ ++ return 0; ++} ++ ++int pas_stream_set_have_own_mute_control(pas_stream *stream, bool have) { ++ pa_assert(stream); ++ ++ if (have == stream->have_own_mute_control) ++ return 0; ++ ++ if (have) { ++ pa_assert(!stream->own_mute_control); ++ ++ if (!stream->create_own_mute_control) { ++ pa_log_debug("Stream %s doesn't support own mute control.", stream->name); ++ return -PA_ERR_NOTSUPPORTED; ++ } ++ ++ stream->own_mute_control = stream->create_own_mute_control(stream); ++ } else { ++ stream->delete_own_mute_control(stream); ++ stream->own_mute_control = NULL; ++ } ++ ++ stream->have_own_mute_control = have; ++ ++ return 0; ++} ++ ++void pas_stream_set_volume_control(pas_stream *stream, pa_volume_control *control) { ++ pa_assert(stream); ++ ++ stream->use_default_volume_control = false; ++ ++ if (stream->volume_control_binding) { ++ pa_binding_free(stream->volume_control_binding); ++ stream->volume_control_binding = NULL; ++ } ++ ++ set_volume_control_internal(stream, control); ++} ++ ++void pas_stream_set_mute_control(pas_stream *stream, pa_mute_control *control) { ++ pa_assert(stream); ++ ++ stream->use_default_mute_control = false; ++ ++ if (stream->mute_control_binding) { ++ pa_binding_free(stream->mute_control_binding); ++ stream->mute_control_binding = NULL; ++ } ++ ++ set_mute_control_internal(stream, control); ++} ++ ++void pas_stream_bind_volume_control(pas_stream *stream, pa_binding_target_info *target_info) { ++ pa_binding_owner_info owner_info = { ++ .userdata = stream, ++ .set_value = (pa_binding_set_value_cb_t) set_volume_control_internal, ++ }; ++ ++ pa_assert(stream); ++ pa_assert(target_info); ++ ++ stream->use_default_volume_control = false; ++ ++ if (stream->volume_control_binding) ++ pa_binding_free(stream->volume_control_binding); ++ ++ stream->volume_control_binding = pa_binding_new(stream->volume_api, &owner_info, target_info); ++} ++ ++void pas_stream_bind_mute_control(pas_stream *stream, pa_binding_target_info *target_info) { ++ pa_binding_owner_info owner_info = { ++ .userdata = stream, ++ .set_value = (pa_binding_set_value_cb_t) set_mute_control_internal, ++ }; ++ ++ pa_assert(stream); ++ pa_assert(target_info); ++ ++ stream->use_default_mute_control = false; ++ ++ if (stream->mute_control_binding) ++ pa_binding_free(stream->mute_control_binding); ++ ++ stream->mute_control_binding = pa_binding_new(stream->volume_api, &owner_info, target_info); ++} ++ ++void pas_stream_description_changed(pas_stream *stream, const char *new_description) { ++ char *old_description; ++ ++ pa_assert(stream); ++ pa_assert(new_description); ++ ++ old_description = stream->description; ++ ++ if (pa_streq(new_description, old_description)) ++ return; ++ ++ stream->description = pa_xstrdup(new_description); ++ pa_log_debug("The description of stream %s changed from \"%s\" to \"%s\".", stream->name, old_description, ++ new_description); ++ pa_xfree(old_description); ++ pa_hook_fire(&stream->volume_api->hooks[PA_VOLUME_API_HOOK_STREAM_DESCRIPTION_CHANGED], stream); ++} ++ ++void pas_stream_set_audio_group_for_volume(pas_stream *stream, pa_audio_group *group) { ++ pa_assert(stream); ++ ++ if (group == stream->audio_group_for_volume) ++ return; ++ ++ if (stream->audio_group_for_volume) ++ pa_audio_group_remove_volume_stream(stream->audio_group_for_volume, stream); ++ ++ stream->audio_group_for_volume = group; ++ ++ if (group) ++ pa_audio_group_add_volume_stream(group, stream); ++} ++ ++void pas_stream_set_audio_group_for_mute(pas_stream *stream, pa_audio_group *group) { ++ pa_assert(stream); ++ ++ if (group == stream->audio_group_for_mute) ++ return; ++ ++ if (stream->audio_group_for_mute) ++ pa_audio_group_remove_mute_stream(stream->audio_group_for_mute, stream); ++ ++ stream->audio_group_for_mute = group; ++ ++ if (group) ++ pa_audio_group_add_mute_stream(group, stream); ++} +diff --git a/src/modules/volume-api/sstream.h b/src/modules/volume-api/sstream.h +new file mode 100644 +index 0000000..a65b34c +--- /dev/null ++++ b/src/modules/volume-api/sstream.h +@@ -0,0 +1,108 @@ ++#ifndef foosstreamhfoo ++#define foosstreamhfoo ++ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#include <modules/volume-api/volume-api.h> ++ ++/* We use the "pas_" prefix in pas_stream, because there's already pa_stream in ++ * the client API, and there's no good alternative term for streams. The 's' in ++ * "pas" means "server", i.e. the point is that this stuff is for servers, ++ * while pa_stream is for clients. */ ++ ++typedef struct pas_stream pas_stream; ++ ++struct pas_stream { ++ pa_volume_api *volume_api; ++ uint32_t index; ++ const char *name; ++ char *description; ++ pa_direction_t direction; ++ pa_proplist *proplist; ++ pa_volume_control *volume_control; ++ pa_mute_control *mute_control; ++ bool use_default_volume_control; ++ bool use_default_mute_control; ++ bool have_own_volume_control; ++ bool have_own_mute_control; ++ pa_volume_control *own_volume_control; ++ pa_mute_control *own_mute_control; ++ ++ pa_binding *volume_control_binding; ++ pa_binding *mute_control_binding; ++ pa_audio_group *audio_group_for_volume; ++ pa_audio_group *audio_group_for_mute; ++ ++ bool linked; ++ bool unlinked; ++ ++ /* Called when the own volume control is enabled. The callback ++ * implementation should return a new linked volume control object. The ++ * callback may be NULL, in which case the own volume control can't be ++ * enabled. */ ++ pa_volume_control *(*create_own_volume_control)(pas_stream *stream); ++ ++ /* Called when the own volume control is disabled. The implementation ++ * should free stream->own_volume_control. The callback may be NULL only if ++ * create_own_volume_control is NULL also. */ ++ void (*delete_own_volume_control)(pas_stream *stream); ++ ++ /* Called when the own mute control is enabled. The callback implementation ++ * should return a new linked mute control object. The callback may be ++ * NULL, in which case the own mute control can't be enabled. */ ++ pa_mute_control *(*create_own_mute_control)(pas_stream *stream); ++ ++ /* Called when the own mute control is disabled. The implementation should ++ * free stream->own_mute_control. The callback may be NULL only if ++ * create_own_mute_control is NULL also. */ ++ void (*delete_own_mute_control)(pas_stream *stream); ++ ++ void *userdata; ++}; ++ ++pas_stream *pas_stream_new(pa_volume_api *api, const char *name, const char *description, pa_direction_t direction); ++void pas_stream_put(pas_stream *stream, pa_proplist *initial_properties); ++void pas_stream_unlink(pas_stream *stream); ++void pas_stream_free(pas_stream *stream); ++ ++/* Called by the stream implementation and possibly by policy modules. ++ * Enabling own controls may fail (the stream may not support own controls), ++ * disabling will never fail. */ ++int pas_stream_set_have_own_volume_control(pas_stream *stream, bool have); ++int pas_stream_set_have_own_mute_control(pas_stream *stream, bool have); ++ ++/* Called by policy modules. */ ++void pas_stream_set_volume_control(pas_stream *stream, pa_volume_control *control); ++void pas_stream_set_mute_control(pas_stream *stream, pa_mute_control *control); ++void pas_stream_bind_volume_control(pas_stream *stream, pa_binding_target_info *target_info); ++void pas_stream_bind_mute_control(pas_stream *stream, pa_binding_target_info *target_info); ++ ++/* Called by the stream implementation. */ ++void pas_stream_description_changed(pas_stream *stream, const char *new_description); ++ ++/* Called by audio-group.c only. Adding a stream to an audio group happens ++ * implicitly when the volume or mute control of a stream is set to point to ++ * the own control of an audio group. */ ++void pas_stream_set_audio_group_for_volume(pas_stream *stream, pa_audio_group *group); ++void pas_stream_set_audio_group_for_mute(pas_stream *stream, pa_audio_group *group); ++ ++#endif +diff --git a/src/modules/volume-api/stream-creator.c b/src/modules/volume-api/stream-creator.c +new file mode 100644 +index 0000000..2bd0053 +--- /dev/null ++++ b/src/modules/volume-api/stream-creator.c +@@ -0,0 +1,691 @@ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#ifdef HAVE_CONFIG_H ++#include <config.h> ++#endif ++ ++#include "stream-creator.h" ++ ++#include <modules/volume-api/sstream.h> ++#include <modules/volume-api/mute-control.h> ++#include <modules/volume-api/volume-control.h> ++ ++#include <pulsecore/core-util.h> ++#include <pulsecore/i18n.h> ++ ++struct pa_stream_creator { ++ pa_volume_api *volume_api; ++ pa_hashmap *streams; /* pa_sink_input/pa_source_output -> struct stream */ ++ pa_hook_slot *sink_input_put_slot; ++ pa_hook_slot *sink_input_unlink_slot; ++ pa_hook_slot *source_output_put_slot; ++ pa_hook_slot *source_output_unlink_slot; ++}; ++ ++enum stream_type { ++ STREAM_TYPE_SINK_INPUT, ++ STREAM_TYPE_SOURCE_OUTPUT, ++}; ++ ++struct stream { ++ pa_stream_creator *creator; ++ enum stream_type type; ++ pa_sink_input *sink_input; ++ pa_source_output *source_output; ++ pa_client *client; ++ pas_stream *stream; ++ ++ bool unlinked; ++ ++ pa_hook_slot *proplist_changed_slot; ++ pa_hook_slot *client_proplist_changed_slot; ++ pa_hook_slot *volume_changed_slot; ++ pa_hook_slot *mute_changed_slot; ++}; ++ ++static char *get_stream_volume_and_mute_control_description_malloc(struct stream *stream) { ++ const char *application_name = NULL; ++ char *description; ++ ++ pa_assert(stream); ++ ++ if (stream->client) ++ application_name = pa_proplist_gets(stream->client->proplist, PA_PROP_APPLICATION_NAME); ++ ++ if (application_name) ++ description = pa_sprintf_malloc("%s: %s", application_name, stream->stream->description); ++ else ++ description = pa_xstrdup(stream->stream->description); ++ ++ return description; ++} ++ ++static int volume_control_set_volume_cb(pa_volume_control *control, const pa_bvolume *volume, bool set_volume, bool set_balance) { ++ struct stream *stream; ++ pa_bvolume bvolume; ++ pa_cvolume cvolume; ++ ++ pa_assert(control); ++ pa_assert(volume); ++ ++ stream = control->userdata; ++ ++ switch (stream->type) { ++ case STREAM_TYPE_SINK_INPUT: ++ pa_bvolume_from_cvolume(&bvolume, &stream->sink_input->volume, &stream->sink_input->channel_map); ++ break; ++ ++ case STREAM_TYPE_SOURCE_OUTPUT: ++ pa_bvolume_from_cvolume(&bvolume, &stream->source_output->volume, &stream->source_output->channel_map); ++ break; ++ } ++ ++ if (set_volume) ++ bvolume.volume = volume->volume; ++ ++ if (set_balance) ++ pa_bvolume_copy_balance(&bvolume, volume); ++ ++ pa_bvolume_to_cvolume(&bvolume, &cvolume); ++ ++ switch (stream->type) { ++ case STREAM_TYPE_SINK_INPUT: ++ pa_sink_input_set_volume(stream->sink_input, &cvolume, true, true); ++ break; ++ ++ case STREAM_TYPE_SOURCE_OUTPUT: ++ pa_source_output_set_volume(stream->source_output, &cvolume, true, true); ++ break; ++ } ++ ++ return 0; ++} ++ ++static pa_hook_result_t sink_input_or_source_output_volume_changed_cb(void *hook_data, void *call_data, void *userdata) { ++ struct stream *stream = userdata; ++ pa_sink_input *input = NULL; ++ pa_source_output *output = NULL; ++ pa_bvolume bvolume; ++ ++ pa_assert(stream); ++ pa_assert(call_data); ++ ++ switch (stream->type) { ++ case STREAM_TYPE_SINK_INPUT: ++ input = call_data; ++ break; ++ ++ case STREAM_TYPE_SOURCE_OUTPUT: ++ output = call_data; ++ break; ++ } ++ ++ if ((input && input != stream->sink_input) || (output && output != stream->source_output)) ++ return PA_HOOK_OK; ++ ++ if (input) ++ pa_bvolume_from_cvolume(&bvolume, &input->volume, &input->channel_map); ++ else ++ pa_bvolume_from_cvolume(&bvolume, &output->volume, &output->channel_map); ++ ++ pa_volume_control_volume_changed(stream->stream->own_volume_control, &bvolume, true, true); ++ ++ return PA_HOOK_OK; ++} ++ ++static void volume_control_set_initial_volume_cb(pa_volume_control *control) { ++ struct stream *stream; ++ pa_cvolume cvolume; ++ ++ pa_assert(control); ++ ++ stream = control->userdata; ++ pa_bvolume_to_cvolume(&control->volume, &cvolume); ++ ++ switch (stream->type) { ++ case STREAM_TYPE_SINK_INPUT: ++ pa_sink_input_set_volume(stream->sink_input, &cvolume, true, true); ++ break; ++ ++ case STREAM_TYPE_SOURCE_OUTPUT: ++ pa_source_output_set_volume(stream->source_output, &cvolume, true, true); ++ break; ++ } ++} ++ ++static int mute_control_set_mute_cb(pa_mute_control *control, bool mute) { ++ struct stream *stream; ++ ++ pa_assert(control); ++ ++ stream = control->userdata; ++ ++ switch (stream->type) { ++ case STREAM_TYPE_SINK_INPUT: ++ pa_sink_input_set_mute(stream->sink_input, mute, true); ++ break; ++ ++ case STREAM_TYPE_SOURCE_OUTPUT: ++ pa_source_output_set_mute(stream->source_output, mute, true); ++ break; ++ } ++ ++ return 0; ++} ++ ++static pa_hook_result_t sink_input_or_source_output_mute_changed_cb(void *hook_data, void *call_data, void *userdata) { ++ struct stream *stream = userdata; ++ pa_sink_input *input = NULL; ++ pa_source_output *output = NULL; ++ bool mute; ++ ++ pa_assert(stream); ++ pa_assert(call_data); ++ ++ switch (stream->type) { ++ case STREAM_TYPE_SINK_INPUT: ++ input = call_data; ++ break; ++ ++ case STREAM_TYPE_SOURCE_OUTPUT: ++ output = call_data; ++ break; ++ } ++ ++ if ((input && input != stream->sink_input) || (output && output != stream->source_output)) ++ return PA_HOOK_OK; ++ ++ if (input) ++ mute = input->muted; ++ else ++ mute = output->muted; ++ ++ pa_mute_control_mute_changed(stream->stream->own_mute_control, mute); ++ ++ return PA_HOOK_OK; ++} ++ ++static void mute_control_set_initial_mute_cb(pa_mute_control *control) { ++ struct stream *stream; ++ ++ pa_assert(control); ++ ++ stream = control->userdata; ++ ++ switch (stream->type) { ++ case STREAM_TYPE_SINK_INPUT: ++ pa_sink_input_set_mute(stream->sink_input, control->mute, true); ++ break; ++ ++ case STREAM_TYPE_SOURCE_OUTPUT: ++ pa_source_output_set_mute(stream->source_output, control->mute, true); ++ break; ++ } ++} ++ ++static const char *get_sink_input_description(pa_sink_input *input) { ++ const char *description; ++ ++ pa_assert(input); ++ ++ description = pa_proplist_gets(input->proplist, PA_PROP_MEDIA_NAME); ++ if (description) ++ return description; ++ ++ return NULL; ++} ++ ++static const char *get_source_output_description(pa_source_output *output) { ++ const char *description; ++ ++ pa_assert(output); ++ ++ description = pa_proplist_gets(output->proplist, PA_PROP_MEDIA_NAME); ++ if (description) ++ return description; ++ ++ return NULL; ++} ++ ++static pa_volume_control *stream_create_own_volume_control_cb(pas_stream *s) { ++ struct stream *stream; ++ const char *name = NULL; ++ char *description; ++ pa_volume_control *control; ++ pa_bvolume volume; ++ ++ pa_assert(s); ++ ++ stream = s->userdata; ++ ++ switch (stream->type) { ++ case STREAM_TYPE_SINK_INPUT: ++ name = "sink-input-volume-control"; ++ break; ++ ++ case STREAM_TYPE_SOURCE_OUTPUT: ++ name = "source-output-volume-control"; ++ break; ++ } ++ ++ description = get_stream_volume_and_mute_control_description_malloc(stream); ++ control = pa_volume_control_new(stream->creator->volume_api, name, description, true, false); ++ pa_xfree(description); ++ control->set_volume = volume_control_set_volume_cb; ++ control->userdata = stream; ++ ++ pa_assert(!stream->volume_changed_slot); ++ ++ switch (stream->type) { ++ case STREAM_TYPE_SINK_INPUT: ++ stream->volume_changed_slot = ++ pa_hook_connect(&stream->sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_VOLUME_CHANGED], PA_HOOK_NORMAL, ++ sink_input_or_source_output_volume_changed_cb, stream); ++ pa_bvolume_from_cvolume(&volume, &stream->sink_input->volume, &stream->sink_input->channel_map); ++ break; ++ ++ case STREAM_TYPE_SOURCE_OUTPUT: ++ stream->volume_changed_slot = ++ pa_hook_connect(&stream->source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_VOLUME_CHANGED], ++ PA_HOOK_NORMAL, sink_input_or_source_output_volume_changed_cb, stream); ++ pa_bvolume_from_cvolume(&volume, &stream->source_output->volume, &stream->source_output->channel_map); ++ break; ++ } ++ ++ pa_volume_control_put(control, &volume, volume_control_set_initial_volume_cb); ++ ++ return control; ++} ++ ++static void stream_delete_own_volume_control_cb(pas_stream *s) { ++ struct stream *stream; ++ ++ pa_assert(s); ++ ++ stream = s->userdata; ++ pa_hook_slot_free(stream->volume_changed_slot); ++ stream->volume_changed_slot = NULL; ++ pa_volume_control_free(s->own_volume_control); ++} ++ ++static pa_mute_control *stream_create_own_mute_control_cb(pas_stream *s) { ++ struct stream *stream; ++ const char *name = NULL; ++ char *description; ++ pa_mute_control *control; ++ bool mute = false; ++ ++ pa_assert(s); ++ ++ stream = s->userdata; ++ ++ switch (stream->type) { ++ case STREAM_TYPE_SINK_INPUT: ++ name = "sink-input-mute-control"; ++ break; ++ ++ case STREAM_TYPE_SOURCE_OUTPUT: ++ name = "source-output-mute-control"; ++ break; ++ } ++ ++ description = get_stream_volume_and_mute_control_description_malloc(stream); ++ control = pa_mute_control_new(stream->creator->volume_api, name, description); ++ pa_xfree(description); ++ control->set_mute = mute_control_set_mute_cb; ++ control->userdata = stream; ++ ++ pa_assert(!stream->mute_changed_slot); ++ ++ switch (stream->type) { ++ case STREAM_TYPE_SINK_INPUT: ++ stream->mute_changed_slot = ++ pa_hook_connect(&stream->sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_MUTE_CHANGED], PA_HOOK_NORMAL, ++ sink_input_or_source_output_mute_changed_cb, stream); ++ mute = stream->sink_input->muted; ++ break; ++ ++ case STREAM_TYPE_SOURCE_OUTPUT: ++ stream->mute_changed_slot = ++ pa_hook_connect(&stream->source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MUTE_CHANGED], ++ PA_HOOK_NORMAL, sink_input_or_source_output_mute_changed_cb, stream); ++ mute = stream->source_output->muted; ++ break; ++ } ++ ++ pa_mute_control_put(control, mute, true, mute_control_set_initial_mute_cb); ++ ++ return control; ++} ++ ++static void stream_delete_own_mute_control_cb(pas_stream *s) { ++ struct stream *stream; ++ ++ pa_assert(s); ++ ++ stream = s->userdata; ++ pa_hook_slot_free(stream->mute_changed_slot); ++ stream->mute_changed_slot = NULL; ++ pa_mute_control_free(s->own_mute_control); ++} ++ ++static pa_hook_result_t sink_input_or_source_output_proplist_changed_cb(void *hook_data, void *call_data, void *userdata) { ++ struct stream *stream = userdata; ++ pa_sink_input *input = NULL; ++ pa_source_output *output = NULL; ++ const char *new_stream_description = NULL; ++ char *new_control_description; ++ ++ pa_assert(stream); ++ pa_assert(call_data); ++ ++ switch (stream->type) { ++ case STREAM_TYPE_SINK_INPUT: ++ input = call_data; ++ ++ if (input != stream->sink_input) ++ return PA_HOOK_OK; ++ ++ new_stream_description = get_sink_input_description(input); ++ if (!new_stream_description) ++ new_stream_description = stream->stream->name; ++ break; ++ ++ case STREAM_TYPE_SOURCE_OUTPUT: ++ output = call_data; ++ ++ if (output != stream->source_output) ++ return PA_HOOK_OK; ++ ++ new_stream_description = get_source_output_description(output); ++ if (!new_stream_description) ++ new_stream_description = stream->stream->name; ++ break; ++ } ++ ++ pas_stream_description_changed(stream->stream, new_stream_description); ++ ++ new_control_description = get_stream_volume_and_mute_control_description_malloc(stream); ++ ++ if (stream->stream->own_volume_control) ++ pa_volume_control_description_changed(stream->stream->own_volume_control, new_control_description); ++ ++ if (stream->stream->own_mute_control) ++ pa_mute_control_description_changed(stream->stream->own_mute_control, new_control_description); ++ ++ pa_xfree(new_control_description); ++ ++ return PA_HOOK_OK; ++} ++ ++static pa_hook_result_t client_proplist_changed_cb(void *hook_data, void *call_data, void *userdata) { ++ struct stream *stream = userdata; ++ pa_client *client = call_data; ++ char *description; ++ ++ pa_assert(stream); ++ pa_assert(client); ++ ++ if (client != stream->client) ++ return PA_HOOK_OK; ++ ++ description = get_stream_volume_and_mute_control_description_malloc(stream); ++ ++ if (stream->stream->own_volume_control) ++ pa_volume_control_description_changed(stream->stream->own_volume_control, description); ++ ++ if (stream->stream->own_mute_control) ++ pa_mute_control_description_changed(stream->stream->own_mute_control, description); ++ ++ pa_xfree(description); ++ ++ return PA_HOOK_OK; ++} ++ ++static struct stream *stream_new(pa_stream_creator *creator, enum stream_type type, void *core_stream) { ++ struct stream *stream; ++ const char *name = NULL; ++ const char *description = NULL; ++ pa_direction_t direction = PA_DIRECTION_OUTPUT; ++ ++ pa_assert(creator); ++ pa_assert(core_stream); ++ ++ stream = pa_xnew0(struct stream, 1); ++ stream->creator = creator; ++ stream->type = type; ++ ++ switch (type) { ++ case STREAM_TYPE_SINK_INPUT: ++ stream->sink_input = core_stream; ++ stream->client = stream->sink_input->client; ++ name = "sink-input-stream"; ++ ++ description = get_sink_input_description(stream->sink_input); ++ if (!description) ++ description = name; ++ ++ direction = PA_DIRECTION_OUTPUT; ++ break; ++ ++ case STREAM_TYPE_SOURCE_OUTPUT: ++ stream->source_output = core_stream; ++ stream->client = stream->source_output->client; ++ name = "source-output-stream"; ++ ++ description = get_source_output_description(stream->source_output); ++ if (!description) ++ description = name; ++ ++ direction = PA_DIRECTION_INPUT; ++ break; ++ } ++ ++ stream->stream = pas_stream_new(creator->volume_api, name, description, direction); ++ stream->stream->create_own_volume_control = stream_create_own_volume_control_cb; ++ stream->stream->delete_own_volume_control = stream_delete_own_volume_control_cb; ++ stream->stream->create_own_mute_control = stream_create_own_mute_control_cb; ++ stream->stream->delete_own_mute_control = stream_delete_own_mute_control_cb; ++ stream->stream->userdata = stream; ++ pas_stream_set_have_own_volume_control(stream->stream, true); ++ pas_stream_set_have_own_mute_control(stream->stream, true); ++ ++ switch (type) { ++ case STREAM_TYPE_SINK_INPUT: ++ stream->proplist_changed_slot = ++ pa_hook_connect(&stream->sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED], PA_HOOK_NORMAL, ++ sink_input_or_source_output_proplist_changed_cb, stream); ++ break; ++ ++ case STREAM_TYPE_SOURCE_OUTPUT: ++ stream->proplist_changed_slot = ++ pa_hook_connect(&stream->source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED], ++ PA_HOOK_NORMAL, sink_input_or_source_output_proplist_changed_cb, stream); ++ break; ++ } ++ ++ stream->client_proplist_changed_slot = ++ pa_hook_connect(&stream->creator->volume_api->core->hooks[PA_CORE_HOOK_CLIENT_PROPLIST_CHANGED], ++ PA_HOOK_NORMAL, client_proplist_changed_cb, stream); ++ ++ return stream; ++} ++ ++static void stream_put(struct stream *stream) { ++ pa_proplist *proplist = NULL; ++ ++ pa_assert(stream); ++ ++ switch (stream->type) { ++ case STREAM_TYPE_SINK_INPUT: ++ proplist = stream->sink_input->proplist; ++ break; ++ ++ case STREAM_TYPE_SOURCE_OUTPUT: ++ proplist = stream->source_output->proplist; ++ break; ++ } ++ ++ pas_stream_put(stream->stream, proplist); ++} ++ ++static void stream_unlink(struct stream *stream) { ++ pa_assert(stream); ++ ++ if (stream->unlinked) ++ return; ++ ++ stream->unlinked = true; ++ ++ if (stream->stream) ++ pas_stream_unlink(stream->stream); ++} ++ ++static void stream_free(struct stream *stream) { ++ pa_assert(stream); ++ ++ if (!stream->unlinked) ++ stream_unlink(stream); ++ ++ if (stream->client_proplist_changed_slot) ++ pa_hook_slot_free(stream->client_proplist_changed_slot); ++ ++ if (stream->proplist_changed_slot) ++ pa_hook_slot_free(stream->proplist_changed_slot); ++ ++ if (stream->stream) ++ pas_stream_free(stream->stream); ++ ++ pa_xfree(stream); ++} ++ ++static void create_stream(pa_stream_creator *creator, enum stream_type type, void *core_stream) { ++ struct stream *stream; ++ ++ pa_assert(creator); ++ pa_assert(core_stream); ++ ++ stream = stream_new(creator, type, core_stream); ++ pa_hashmap_put(creator->streams, core_stream, stream); ++ stream_put(stream); ++} ++ ++static pa_hook_result_t sink_input_put_cb(void *hook_data, void *call_data, void *userdata) { ++ pa_stream_creator *creator = userdata; ++ pa_sink_input *input = call_data; ++ ++ pa_assert(creator); ++ pa_assert(input); ++ ++ create_stream(creator, STREAM_TYPE_SINK_INPUT, input); ++ ++ return PA_HOOK_OK; ++} ++ ++static pa_hook_result_t sink_input_unlink_cb(void *hook_data, void *call_data, void *userdata) { ++ pa_stream_creator *creator = userdata; ++ pa_sink_input *input = call_data; ++ ++ pa_assert(creator); ++ pa_assert(input); ++ ++ pa_hashmap_remove_and_free(creator->streams, input); ++ ++ return PA_HOOK_OK; ++} ++ ++static pa_hook_result_t source_output_put_cb(void *hook_data, void *call_data, void *userdata) { ++ pa_stream_creator *creator = userdata; ++ pa_source_output *output = call_data; ++ ++ pa_assert(creator); ++ pa_assert(output); ++ ++ create_stream(creator, STREAM_TYPE_SOURCE_OUTPUT, output); ++ ++ return PA_HOOK_OK; ++} ++ ++static pa_hook_result_t source_output_unlink_cb(void *hook_data, void *call_data, void *userdata) { ++ pa_stream_creator *creator = userdata; ++ pa_source_output *output = call_data; ++ ++ pa_assert(creator); ++ pa_assert(output); ++ ++ pa_hashmap_remove_and_free(creator->streams, output); ++ ++ return PA_HOOK_OK; ++} ++ ++pa_stream_creator *pa_stream_creator_new(pa_volume_api *api) { ++ pa_stream_creator *creator; ++ uint32_t idx; ++ pa_sink_input *input; ++ pa_source_output *output; ++ ++ pa_assert(api); ++ ++ creator = pa_xnew0(pa_stream_creator, 1); ++ creator->volume_api = api; ++ creator->streams = pa_hashmap_new_full(NULL, NULL, NULL, (pa_free_cb_t) stream_free); ++ creator->sink_input_put_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], PA_HOOK_NORMAL, ++ sink_input_put_cb, creator); ++ creator->sink_input_unlink_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], PA_HOOK_NORMAL, ++ sink_input_unlink_cb, creator); ++ creator->source_output_put_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], PA_HOOK_NORMAL, ++ source_output_put_cb, creator); ++ creator->source_output_unlink_slot = pa_hook_connect(&api->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], PA_HOOK_NORMAL, ++ source_output_unlink_cb, creator); ++ ++ PA_IDXSET_FOREACH(input, api->core->sink_inputs, idx) ++ create_stream(creator, STREAM_TYPE_SINK_INPUT, input); ++ ++ PA_IDXSET_FOREACH(output, api->core->source_outputs, idx) ++ create_stream(creator, STREAM_TYPE_SOURCE_OUTPUT, output); ++ ++ return creator; ++} ++ ++void pa_stream_creator_free(pa_stream_creator *creator) { ++ pa_assert(creator); ++ ++ if (creator->streams) ++ pa_hashmap_remove_all(creator->streams); ++ ++ if (creator->source_output_unlink_slot) ++ pa_hook_slot_free(creator->source_output_unlink_slot); ++ ++ if (creator->source_output_put_slot) ++ pa_hook_slot_free(creator->source_output_put_slot); ++ ++ if (creator->sink_input_unlink_slot) ++ pa_hook_slot_free(creator->sink_input_unlink_slot); ++ ++ if (creator->sink_input_put_slot) ++ pa_hook_slot_free(creator->sink_input_put_slot); ++ ++ if (creator->streams) ++ pa_hashmap_free(creator->streams); ++ ++ pa_xfree(creator); ++} +diff --git a/src/modules/volume-api/stream-creator.h b/src/modules/volume-api/stream-creator.h +new file mode 100644 +index 0000000..97a03a4 +--- /dev/null ++++ b/src/modules/volume-api/stream-creator.h +@@ -0,0 +1,32 @@ ++#ifndef foostreamcreatorhfoo ++#define foostreamcreatorhfoo ++ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#include <modules/volume-api/volume-api.h> ++ ++typedef struct pa_stream_creator pa_stream_creator; ++ ++pa_stream_creator *pa_stream_creator_new(pa_volume_api *api); ++void pa_stream_creator_free(pa_stream_creator *creator); ++ ++#endif +diff --git a/src/modules/volume-api/volume-api.c b/src/modules/volume-api/volume-api.c +new file mode 100644 +index 0000000..9abea7e +--- /dev/null ++++ b/src/modules/volume-api/volume-api.c +@@ -0,0 +1,647 @@ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#ifdef HAVE_CONFIG_H ++#include <config.h> ++#endif ++ ++#include "volume-api.h" ++ ++#include <modules/volume-api/audio-group.h> ++#include <modules/volume-api/binding.h> ++#include <modules/volume-api/device.h> ++#include <modules/volume-api/device-creator.h> ++#include <modules/volume-api/sstream.h> ++#include <modules/volume-api/stream-creator.h> ++#include <modules/volume-api/volume-control.h> ++ ++#include <pulsecore/core-util.h> ++#include <pulsecore/shared.h> ++ ++static pa_volume_api *volume_api_new(pa_core *core); ++static void volume_api_free(pa_volume_api *api); ++ ++pa_volume_api *pa_volume_api_get(pa_core *core) { ++ pa_volume_api *api; ++ ++ pa_assert(core); ++ ++ api = pa_shared_get(core, "volume-api"); ++ ++ if (api) ++ pa_volume_api_ref(api); ++ else { ++ api = volume_api_new(core); ++ pa_assert_se(pa_shared_set(core, "volume-api", api) >= 0); ++ } ++ ++ return api; ++} ++ ++pa_volume_api *pa_volume_api_ref(pa_volume_api *api) { ++ pa_assert(api); ++ ++ api->refcnt++; ++ ++ return api; ++} ++ ++void pa_volume_api_unref(pa_volume_api *api) { ++ pa_assert(api); ++ pa_assert(api->refcnt > 0); ++ ++ api->refcnt--; ++ ++ if (api->refcnt == 0) { ++ pa_assert_se(pa_shared_remove(api->core, "volume-api") >= 0); ++ volume_api_free(api); ++ } ++} ++ ++void pa_volume_api_add_binding_target_type(pa_volume_api *api, pa_binding_target_type *type) { ++ pa_assert(api); ++ pa_assert(type); ++ ++ pa_assert_se(pa_hashmap_put(api->binding_target_types, type->name, type) >= 0); ++ ++ pa_log_debug("Added binding target type %s.", type->name); ++ ++ pa_hook_fire(&api->hooks[PA_VOLUME_API_HOOK_BINDING_TARGET_TYPE_ADDED], type); ++} ++ ++void pa_volume_api_remove_binding_target_type(pa_volume_api *api, pa_binding_target_type *type) { ++ pa_assert(api); ++ pa_assert(type); ++ ++ pa_log_debug("Removing binding target type %s.", type->name); ++ ++ pa_hook_fire(&api->hooks[PA_VOLUME_API_HOOK_BINDING_TARGET_TYPE_REMOVED], type); ++ ++ pa_assert_se(pa_hashmap_remove(api->binding_target_types, type->name)); ++} ++ ++static void create_builtin_binding_target_types(pa_volume_api *api) { ++ pa_binding_target_type *type; ++ ++ pa_assert(api); ++ ++ type = pa_audio_group_create_binding_target_type(api); ++ pa_volume_api_add_binding_target_type(api, type); ++} ++ ++static void delete_builtin_binding_target_types(pa_volume_api *api) { ++ pa_binding_target_type *type; ++ ++ pa_assert(api); ++ ++ type = pa_hashmap_get(api->binding_target_types, PA_AUDIO_GROUP_BINDING_TARGET_TYPE); ++ pa_volume_api_remove_binding_target_type(api, type); ++} ++ ++static void create_objects_defer_event_cb(pa_mainloop_api *mainloop_api, pa_defer_event *event, void *userdata) { ++ pa_volume_api *volume_api = userdata; ++ ++ pa_assert(volume_api); ++ pa_assert(event == volume_api->create_objects_defer_event); ++ ++ mainloop_api->defer_free(event); ++ volume_api->create_objects_defer_event = NULL; ++ ++ volume_api->device_creator = pa_device_creator_new(volume_api); ++ volume_api->stream_creator = pa_stream_creator_new(volume_api); ++} ++ ++static pa_volume_api *volume_api_new(pa_core *core) { ++ pa_volume_api *api; ++ unsigned i; ++ ++ pa_assert(core); ++ ++ api = pa_xnew0(pa_volume_api, 1); ++ api->core = core; ++ api->refcnt = 1; ++ api->binding_target_types = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); ++ api->names = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, pa_xfree); ++ api->volume_controls = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); ++ api->mute_controls = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); ++ api->devices = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); ++ api->streams = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); ++ api->audio_groups = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); ++ ++ for (i = 0; i < PA_VOLUME_API_HOOK_MAX; i++) ++ pa_hook_init(&api->hooks[i], api); ++ ++ create_builtin_binding_target_types(api); ++ ++ /* We delay the object creation to ensure that policy modules have a chance ++ * to affect the initialization of the objects. If we created the objects ++ * immediately, policy modules wouldn't have a chance of connecting to the ++ * object creation hooks before the objects are created. */ ++ api->create_objects_defer_event = core->mainloop->defer_new(core->mainloop, create_objects_defer_event_cb, api); ++ ++ pa_log_debug("Created a pa_volume_api object."); ++ ++ return api; ++} ++ ++static void volume_api_free(pa_volume_api *api) { ++ unsigned i; ++ ++ pa_assert(api); ++ pa_assert(api->refcnt == 0); ++ ++ pa_log_debug("Freeing the pa_volume_api object."); ++ ++ if (api->stream_creator) ++ pa_stream_creator_free(api->stream_creator); ++ ++ if (api->device_creator) ++ pa_device_creator_free(api->device_creator); ++ ++ if (api->create_objects_defer_event) ++ api->core->mainloop->defer_free(api->create_objects_defer_event); ++ ++ if (api->binding_target_types) ++ delete_builtin_binding_target_types(api); ++ ++ for (i = 0; i < PA_VOLUME_API_HOOK_MAX; i++) ++ pa_hook_done(&api->hooks[i]); ++ ++ if (api->audio_groups) { ++ pa_assert(pa_hashmap_isempty(api->audio_groups)); ++ pa_hashmap_free(api->audio_groups); ++ } ++ ++ if (api->streams) { ++ pa_assert(pa_hashmap_isempty(api->streams)); ++ pa_hashmap_free(api->streams); ++ } ++ ++ if (api->devices) { ++ pa_assert(pa_hashmap_isempty(api->devices)); ++ pa_hashmap_free(api->devices); ++ } ++ ++ if (api->mute_controls) { ++ pa_assert(pa_hashmap_isempty(api->mute_controls)); ++ pa_hashmap_free(api->mute_controls); ++ } ++ ++ if (api->volume_controls) { ++ pa_assert(pa_hashmap_isempty(api->volume_controls)); ++ pa_hashmap_free(api->volume_controls); ++ } ++ ++ if (api->names) { ++ pa_assert(pa_hashmap_isempty(api->names)); ++ pa_hashmap_free(api->names); ++ } ++ ++ if (api->binding_target_types) { ++ pa_assert(pa_hashmap_isempty(api->binding_target_types)); ++ pa_hashmap_free(api->binding_target_types); ++ } ++ ++ pa_xfree(api); ++} ++ ++int pa_volume_api_register_name(pa_volume_api *api, const char *requested_name, bool fail_if_already_registered, ++ const char **registered_name) { ++ char *n; ++ ++ pa_assert(api); ++ pa_assert(requested_name); ++ pa_assert(registered_name); ++ ++ n = pa_xstrdup(requested_name); ++ ++ if (pa_hashmap_put(api->names, n, n) < 0) { ++ unsigned i = 1; ++ ++ pa_xfree(n); ++ ++ if (fail_if_already_registered) { ++ pa_log("Name %s already registered.", requested_name); ++ return -PA_ERR_EXIST; ++ } ++ ++ do { ++ i++; ++ n = pa_sprintf_malloc("%s.%u", requested_name, i); ++ } while (pa_hashmap_put(api->names, n, n) < 0); ++ } ++ ++ *registered_name = n; ++ ++ return 0; ++} ++ ++void pa_volume_api_unregister_name(pa_volume_api *api, const char *name) { ++ pa_assert(api); ++ pa_assert(name); ++ ++ pa_assert_se(pa_hashmap_remove_and_free(api->names, name) >= 0); ++} ++ ++uint32_t pa_volume_api_allocate_volume_control_index(pa_volume_api *api) { ++ uint32_t idx; ++ ++ pa_assert(api); ++ ++ idx = api->next_volume_control_index++; ++ ++ return idx; ++} ++ ++static void set_main_output_volume_control_internal(pa_volume_api *api, pa_volume_control *control) { ++ pa_volume_control *old_control; ++ ++ pa_assert(api); ++ ++ old_control = api->main_output_volume_control; ++ ++ if (control == old_control) ++ return; ++ ++ api->main_output_volume_control = control; ++ pa_log_debug("Main output volume control changed from %s to %s.", old_control ? old_control->name : "(unset)", ++ control ? control->name : "(unset)"); ++ pa_hook_fire(&api->hooks[PA_VOLUME_API_HOOK_MAIN_OUTPUT_VOLUME_CONTROL_CHANGED], api); ++} ++ ++static void set_main_input_volume_control_internal(pa_volume_api *api, pa_volume_control *control) { ++ pa_volume_control *old_control; ++ ++ pa_assert(api); ++ ++ old_control = api->main_input_volume_control; ++ ++ if (control == old_control) ++ return; ++ ++ api->main_input_volume_control = control; ++ pa_log_debug("Main input volume control changed from %s to %s.", old_control ? old_control->name : "(unset)", ++ control ? control->name : "(unset)"); ++ pa_hook_fire(&api->hooks[PA_VOLUME_API_HOOK_MAIN_INPUT_VOLUME_CONTROL_CHANGED], api); ++} ++ ++void pa_volume_api_add_volume_control(pa_volume_api *api, pa_volume_control *control) { ++ pa_assert(api); ++ pa_assert(control); ++ ++ pa_assert_se(pa_hashmap_put(api->volume_controls, (void *) control->name, control) >= 0); ++} ++ ++int pa_volume_api_remove_volume_control(pa_volume_api *api, pa_volume_control *control) { ++ pa_assert(api); ++ pa_assert(control); ++ ++ if (!pa_hashmap_remove(api->volume_controls, control->name)) ++ return -1; ++ ++ if (control == api->main_output_volume_control) ++ set_main_output_volume_control_internal(api, NULL); ++ ++ if (control == api->main_input_volume_control) ++ set_main_input_volume_control_internal(api, NULL); ++ ++ return 0; ++} ++ ++pa_volume_control *pa_volume_api_get_volume_control_by_index(pa_volume_api *api, uint32_t idx) { ++ pa_volume_control *control; ++ void *state; ++ ++ pa_assert(api); ++ ++ PA_HASHMAP_FOREACH(control, api->volume_controls, state) { ++ if (control->index == idx) ++ return control; ++ } ++ ++ return NULL; ++} ++ ++uint32_t pa_volume_api_allocate_mute_control_index(pa_volume_api *api) { ++ uint32_t idx; ++ ++ pa_assert(api); ++ ++ idx = api->next_mute_control_index++; ++ ++ return idx; ++} ++ ++static void set_main_output_mute_control_internal(pa_volume_api *api, pa_mute_control *control) { ++ pa_mute_control *old_control; ++ ++ pa_assert(api); ++ ++ old_control = api->main_output_mute_control; ++ ++ if (control == old_control) ++ return; ++ ++ api->main_output_mute_control = control; ++ pa_log_debug("Main output mute control changed from %s to %s.", old_control ? old_control->name : "(unset)", ++ control ? control->name : "(unset)"); ++ pa_hook_fire(&api->hooks[PA_VOLUME_API_HOOK_MAIN_OUTPUT_MUTE_CONTROL_CHANGED], api); ++} ++ ++static void set_main_input_mute_control_internal(pa_volume_api *api, pa_mute_control *control) { ++ pa_mute_control *old_control; ++ ++ pa_assert(api); ++ ++ old_control = api->main_input_mute_control; ++ ++ if (control == old_control) ++ return; ++ ++ api->main_input_mute_control = control; ++ pa_log_debug("Main input mute control changed from %s to %s.", old_control ? old_control->name : "(unset)", ++ control ? control->name : "(unset)"); ++ pa_hook_fire(&api->hooks[PA_VOLUME_API_HOOK_MAIN_INPUT_MUTE_CONTROL_CHANGED], api); ++} ++ ++void pa_volume_api_add_mute_control(pa_volume_api *api, pa_mute_control *control) { ++ pa_assert(api); ++ pa_assert(control); ++ ++ pa_assert_se(pa_hashmap_put(api->mute_controls, (void *) control->name, control) >= 0); ++} ++ ++int pa_volume_api_remove_mute_control(pa_volume_api *api, pa_mute_control *control) { ++ pa_assert(api); ++ pa_assert(control); ++ ++ if (!pa_hashmap_remove(api->mute_controls, control->name)) ++ return -1; ++ ++ if (control == api->main_output_mute_control) ++ set_main_output_mute_control_internal(api, NULL); ++ ++ if (control == api->main_input_mute_control) ++ set_main_input_mute_control_internal(api, NULL); ++ ++ return 0; ++} ++ ++pa_mute_control *pa_volume_api_get_mute_control_by_index(pa_volume_api *api, uint32_t idx) { ++ pa_mute_control *control; ++ void *state; ++ ++ pa_assert(api); ++ ++ PA_HASHMAP_FOREACH(control, api->mute_controls, state) { ++ if (control->index == idx) ++ return control; ++ } ++ ++ return NULL; ++} ++ ++uint32_t pa_volume_api_allocate_device_index(pa_volume_api *api) { ++ uint32_t idx; ++ ++ pa_assert(api); ++ ++ idx = api->next_device_index++; ++ ++ return idx; ++} ++ ++void pa_volume_api_add_device(pa_volume_api *api, pa_device *device) { ++ pa_assert(api); ++ pa_assert(device); ++ ++ pa_assert_se(pa_hashmap_put(api->devices, (void *) device->name, device) >= 0); ++} ++ ++int pa_volume_api_remove_device(pa_volume_api *api, pa_device *device) { ++ pa_assert(api); ++ pa_assert(device); ++ ++ if (!pa_hashmap_remove(api->devices, device->name)) ++ return -1; ++ ++ return 0; ++} ++ ++pa_device *pa_volume_api_get_device_by_index(pa_volume_api *api, uint32_t idx) { ++ pa_device *device; ++ void *state; ++ ++ pa_assert(api); ++ ++ PA_HASHMAP_FOREACH(device, api->devices, state) { ++ if (device->index == idx) ++ return device; ++ } ++ ++ return NULL; ++} ++ ++uint32_t pa_volume_api_allocate_stream_index(pa_volume_api *api) { ++ uint32_t idx; ++ ++ pa_assert(api); ++ ++ idx = api->next_stream_index++; ++ ++ return idx; ++} ++ ++void pa_volume_api_add_stream(pa_volume_api *api, pas_stream *stream) { ++ pa_assert(api); ++ pa_assert(stream); ++ ++ pa_assert_se(pa_hashmap_put(api->streams, (void *) stream->name, stream) >= 0); ++} ++ ++int pa_volume_api_remove_stream(pa_volume_api *api, pas_stream *stream) { ++ pa_assert(api); ++ pa_assert(stream); ++ ++ if (!pa_hashmap_remove(api->streams, stream->name)) ++ return -1; ++ ++ return 0; ++} ++ ++pas_stream *pa_volume_api_get_stream_by_index(pa_volume_api *api, uint32_t idx) { ++ pas_stream *stream; ++ void *state; ++ ++ pa_assert(api); ++ ++ PA_HASHMAP_FOREACH(stream, api->streams, state) { ++ if (stream->index == idx) ++ return stream; ++ } ++ ++ return NULL; ++} ++ ++uint32_t pa_volume_api_allocate_audio_group_index(pa_volume_api *api) { ++ uint32_t idx; ++ ++ pa_assert(api); ++ ++ idx = api->next_audio_group_index++; ++ ++ return idx; ++} ++ ++void pa_volume_api_add_audio_group(pa_volume_api *api, pa_audio_group *group) { ++ pa_assert(api); ++ pa_assert(group); ++ ++ pa_assert_se(pa_hashmap_put(api->audio_groups, (void *) group->name, group) >= 0); ++} ++ ++int pa_volume_api_remove_audio_group(pa_volume_api *api, pa_audio_group *group) { ++ pa_assert(api); ++ pa_assert(group); ++ ++ if (!pa_hashmap_remove(api->audio_groups, group->name)) ++ return -1; ++ ++ return 0; ++} ++ ++pa_audio_group *pa_volume_api_get_audio_group_by_index(pa_volume_api *api, uint32_t idx) { ++ pa_audio_group *group; ++ void *state; ++ ++ pa_assert(api); ++ ++ PA_HASHMAP_FOREACH(group, api->audio_groups, state) { ++ if (group->index == idx) ++ return group; ++ } ++ ++ return NULL; ++} ++ ++void pa_volume_api_set_main_output_volume_control(pa_volume_api *api, pa_volume_control *control) { ++ pa_assert(api); ++ ++ if (api->main_output_volume_control_binding) { ++ pa_binding_free(api->main_output_volume_control_binding); ++ api->main_output_volume_control_binding = NULL; ++ } ++ ++ set_main_output_volume_control_internal(api, control); ++} ++ ++void pa_volume_api_set_main_input_volume_control(pa_volume_api *api, pa_volume_control *control) { ++ pa_assert(api); ++ ++ if (api->main_input_volume_control_binding) { ++ pa_binding_free(api->main_input_volume_control_binding); ++ api->main_input_volume_control_binding = NULL; ++ } ++ ++ set_main_input_volume_control_internal(api, control); ++} ++ ++void pa_volume_api_set_main_output_mute_control(pa_volume_api *api, pa_mute_control *control) { ++ pa_assert(api); ++ ++ if (api->main_output_mute_control_binding) { ++ pa_binding_free(api->main_output_mute_control_binding); ++ api->main_output_mute_control_binding = NULL; ++ } ++ ++ set_main_output_mute_control_internal(api, control); ++} ++ ++void pa_volume_api_set_main_input_mute_control(pa_volume_api *api, pa_mute_control *control) { ++ pa_assert(api); ++ ++ if (api->main_input_mute_control_binding) { ++ pa_binding_free(api->main_input_mute_control_binding); ++ api->main_input_mute_control_binding = NULL; ++ } ++ ++ set_main_input_mute_control_internal(api, control); ++} ++ ++void pa_volume_api_bind_main_output_volume_control(pa_volume_api *api, pa_binding_target_info *target_info) { ++ pa_binding_owner_info owner_info = { ++ .userdata = api, ++ .set_value = (pa_binding_set_value_cb_t) set_main_output_volume_control_internal, ++ }; ++ ++ pa_assert(api); ++ pa_assert(target_info); ++ ++ if (api->main_output_volume_control_binding) ++ pa_binding_free(api->main_output_volume_control_binding); ++ ++ api->main_output_volume_control_binding = pa_binding_new(api, &owner_info, target_info); ++} ++ ++void pa_volume_api_bind_main_input_volume_control(pa_volume_api *api, pa_binding_target_info *target_info) { ++ pa_binding_owner_info owner_info = { ++ .userdata = api, ++ .set_value = (pa_binding_set_value_cb_t) set_main_input_volume_control_internal, ++ }; ++ ++ pa_assert(api); ++ pa_assert(target_info); ++ ++ if (api->main_input_volume_control_binding) ++ pa_binding_free(api->main_input_volume_control_binding); ++ ++ api->main_input_volume_control_binding = pa_binding_new(api, &owner_info, target_info); ++} ++ ++void pa_volume_api_bind_main_output_mute_control(pa_volume_api *api, pa_binding_target_info *target_info) { ++ pa_binding_owner_info owner_info = { ++ .userdata = api, ++ .set_value = (pa_binding_set_value_cb_t) set_main_output_mute_control_internal, ++ }; ++ ++ pa_assert(api); ++ pa_assert(target_info); ++ ++ if (api->main_output_mute_control_binding) ++ pa_binding_free(api->main_output_mute_control_binding); ++ ++ api->main_output_mute_control_binding = pa_binding_new(api, &owner_info, target_info); ++} ++ ++void pa_volume_api_bind_main_input_mute_control(pa_volume_api *api, pa_binding_target_info *target_info) { ++ pa_binding_owner_info owner_info = { ++ .userdata = api, ++ .set_value = (pa_binding_set_value_cb_t) set_main_input_mute_control_internal, ++ }; ++ ++ pa_assert(api); ++ pa_assert(target_info); ++ ++ if (api->main_input_mute_control_binding) ++ pa_binding_free(api->main_input_mute_control_binding); ++ ++ api->main_input_mute_control_binding = pa_binding_new(api, &owner_info, target_info); ++} +diff --git a/src/modules/volume-api/volume-api.h b/src/modules/volume-api/volume-api.h +new file mode 100644 +index 0000000..73a1410 +--- /dev/null ++++ b/src/modules/volume-api/volume-api.h +@@ -0,0 +1,163 @@ ++#ifndef foovolumeapihfoo ++#define foovolumeapihfoo ++ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#include <pulsecore/core.h> ++ ++typedef struct pa_volume_api pa_volume_api; ++ ++/* Avoid circular dependencies... */ ++typedef struct pa_audio_group pa_audio_group; ++typedef struct pa_binding pa_binding; ++typedef struct pa_binding_target_info pa_binding_target_info; ++typedef struct pa_binding_target_type pa_binding_target_type; ++typedef struct pa_device pa_device; ++typedef struct pa_device_creator pa_device_creator; ++typedef struct pa_mute_control pa_mute_control; ++typedef struct pas_stream pas_stream; ++typedef struct pa_stream_creator pa_stream_creator; ++typedef struct pa_volume_control pa_volume_control; ++ ++enum { ++ PA_VOLUME_API_HOOK_BINDING_TARGET_TYPE_ADDED, ++ PA_VOLUME_API_HOOK_BINDING_TARGET_TYPE_REMOVED, ++ PA_VOLUME_API_HOOK_VOLUME_CONTROL_PUT, ++ PA_VOLUME_API_HOOK_VOLUME_CONTROL_UNLINK, ++ PA_VOLUME_API_HOOK_VOLUME_CONTROL_DESCRIPTION_CHANGED, ++ PA_VOLUME_API_HOOK_VOLUME_CONTROL_VOLUME_CHANGED, ++ PA_VOLUME_API_HOOK_MUTE_CONTROL_PUT, ++ PA_VOLUME_API_HOOK_MUTE_CONTROL_UNLINK, ++ PA_VOLUME_API_HOOK_MUTE_CONTROL_DESCRIPTION_CHANGED, ++ PA_VOLUME_API_HOOK_MUTE_CONTROL_MUTE_CHANGED, ++ PA_VOLUME_API_HOOK_DEVICE_PUT, ++ PA_VOLUME_API_HOOK_DEVICE_UNLINK, ++ PA_VOLUME_API_HOOK_DEVICE_DESCRIPTION_CHANGED, ++ PA_VOLUME_API_HOOK_DEVICE_VOLUME_CONTROL_CHANGED, ++ PA_VOLUME_API_HOOK_DEVICE_MUTE_CONTROL_CHANGED, ++ ++ /* Policy modules can use this to set the initial volume control for a ++ * stream. The hook callback should use pas_stream_set_volume_control() to ++ * set the volume control. The hook callback should not do anything if ++ * stream->volume_control is already non-NULL. */ ++ PA_VOLUME_API_HOOK_STREAM_SET_INITIAL_VOLUME_CONTROL, ++ ++ /* Policy modules can use this to set the initial mute control for a ++ * stream. The hook callback should use pas_stream_set_mute_control() to ++ * set the mute control. The hook callback should not do anything if ++ * stream->mute_control is already non-NULL. */ ++ PA_VOLUME_API_HOOK_STREAM_SET_INITIAL_MUTE_CONTROL, ++ ++ PA_VOLUME_API_HOOK_STREAM_PUT, ++ PA_VOLUME_API_HOOK_STREAM_UNLINK, ++ PA_VOLUME_API_HOOK_STREAM_DESCRIPTION_CHANGED, ++ PA_VOLUME_API_HOOK_STREAM_VOLUME_CONTROL_CHANGED, ++ PA_VOLUME_API_HOOK_STREAM_MUTE_CONTROL_CHANGED, ++ PA_VOLUME_API_HOOK_AUDIO_GROUP_PUT, ++ PA_VOLUME_API_HOOK_AUDIO_GROUP_UNLINK, ++ PA_VOLUME_API_HOOK_AUDIO_GROUP_VOLUME_CONTROL_CHANGED, ++ PA_VOLUME_API_HOOK_AUDIO_GROUP_MUTE_CONTROL_CHANGED, ++ PA_VOLUME_API_HOOK_MAIN_OUTPUT_VOLUME_CONTROL_CHANGED, ++ PA_VOLUME_API_HOOK_MAIN_INPUT_VOLUME_CONTROL_CHANGED, ++ PA_VOLUME_API_HOOK_MAIN_OUTPUT_MUTE_CONTROL_CHANGED, ++ PA_VOLUME_API_HOOK_MAIN_INPUT_MUTE_CONTROL_CHANGED, ++ PA_VOLUME_API_HOOK_MAX ++}; ++ ++struct pa_volume_api { ++ pa_core *core; ++ unsigned refcnt; ++ pa_hashmap *binding_target_types; /* name -> pa_binding_target_type */ ++ pa_hashmap *names; /* object name -> object name (hashmap-as-a-set) */ ++ pa_hashmap *volume_controls; /* name -> pa_volume_control */ ++ pa_hashmap *mute_controls; /* name -> pa_mute_control */ ++ pa_hashmap *devices; /* name -> pa_device */ ++ pa_hashmap *streams; /* name -> pas_stream */ ++ pa_hashmap *audio_groups; /* name -> pa_audio_group */ ++ pa_volume_control *main_output_volume_control; ++ pa_volume_control *main_input_volume_control; ++ pa_mute_control *main_output_mute_control; ++ pa_mute_control *main_input_mute_control; ++ ++ uint32_t next_volume_control_index; ++ uint32_t next_mute_control_index; ++ uint32_t next_device_index; ++ uint32_t next_stream_index; ++ uint32_t next_audio_group_index; ++ pa_binding *main_output_volume_control_binding; ++ pa_binding *main_input_volume_control_binding; ++ pa_binding *main_output_mute_control_binding; ++ pa_binding *main_input_mute_control_binding; ++ pa_hook hooks[PA_VOLUME_API_HOOK_MAX]; ++ pa_defer_event *create_objects_defer_event; ++ pa_device_creator *device_creator; ++ pa_stream_creator *stream_creator; ++}; ++ ++pa_volume_api *pa_volume_api_get(pa_core *core); ++pa_volume_api *pa_volume_api_ref(pa_volume_api *api); ++void pa_volume_api_unref(pa_volume_api *api); ++ ++void pa_volume_api_add_binding_target_type(pa_volume_api *api, pa_binding_target_type *type); ++void pa_volume_api_remove_binding_target_type(pa_volume_api *api, pa_binding_target_type *type); ++ ++/* If fail_if_already_registered is false, this function never fails. */ ++int pa_volume_api_register_name(pa_volume_api *api, const char *requested_name, bool fail_if_already_registered, ++ const char **registered_name); ++ ++void pa_volume_api_unregister_name(pa_volume_api *api, const char *name); ++ ++uint32_t pa_volume_api_allocate_volume_control_index(pa_volume_api *api); ++void pa_volume_api_add_volume_control(pa_volume_api *api, pa_volume_control *control); ++int pa_volume_api_remove_volume_control(pa_volume_api *api, pa_volume_control *control); ++pa_volume_control *pa_volume_api_get_volume_control_by_index(pa_volume_api *api, uint32_t idx); ++ ++uint32_t pa_volume_api_allocate_mute_control_index(pa_volume_api *api); ++void pa_volume_api_add_mute_control(pa_volume_api *api, pa_mute_control *control); ++int pa_volume_api_remove_mute_control(pa_volume_api *api, pa_mute_control *control); ++pa_mute_control *pa_volume_api_get_mute_control_by_index(pa_volume_api *api, uint32_t idx); ++ ++uint32_t pa_volume_api_allocate_device_index(pa_volume_api *api); ++void pa_volume_api_add_device(pa_volume_api *api, pa_device *device); ++int pa_volume_api_remove_device(pa_volume_api *api, pa_device *device); ++pa_device *pa_volume_api_get_device_by_index(pa_volume_api *api, uint32_t idx); ++ ++uint32_t pa_volume_api_allocate_stream_index(pa_volume_api *api); ++void pa_volume_api_add_stream(pa_volume_api *api, pas_stream *stream); ++int pa_volume_api_remove_stream(pa_volume_api *api, pas_stream *stream); ++pas_stream *pa_volume_api_get_stream_by_index(pa_volume_api *api, uint32_t idx); ++ ++uint32_t pa_volume_api_allocate_audio_group_index(pa_volume_api *api); ++void pa_volume_api_add_audio_group(pa_volume_api *api, pa_audio_group *group); ++int pa_volume_api_remove_audio_group(pa_volume_api *api, pa_audio_group *group); ++pa_audio_group *pa_volume_api_get_audio_group_by_index(pa_volume_api *api, uint32_t idx); ++ ++void pa_volume_api_set_main_output_volume_control(pa_volume_api *api, pa_volume_control *control); ++void pa_volume_api_set_main_input_volume_control(pa_volume_api *api, pa_volume_control *control); ++void pa_volume_api_set_main_output_mute_control(pa_volume_api *api, pa_mute_control *control); ++void pa_volume_api_set_main_input_mute_control(pa_volume_api *api, pa_mute_control *control); ++void pa_volume_api_bind_main_output_volume_control(pa_volume_api *api, pa_binding_target_info *target_info); ++void pa_volume_api_bind_main_input_volume_control(pa_volume_api *api, pa_binding_target_info *target_info); ++void pa_volume_api_bind_main_output_mute_control(pa_volume_api *api, pa_binding_target_info *target_info); ++void pa_volume_api_bind_main_input_mute_control(pa_volume_api *api, pa_binding_target_info *target_info); ++ ++#endif +diff --git a/src/modules/volume-api/volume-control.c b/src/modules/volume-api/volume-control.c +new file mode 100644 +index 0000000..c7f5dbb +--- /dev/null ++++ b/src/modules/volume-api/volume-control.c +@@ -0,0 +1,363 @@ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#ifdef HAVE_CONFIG_H ++#include <config.h> ++#endif ++ ++#include "volume-control.h" ++ ++#include <modules/volume-api/audio-group.h> ++#include <modules/volume-api/device.h> ++#include <modules/volume-api/sstream.h> ++ ++#include <pulsecore/core-util.h> ++ ++pa_volume_control *pa_volume_control_new(pa_volume_api *api, const char *name, const char *description, bool convertible_to_dB, ++ bool channel_map_is_writable) { ++ pa_volume_control *control; ++ ++ pa_assert(api); ++ pa_assert(name); ++ pa_assert(description); ++ ++ control = pa_xnew0(pa_volume_control, 1); ++ control->volume_api = api; ++ control->index = pa_volume_api_allocate_volume_control_index(api); ++ pa_assert_se(pa_volume_api_register_name(api, name, false, &control->name) >= 0); ++ control->description = pa_xstrdup(description); ++ control->proplist = pa_proplist_new(); ++ pa_bvolume_init_invalid(&control->volume); ++ control->convertible_to_dB = convertible_to_dB; ++ control->channel_map_is_writable = channel_map_is_writable; ++ control->devices = pa_hashmap_new(NULL, NULL); ++ control->default_for_devices = pa_hashmap_new(NULL, NULL); ++ control->streams = pa_hashmap_new(NULL, NULL); ++ control->audio_groups = pa_hashmap_new(NULL, NULL); ++ ++ return control; ++} ++ ++void pa_volume_control_put(pa_volume_control *control, const pa_bvolume *initial_volume, ++ pa_volume_control_set_initial_volume_cb_t set_initial_volume_cb) { ++ const char *prop_key; ++ void *state = NULL; ++ char volume_str[PA_VOLUME_SNPRINT_VERBOSE_MAX]; ++ char balance_str[PA_BVOLUME_SNPRINT_BALANCE_MAX]; ++ ++ pa_assert(control); ++ pa_assert((initial_volume && pa_bvolume_valid(initial_volume, true, true)) || control->set_volume); ++ pa_assert((initial_volume && pa_channel_map_valid(&initial_volume->channel_map)) || control->channel_map_is_writable); ++ pa_assert(set_initial_volume_cb || !control->set_volume); ++ ++ if (initial_volume && pa_bvolume_valid(initial_volume, true, false)) ++ control->volume.volume = initial_volume->volume; ++ else ++ control->volume.volume = PA_VOLUME_NORM / 3; ++ ++ if (initial_volume && pa_bvolume_valid(initial_volume, false, true)) ++ pa_bvolume_copy_balance(&control->volume, initial_volume); ++ else if (initial_volume && pa_channel_map_valid(&initial_volume->channel_map)) ++ pa_bvolume_reset_balance(&control->volume, &initial_volume->channel_map); ++ else { ++ pa_channel_map_init_mono(&control->volume.channel_map); ++ pa_bvolume_reset_balance(&control->volume, &control->volume.channel_map); ++ } ++ ++ if (set_initial_volume_cb) ++ set_initial_volume_cb(control); ++ ++ pa_volume_api_add_volume_control(control->volume_api, control); ++ ++ control->linked = true; ++ ++ pa_log_debug("Created volume control #%u.", control->index); ++ pa_log_debug(" Name: %s", control->name); ++ pa_log_debug(" Description: %s", control->description); ++ pa_log_debug(" Properties:"); ++ ++ while ((prop_key = pa_proplist_iterate(control->proplist, &state))) ++ pa_log_debug(" %s = %s", prop_key, pa_strnull(pa_proplist_gets(control->proplist, prop_key))); ++ ++ pa_log_debug(" Volume: %s", pa_volume_snprint_verbose(volume_str, sizeof(volume_str), control->volume.volume, ++ control->convertible_to_dB)); ++ pa_log_debug(" Balance: %s", pa_bvolume_snprint_balance(balance_str, sizeof(balance_str), &control->volume)); ++ pa_log_debug(" Channel map is writable: %s", pa_yes_no(control->channel_map_is_writable)); ++ ++ pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_PUT], control); ++} ++ ++void pa_volume_control_unlink(pa_volume_control *control) { ++ pa_audio_group *group; ++ pa_device *device; ++ pas_stream *stream; ++ ++ pa_assert(control); ++ ++ if (control->unlinked) { ++ pa_log_debug("Unlinking volume control %s (already unlinked, this is a no-op).", control->name); ++ return; ++ } ++ ++ control->unlinked = true; ++ ++ pa_log_debug("Unlinking volume control %s.", control->name); ++ ++ if (control->linked) ++ pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_UNLINK], control); ++ ++ pa_volume_api_remove_volume_control(control->volume_api, control); ++ ++ while ((group = pa_hashmap_first(control->audio_groups))) ++ pa_audio_group_set_volume_control(group, NULL); ++ ++ while ((stream = pa_hashmap_first(control->streams))) ++ pas_stream_set_volume_control(stream, NULL); ++ ++ while ((device = pa_hashmap_first(control->default_for_devices))) ++ pa_device_set_default_volume_control(device, NULL); ++ ++ while ((device = pa_hashmap_first(control->devices))) { ++ /* Why do we have this assertion here? The concern is that if we call ++ * pa_device_set_volume_control() for some device that has the ++ * use_default_volume_control flag set, then that flag will be unset as ++ * a side effect, and we don't want that side effect. This assertion ++ * should be safe, because we just called ++ * pa_device_set_default_volume_control(NULL) for each device that this ++ * control was the default for, and that should ensure that we don't ++ * any more hold any references to devices that used to use this ++ * control as the default. */ ++ pa_assert(!device->use_default_volume_control); ++ pa_device_set_volume_control(device, NULL); ++ } ++} ++ ++void pa_volume_control_free(pa_volume_control *control) { ++ pa_assert(control); ++ ++ if (!control->unlinked) ++ pa_volume_control_unlink(control); ++ ++ if (control->audio_groups) { ++ pa_assert(pa_hashmap_isempty(control->audio_groups)); ++ pa_hashmap_free(control->audio_groups); ++ } ++ ++ if (control->streams) { ++ pa_assert(pa_hashmap_isempty(control->streams)); ++ pa_hashmap_free(control->streams); ++ } ++ ++ if (control->default_for_devices) { ++ pa_assert(pa_hashmap_isempty(control->default_for_devices)); ++ pa_hashmap_free(control->default_for_devices); ++ } ++ ++ if (control->devices) { ++ pa_assert(pa_hashmap_isempty(control->devices)); ++ pa_hashmap_free(control->devices); ++ } ++ ++ if (control->proplist) ++ pa_proplist_free(control->proplist); ++ ++ pa_xfree(control->description); ++ ++ if (control->name) ++ pa_volume_api_unregister_name(control->volume_api, control->name); ++ ++ pa_xfree(control); ++} ++ ++void pa_volume_control_set_owner_audio_group(pa_volume_control *control, pa_audio_group *group) { ++ pa_assert(control); ++ pa_assert(group); ++ ++ control->owner_audio_group = group; ++} ++ ++static void set_volume_internal(pa_volume_control *control, const pa_bvolume *volume, bool set_volume, bool set_balance) { ++ pa_bvolume old_volume; ++ bool volume_changed; ++ bool balance_changed; ++ ++ pa_assert(control); ++ pa_assert(volume); ++ ++ old_volume = control->volume; ++ volume_changed = !pa_bvolume_equal(volume, &old_volume, set_volume, false); ++ balance_changed = !pa_bvolume_equal(volume, &old_volume, false, set_balance); ++ ++ if (!volume_changed && !balance_changed) ++ return; ++ ++ if (volume_changed) ++ control->volume.volume = volume->volume; ++ ++ if (balance_changed) ++ pa_bvolume_copy_balance(&control->volume, volume); ++ ++ if (!control->linked || control->unlinked) ++ return; ++ ++ if (volume_changed) { ++ char old_volume_str[PA_VOLUME_SNPRINT_VERBOSE_MAX]; ++ char new_volume_str[PA_VOLUME_SNPRINT_VERBOSE_MAX]; ++ ++ pa_log_debug("The volume of volume control %s changed from %s to %s.", control->name, ++ pa_volume_snprint_verbose(old_volume_str, sizeof(old_volume_str), old_volume.volume, ++ control->convertible_to_dB), ++ pa_volume_snprint_verbose(new_volume_str, sizeof(new_volume_str), control->volume.volume, ++ control->convertible_to_dB)); ++ } ++ ++ if (balance_changed) { ++ char old_balance_str[PA_BVOLUME_SNPRINT_BALANCE_MAX]; ++ char new_balance_str[PA_BVOLUME_SNPRINT_BALANCE_MAX]; ++ ++ pa_log_debug("The balance of volume control %s changed from %s to %s.", control->name, ++ pa_bvolume_snprint_balance(old_balance_str, sizeof(old_balance_str), &control->volume), ++ pa_bvolume_snprint_balance(new_balance_str, sizeof(new_balance_str), &control->volume)); ++ } ++ ++ pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_VOLUME_CHANGED], control); ++} ++ ++int pa_volume_control_set_volume(pa_volume_control *control, const pa_bvolume *volume, bool set_volume, bool set_balance) { ++ pa_bvolume volume_local; ++ int r; ++ ++ pa_assert(control); ++ pa_assert(volume); ++ ++ volume_local = *volume; ++ ++ if (!control->set_volume) { ++ pa_log_info("Tried to set the volume of volume control %s, but the volume control doesn't support the operation.", ++ control->name); ++ return -PA_ERR_NOTSUPPORTED; ++ } ++ ++ if (set_balance ++ && !control->channel_map_is_writable ++ && !pa_channel_map_equal(&volume_local.channel_map, &control->volume.channel_map)) ++ pa_bvolume_remap(&volume_local, &control->volume.channel_map); ++ ++ if (pa_bvolume_equal(&volume_local, &control->volume, set_volume, set_balance)) ++ return 0; ++ ++ control->set_volume_in_progress = true; ++ r = control->set_volume(control, &volume_local, set_volume, set_balance); ++ control->set_volume_in_progress = false; ++ ++ if (r >= 0) ++ set_volume_internal(control, &volume_local, set_volume, set_balance); ++ ++ return r; ++} ++ ++void pa_volume_control_description_changed(pa_volume_control *control, const char *new_description) { ++ char *old_description; ++ ++ pa_assert(control); ++ pa_assert(new_description); ++ ++ old_description = control->description; ++ ++ if (pa_streq(new_description, old_description)) ++ return; ++ ++ control->description = pa_xstrdup(new_description); ++ pa_log_debug("The description of volume control %s changed from \"%s\" to \"%s\".", control->name, old_description, ++ new_description); ++ pa_xfree(old_description); ++ pa_hook_fire(&control->volume_api->hooks[PA_VOLUME_API_HOOK_VOLUME_CONTROL_DESCRIPTION_CHANGED], control); ++} ++ ++void pa_volume_control_volume_changed(pa_volume_control *control, const pa_bvolume *new_volume, bool volume_changed, ++ bool balance_changed) { ++ pa_assert(control); ++ pa_assert(new_volume); ++ ++ if (!control->linked) ++ return; ++ ++ if (control->set_volume_in_progress) ++ return; ++ ++ set_volume_internal(control, new_volume, volume_changed, balance_changed); ++} ++ ++void pa_volume_control_add_device(pa_volume_control *control, pa_device *device) { ++ pa_assert(control); ++ pa_assert(device); ++ ++ pa_assert_se(pa_hashmap_put(control->devices, device, device) >= 0); ++} ++ ++void pa_volume_control_remove_device(pa_volume_control *control, pa_device *device) { ++ pa_assert(control); ++ pa_assert(device); ++ ++ pa_assert_se(pa_hashmap_remove(control->devices, device)); ++} ++ ++void pa_volume_control_add_default_for_device(pa_volume_control *control, pa_device *device) { ++ pa_assert(control); ++ pa_assert(device); ++ ++ pa_assert_se(pa_hashmap_put(control->default_for_devices, device, device) >= 0); ++} ++ ++void pa_volume_control_remove_default_for_device(pa_volume_control *control, pa_device *device) { ++ pa_assert(control); ++ pa_assert(device); ++ ++ pa_assert_se(pa_hashmap_remove(control->default_for_devices, device)); ++} ++ ++void pa_volume_control_add_stream(pa_volume_control *control, pas_stream *stream) { ++ pa_assert(control); ++ pa_assert(stream); ++ ++ pa_assert_se(pa_hashmap_put(control->streams, stream, stream) >= 0); ++} ++ ++void pa_volume_control_remove_stream(pa_volume_control *control, pas_stream *stream) { ++ pa_assert(control); ++ pa_assert(stream); ++ ++ pa_assert_se(pa_hashmap_remove(control->streams, stream)); ++} ++ ++void pa_volume_control_add_audio_group(pa_volume_control *control, pa_audio_group *group) { ++ pa_assert(control); ++ pa_assert(group); ++ ++ pa_assert_se(pa_hashmap_put(control->audio_groups, group, group) >= 0); ++} ++ ++void pa_volume_control_remove_audio_group(pa_volume_control *control, pa_audio_group *group) { ++ pa_assert(control); ++ pa_assert(group); ++ ++ pa_assert_se(pa_hashmap_remove(control->audio_groups, group)); ++} +diff --git a/src/modules/volume-api/volume-control.h b/src/modules/volume-api/volume-control.h +new file mode 100644 +index 0000000..aaba758 +--- /dev/null ++++ b/src/modules/volume-api/volume-control.h +@@ -0,0 +1,112 @@ ++#ifndef foovolumecontrolhfoo ++#define foovolumecontrolhfoo ++ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#include <modules/volume-api/bvolume.h> ++#include <modules/volume-api/volume-api.h> ++ ++typedef struct pa_volume_control pa_volume_control; ++ ++struct pa_volume_control { ++ pa_volume_api *volume_api; ++ uint32_t index; ++ const char *name; ++ char *description; ++ pa_proplist *proplist; ++ pa_bvolume volume; ++ bool convertible_to_dB; ++ bool channel_map_is_writable; ++ ++ /* If this volume control is the "own volume control" of an audio group, ++ * this is set to point to that group, otherwise this is NULL. */ ++ pa_audio_group *owner_audio_group; ++ ++ pa_hashmap *devices; /* pa_device -> pa_device (hashmap-as-a-set) */ ++ pa_hashmap *default_for_devices; /* pa_device -> pa_device (hashmap-as-a-set) */ ++ pa_hashmap *streams; /* pas_stream -> pas_stream (hashmap-as-a-set) */ ++ pa_hashmap *audio_groups; /* pa_audio_group -> pa_audio_group (hashmap-as-a-set) */ ++ ++ bool linked; ++ bool unlinked; ++ bool set_volume_in_progress; ++ ++ /* Called from pa_volume_control_set_volume(). The implementation is ++ * expected to return a negative error code on failure. May be NULL, if the ++ * volume control is read-only. */ ++ int (*set_volume)(pa_volume_control *control, const pa_bvolume *volume, bool set_volume, bool set_balance); ++ ++ void *userdata; ++}; ++ ++pa_volume_control *pa_volume_control_new(pa_volume_api *api, const char *name, const char *description, bool convertible_to_dB, ++ bool channel_map_is_writable); ++ ++typedef void (*pa_volume_control_set_initial_volume_cb_t)(pa_volume_control *control); ++ ++/* initial_volume is the preferred initial volume of the volume control ++ * implementation. It may be NULL or partially invalid, if the implementation ++ * doesn't care about the initial state of the volume control, as long as these ++ * two rules are followed: ++ * ++ * 1) Read-only volume controls must always specify fully valid initial ++ * volume. ++ * 2) Volume controls with read-only channel map must always specify a valid ++ * channel map in initial_volume. ++ * ++ * The implementation's initial volume preference may be overridden by policy, ++ * if the volume control isn't read-only. When the final initial volume is ++ * known, the implementation is notified via set_initial_volume_cb (the volume ++ * can be read from control->volume). set_initial_volume_cb may be NULL, if the ++ * volume control is read-only. */ ++void pa_volume_control_put(pa_volume_control *control, const pa_bvolume *initial_volume, ++ pa_volume_control_set_initial_volume_cb_t set_initial_volume_cb); ++ ++void pa_volume_control_unlink(pa_volume_control *control); ++void pa_volume_control_free(pa_volume_control *control); ++ ++/* Called by audio-group.c only. */ ++void pa_volume_control_set_owner_audio_group(pa_volume_control *control, pa_audio_group *group); ++ ++/* Called by clients and policy modules. */ ++int pa_volume_control_set_volume(pa_volume_control *control, const pa_bvolume *volume, bool set_volume, bool set_balance); ++ ++/* Called by the volume control implementation. */ ++void pa_volume_control_description_changed(pa_volume_control *control, const char *new_description); ++void pa_volume_control_volume_changed(pa_volume_control *control, const pa_bvolume *new_volume, bool volume_changed, ++ bool balance_changed); ++ ++/* Called from device.c only. */ ++void pa_volume_control_add_device(pa_volume_control *control, pa_device *device); ++void pa_volume_control_remove_device(pa_volume_control *control, pa_device *device); ++void pa_volume_control_add_default_for_device(pa_volume_control *control, pa_device *device); ++void pa_volume_control_remove_default_for_device(pa_volume_control *control, pa_device *device); ++ ++/* Called from sstream.c only. */ ++void pa_volume_control_add_stream(pa_volume_control *control, pas_stream *stream); ++void pa_volume_control_remove_stream(pa_volume_control *control, pas_stream *stream); ++ ++/* Called from audio-group.c only. */ ++void pa_volume_control_add_audio_group(pa_volume_control *control, pa_audio_group *group); ++void pa_volume_control_remove_audio_group(pa_volume_control *control, pa_audio_group *group); ++ ++#endif +diff --git a/src/pulse/ext-volume-api.c b/src/pulse/ext-volume-api.c +new file mode 100644 +index 0000000..8e93bce +--- /dev/null ++++ b/src/pulse/ext-volume-api.c +@@ -0,0 +1,275 @@ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#ifdef HAVE_CONFIG_H ++#include <config.h> ++#endif ++ ++#include "ext-volume-api.h" ++ ++#include <pulsecore/core-util.h> ++#include <pulsecore/i18n.h> ++#include <pulsecore/macro.h> ++ ++#include <math.h> ++ ++int pa_ext_volume_api_balance_valid(double balance) { ++ return balance >= 0.0 && balance <= 1.0; ++} ++ ++int pa_ext_volume_api_bvolume_valid(const pa_ext_volume_api_bvolume *volume, int check_volume, int check_balance) { ++ unsigned channel; ++ ++ pa_assert(volume); ++ ++ if (check_volume && !PA_VOLUME_IS_VALID(volume->volume)) ++ return 0; ++ ++ if (!check_balance) ++ return 1; ++ ++ if (!pa_channel_map_valid(&volume->channel_map)) ++ return 0; ++ ++ for (channel = 0; channel < volume->channel_map.channels; channel++) { ++ if (!pa_ext_volume_api_balance_valid(volume->balance[channel])) ++ return 0; ++ } ++ ++ return 1; ++} ++ ++void pa_ext_volume_api_bvolume_init_invalid(pa_ext_volume_api_bvolume *volume) { ++ unsigned i; ++ ++ pa_assert(volume); ++ ++ volume->volume = PA_VOLUME_INVALID; ++ ++ for (i = 0; i < PA_CHANNELS_MAX; i++) ++ volume->balance[i] = -1.0; ++ ++ pa_channel_map_init(&volume->channel_map); ++} ++ ++void pa_ext_volume_api_bvolume_init_mono(pa_ext_volume_api_bvolume *bvolume, pa_volume_t volume) { ++ pa_assert(bvolume); ++ pa_assert(PA_VOLUME_IS_VALID(volume)); ++ ++ bvolume->volume = volume; ++ bvolume->balance[0] = 1.0; ++ pa_channel_map_init_mono(&bvolume->channel_map); ++} ++ ++int pa_ext_volume_api_bvolume_equal(const pa_ext_volume_api_bvolume *a, const pa_ext_volume_api_bvolume *b, ++ int check_volume, int check_balance) { ++ unsigned i; ++ ++ pa_assert(a); ++ pa_assert(b); ++ ++ if (check_volume && a->volume != b->volume) ++ return 0; ++ ++ if (!check_balance) ++ return 1; ++ ++ if (!pa_channel_map_equal(&a->channel_map, &b->channel_map)) ++ return 0; ++ ++ for (i = 0; i < a->channel_map.channels; i++) { ++ if (fabs(a->balance[i] - b->balance[i]) > 0.00001) ++ return 0; ++ } ++ ++ return 1; ++} ++ ++void pa_ext_volume_api_bvolume_from_cvolume(pa_ext_volume_api_bvolume *bvolume, const pa_cvolume *cvolume, ++ const pa_channel_map *map) { ++ unsigned i; ++ ++ pa_assert(bvolume); ++ pa_assert(cvolume); ++ pa_assert(map); ++ pa_assert(cvolume->channels == map->channels); ++ ++ bvolume->volume = pa_cvolume_max(cvolume); ++ bvolume->channel_map = *map; ++ ++ for (i = 0; i < map->channels; i++) { ++ if (bvolume->volume != PA_VOLUME_MUTED) ++ bvolume->balance[i] = ((double) cvolume->values[i]) / ((double) bvolume->volume); ++ else ++ bvolume->balance[i] = 1.0; ++ } ++} ++ ++void pa_ext_volume_api_bvolume_to_cvolume(const pa_ext_volume_api_bvolume *bvolume, pa_cvolume *cvolume) { ++ unsigned i; ++ ++ pa_assert(bvolume); ++ pa_assert(cvolume); ++ pa_assert(pa_ext_volume_api_bvolume_valid(bvolume, true, true)); ++ ++ cvolume->channels = bvolume->channel_map.channels; ++ ++ for (i = 0; i < bvolume->channel_map.channels; i++) ++ cvolume->values[i] = bvolume->volume * bvolume->balance[i]; ++} ++ ++void pa_ext_volume_api_bvolume_copy_balance(pa_ext_volume_api_bvolume *to, ++ const pa_ext_volume_api_bvolume *from) { ++ pa_assert(to); ++ pa_assert(from); ++ ++ memcpy(to->balance, from->balance, sizeof(from->balance)); ++ to->channel_map = from->channel_map; ++} ++ ++void pa_ext_volume_api_bvolume_reset_balance(pa_ext_volume_api_bvolume *volume, const pa_channel_map *map) { ++ unsigned i; ++ ++ pa_assert(volume); ++ pa_assert(map); ++ pa_assert(pa_channel_map_valid(map)); ++ ++ for (i = 0; i < map->channels; i++) ++ volume->balance[i] = 1.0; ++ ++ volume->channel_map = *map; ++} ++ ++void pa_ext_volume_api_bvolume_remap(pa_ext_volume_api_bvolume *volume, const pa_channel_map *to) { ++ unsigned i; ++ pa_cvolume cvolume; ++ ++ pa_assert(volume); ++ pa_assert(to); ++ pa_assert(pa_ext_volume_api_bvolume_valid(volume, false, true)); ++ pa_assert(pa_channel_map_valid(to)); ++ ++ cvolume.channels = volume->channel_map.channels; ++ ++ for (i = 0; i < cvolume.channels; i++) ++ cvolume.values[i] = volume->balance[i] * (double) PA_VOLUME_NORM; ++ ++ pa_cvolume_remap(&cvolume, &volume->channel_map, to); ++ ++ for (i = 0; i < to->channels; i++) ++ volume->balance[i] = (double) cvolume.values[i] / (double) PA_VOLUME_NORM; ++ ++ volume->channel_map = *to; ++} ++ ++double pa_ext_volume_api_bvolume_get_left_right_balance(const pa_ext_volume_api_bvolume *volume) { ++ pa_ext_volume_api_bvolume bvolume; ++ pa_cvolume cvolume; ++ double ret; ++ ++ pa_assert(volume); ++ ++ bvolume.volume = PA_VOLUME_NORM; ++ pa_ext_volume_api_bvolume_copy_balance(&bvolume, volume); ++ pa_ext_volume_api_bvolume_to_cvolume(&bvolume, &cvolume); ++ ret = pa_cvolume_get_balance(&cvolume, &volume->channel_map); ++ ++ return ret; ++} ++ ++void pa_ext_volume_api_bvolume_set_left_right_balance(pa_ext_volume_api_bvolume *volume, double balance) { ++ pa_cvolume cvolume; ++ pa_volume_t old_volume; ++ ++ pa_assert(volume); ++ ++ if (!pa_channel_map_can_balance(&volume->channel_map)) ++ return; ++ ++ pa_cvolume_reset(&cvolume, volume->channel_map.channels); ++ pa_cvolume_set_balance(&cvolume, &volume->channel_map, balance); ++ old_volume = volume->volume; ++ pa_ext_volume_api_bvolume_from_cvolume(volume, &cvolume, &volume->channel_map); ++ volume->volume = old_volume; ++} ++ ++double pa_ext_volume_api_bvolume_get_rear_front_balance(const pa_ext_volume_api_bvolume *volume) { ++ pa_ext_volume_api_bvolume bvolume; ++ pa_cvolume cvolume; ++ double ret; ++ ++ pa_assert(volume); ++ ++ bvolume.volume = PA_VOLUME_NORM; ++ pa_ext_volume_api_bvolume_copy_balance(&bvolume, volume); ++ pa_ext_volume_api_bvolume_to_cvolume(&bvolume, &cvolume); ++ ret = pa_cvolume_get_fade(&cvolume, &volume->channel_map); ++ ++ return ret; ++} ++ ++void pa_ext_volume_api_bvolume_set_rear_front_balance(pa_ext_volume_api_bvolume *volume, double balance) { ++ pa_cvolume cvolume; ++ pa_volume_t old_volume; ++ ++ pa_assert(volume); ++ ++ if (!pa_channel_map_can_fade(&volume->channel_map)) ++ return; ++ ++ pa_cvolume_reset(&cvolume, volume->channel_map.channels); ++ pa_cvolume_set_fade(&cvolume, &volume->channel_map, balance); ++ old_volume = volume->volume; ++ pa_ext_volume_api_bvolume_from_cvolume(volume, &cvolume, &volume->channel_map); ++ volume->volume = old_volume; ++} ++ ++char *pa_ext_volume_api_bvolume_snprint_balance(char *buf, size_t buf_len, ++ const pa_ext_volume_api_bvolume *volume) { ++ char *e; ++ unsigned channel; ++ bool first = true; ++ ++ pa_assert(buf); ++ pa_assert(buf_len > 0); ++ pa_assert(volume); ++ ++ pa_init_i18n(); ++ ++ if (!pa_ext_volume_api_bvolume_valid(volume, true, true)) { ++ pa_snprintf(buf, buf_len, _("(invalid)")); ++ return buf; ++ } ++ ++ *(e = buf) = 0; ++ ++ for (channel = 0; channel < volume->channel_map.channels && buf_len > 1; channel++) { ++ buf_len -= pa_snprintf(e, buf_len, "%s%s: %u%%", ++ first ? "" : ", ", ++ pa_channel_position_to_string(volume->channel_map.map[channel]), ++ (unsigned) (volume->balance[channel] * 100 + 0.5)); ++ ++ e = strchr(e, 0); ++ first = false; ++ } ++ ++ return buf; ++} +diff --git a/src/pulse/ext-volume-api.h b/src/pulse/ext-volume-api.h +new file mode 100644 +index 0000000..36b7748 +--- /dev/null ++++ b/src/pulse/ext-volume-api.h +@@ -0,0 +1,68 @@ ++#ifndef fooextvolumeapihfoo ++#define fooextvolumeapihfoo ++ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#include <pulse/cdecl.h> ++#include <pulse/context.h> ++#include <pulse/volume.h> ++ ++/* This API is temporary, and has no stability guarantees whatsoever. Think ++ * twice before making anything that relies on this API. This is undocumented ++ * for a reason. */ ++ ++PA_C_DECL_BEGIN ++ ++typedef struct pa_ext_volume_api_bvolume pa_ext_volume_api_bvolume; ++ ++struct pa_ext_volume_api_bvolume { ++ pa_volume_t volume; ++ double balance[PA_CHANNELS_MAX]; ++ pa_channel_map channel_map; ++}; ++ ++int pa_ext_volume_api_balance_valid(double balance) PA_GCC_CONST; ++int pa_ext_volume_api_bvolume_valid(const pa_ext_volume_api_bvolume *volume, int check_volume, int check_balance) ++ PA_GCC_PURE; ++void pa_ext_volume_api_bvolume_init_invalid(pa_ext_volume_api_bvolume *volume); ++void pa_ext_volume_api_bvolume_init_mono(pa_ext_volume_api_bvolume *bvolume, pa_volume_t volume); ++int pa_ext_volume_api_bvolume_equal(const pa_ext_volume_api_bvolume *a, const pa_ext_volume_api_bvolume *b, ++ int check_volume, int check_balance) PA_GCC_PURE; ++void pa_ext_volume_api_bvolume_from_cvolume(pa_ext_volume_api_bvolume *bvolume, const pa_cvolume *cvolume, ++ const pa_channel_map *map); ++void pa_ext_volume_api_bvolume_to_cvolume(const pa_ext_volume_api_bvolume *bvolume, pa_cvolume *cvolume); ++void pa_ext_volume_api_bvolume_copy_balance(pa_ext_volume_api_bvolume *to, ++ const pa_ext_volume_api_bvolume *from); ++void pa_ext_volume_api_bvolume_reset_balance(pa_ext_volume_api_bvolume *volume, const pa_channel_map *map); ++void pa_ext_volume_api_bvolume_remap(pa_ext_volume_api_bvolume *volume, const pa_channel_map *to); ++double pa_ext_volume_api_bvolume_get_left_right_balance(const pa_ext_volume_api_bvolume *volume) PA_GCC_PURE; ++void pa_ext_volume_api_bvolume_set_left_right_balance(pa_ext_volume_api_bvolume *volume, double balance); ++double pa_ext_volume_api_bvolume_get_rear_front_balance(const pa_ext_volume_api_bvolume *volume) PA_GCC_PURE; ++void pa_ext_volume_api_bvolume_set_rear_front_balance(pa_ext_volume_api_bvolume *volume, double balance); ++ ++#define PA_EXT_VOLUME_API_BVOLUME_SNPRINT_BALANCE_MAX 500 ++char *pa_ext_volume_api_bvolume_snprint_balance(char *buf, size_t buf_size, ++ const pa_ext_volume_api_bvolume *volume); ++ ++PA_C_DECL_END ++ ++#endif +-- +2.1.4 + +--- a/po/POTFILES.in 2016-04-13 17:40:00.818008672 +0200 ++++ b/po/POTFILES.in 2016-04-13 17:40:30.885008622 +0200 +@@ -198,3 +198,5 @@ + src/utils/padsp.c + src/utils/pasuspender.c + src/utils/pax11publish.c ++src/modules/volume-api/device-creator.c ++src/pulse/ext-volume-api.c diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0031-Add-module-main-volume-policy.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0031-Add-module-main-volume-policy.patch new file mode 100644 index 000000000..216ed21e9 --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0031-Add-module-main-volume-policy.patch @@ -0,0 +1,1418 @@ +From cfb39f18569679f59c9b6283c47e8d90ddd9763d Mon Sep 17 00:00:00 2001 +From: Tanu Kaskinen <tanu.kaskinen@linux.intel.com> +Date: Wed, 21 May 2014 14:13:41 +0300 +Subject: [PATCH] Add module-main-volume-policy + +Change-Id: I787141b43cafb652aa752c64ae28b6b7aa052d8e +Signed-off-by: Jaska Uimonen <jaska.uimonen@intel.com> +--- + Makefile.am | 3 + + src/Makefile.am | 15 + + src/daemon/default.pa.in | 4 + + .../main-volume-policy/main-volume-context.c | 325 ++++++++++++ + .../main-volume-policy/main-volume-context.h | 75 +++ + .../main-volume-policy/main-volume-policy.c | 213 ++++++++ + .../main-volume-policy.conf.example | 20 + + .../main-volume-policy/main-volume-policy.h | 72 +++ + .../main-volume-policy/module-main-volume-policy.c | 556 +++++++++++++++++++++ + 9 files changed, 1283 insertions(+) + create mode 100644 src/modules/main-volume-policy/main-volume-context.c + create mode 100644 src/modules/main-volume-policy/main-volume-context.h + create mode 100644 src/modules/main-volume-policy/main-volume-policy.c + create mode 100644 src/modules/main-volume-policy/main-volume-policy.conf.example + create mode 100644 src/modules/main-volume-policy/main-volume-policy.h + create mode 100644 src/modules/main-volume-policy/module-main-volume-policy.c + +diff --git a/Makefile.am b/Makefile.am +index cf4a648..646b7fc 100644 +--- a/Makefile.am 2016-04-13 15:14:28.942023245 +0200 ++++ b/Makefile.am 2016-04-13 15:16:32.691023039 +0200 +@@ -60,6 +60,9 @@ + moduledevvolumeapi_DATA = src/modules/volume-api/*.h + moduledevvolumeapidir = $(includedir)/pulsemodule/modules/volume-api + ++moduledevmainvolumepolicy_DATA = $(top_srcdir)/src/modules/main-volume-policy/*.h ++moduledevmainvolumepolicydir = $(includedir)/pulsemodule/modules/main-volume-policy ++ + if HAVE_GLIB20 + pkgconfig_DATA += \ + libpulse-mainloop-glib.pc + libpulse-mainloop-glib.pc +diff --git a/src/Makefile.am b/src/Makefile.am +index a6bb319..8fa60ec 100644 +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -1050,7 +1050,8 @@ + libprotocol-simple.la \ + libprotocol-http.la \ + libprotocol-native.la \ +- libvolume-api.la ++ libvolume-api.la \ ++ libmain-volume-policy.la + + if HAVE_WEBRTC + modlibexec_LTLIBRARIES += libwebrtc-util.la +@@ -1051,6 +1052,12 @@ libcli_la_SOURCES = pulsecore/cli.c pulsecore/cli.h + libcli_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version + libcli_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINOR@.la libpulsecommon-@PA_MAJORMINOR@.la libpulse.la + ++libmain_volume_policy_la_SOURCES = \ ++ modules/main-volume-policy/main-volume-context.c modules/main-volume-policy/main-volume-context.h \ ++ modules/main-volume-policy/main-volume-policy.c modules/main-volume-policy/main-volume-policy.h ++libmain_volume_policy_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version ++libmain_volume_policy_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINOR@.la libpulsecommon-@PA_MAJORMINOR@.la libpulse.la libvolume-api.la ++ + libprotocol_cli_la_SOURCES = pulsecore/protocol-cli.c pulsecore/protocol-cli.h + libprotocol_cli_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version + libprotocol_cli_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINOR@.la libpulsecommon-@PA_MAJORMINOR@.la libpulse.la libcli.la +@@ -1136,6 +1136,7 @@ endif + modlibexec_LTLIBRARIES += \ + module-cli.la \ + module-cli-protocol-tcp.la \ ++ module-main-volume-policy.la \ + module-simple-protocol-tcp.la \ + module-null-sink.la \ + module-null-source.la \ +@@ -1426,6 +1434,7 @@ SYMDEF_FILES = \ + module-cli-symdef.h \ + module-cli-protocol-tcp-symdef.h \ + module-cli-protocol-unix-symdef.h \ ++ module-main-volume-policy-symdef.h \ + module-pipe-sink-symdef.h \ + module-pipe-source-symdef.h \ + module-simple-protocol-tcp-symdef.h \ +@@ -1575,6 +1584,12 @@ module_cli_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_CLI $(AM_ + module_cli_protocol_unix_la_LDFLAGS = $(MODULE_LDFLAGS) + module_cli_protocol_unix_la_LIBADD = $(MODULE_LIBADD) libprotocol-cli.la + ++# Main volume and mute policy ++ ++module_main_volume_policy_la_SOURCES = modules/main-volume-policy/module-main-volume-policy.c ++module_main_volume_policy_la_LDFLAGS = $(MODULE_LDFLAGS) ++module_main_volume_policy_la_LIBADD = $(MODULE_LIBADD) libmain-volume-policy.la libvolume-api.la ++ + # HTTP protocol + + module_http_protocol_tcp_la_SOURCES = modules/module-protocol-stub.c +diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in +index 7cf52a4..f70804c 100755 +--- a/src/daemon/default.pa.in ++++ b/src/daemon/default.pa.in +@@ -188,6 +188,10 @@ + #.endif + ])dnl + ++.ifexists module-main-volume-policy ++load-module module-main-volume-policy ++.endif ++ + ### Make some devices default + #set-default-sink output + #set-default-source input +diff --git a/src/modules/main-volume-policy/main-volume-context.c b/src/modules/main-volume-policy/main-volume-context.c +new file mode 100644 +index 0000000..7ac35c6 +--- /dev/null ++++ b/src/modules/main-volume-policy/main-volume-context.c +@@ -0,0 +1,325 @@ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#ifdef HAVE_CONFIG_H ++#include <config.h> ++#endif ++ ++#include "main-volume-context.h" ++ ++#include <modules/volume-api/mute-control.h> ++#include <modules/volume-api/volume-control.h> ++ ++int pa_main_volume_context_new(pa_main_volume_policy *policy, const char *name, const char *description, ++ pa_main_volume_context **context) { ++ pa_main_volume_context *context_local; ++ int r; ++ ++ pa_assert(policy); ++ pa_assert(name); ++ pa_assert(description); ++ pa_assert(context); ++ ++ context_local = pa_xnew0(struct pa_main_volume_context, 1); ++ context_local->main_volume_policy = policy; ++ context_local->index = pa_main_volume_policy_allocate_main_volume_context_index(policy); ++ ++ r = pa_main_volume_policy_register_name(policy, name, true, &context_local->name); ++ if (r < 0) ++ goto fail; ++ ++ context_local->description = pa_xstrdup(description); ++ ++ *context = context_local; ++ ++ return 0; ++ ++fail: ++ pa_main_volume_context_free(context_local); ++ ++ return r; ++} ++ ++void pa_main_volume_context_put(pa_main_volume_context *context) { ++ pa_assert(context); ++ ++ pa_main_volume_policy_add_main_volume_context(context->main_volume_policy, context); ++ ++ context->linked = true; ++ ++ pa_log_debug("Created main volume context #%u.", context->index); ++ pa_log_debug(" Name: %s", context->name); ++ pa_log_debug(" Description: %s", context->description); ++ pa_log_debug(" Main output volume control: %s", ++ context->main_output_volume_control ? context->main_output_volume_control->name : "(unset)"); ++ pa_log_debug(" Main input volume control: %s", ++ context->main_input_volume_control ? context->main_input_volume_control->name : "(unset)"); ++ pa_log_debug(" Main output mute control: %s", ++ context->main_output_mute_control ? context->main_output_mute_control->name : "(unset)"); ++ pa_log_debug(" Main input mute control: %s", ++ context->main_input_mute_control ? context->main_input_mute_control->name : "(unset)"); ++ ++ pa_hook_fire(&context->main_volume_policy->hooks[PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_PUT], context); ++} ++ ++void pa_main_volume_context_unlink(pa_main_volume_context *context) { ++ pa_assert(context); ++ ++ if (context->unlinked) { ++ pa_log_debug("Unlinking main volume context %s (already unlinked, this is a no-op).", context->name); ++ return; ++ } ++ ++ context->unlinked = true; ++ ++ pa_log_debug("Unlinking main volume context %s.", context->name); ++ ++ if (context->linked) ++ pa_hook_fire(&context->main_volume_policy->hooks[PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_UNLINK], context); ++ ++ if (context->main_input_mute_control_binding) { ++ pa_binding_free(context->main_input_mute_control_binding); ++ context->main_input_mute_control_binding = NULL; ++ } ++ ++ if (context->main_output_mute_control_binding) { ++ pa_binding_free(context->main_output_mute_control_binding); ++ context->main_output_mute_control_binding = NULL; ++ } ++ ++ if (context->main_input_volume_control_binding) { ++ pa_binding_free(context->main_input_volume_control_binding); ++ context->main_input_volume_control_binding = NULL; ++ } ++ ++ if (context->main_output_volume_control_binding) { ++ pa_binding_free(context->main_output_volume_control_binding); ++ context->main_output_volume_control_binding = NULL; ++ } ++ ++ context->main_input_mute_control = NULL; ++ context->main_output_mute_control = NULL; ++ context->main_input_volume_control = NULL; ++ context->main_output_volume_control = NULL; ++ ++ pa_main_volume_policy_remove_main_volume_context(context->main_volume_policy, context); ++} ++ ++void pa_main_volume_context_free(pa_main_volume_context *context) { ++ pa_assert(context); ++ ++ if (!context->unlinked) ++ pa_main_volume_context_unlink(context); ++ ++ pa_xfree(context->description); ++ ++ if (context->name) ++ pa_main_volume_policy_unregister_name(context->main_volume_policy, context->name); ++ ++ pa_xfree(context); ++} ++ ++const char *pa_main_volume_context_get_name(pa_main_volume_context *context) { ++ pa_assert(context); ++ ++ return context->name; ++} ++ ++static void set_main_output_volume_control_internal(pa_main_volume_context *context, pa_volume_control *control) { ++ pa_volume_control *old_control; ++ ++ pa_assert(context); ++ ++ old_control = context->main_output_volume_control; ++ ++ if (control == old_control) ++ return; ++ ++ context->main_output_volume_control = control; ++ ++ if (!context->linked || context->unlinked) ++ return; ++ ++ pa_log_debug("The main output volume control of main volume context %s changed from %s to %s.", context->name, ++ old_control ? old_control->name : "(unset)", control ? control->name : "(unset)"); ++ ++ pa_hook_fire(&context->main_volume_policy->hooks ++ [PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_OUTPUT_VOLUME_CONTROL_CHANGED], ++ context); ++} ++ ++void pa_main_volume_context_bind_main_output_volume_control(pa_main_volume_context *context, ++ pa_binding_target_info *target_info) { ++ pa_binding_owner_info owner_info = { ++ .userdata = context, ++ .set_value = (pa_binding_set_value_cb_t) set_main_output_volume_control_internal, ++ }; ++ ++ pa_assert(context); ++ pa_assert(target_info); ++ ++ if (context->main_output_volume_control_binding) ++ pa_binding_free(context->main_output_volume_control_binding); ++ ++ context->main_output_volume_control_binding = pa_binding_new(context->main_volume_policy->volume_api, &owner_info, ++ target_info); ++} ++ ++static void set_main_input_volume_control_internal(pa_main_volume_context *context, pa_volume_control *control) { ++ pa_volume_control *old_control; ++ ++ pa_assert(context); ++ ++ old_control = context->main_input_volume_control; ++ ++ if (control == old_control) ++ return; ++ ++ context->main_input_volume_control = control; ++ ++ if (!context->linked || context->unlinked) ++ return; ++ ++ pa_log_debug("The main input volume control of main volume context %s changed from %s to %s.", context->name, ++ old_control ? old_control->name : "(unset)", control ? control->name : "(unset)"); ++ ++ pa_hook_fire(&context->main_volume_policy->hooks ++ [PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_INPUT_VOLUME_CONTROL_CHANGED], ++ context); ++} ++ ++void pa_main_volume_context_bind_main_input_volume_control(pa_main_volume_context *context, ++ pa_binding_target_info *target_info) { ++ pa_binding_owner_info owner_info = { ++ .userdata = context, ++ .set_value = (pa_binding_set_value_cb_t) set_main_input_volume_control_internal, ++ }; ++ ++ pa_assert(context); ++ pa_assert(target_info); ++ ++ if (context->main_input_volume_control_binding) ++ pa_binding_free(context->main_input_volume_control_binding); ++ ++ context->main_input_volume_control_binding = pa_binding_new(context->main_volume_policy->volume_api, &owner_info, ++ target_info); ++} ++ ++static void set_main_output_mute_control_internal(pa_main_volume_context *context, pa_mute_control *control) { ++ pa_mute_control *old_control; ++ ++ pa_assert(context); ++ ++ old_control = context->main_output_mute_control; ++ ++ if (control == old_control) ++ return; ++ ++ context->main_output_mute_control = control; ++ ++ if (!context->linked || context->unlinked) ++ return; ++ ++ pa_log_debug("The main output mute control of main volume context %s changed from %s to %s.", context->name, ++ old_control ? old_control->name : "(unset)", control ? control->name : "(unset)"); ++ ++ pa_hook_fire(&context->main_volume_policy->hooks ++ [PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_OUTPUT_MUTE_CONTROL_CHANGED], ++ context); ++} ++ ++void pa_main_volume_context_bind_main_output_mute_control(pa_main_volume_context *context, ++ pa_binding_target_info *target_info) { ++ pa_binding_owner_info owner_info = { ++ .userdata = context, ++ .set_value = (pa_binding_set_value_cb_t) set_main_output_mute_control_internal, ++ }; ++ ++ pa_assert(context); ++ pa_assert(target_info); ++ ++ if (context->main_output_mute_control_binding) ++ pa_binding_free(context->main_output_mute_control_binding); ++ ++ context->main_output_mute_control_binding = pa_binding_new(context->main_volume_policy->volume_api, &owner_info, ++ target_info); ++} ++ ++static void set_main_input_mute_control_internal(pa_main_volume_context *context, pa_mute_control *control) { ++ pa_mute_control *old_control; ++ ++ pa_assert(context); ++ ++ old_control = context->main_input_mute_control; ++ ++ if (control == old_control) ++ return; ++ ++ context->main_input_mute_control = control; ++ ++ if (!context->linked || context->unlinked) ++ return; ++ ++ pa_log_debug("The main input mute control of main volume context %s changed from %s to %s.", context->name, ++ old_control ? old_control->name : "(unset)", control ? control->name : "(unset)"); ++ ++ pa_hook_fire(&context->main_volume_policy->hooks ++ [PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_INPUT_MUTE_CONTROL_CHANGED], ++ context); ++} ++ ++void pa_main_volume_context_bind_main_input_mute_control(pa_main_volume_context *context, ++ pa_binding_target_info *target_info) { ++ pa_binding_owner_info owner_info = { ++ .userdata = context, ++ .set_value = (pa_binding_set_value_cb_t) set_main_input_mute_control_internal, ++ }; ++ ++ pa_assert(context); ++ pa_assert(target_info); ++ ++ if (context->main_input_mute_control_binding) ++ pa_binding_free(context->main_input_mute_control_binding); ++ ++ context->main_input_mute_control_binding = pa_binding_new(context->main_volume_policy->volume_api, &owner_info, ++ target_info); ++} ++ ++pa_binding_target_type *pa_main_volume_context_create_binding_target_type(pa_main_volume_policy *policy) { ++ pa_binding_target_type *type; ++ ++ pa_assert(policy); ++ ++ type = pa_binding_target_type_new(PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_TYPE, policy->main_volume_contexts, ++ &policy->hooks[PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_PUT], ++ &policy->hooks[PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_UNLINK], ++ (pa_binding_target_type_get_name_cb_t) pa_main_volume_context_get_name); ++ pa_binding_target_type_add_field(type, PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_OUTPUT_VOLUME_CONTROL, ++ PA_BINDING_CALCULATE_FIELD_OFFSET(pa_main_volume_context, main_output_volume_control)); ++ pa_binding_target_type_add_field(type, PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_INPUT_VOLUME_CONTROL, ++ PA_BINDING_CALCULATE_FIELD_OFFSET(pa_main_volume_context, main_input_volume_control)); ++ pa_binding_target_type_add_field(type, PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_OUTPUT_MUTE_CONTROL, ++ PA_BINDING_CALCULATE_FIELD_OFFSET(pa_main_volume_context, main_output_mute_control)); ++ pa_binding_target_type_add_field(type, PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_INPUT_MUTE_CONTROL, ++ PA_BINDING_CALCULATE_FIELD_OFFSET(pa_main_volume_context, main_input_mute_control)); ++ ++ return type; ++} +diff --git a/src/modules/main-volume-policy/main-volume-context.h b/src/modules/main-volume-policy/main-volume-context.h +new file mode 100644 +index 0000000..4a0a6f7 +--- /dev/null ++++ b/src/modules/main-volume-policy/main-volume-context.h +@@ -0,0 +1,75 @@ ++#ifndef foomainvolumecontexthfoo ++#define foomainvolumecontexthfoo ++ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#include <modules/main-volume-policy/main-volume-policy.h> ++ ++#include <modules/volume-api/binding.h> ++ ++typedef struct pa_main_volume_context pa_main_volume_context; ++ ++#define PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_TYPE "MainVolumeContext" ++#define PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_OUTPUT_VOLUME_CONTROL "main_output_volume_control" ++#define PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_INPUT_VOLUME_CONTROL "main_input_volume_control" ++#define PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_OUTPUT_MUTE_CONTROL "main_output_mute_control" ++#define PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_INPUT_MUTE_CONTROL "main_input_mute_control" ++ ++struct pa_main_volume_context { ++ pa_main_volume_policy *main_volume_policy; ++ uint32_t index; ++ const char *name; ++ char *description; ++ pa_volume_control *main_output_volume_control; ++ pa_volume_control *main_input_volume_control; ++ pa_mute_control *main_output_mute_control; ++ pa_mute_control *main_input_mute_control; ++ ++ pa_binding *main_output_volume_control_binding; ++ pa_binding *main_input_volume_control_binding; ++ pa_binding *main_output_mute_control_binding; ++ pa_binding *main_input_mute_control_binding; ++ ++ bool linked; ++ bool unlinked; ++}; ++ ++int pa_main_volume_context_new(pa_main_volume_policy *policy, const char *name, const char *description, ++ pa_main_volume_context **context); ++void pa_main_volume_context_put(pa_main_volume_context *context); ++void pa_main_volume_context_unlink(pa_main_volume_context *context); ++void pa_main_volume_context_free(pa_main_volume_context *context); ++ ++const char *pa_main_volume_context_get_name(pa_main_volume_context *context); ++ ++void pa_main_volume_context_bind_main_output_volume_control(pa_main_volume_context *context, ++ pa_binding_target_info *target_info); ++void pa_main_volume_context_bind_main_input_volume_control(pa_main_volume_context *context, ++ pa_binding_target_info *target_info); ++void pa_main_volume_context_bind_main_output_mute_control(pa_main_volume_context *context, ++ pa_binding_target_info *target_info); ++void pa_main_volume_context_bind_main_input_mute_control(pa_main_volume_context *context, pa_binding_target_info *target_info); ++ ++/* Called from main-volume-policy.c only. */ ++pa_binding_target_type *pa_main_volume_context_create_binding_target_type(pa_main_volume_policy *policy); ++ ++#endif +diff --git a/src/modules/main-volume-policy/main-volume-policy.c b/src/modules/main-volume-policy/main-volume-policy.c +new file mode 100644 +index 0000000..b0b4ede +--- /dev/null ++++ b/src/modules/main-volume-policy/main-volume-policy.c +@@ -0,0 +1,213 @@ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#ifdef HAVE_CONFIG_H ++#include <config.h> ++#endif ++ ++#include "main-volume-policy.h" ++ ++#include <modules/main-volume-policy/main-volume-context.h> ++ ++#include <pulsecore/core-util.h> ++#include <pulsecore/shared.h> ++ ++static pa_main_volume_policy *main_volume_policy_new(pa_core *core); ++static void main_volume_policy_free(pa_main_volume_policy *policy); ++ ++pa_main_volume_policy *pa_main_volume_policy_get(pa_core *core) { ++ pa_main_volume_policy *policy; ++ ++ pa_assert(core); ++ ++ policy = pa_shared_get(core, "main-volume-policy"); ++ ++ if (policy) ++ pa_main_volume_policy_ref(policy); ++ else { ++ policy = main_volume_policy_new(core); ++ pa_assert_se(pa_shared_set(core, "main-volume-policy", policy) >= 0); ++ } ++ ++ return policy; ++} ++ ++pa_main_volume_policy *pa_main_volume_policy_ref(pa_main_volume_policy *policy) { ++ pa_assert(policy); ++ ++ policy->refcnt++; ++ ++ return policy; ++} ++ ++void pa_main_volume_policy_unref(pa_main_volume_policy *policy) { ++ pa_assert(policy); ++ pa_assert(policy->refcnt > 0); ++ ++ policy->refcnt--; ++ ++ if (policy->refcnt == 0) { ++ pa_assert_se(pa_shared_remove(policy->core, "main-volume-policy") >= 0); ++ main_volume_policy_free(policy); ++ } ++} ++ ++static pa_main_volume_policy *main_volume_policy_new(pa_core *core) { ++ pa_main_volume_policy *policy; ++ unsigned i; ++ ++ pa_assert(core); ++ ++ policy = pa_xnew0(pa_main_volume_policy, 1); ++ policy->core = core; ++ policy->refcnt = 1; ++ policy->volume_api = pa_volume_api_get(core); ++ policy->names = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, pa_xfree); ++ policy->main_volume_contexts = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); ++ ++ for (i = 0; i < PA_MAIN_VOLUME_POLICY_HOOK_MAX; i++) ++ pa_hook_init(&policy->hooks[i], policy); ++ ++ policy->main_volume_context_binding_target_type = pa_main_volume_context_create_binding_target_type(policy); ++ pa_volume_api_add_binding_target_type(policy->volume_api, policy->main_volume_context_binding_target_type); ++ ++ pa_log_debug("Created a pa_main_volume_policy object."); ++ ++ return policy; ++} ++ ++static void main_volume_policy_free(pa_main_volume_policy *policy) { ++ unsigned i; ++ ++ pa_assert(policy); ++ pa_assert(policy->refcnt == 0); ++ ++ pa_log_debug("Freeing the pa_main_volume_policy object."); ++ ++ if (policy->main_volume_context_binding_target_type) { ++ pa_volume_api_remove_binding_target_type(policy->volume_api, policy->main_volume_context_binding_target_type); ++ pa_binding_target_type_free(policy->main_volume_context_binding_target_type); ++ } ++ ++ for (i = 0; i < PA_MAIN_VOLUME_POLICY_HOOK_MAX; i++) ++ pa_hook_done(&policy->hooks[i]); ++ ++ if (policy->main_volume_contexts) { ++ pa_assert(pa_hashmap_isempty(policy->main_volume_contexts)); ++ pa_hashmap_free(policy->main_volume_contexts); ++ } ++ ++ if (policy->names) { ++ pa_assert(pa_hashmap_isempty(policy->names)); ++ pa_hashmap_free(policy->names); ++ } ++ ++ if (policy->volume_api) ++ pa_volume_api_unref(policy->volume_api); ++ ++ pa_xfree(policy); ++} ++ ++int pa_main_volume_policy_register_name(pa_main_volume_policy *policy, const char *requested_name, ++ bool fail_if_already_registered, const char **registered_name) { ++ char *n; ++ ++ pa_assert(policy); ++ pa_assert(requested_name); ++ pa_assert(registered_name); ++ ++ n = pa_xstrdup(requested_name); ++ ++ if (pa_hashmap_put(policy->names, n, n) < 0) { ++ unsigned i = 1; ++ ++ pa_xfree(n); ++ ++ if (fail_if_already_registered) { ++ pa_log("Name %s already registered.", requested_name); ++ return -PA_ERR_EXIST; ++ } ++ ++ do { ++ i++; ++ n = pa_sprintf_malloc("%s.%u", requested_name, i); ++ } while (pa_hashmap_put(policy->names, n, n) < 0); ++ } ++ ++ *registered_name = n; ++ ++ return 0; ++} ++ ++void pa_main_volume_policy_unregister_name(pa_main_volume_policy *policy, const char *name) { ++ pa_assert(policy); ++ pa_assert(name); ++ ++ pa_assert_se(pa_hashmap_remove_and_free(policy->names, name) >= 0); ++} ++ ++uint32_t pa_main_volume_policy_allocate_main_volume_context_index(pa_main_volume_policy *policy) { ++ uint32_t idx; ++ ++ pa_assert(policy); ++ ++ idx = policy->next_main_volume_context_index++; ++ ++ return idx; ++} ++ ++void pa_main_volume_policy_add_main_volume_context(pa_main_volume_policy *policy, pa_main_volume_context *context) { ++ pa_assert(policy); ++ pa_assert(context); ++ ++ pa_assert_se(pa_hashmap_put(policy->main_volume_contexts, (void *) context->name, context) >= 0); ++} ++ ++int pa_main_volume_policy_remove_main_volume_context(pa_main_volume_policy *policy, pa_main_volume_context *context) { ++ pa_assert(policy); ++ pa_assert(context); ++ ++ if (!pa_hashmap_remove(policy->main_volume_contexts, context->name)) ++ return -1; ++ ++ if (context == policy->active_main_volume_context) ++ pa_main_volume_policy_set_active_main_volume_context(policy, NULL); ++ ++ return 0; ++} ++ ++void pa_main_volume_policy_set_active_main_volume_context(pa_main_volume_policy *policy, pa_main_volume_context *context) { ++ pa_main_volume_context *old_context; ++ ++ pa_assert(policy); ++ ++ old_context = policy->active_main_volume_context; ++ ++ if (context == old_context) ++ return; ++ ++ policy->active_main_volume_context = context; ++ ++ pa_log_debug("The active main volume context changed from %s to %s.", old_context ? old_context->name : "(unset)", ++ context ? context->name : "(unset)"); ++ ++ pa_hook_fire(&policy->hooks[PA_MAIN_VOLUME_POLICY_HOOK_ACTIVE_MAIN_VOLUME_CONTEXT_CHANGED], NULL); ++} +diff --git a/src/modules/main-volume-policy/main-volume-policy.conf.example b/src/modules/main-volume-policy/main-volume-policy.conf.example +new file mode 100644 +index 0000000..a4a35d3 +--- /dev/null ++++ b/src/modules/main-volume-policy/main-volume-policy.conf.example +@@ -0,0 +1,20 @@ ++[General] ++output-volume-model = by-active-main-volume-context ++input-volume-model = by-active-main-volume-context ++output-mute-model = none ++input-mute-model = none ++main-volume-contexts = x-example-call-main-volume-context x-example-default-main-volume-context ++ ++[MainVolumeContext x-example-call-main-volume-context] ++description = Call main volume context ++main-output-volume-control = bind:AudioGroup:x-example-call-downlink-audio-group ++main-input-volume-control = bind:AudioGroup:x-example-call-uplink-audio-group ++main-output-mute-control = none ++main-input-mute-control = none ++ ++[MainVolumeContext x-example-default-main-volume-context] ++description = Default main volume context ++main-output-volume-control = bind:AudioGroup:x-example-default-output-audio-group ++main-input-volume-control = bind:AudioGroup:x-example-default-input-audio-group ++main-output-mute-control = none ++main-input-mute-control = none +diff --git a/src/modules/main-volume-policy/main-volume-policy.h b/src/modules/main-volume-policy/main-volume-policy.h +new file mode 100644 +index 0000000..5cd669e +--- /dev/null ++++ b/src/modules/main-volume-policy/main-volume-policy.h +@@ -0,0 +1,72 @@ ++#ifndef foomainvolumepolicyhfoo ++#define foomainvolumepolicyhfoo ++ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#include <modules/volume-api/binding.h> ++#include <modules/volume-api/volume-api.h> ++ ++#include <pulsecore/core.h> ++ ++typedef struct pa_main_volume_policy pa_main_volume_policy; ++ ++/* Avoid circular dependencies... */ ++typedef struct pa_main_volume_context pa_main_volume_context; ++ ++enum { ++ PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_PUT, ++ PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_UNLINK, ++ PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_OUTPUT_VOLUME_CONTROL_CHANGED, ++ PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_INPUT_VOLUME_CONTROL_CHANGED, ++ PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_OUTPUT_MUTE_CONTROL_CHANGED, ++ PA_MAIN_VOLUME_POLICY_HOOK_MAIN_VOLUME_CONTEXT_MAIN_INPUT_MUTE_CONTROL_CHANGED, ++ PA_MAIN_VOLUME_POLICY_HOOK_ACTIVE_MAIN_VOLUME_CONTEXT_CHANGED, ++ PA_MAIN_VOLUME_POLICY_HOOK_MAX, ++}; ++ ++struct pa_main_volume_policy { ++ pa_core *core; ++ unsigned refcnt; ++ pa_volume_api *volume_api; ++ pa_hashmap *names; /* object name -> object name (hashmap-as-a-set) */ ++ pa_hashmap *main_volume_contexts; /* name -> pa_main_volume_context */ ++ pa_main_volume_context *active_main_volume_context; ++ ++ uint32_t next_main_volume_context_index; ++ pa_hook hooks[PA_MAIN_VOLUME_POLICY_HOOK_MAX]; ++ pa_binding_target_type *main_volume_context_binding_target_type; ++}; ++ ++pa_main_volume_policy *pa_main_volume_policy_get(pa_core *core); ++pa_main_volume_policy *pa_main_volume_policy_ref(pa_main_volume_policy *policy); ++void pa_main_volume_policy_unref(pa_main_volume_policy *policy); ++ ++int pa_main_volume_policy_register_name(pa_main_volume_policy *policy, const char *requested_name, ++ bool fail_if_already_registered, const char **registered_name); ++void pa_main_volume_policy_unregister_name(pa_main_volume_policy *policy, const char *name); ++ ++uint32_t pa_main_volume_policy_allocate_main_volume_context_index(pa_main_volume_policy *policy); ++void pa_main_volume_policy_add_main_volume_context(pa_main_volume_policy *policy, pa_main_volume_context *context); ++int pa_main_volume_policy_remove_main_volume_context(pa_main_volume_policy *policy, pa_main_volume_context *context); ++void pa_main_volume_policy_set_active_main_volume_context(pa_main_volume_policy *policy, pa_main_volume_context *context); ++ ++#endif +diff --git a/src/modules/main-volume-policy/module-main-volume-policy.c b/src/modules/main-volume-policy/module-main-volume-policy.c +new file mode 100644 +index 0000000..a14699d +--- /dev/null ++++ b/src/modules/main-volume-policy/module-main-volume-policy.c +@@ -0,0 +1,556 @@ ++/*** ++ This file is part of PulseAudio. ++ ++ Copyright 2014 Intel Corporation ++ ++ PulseAudio is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 of the License, ++ or (at your option) any later version. ++ ++ PulseAudio 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 Lesser General Public License ++ along with PulseAudio; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ++ USA. ++***/ ++ ++#ifdef HAVE_CONFIG_H ++#include <config.h> ++#endif ++ ++#include "module-main-volume-policy-symdef.h" ++ ++#include <modules/main-volume-policy/main-volume-context.h> ++ ++#include <modules/volume-api/binding.h> ++#include <modules/volume-api/volume-api.h> ++ ++#include <pulse/direction.h> ++ ++#include <pulsecore/conf-parser.h> ++#include <pulsecore/core-util.h> ++#include <pulsecore/i18n.h> ++ ++PA_MODULE_AUTHOR("Tanu Kaskinen"); ++PA_MODULE_DESCRIPTION(_("Main volume and mute policy")); ++PA_MODULE_VERSION(PACKAGE_VERSION); ++PA_MODULE_LOAD_ONCE(true); ++ ++enum control_type { ++ CONTROL_TYPE_VOLUME, ++ CONTROL_TYPE_MUTE, ++}; ++ ++enum model { ++ MODEL_NONE, ++ MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT, ++}; ++ ++struct userdata { ++ pa_main_volume_policy *main_volume_policy; ++ enum model output_volume_model; ++ enum model input_volume_model; ++ enum model output_mute_model; ++ enum model input_mute_model; ++ pa_hashmap *contexts; /* name -> struct context */ ++ ++ pa_hook_slot *active_main_volume_context_changed_slot; ++ ++ /* The following fields are only used during initialization. */ ++ pa_hashmap *context_names; /* name -> name (hashmap-as-a-set) */ ++ pa_hashmap *unused_contexts; /* name -> struct context */ ++}; ++ ++struct context { ++ struct userdata *userdata; ++ char *name; ++ char *description; ++ pa_binding_target_info *main_output_volume_control_target_info; ++ pa_binding_target_info *main_input_volume_control_target_info; ++ pa_binding_target_info *main_output_mute_control_target_info; ++ pa_binding_target_info *main_input_mute_control_target_info; ++ pa_main_volume_context *main_volume_context; ++ ++ bool unlinked; ++}; ++ ++static void context_unlink(struct context *context); ++ ++static const char *model_to_string(enum model model) { ++ switch (model) { ++ case MODEL_NONE: ++ return "none"; ++ ++ case MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT: ++ return "by-active-main-volume-context"; ++ } ++ ++ pa_assert_not_reached(); ++} ++ ++static int model_from_string(const char *str, enum model *model) { ++ pa_assert(str); ++ pa_assert(model); ++ ++ if (pa_streq(str, "none")) ++ *model = MODEL_NONE; ++ else if (pa_streq(str, "by-active-main-volume-context")) ++ *model = MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT; ++ else ++ return -PA_ERR_INVALID; ++ ++ return 0; ++} ++ ++static struct context *context_new(struct userdata *u, const char *name) { ++ struct context *context; ++ ++ pa_assert(u); ++ pa_assert(name); ++ ++ context = pa_xnew0(struct context, 1); ++ context->userdata = u; ++ context->name = pa_xstrdup(name); ++ context->description = pa_xstrdup(name); ++ ++ return context; ++} ++ ++static int context_put(struct context *context) { ++ int r; ++ ++ pa_assert(context); ++ ++ r = pa_main_volume_context_new(context->userdata->main_volume_policy, context->name, context->description, ++ &context->main_volume_context); ++ if (r < 0) ++ goto fail; ++ ++ if (context->main_output_volume_control_target_info) ++ pa_main_volume_context_bind_main_output_volume_control(context->main_volume_context, ++ context->main_output_volume_control_target_info); ++ ++ if (context->main_input_volume_control_target_info) ++ pa_main_volume_context_bind_main_input_volume_control(context->main_volume_context, ++ context->main_input_volume_control_target_info); ++ ++ if (context->main_output_mute_control_target_info) ++ pa_main_volume_context_bind_main_output_mute_control(context->main_volume_context, ++ context->main_output_mute_control_target_info); ++ ++ if (context->main_input_mute_control_target_info) ++ pa_main_volume_context_bind_main_input_mute_control(context->main_volume_context, ++ context->main_input_mute_control_target_info); ++ ++ pa_main_volume_context_put(context->main_volume_context); ++ ++ return 0; ++ ++fail: ++ context_unlink(context); ++ ++ return r; ++} ++ ++static void context_unlink(struct context *context) { ++ pa_assert(context); ++ ++ if (context->unlinked) ++ return; ++ ++ context->unlinked = true; ++ ++ if (context->main_volume_context) { ++ pa_main_volume_context_free(context->main_volume_context); ++ context->main_volume_context = NULL; ++ } ++} ++ ++static void context_free(struct context *context) { ++ pa_assert(context); ++ ++ if (!context->unlinked) ++ context_unlink(context); ++ ++ if (context->main_input_mute_control_target_info) ++ pa_binding_target_info_free(context->main_input_mute_control_target_info); ++ ++ if (context->main_output_mute_control_target_info) ++ pa_binding_target_info_free(context->main_output_mute_control_target_info); ++ ++ if (context->main_input_volume_control_target_info) ++ pa_binding_target_info_free(context->main_input_volume_control_target_info); ++ ++ if (context->main_output_volume_control_target_info) ++ pa_binding_target_info_free(context->main_output_volume_control_target_info); ++ ++ pa_xfree(context->description); ++ pa_xfree(context->name); ++ pa_xfree(context); ++} ++ ++static void context_set_description(struct context *context, const char *description) { ++ pa_assert(context); ++ pa_assert(description); ++ ++ pa_xfree(context->description); ++ context->description = pa_xstrdup(description); ++} ++ ++static void context_set_main_control_target_info(struct context *context, enum control_type type, pa_direction_t direction, ++ pa_binding_target_info *info) { ++ pa_assert(context); ++ ++ switch (type) { ++ case CONTROL_TYPE_VOLUME: ++ if (direction == PA_DIRECTION_OUTPUT) { ++ if (context->main_output_volume_control_target_info) ++ pa_binding_target_info_free(context->main_output_volume_control_target_info); ++ ++ if (info) ++ context->main_output_volume_control_target_info = pa_binding_target_info_copy(info); ++ else ++ context->main_output_volume_control_target_info = NULL; ++ } else { ++ if (context->main_input_volume_control_target_info) ++ pa_binding_target_info_free(context->main_input_volume_control_target_info); ++ ++ if (info) ++ context->main_input_volume_control_target_info = pa_binding_target_info_copy(info); ++ else ++ context->main_input_volume_control_target_info = NULL; ++ } ++ break; ++ ++ case CONTROL_TYPE_MUTE: ++ if (direction == PA_DIRECTION_OUTPUT) { ++ if (context->main_output_mute_control_target_info) ++ pa_binding_target_info_free(context->main_output_mute_control_target_info); ++ ++ if (info) ++ context->main_output_mute_control_target_info = pa_binding_target_info_copy(info); ++ else ++ context->main_output_mute_control_target_info = NULL; ++ } else { ++ if (context->main_input_mute_control_target_info) ++ pa_binding_target_info_free(context->main_input_mute_control_target_info); ++ ++ if (info) ++ context->main_input_mute_control_target_info = pa_binding_target_info_copy(info); ++ else ++ context->main_input_mute_control_target_info = NULL; ++ } ++ break; ++ } ++} ++ ++static pa_hook_result_t active_main_volume_context_changed_cb(void *hook_data, void *call_data, void *userdata) { ++ struct userdata *u = userdata; ++ pa_main_volume_context *context; ++ pa_volume_api *api; ++ pa_binding_target_info *info = NULL; ++ ++ pa_assert(u); ++ ++ context = u->main_volume_policy->active_main_volume_context; ++ api = u->main_volume_policy->volume_api; ++ ++ if (u->output_volume_model == MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT) { ++ if (context) { ++ info = pa_binding_target_info_new(PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_TYPE, context->name, ++ PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_OUTPUT_VOLUME_CONTROL); ++ pa_volume_api_bind_main_output_volume_control(api, info); ++ } else ++ pa_volume_api_set_main_output_volume_control(api, NULL); ++ } ++ ++ if (u->input_volume_model == MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT) { ++ if (context) { ++ info = pa_binding_target_info_new(PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_TYPE, context->name, ++ PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_INPUT_VOLUME_CONTROL); ++ pa_volume_api_bind_main_input_volume_control(api, info); ++ } else ++ pa_volume_api_set_main_input_volume_control(api, NULL); ++ } ++ ++ if (u->output_mute_model == MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT) { ++ if (context) { ++ info = pa_binding_target_info_new(PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_TYPE, context->name, ++ PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_OUTPUT_MUTE_CONTROL); ++ pa_volume_api_bind_main_output_mute_control(api, info); ++ } else ++ pa_volume_api_set_main_output_mute_control(api, NULL); ++ } ++ ++ if (u->input_mute_model == MODEL_BY_ACTIVE_MAIN_VOLUME_CONTEXT) { ++ if (context) { ++ info = pa_binding_target_info_new(PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_TYPE, context->name, ++ PA_MAIN_VOLUME_CONTEXT_BINDING_TARGET_FIELD_MAIN_INPUT_MUTE_CONTROL); ++ pa_volume_api_bind_main_input_mute_control(api, info); ++ } else ++ pa_volume_api_set_main_input_mute_control(api, NULL); ++ } ++ ++ if (info) ++ pa_binding_target_info_free(info); ++ ++ return PA_HOOK_OK; ++} ++ ++static int parse_model(pa_config_parser_state *state) { ++ int r; ++ ++ pa_assert(state); ++ ++ r = model_from_string(state->rvalue, state->data); ++ if (r < 0) ++ pa_log("[%s:%u] Failed to parse model: %s", state->filename, state->lineno, state->rvalue); ++ ++ return r; ++} ++ ++static int parse_main_volume_contexts(pa_config_parser_state *state) { ++ struct userdata *u; ++ char *name; ++ const char *split_state = NULL; ++ ++ pa_assert(state); ++ ++ u = state->userdata; ++ ++ while ((name = pa_split_spaces(state->rvalue, &split_state))) ++ pa_hashmap_put(u->context_names, name, name); ++ ++ return 0; ++} ++ ++static struct context *get_context(struct userdata *u, const char *section) { ++ const char *name; ++ struct context *context; ++ ++ pa_assert(u); ++ ++ if (!section) ++ return NULL; ++ ++ if (!pa_startswith(section, "MainVolumeContext ")) ++ return NULL; ++ ++ name = section + 18; ++ ++ context = pa_hashmap_get(u->unused_contexts, name); ++ if (!context) { ++ context = context_new(u, name); ++ pa_hashmap_put(u->unused_contexts, context->name, context); ++ } ++ ++ return context; ++} ++ ++static int parse_description(pa_config_parser_state *state) { ++ struct userdata *u; ++ struct context *context; ++ ++ pa_assert(state); ++ ++ u = state->userdata; ++ ++ context = get_context(u, state->section); ++ if (!context) { ++ pa_log("[%s:%u] Key \"%s\" not expected in section %s.", state->filename, state->lineno, state->lvalue, ++ pa_strnull(state->section)); ++ return -PA_ERR_INVALID; ++ } ++ ++ context_set_description(context, state->rvalue); ++ ++ return 0; ++} ++ ++static const char *get_target_field_name(enum control_type type) { ++ switch (type) { ++ case CONTROL_TYPE_VOLUME: ++ return "volume_control"; ++ ++ case CONTROL_TYPE_MUTE: ++ return "mute_control"; ++ } ++ ++ pa_assert_not_reached(); ++} ++ ++static int parse_main_control(pa_config_parser_state *state, enum control_type type, pa_direction_t direction) { ++ struct userdata *u; ++ struct context *context; ++ ++ pa_assert(state); ++ ++ u = state->userdata; ++ ++ context = get_context(u, state->section); ++ if (!context) { ++ pa_log("[%s:%u] Key \"%s\" not expected in section %s.", state->filename, state->lineno, state->lvalue, ++ pa_strnull(state->section)); ++ return -PA_ERR_INVALID; ++ } ++ ++ if (pa_streq(state->rvalue, "none")) ++ context_set_main_control_target_info(context, type, direction, NULL); ++ else if (pa_startswith(state->rvalue, "bind:")) { ++ int r; ++ pa_binding_target_info *info; ++ ++ r = pa_binding_target_info_new_from_string(state->rvalue, get_target_field_name(type), &info); ++ if (r < 0) { ++ pa_log("[%s:%u] Failed to parse binding target \"%s\".", state->filename, state->lineno, state->rvalue); ++ return r; ++ } ++ ++ context_set_main_control_target_info(context, type, direction, info); ++ pa_binding_target_info_free(info); ++ } else { ++ pa_log("[%s:%u] Failed to parse value \"%s\".", state->filename, state->lineno, state->rvalue); ++ return -PA_ERR_INVALID; ++ } ++ ++ return 0; ++} ++ ++static int parse_main_output_volume_control(pa_config_parser_state *state) { ++ pa_assert(state); ++ ++ return parse_main_control(state, CONTROL_TYPE_VOLUME, PA_DIRECTION_OUTPUT); ++} ++ ++static int parse_main_input_volume_control(pa_config_parser_state *state) { ++ pa_assert(state); ++ ++ return parse_main_control(state, CONTROL_TYPE_VOLUME, PA_DIRECTION_INPUT); ++} ++ ++static int parse_main_output_mute_control(pa_config_parser_state *state) { ++ pa_assert(state); ++ ++ return parse_main_control(state, CONTROL_TYPE_MUTE, PA_DIRECTION_OUTPUT); ++} ++ ++static int parse_main_input_mute_control(pa_config_parser_state *state) { ++ pa_assert(state); ++ ++ return parse_main_control(state, CONTROL_TYPE_MUTE, PA_DIRECTION_INPUT); ++} ++ ++static void finalize_config(struct userdata *u) { ++ const char *context_name; ++ void *state; ++ struct context *context; ++ ++ pa_assert(u); ++ ++ PA_HASHMAP_FOREACH(context_name, u->context_names, state) { ++ int r; ++ ++ context = pa_hashmap_remove(u->unused_contexts, context_name); ++ if (!context) ++ context = context_new(u, context_name); ++ ++ r = context_put(context); ++ if (r < 0) { ++ pa_log_warn("Failed to create main volume context %s.", context_name); ++ context_free(context); ++ continue; ++ } ++ ++ pa_assert_se(pa_hashmap_put(u->contexts, context->name, context) >= 0); ++ } ++ ++ PA_HASHMAP_FOREACH(context, u->unused_contexts, state) ++ pa_log_debug("Main volume context %s is not used.", context->name); ++ ++ pa_hashmap_free(u->unused_contexts); ++ u->unused_contexts = NULL; ++ ++ pa_hashmap_free(u->context_names); ++ u->context_names = NULL; ++} ++ ++int pa__init(pa_module *module) { ++ struct userdata *u; ++ FILE *f; ++ char *fn = NULL; ++ ++ pa_assert(module); ++ ++ u = module->userdata = pa_xnew0(struct userdata, 1); ++ u->main_volume_policy = pa_main_volume_policy_get(module->core); ++ u->output_volume_model = MODEL_NONE; ++ u->input_volume_model = MODEL_NONE; ++ u->output_mute_model = MODEL_NONE; ++ u->input_mute_model = MODEL_NONE; ++ u->contexts = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, ++ (pa_free_cb_t) context_free); ++ u->active_main_volume_context_changed_slot = ++ pa_hook_connect(&u->main_volume_policy->hooks[PA_MAIN_VOLUME_POLICY_HOOK_ACTIVE_MAIN_VOLUME_CONTEXT_CHANGED], ++ PA_HOOK_NORMAL, active_main_volume_context_changed_cb, u); ++ u->context_names = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, pa_xfree); ++ u->unused_contexts = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, ++ (pa_free_cb_t) context_free); ++ ++ f = pa_open_config_file(PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "main-volume-policy.conf", "main-volume-policy.conf", NULL, &fn); ++ if (f) { ++ pa_config_item config_items[] = { ++ { "output-volume-model", parse_model, &u->output_volume_model, "General" }, ++ { "input-volume-model", parse_model, &u->input_volume_model, "General" }, ++ { "output-mute-model", parse_model, &u->output_mute_model, "General" }, ++ { "input-mute-model", parse_model, &u->input_mute_model, "General" }, ++ { "main-volume-contexts", parse_main_volume_contexts, NULL, "General" }, ++ { "description", parse_description, NULL, NULL }, ++ { "main-output-volume-control", parse_main_output_volume_control, NULL, NULL }, ++ { "main-input-volume-control", parse_main_input_volume_control, NULL, NULL }, ++ { "main-output-mute-control", parse_main_output_mute_control, NULL, NULL }, ++ { "main-input-mute-control", parse_main_input_mute_control, NULL, NULL }, ++ { NULL }, ++ }; ++ ++ pa_config_parse(fn, f, config_items, NULL, u); ++ pa_xfree(fn); ++ fn = NULL; ++ fclose(f); ++ f = NULL; ++ } ++ ++ finalize_config(u); ++ ++ pa_log_debug("Output volume model: %s", model_to_string(u->output_volume_model)); ++ pa_log_debug("Input volume model: %s", model_to_string(u->input_volume_model)); ++ pa_log_debug("Output mute model: %s", model_to_string(u->output_mute_model)); ++ pa_log_debug("Input mute model: %s", model_to_string(u->input_mute_model)); ++ ++ return 0; ++} ++ ++void pa__done(pa_module *module) { ++ struct userdata *u; ++ ++ pa_assert(module); ++ ++ u = module->userdata; ++ if (!u) ++ return; ++ ++ if (u->active_main_volume_context_changed_slot) ++ pa_hook_slot_free(u->active_main_volume_context_changed_slot); ++ ++ if (u->contexts) ++ pa_hashmap_free(u->contexts); ++ ++ if (u->main_volume_policy) ++ pa_main_volume_policy_unref(u->main_volume_policy); ++ ++ pa_xfree(u); ++} +-- +2.1.4 + +--- a/po/POTFILES.in 2016-04-14 13:03:50.715006116 +0200 ++++ b/po/POTFILES.in 2016-04-14 13:04:23.097006062 +0200 +@@ -200,3 +200,4 @@ + src/utils/pax11publish.c + src/modules/volume-api/device-creator.c + src/pulse/ext-volume-api.c ++src/modules/main-volume-policy/module-main-volume-policy.c diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0039-main-volume-policy-adapt-to-pa6rev.patch b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0039-main-volume-policy-adapt-to-pa6rev.patch new file mode 100644 index 000000000..4f2777112 --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0039-main-volume-policy-adapt-to-pa6rev.patch @@ -0,0 +1,11 @@ +--- a/src/modules/main-volume-policy/module-main-volume-policy.c 2016-04-18 10:59:46.124086205 +0200 ++++ b/src/modules/main-volume-policy/module-main-volume-policy.c 2016-04-18 11:01:31.497089360 +0200 +@@ -517,7 +517,7 @@ + { NULL }, + }; + +- pa_config_parse(fn, f, config_items, NULL, u); ++ pa_config_parse(fn, f, config_items, NULL, false, u); + pa_xfree(fn); + fn = NULL; + fclose(f); diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio_%.bbappend b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio_%.bbappend new file mode 100644 index 000000000..a54ec60f1 --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio_%.bbappend @@ -0,0 +1,28 @@ +FILESEXTRAPATHS_append := ":${THISDIR}/${PN}" + +inherit systemd + +do_install_append() { + # Install pulseaudio systemd service + if ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'true', 'false', d)}; then + install -m 644 -p -D ${WORKDIR}/build/src/pulseaudio.service ${D}${systemd_user_unitdir}/pulseaudio.service + install -m 644 -p -D ${WORKDIR}/pulseaudio-${PV}/src/daemon/systemd/user/pulseaudio.socket ${D}${systemd_user_unitdir}/pulseaudio.socket + + # Execute these manually on behalf of systemctl script (from systemd-systemctl-native.bb) + # because it does not support systemd's user mode. + install -d ${D}${systemd_user_unitdir}/sockets.target.wants/ + ln -sf ${systemd_user_unitdir}/pulseaudio.socket ${D}${systemd_user_unitdir}/sockets.target.wants/ + + install -d ${D}${systemd_user_unitdir}/default.target.wants/ + ln -sf ${systemd_user_unitdir}/pulseaudio.service ${D}${systemd_user_unitdir}/default.target.wants/ + fi + mkdir -p ${D}/${bindir} + install -m 755 -p -D ${WORKDIR}/build/src/.libs/pacat ${D}/${bindir}/ +} + +FILES_${PN}-server += " \ + ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', '${systemd_user_unitdir}/pulseaudio.socket', '', d)} \ + ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', '${systemd_user_unitdir}/sockets.target.wants/pulseaudio.socket', '', d)} \ + ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', '${systemd_user_unitdir}/pulseaudio.service', '', d)} \ + ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', '${systemd_user_unitdir}/default.target.wants/pulseaudio.service', '', d)} \ +" diff --git a/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio_10.0.bbappend b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio_10.0.bbappend new file mode 100644 index 000000000..f59ee89d5 --- /dev/null +++ b/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio_10.0.bbappend @@ -0,0 +1,15 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/pulseaudio-10.0:" + +SRC_URI += " \ + file://0001-install-files-for-a-module-development.patch \ + file://0002-volume-ramp-additions-to-the-low-level-infra.patch \ + file://0003-volume-ramp-adding-volume-ramping-to-sink-input.patch \ + file://0004-sink-input-Code-cleanup-regarding-volume-ramping.patch \ + file://0005-sink-input-volume-Add-support-for-volume-ramp-factor.patch \ + file://0006-sink-input-Remove-pa_sink_input_set_volume_ramp.patch;apply=no \ + file://enable-ofono-hfp-backend.patch \ +" + +PACKAGES =+ " pulseaudio-module-dev" + +FILES_pulseaudio-module-dev = "${includedir}/pulsemodule/* ${libdir}/pkgconfig/pulseaudio-module-devel.pc" diff --git a/meta-agl-profile-core/recipes-navigation/geoclue/files/org.freedesktop.GeoClue2.Client.conf b/meta-agl-profile-core/recipes-navigation/geoclue/files/org.freedesktop.GeoClue2.Client.conf new file mode 100644 index 000000000..a7486d055 --- /dev/null +++ b/meta-agl-profile-core/recipes-navigation/geoclue/files/org.freedesktop.GeoClue2.Client.conf @@ -0,0 +1,8 @@ +<!DOCTYPE busconfig PUBLIC + "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> +<busconfig> + <policy user="root"> + <allow receive_type="signal" receive_interface="org.freedesktop.GeoClue2.Client" /> + </policy> +</busconfig> diff --git a/meta-agl-profile-core/recipes-navigation/geoclue/geoclue_%.bbappend b/meta-agl-profile-core/recipes-navigation/geoclue/geoclue_%.bbappend new file mode 100644 index 000000000..9d61a9f61 --- /dev/null +++ b/meta-agl-profile-core/recipes-navigation/geoclue/geoclue_%.bbappend @@ -0,0 +1,9 @@ +inherit gobject-introspection + +FILESEXTRAPATHS_prepend := "${THISDIR}/files:" +SRC_URI_append = "file://org.freedesktop.GeoClue2.Client.conf" + +do_install_append() { + install -d ${D}/etc/dbus-1/system.d + install -m 0644 ${WORKDIR}/org.freedesktop.GeoClue2.Client.conf ${D}/etc/dbus-1/system.d/org.freedesktop.GeoClue2.Client.conf +} diff --git a/meta-agl-profile-core/recipes-navigation/gpsd/gpsd_%.bbappend b/meta-agl-profile-core/recipes-navigation/gpsd/gpsd_%.bbappend new file mode 100644 index 000000000..af72aece9 --- /dev/null +++ b/meta-agl-profile-core/recipes-navigation/gpsd/gpsd_%.bbappend @@ -0,0 +1,14 @@ +SYSTEMD_SERVICE_${PN} += " gpsdctl@.service" + +do_install_append() { + # use the systemd compatible gpsd.rules + install -d ${D}/${sysconfdir}/udev/rules.d + install -m 0644 ${S}/gpsd.rules ${D}/${sysconfdir}/udev/rules.d/60-gpsd.rules + + #support for systemd + install -d ${D}${systemd_unitdir}/system/ + install -m 0644 ${S}/systemd/gpsdctl@.service ${D}${systemd_unitdir}/system + + #autoprobe usb gps devices + echo 'USBAUTO="true"' >> ${D}${sysconfdir}/default/gpsd.default +} diff --git a/meta-agl-profile-core/recipes-support/libsoup/libsoup-2.4_%.bbappend b/meta-agl-profile-core/recipes-support/libsoup/libsoup-2.4_%.bbappend new file mode 100644 index 000000000..06651fc11 --- /dev/null +++ b/meta-agl-profile-core/recipes-support/libsoup/libsoup-2.4_%.bbappend @@ -0,0 +1 @@ +EXTRA_OECONF_append_class-native = " --disable-tls-check" diff --git a/meta-agl-profile-core/recipes-test/aiostress/aiostress_0.22.bb b/meta-agl-profile-core/recipes-test/aiostress/aiostress_0.22.bb new file mode 100644 index 000000000..7803d74ed --- /dev/null +++ b/meta-agl-profile-core/recipes-test/aiostress/aiostress_0.22.bb @@ -0,0 +1,24 @@ +SUMMARY = "Async IO testing utility" +DESCRIPTION = "aio-stress will open or create each file on the command line, and start a series of aio to it.\ +aio is done in a rotating loop. first file1 gets 8 requests, then file2, then file3 etc.\ +As each file finishes writing, it is switched to reads io buffers are aligned in case you want to do raw io" +HOMEPAGE = "https://oss.oracle.com/~mason/aio-stress/" +LICENSE = "GPLv2" + +S="${WORKDIR}" + +LIC_FILES_CHKSUM = "file://${S}/aio-stress.c;md5=ccb5d196a3736bbd835d582a4e2329c3" + +SRC_URI = "https://oss.oracle.com/~mason/aio-stress/aio-stress.c" +SRC_URI[md5sum] = "ccb5d196a3736bbd835d582a4e2329c3" +SRC_URI[sha256sum] = "3f4cffcc946fb717fff9d8fe932c7c2ee606efff198408d9fbe16955151445f7" + +do_compile () { + ${CC} -Wall -Wshadow -o aio-stress -lpthread -laio aio-stress.c +} + +do_install () { + install -d ${D}${bindir} + install -m 0755 aio-stress ${D}${bindir} +} + diff --git a/meta-agl-profile-core/recipes-test/blobsallad/blobsallad/0001-Makefile.patch b/meta-agl-profile-core/recipes-test/blobsallad/blobsallad/0001-Makefile.patch new file mode 100644 index 000000000..0ae56cee1 --- /dev/null +++ b/meta-agl-profile-core/recipes-test/blobsallad/blobsallad/0001-Makefile.patch @@ -0,0 +1,53 @@ +--- a/Makefile.orig 2016-04-01 15:50:20.636358716 +0200 ++++ b/Makefile 2016-04-01 15:51:58.916361191 +0200 +@@ -1,3 +1,9 @@ ++INCDIR = $(SDKROOT)/usr/include ++LIBDIR = $(SDKROOT)/usr/lib ++ ++EXTRA_CFLAGS=-I$(INCDIR) ++EXTRA_LDFLAGS=-Wl,-rpath-link=$(LIBDIR) -L$(LIBDIR) ++ + OBJECTS = bs_main.o \ + bs_vector.o \ + bs_pointmass.o \ +@@ -15,21 +21,21 @@ + bs_profiler.o \ + bs_rubberband.o + +-CC = gcc ++#CC = gcc + + DISTDIR = blobsallad-src + +-CFLAGS = `pkg-config --cflags cairo; sdl-config --cflags` +-LIBS = `pkg-config --libs cairo; sdl-config --libs` -lm -lGL -lGLU ++EXTRA_CFLAGS += -I$(INCDIR)/cairo -I$(INCDIR)/SDL -D_GNU_SOURCE=1 -D_REENTRANT ++EXTRA_LDFLAGS += -lcairo -lSDL -lpthread -lm + + all: $(OBJECTS) +- $(CC) -g -o blobsallad $(OBJECTS) $(LIBS) ++ $(CC) -g -o blobsallad $(OBJECTS) $(EXTRA_LDFLAGS) + + map: +- gcc -o createmap create_testdata.c -Wall -g -lm ++ $(CC) -o createmap create_testdata.c -Wall -g -lm + + octree: +- gcc -o test_octree test_octree.c bs_octree.c bs_list.c bs_vector.c bs_vector_util.c bs_timer.c bs_array.c -Wall -O2 $(LIBS) $(CFLAGS) ++ $(CC) -o test_octree test_octree.c bs_octree.c bs_list.c bs_vector.c bs_vector_util.c bs_timer.c bs_array.c -Wall -O2 $(EXTRA_LDFLAGS) $(EXTRA_CFLAGS) + + GFX_OBJECTS = gfx_main.o \ + bs_gfx.o \ +@@ -41,10 +47,10 @@ + bs_list.o + + gfx: $(GFX_OBJECTS) +- gcc -o gfx_main -Wall -g $(GFX_OBJECTS) $(LIBS) ++ $(CC) -o gfx_main -Wall -g $(GFX_OBJECTS) $(EXTRA_LDFLAGS) + + .c.o: +- $(CC) -g -Wall $(CFLAGS) $ -c $< ++ $(CC) -g -Wall $(EXTRA_CFLAGS) $ -c $< + + clean: + rm -f *.o; rm -f blobsallad; diff --git a/meta-agl-profile-core/recipes-test/blobsallad/blobsallad/0002-auto.patch b/meta-agl-profile-core/recipes-test/blobsallad/blobsallad/0002-auto.patch new file mode 100644 index 000000000..b61da2c1f --- /dev/null +++ b/meta-agl-profile-core/recipes-test/blobsallad/blobsallad/0002-auto.patch @@ -0,0 +1,95 @@ +--- a/bs_main.c ++++ b/bs_main.c +@@ -11,6 +11,9 @@ + #include "bs_profiler.h" + #include "bs_rubberband.h" + ++static struct timeval beginTime; /* Time of the benchmark start */ ++static int cur_step; /* Current benchmark phase. Used to subsequently increase number of objects each 10 seconds */ ++ + typedef struct bs_main_data_st + { + bs_cairo_sdl_t *pCairoSdl; +@@ -113,7 +116,9 @@ + SDL_Event event; + SDL_UserEvent userevent; + bs_main_data_t *pMainData; +- ++ struct timeval curTime; ++ int hunsec; ++ + pMainData = (bs_main_data_t*) pUserData; + + userevent.type = SDL_USEREVENT; +@@ -121,6 +126,20 @@ + userevent.data1 = NULL; + userevent.data2 = NULL; + ++ gettimeofday(&curTime, NULL); ++ hunsec = curTime.tv_sec - beginTime.tv_sec; ++ ++ /* increase cur_step each 10 seconds */ ++ if (cur_step < hunsec / 10) { ++ printf("%d objects = %.2f fps\n", 1 << (cur_step + 1), pMainData->fps); ++ userevent.code = 2; /* add more objects */ ++ cur_step++; ++ } ++ ++ /* exit if requested number of objects is reached */ ++ if (cur_step == 4) ++ userevent.code = 3; ++ + event.type = SDL_USEREVENT; + event.user = userevent; + +@@ -152,14 +171,19 @@ + pMainData->newTimerInterval = 50; + pMainData->fps = 20.0; + pMainData->running = TRUE; +- ++ ++ cur_step = 0; ++ + bs_profiler_init(); + ++ gettimeofday(&beginTime, NULL); + gettimeofday(&startTime, NULL); + pMainData->lastFrameTimeStamp = startTime.tv_sec * 1000 + startTime.tv_usec / 1000; + + SDL_AddTimer(50, bs_main_sdl_timer_callback, pMainData); + ++ bs_blob_collective_split(pMainData->pCollective); ++ + for(;;) + { + SDL_WaitEvent(&event); +@@ -253,8 +277,7 @@ + break; + + case SDL_USEREVENT: +- if(event.user.code == 1) +- { ++ if (event.user.code == 1) { + gettimeofday(&startTime, NULL); + bs_main_update_simulation(pMainData); + bs_main_redraw(pMainData); +@@ -268,10 +291,15 @@ + usedTime = 50; + } + +- pMainData->newTimerInterval = usedTime; +- } +- break; +- ++ pMainData->newTimerInterval = usedTime; ++ } else if (event.user.code == 2) { ++ int i; ++ for (i = 0; i < (1 << cur_step); i++) ++ bs_blob_collective_split(pMainData->pCollective); ++ } else if (event.user.code == 3) { ++ exit(0); ++ } ++ break; + case SDL_QUIT: + exit(0); + break; diff --git a/meta-agl-profile-core/recipes-test/blobsallad/blobsallad/0003-printcleanup.patch b/meta-agl-profile-core/recipes-test/blobsallad/blobsallad/0003-printcleanup.patch new file mode 100644 index 000000000..630871dfd --- /dev/null +++ b/meta-agl-profile-core/recipes-test/blobsallad/blobsallad/0003-printcleanup.patch @@ -0,0 +1,11 @@ +--- a/bs_blob_collective.c ++++ b/bs_blob_collective.c +@@ -152,7 +152,7 @@ + + bs_list_unlink_p_cont(pCollective->pBlobs, bs_blob_collective_remove_blob_cb, findData.pMotherBlob); + +- printf("number of blobs: %d\n", bs_list_get_length(pCollective->pBlobs)); ++/* printf("number of blobs: %d\n", bs_list_get_length(pCollective->pBlobs)); */ + } + + typedef struct bs_blob_collective_join_find_smallest_st diff --git a/meta-agl-profile-core/recipes-test/blobsallad/blobsallad/0004-bs_main.c.patch b/meta-agl-profile-core/recipes-test/blobsallad/blobsallad/0004-bs_main.c.patch new file mode 100644 index 000000000..ae15408de --- /dev/null +++ b/meta-agl-profile-core/recipes-test/blobsallad/blobsallad/0004-bs_main.c.patch @@ -0,0 +1,15 @@ +--- a/bs_main.c ++++ b/bs_main.c +@@ -165,9 +165,9 @@ + //pMainData->pRubberband = bs_rubberband_create(2.5f, 3.0f); + pMainData->pEnv = bs_env_create(0.0f, 0.0f, 6.0f, 4.0f); + pMainData->pGravity = bs_vector_create(0.0f, 10.0f); +- pMainData->pCairoSdl = bs_cairo_sdl_create(600, 400); +- pMainData->width = 600.0; +- pMainData->height = 400.0; ++ pMainData->pCairoSdl = bs_cairo_sdl_create(1600, 1024); ++ pMainData->width = 1600.0; ++ pMainData->height = 1024.0; + pMainData->newTimerInterval = 50; + pMainData->fps = 20.0; + pMainData->running = TRUE; diff --git a/meta-agl-profile-core/recipes-test/blobsallad/blobsallad_2006-11-14-23-57.bb b/meta-agl-profile-core/recipes-test/blobsallad/blobsallad_2006-11-14-23-57.bb new file mode 100644 index 000000000..373d4ddc6 --- /dev/null +++ b/meta-agl-profile-core/recipes-test/blobsallad/blobsallad_2006-11-14-23-57.bb @@ -0,0 +1,36 @@ +DESCRIPTION = "" +HOMEPAGE = "http://blobsallad.se/" +LICENSE = "CLOSED" +LIC_FILES_CHKSUM = "" + +SRC_URI = " \ + http://blobsallad.se/src/blobsallad-src-${PV}.tar.gz \ + file://0001-Makefile.patch \ + file://0002-auto.patch \ + file://0003-printcleanup.patch \ + file://0004-bs_main.c.patch" + +SRC_URI[md5sum] = "a2e3342cbf0f3a4a9b110af2663bed36" +SRC_URI[sha256sum] = "cd6309df1929d3e6b7bce1dbecc751849aeaafe17c01e05fd2567dc4267faaa2" + +DEPENDS = "cairo virtual/libsdl" + +INSANE_SKIP_${PN} = "ldflags" + +S = "${WORKDIR}/blobsallad-src" + +do_configure () { + # Specify any needed configure commands here + : +} + +do_compile () { + # You will almost certainly need to add additional arguments here + oe_runmake SDKROOT=${STAGING_DIR_HOST} +} + +do_install () { + install -d ${D}${bindir} + install -m 0755 blobsallad ${D}${bindir} +} + diff --git a/meta-agl-profile-core/recipes-test/dung/dung_3.4.25-m2.bb b/meta-agl-profile-core/recipes-test/dung/dung_3.4.25-m2.bb new file mode 100644 index 000000000..28bf858a0 --- /dev/null +++ b/meta-agl-profile-core/recipes-test/dung/dung_3.4.25-m2.bb @@ -0,0 +1,18 @@ +SUMMARY = "Kernel test scripts" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6" + +SRC_URI = "git://gerrit.automotivelinux.org/gerrit/src/qa-test-misc;protocol=https;branch=${AGL_BRANCH}" +SRCREV = "e2472c7b1d061aef8bb05a4d7940fd8159c4a329" + +inherit allarch + +S = "${WORKDIR}/git/${PN}-${PV}" + +do_install () { + for subdir in arch_timer cmt common scifab sdhi.0; do + install -d -m 0755 ${D}/${datadir}/${PN}/$subdir + install -m 0755 -t ${D}/${datadir}/${PN}/$subdir ${S}/$subdir/* + done +} + diff --git a/meta-agl-profile-core/recipes-test/ebizzy/ebizzy_0.3.bb b/meta-agl-profile-core/recipes-test/ebizzy/ebizzy_0.3.bb new file mode 100644 index 000000000..08b0425c0 --- /dev/null +++ b/meta-agl-profile-core/recipes-test/ebizzy/ebizzy_0.3.bb @@ -0,0 +1,20 @@ +DESCRIPTION = "Benchmark tool that generates a workload resembling common web application server workloads" +HOMEPAGE = "http://ebizzy.sourceforge.net/" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://LICENSE;md5=eb723b61539feef013de476e68b5c50a" + +SRC_URI = "http://downloads.sourceforge.net/project/ebizzy/ebizzy/${PV}/ebizzy-${PV}.tar.gz" +SRC_URI[md5sum] = "af038bc506066bb3d28db08aba62bc38" +SRC_URI[sha256sum] = "77286029d6348f3d9b3f04eae1feadb5ad1ad07b9f688f4d9f002960862467f2" + +INSANE_SKIP_${PN} = "ldflags" + +do_compile () { + ${CC} -Wall -Wshadow -lpthread -o ebizzy ebizzy.c +} + +do_install () { + install -d ${D}${bindir} + install -m 0755 ebizzy ${D}${bindir} +} + diff --git a/meta-agl-profile-core/recipes-test/ffsb/ffsb_6.0-rc2.bb b/meta-agl-profile-core/recipes-test/ffsb/ffsb_6.0-rc2.bb new file mode 100644 index 000000000..66db133e3 --- /dev/null +++ b/meta-agl-profile-core/recipes-test/ffsb/ffsb_6.0-rc2.bb @@ -0,0 +1,14 @@ +DESCRIPTION = "Flexible File System Benchmark" +HOMEPAGE = "https://sourceforge.net/projects/ffsb/" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://LICENSE;md5=fd5d9bcabd8ed5a54a01ce8d183d592a" + +SRC_URI = "http://downloads.sourceforge.net/project/ffsb/ffsb/ffsb-${PV}/ffsb-${PV}.tar.bz2" +SRC_URI[md5sum] = "cabfc1021c2ec6c6b168fefc84210891" +SRC_URI[sha256sum] = "e5867692aae8c9bfbcdc774599022289c4d89c1d90f4dd7101fb9865ac773c71" + +inherit autotools + +# extra args to configure +EXTRA_OECONF = "" + diff --git a/meta-agl-profile-core/recipes-test/fontconfig/fontconfig_%.bbappend b/meta-agl-profile-core/recipes-test/fontconfig/fontconfig_%.bbappend new file mode 100644 index 000000000..c4bebdc1f --- /dev/null +++ b/meta-agl-profile-core/recipes-test/fontconfig/fontconfig_%.bbappend @@ -0,0 +1,17 @@ +PACKAGES =+ "fontconfig-test" + +do_install_append() { + install -m 755 -d ${D}/${datadir}/fontconfig-test + install -m 755 ${S}/test/run-test.sh ${D}/${datadir}/fontconfig-test/ + + sed -i -e "s/FCLIST=\.\.\/fc\-list\/fc\-list/FCLIST=\/usr\/bin\/fc\-list/g" -e "s/FCCACHE=\.\.\/fc\-cache\/fc\-cache/FCCACHE=\/usr\/bin\/fc\-cache/g" ${D}/${datadir}/fontconfig-test/run-test.sh + + for x in 4x6.pcf 8x16.pcf out.expected fonts.conf.in; do + install -m 644 ${S}/test/$x ${D}/${datadir}/fontconfig-test/ + done +} + +DEBIAN_NOAUTONAME_fontconfig-test = "1" +FILES_fontconfig-test = "${datadir}/fontconfig-test/*" + + diff --git a/meta-agl-profile-core/recipes-test/freetype/files/0001-Makefile-dont-build-gfx-demos.patch b/meta-agl-profile-core/recipes-test/freetype/files/0001-Makefile-dont-build-gfx-demos.patch new file mode 100644 index 000000000..1f3acf28e --- /dev/null +++ b/meta-agl-profile-core/recipes-test/freetype/files/0001-Makefile-dont-build-gfx-demos.patch @@ -0,0 +1,32 @@ +diff -urN /tmp/ft2demos-2.6.orig/Makefile /tmp/ft2demos-2.6/Makefile +--- ft2demos-2.6.orig/Makefile 2015-06-07 07:34:19.000000000 +0000 ++++ ft2demos-2.6/Makefile 2016-06-17 14:25:37.640456725 +0000 +@@ -153,7 +153,8 @@ + + ifeq ($(PLATFORM),unix) + CC = $(CCraw) +- LINK_CMD = $(subst /,$(SEP),$(OBJ_BUILD)/libtool) \ ++ LIBTOOL = $(OBJ_BUILD)/libtool ++ LINK_CMD = $(subst /,$(SEP),$(LIBTOOL)) \ + --mode=link $(CC) \ + $(subst /,$(COMPILER_SEP),$(LDFLAGS)) + LINK_LIBS = $(subst /,$(COMPILER_SEP),$(FTLIB) $(EFENCE)) +@@ -279,12 +280,12 @@ + ttdebug + + # Comment out the next line if you don't have a graphics subsystem. +- EXES += ftdiff \ +- ftgamma \ +- ftgrid \ +- ftmulti \ +- ftstring \ +- ftview ++ # EXES += ftdiff \ ++ # ftgamma \ ++ # ftgrid \ ++ # ftmulti \ ++ # ftstring \ ++ # ftview + + # ftvalid requires ftgxval.c and ftotval.c + # diff --git a/meta-agl-profile-core/recipes-test/freetype/files/0001-ft2demos-Makefile-Do-not-hardcode-libtool-path.patch b/meta-agl-profile-core/recipes-test/freetype/files/0001-ft2demos-Makefile-Do-not-hardcode-libtool-path.patch new file mode 100644 index 000000000..7803ad7e0 --- /dev/null +++ b/meta-agl-profile-core/recipes-test/freetype/files/0001-ft2demos-Makefile-Do-not-hardcode-libtool-path.patch @@ -0,0 +1,30 @@ +From 8c4f135619de929f9348b830a07a46a0c2c38e51 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jan-Simon=20M=C3=B6ller?= <jsmoeller@linuxfoundation.org> +Date: Fri, 7 Oct 2016 15:26:20 +0200 +Subject: [PATCH] Do not hardcode libtool path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It is already known and imported through config.mk. + +Signed-off-by: Jan-Simon Möller <jsmoeller@linuxfoundation.org> +--- + Makefile | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/Makefile b/Makefile +index a5d34bd..254aad4 100644 +--- a/Makefile ++++ b/Makefile +@@ -153,7 +153,6 @@ else + + ifeq ($(PLATFORM),unix) + CC = $(CCraw) +- LIBTOOL = $(OBJ_BUILD)/libtool + LINK_CMD = $(subst /,$(SEP),$(LIBTOOL)) \ + --mode=link $(CC) \ + $(subst /,$(COMPILER_SEP),$(LDFLAGS)) +-- +2.1.4 + diff --git a/meta-agl-profile-core/recipes-test/freetype/freetype_2.8.bbappend b/meta-agl-profile-core/recipes-test/freetype/freetype_2.8.bbappend new file mode 100644 index 000000000..282ce784a --- /dev/null +++ b/meta-agl-profile-core/recipes-test/freetype/freetype_2.8.bbappend @@ -0,0 +1,32 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/files:" + +SRC_URI =+ "${SOURCEFORGE_MIRROR}/freetype/ft2demos-${PV}.tar.bz2;name=ft2demos \ + file://0001-Makefile-dont-build-gfx-demos.patch;patchdir=../ft2demos-${PV} \ + file://0001-ft2demos-Makefile-Do-not-hardcode-libtool-path.patch;patchdir=../ft2demos-${PV} \ + " +SRC_URI[ft2demos.md5sum] = "61db5831e213acb843f0fc6d10186054" +SRC_URI[ft2demos.sha256sum] = "2b6ce0d36bcb43fcc8aac07a0287982d855571ee271c3803c768e501f9c1a233" + +PACKAGES =+ "${PN}-demos" + +B = "${S}" + +do_compile_append () { + + oe_runmake -C ${WORKDIR}/ft2demos-${PV} TOP_DIR=${WORKDIR}/${BPN}-${PV}/ +} + +do_install_append () { + install -d -m 0755 ${D}/${bindir} + for x in ftbench ftdump ftlint ftvalid ttdebug; do + install -m 0755 ${WORKDIR}/ft2demos-${PV}/bin/.libs/$x ${D}/${bindir} + done +} + +FILES_${PN}-demos = "\ + ${bindir}/ftbench \ + ${bindir}/ftdump \ + ${bindir}/ftlint \ + ${bindir}/ftvalid \ + ${bindir}/ttdebug \ +" diff --git a/meta-agl-profile-core/recipes-test/fsfuzzer/files/0001-fix_missing_header_sys_stat.patch b/meta-agl-profile-core/recipes-test/fsfuzzer/files/0001-fix_missing_header_sys_stat.patch new file mode 100644 index 000000000..e834becf3 --- /dev/null +++ b/meta-agl-profile-core/recipes-test/fsfuzzer/files/0001-fix_missing_header_sys_stat.patch @@ -0,0 +1,11 @@ +diff -urN fsfuzzer-0.7.orig/fstest.c fsfuzzer-0.7/fstest.c +--- fsfuzzer-0.7.orig/fstest.c 2009-01-25 14:50:06.000000000 +0000 ++++ fsfuzzer-0.7/fstest.c 2016-06-16 17:49:27.264565819 +0000 +@@ -35,6 +35,7 @@ + #include <signal.h> + #include <sys/file.h> + #include <sys/mman.h> ++#include <sys/stat.h> + + #define LOGGIT 1 + #define CHECK_XATTR 1 diff --git a/meta-agl-profile-core/recipes-test/fsfuzzer/fsfuzzer_0.7.bb b/meta-agl-profile-core/recipes-test/fsfuzzer/fsfuzzer_0.7.bb new file mode 100644 index 000000000..d2ddb59b1 --- /dev/null +++ b/meta-agl-profile-core/recipes-test/fsfuzzer/fsfuzzer_0.7.bb @@ -0,0 +1,18 @@ +SUMMARY = "The fsfuzzer is a filesystem fuzzer tool that does stress tests of various filesystems in a reproducible and logged way." +DESCRIPTION = "This tool creates initial (valid) filesystem images and then manipulates their binary format and structure for detecting flaws/bugs/design problems in the parsing/handling code for that particular filesystem. The program expects that you have a /media directory. It uses that one for mounting test images in." +HOMEPAGE = "https://www.ee.oulu.fi/research/ouspg/fsfuzzer" + +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://COPYING;md5=94d55d512a9ba36caa9b7df079bae19f" + +SRC_URI = "http://people.redhat.com/sgrubb/files/fsfuzzer-${PV}.tar.gz \ + file://0001-fix_missing_header_sys_stat.patch \ + " +SRC_URI[md5sum] = "d69ac4b67aaba52a889c9188eb456c15" +SRC_URI[sha256sum] = "094aa17c4f66c525a04e5db5ad444b4a561b6f8e310d0bd70b9ca421cdf0a434" + +inherit autotools + +# Specify any options you want to pass to the configure script using EXTRA_OECONF: +EXTRA_OECONF = "" + diff --git a/meta-agl-profile-core/recipes-test/glmark2/glmark2_%.bbappend b/meta-agl-profile-core/recipes-test/glmark2/glmark2_%.bbappend new file mode 100644 index 000000000..a64e0506c --- /dev/null +++ b/meta-agl-profile-core/recipes-test/glmark2/glmark2_%.bbappend @@ -0,0 +1,2 @@ +PACKAGECONFIG = "wayland-gles2" +PACKAGECONFIG[wayland-gles2] = ",,virtual/egl virtual/libgles2 wayland" diff --git a/meta-agl-profile-core/recipes-test/himeno/himeno_2.0.bb b/meta-agl-profile-core/recipes-test/himeno/himeno_2.0.bb new file mode 100644 index 000000000..f890e23a4 --- /dev/null +++ b/meta-agl-profile-core/recipes-test/himeno/himeno_2.0.bb @@ -0,0 +1,27 @@ +DESCRIPTION = "Himeno Benchmark" +LICENSE = "LGPL-2.0" +URL = "http://accc.riken.jp/en/supercom/himenobmt/" + +SRC_URI = "http://accc.riken.jp/en/wp-content/uploads/sites/2/2015/07/himenobmt.c.zip" +SRC_URI[md5sum] = "8d8e837dfc3e00a3b322eb4ae3edd551" +SRC_URI[sha256sum] = "8780bfbdacb0d4dcab2931e65cadd69411731e3f2afcc1231d0743a036298077" + +LIC_FILES_CHKSUM = "file://himenoBMT.c;md5=8e8771ddc01c6d1a795e088e2d6dee78" + +# Upstream ZIP file contains an LZH archive, thus a 2 steps "unpack" is required. +# The LZH archive is unpacked after native tools dependency resolution, +# thus. after "configure" task in our case: + +DEPENDS = "p7zip-native" + +do_configure_append() { + 7z x -y -o${S} ${WORKDIR}/himenobmt.c.lzh + cd ${S} + sed -i -e 's/CC= gcc/#CC= gcc/' Makefile + sed -i -e 's/CFLAGS = /#CFLAGS = /' Makefile +} + +do_install () { + install -d ${D}${bindir} + install -m 0755 bmt ${D}${bindir} +} diff --git a/meta-agl-profile-core/recipes-test/interbench/files/interbench.c.patch b/meta-agl-profile-core/recipes-test/interbench/files/interbench.c.patch new file mode 100644 index 000000000..c882739ba --- /dev/null +++ b/meta-agl-profile-core/recipes-test/interbench/files/interbench.c.patch @@ -0,0 +1,68 @@ +--- interbench.c.orig 2009-10-30 23:14:59.000000000 -0500 ++++ interbench.c 2012-07-10 19:06:00.000000000 -0500 +@@ -71,6 +71,7 @@ struct user_data { + char datestamp[13]; + FILE *logfile; + } ud = { ++ .ram = 0, + .duration = 30, + .cpu_load = 4, + .log = 1, +@@ -652,6 +653,8 @@ void emulate_write(struct thread *th) + terminal_error("fopen"); + if (stat(name, &statbuf) == -1) + terminal_fileopen_error(fp, "stat"); ++ if (statbuf.st_blksize < MIN_BLK_SIZE) ++ statbuf.st_blksize = MIN_BLK_SIZE; + for (i = 0 ; i < mem; i++) { + if (fwrite(buf, statbuf.st_blksize, 1, fp) != 1) + terminal_fileopen_error(fp, "fwrite"); +@@ -1136,14 +1139,17 @@ void get_ram(void) + if(!(meminfo = fopen("/proc/meminfo", "r"))) + terminal_error("fopen"); + +- ud.ram = ud.swap = 0; +- while( !feof(meminfo) && !fscanf(meminfo, "MemTotal: %lu kB", &ud.ram) ) +- fgets(aux,sizeof(aux),meminfo); ++ if (!ud.ram) ++ { ++ while( !feof(meminfo) && !fscanf(meminfo, "MemTotal: %lu kB", &ud.ram) ) ++ fgets(aux,sizeof(aux),meminfo); ++ } ++ ud.swap = 0; + while( !feof(meminfo) && !fscanf(meminfo, "SwapTotal: %lu kB", &ud.swap) ) + fgets(aux,sizeof(aux),meminfo); + if (fclose(meminfo) == -1) + terminal_error("fclose"); +- ++ + if( !ud.ram || !ud.swap ) { + unsigned long i; + fprintf(stderr, "\nCould not get memory or swap size. "); +@@ -1399,6 +1405,7 @@ void usage(void) + fprintf(stderr, "\t[-h]\n\n"); + fprintf(stderr, " -l\tUse <int> loops per sec (default: use saved benchmark)\n"); + fprintf(stderr, " -L\tUse cpu load of <int> with burn load (default: 4)\n"); ++ fprintf(stderr, " -M\tForce RAM size to <int>. Useful when disk is smaller than RAM.\n"); + fprintf(stderr, " -t\tSeconds to run each benchmark (default: 30)\n"); + fprintf(stderr, " -B\tNice the benchmarked thread to <int> (default: 0)\n"); + fprintf(stderr, " -N\tNice the load thread to <int> (default: 0)\n"); +@@ -1482,7 +1489,7 @@ int main(int argc, char **argv) + terminal_error("signal"); + #endif + +- while ((q = getopt(argc, argv, "hl:L:B:N:ut:bcnrC:I:m:w:x:W:X:")) != -1) { ++ while ((q = getopt(argc, argv, "hl:L:M:B:N:ut:bcnrC:I:m:w:x:W:X:")) != -1) { + switch (q) { + case 'h': + usage(); +@@ -1496,6 +1503,9 @@ int main(int argc, char **argv) + case 'L': + ud.cpu_load = atoi(optarg); + break; ++ case 'M': ++ ud.ram = atoi(optarg); ++ break; + case 'B': + ud.bench_nice = atoi(optarg); + break; diff --git a/meta-agl-profile-core/recipes-test/interbench/interbench_0.31.bb b/meta-agl-profile-core/recipes-test/interbench/interbench_0.31.bb new file mode 100644 index 000000000..3e6490374 --- /dev/null +++ b/meta-agl-profile-core/recipes-test/interbench/interbench_0.31.bb @@ -0,0 +1,31 @@ +DESCRIPTION = "The Linux interactivity benchmark" +HOMEPAGE = "http://users.tpg.com.au/ckolivas/interbench/" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://COPYING;md5=393a5ca445f6965873eca0259a17f833" +SRC_URI = "http://ck.kolivas.org/apps/interbench/interbench-${PV}.tar.bz2" + +SRC_URI += "file://interbench.c.patch;striplevel=0" + +inherit autotools + +INSANE_SKIP_${PN} = "ldflags" + +B = "${S}" +EXTRA_OEMAKE = "CC='${CC}'" + +# upstream tarball contains x86_64 binaries, we need a clean source tree +do_compile() { + oe_runmake clean + oe_runmake +} + +do_install() { + install -d ${D}${bindir} ${D}${datadir}/doc/${PN}/ ${D}${mandir}/man8/ + install -m 0755 ${B}/interbench ${D}${bindir} + install -m 0644 ${S}/readme* ${D}${datadir}/doc/${PN}/ + install -m 0644 ${S}/interbench.8 ${D}${mandir}/man8/ +} + +SRC_URI[md5sum] = "832254d7fd1255c548ebea7b97f01015" +SRC_URI[sha256sum] = "89d438b28aef22d26e79812762a57a9f9344a8dd8826edebfe60dad48ee1c784" + diff --git a/meta-agl-profile-core/recipes-test/iperf/iperf-2.0.9/0001-fix-out-of-tree-config.patch b/meta-agl-profile-core/recipes-test/iperf/iperf-2.0.9/0001-fix-out-of-tree-config.patch new file mode 100644 index 000000000..e8a029790 --- /dev/null +++ b/meta-agl-profile-core/recipes-test/iperf/iperf-2.0.9/0001-fix-out-of-tree-config.patch @@ -0,0 +1,52 @@ +iperf: fix out of tree configuration + +The configure step uses a package header to check for support of types/declares, +this package header encapsulates all the required system header for providing +the needed resources. When configured from an out of tree directory the package +header is not found due to the hard path. +We now make the path for package header relative to our 'srcdir' so it is +found appropriately. + +Signed-off-by: Awais Belal <awais_belal@mentor.com> +--- +diff --git a/configure.ac b/configure.ac +index 2b3fd20..d420f9e 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -176,8 +176,8 @@ dnl Check for system services + + dnl check for multicast + if test "$ac_cv_multicast" != no; then +- AC_CHECK_TYPES(struct ip_mreq,,,[#include "compat/headers_slim.h"]) +- AC_CHECK_DECLS(IP_ADD_MEMBERSHIP,,,[#include "compat/headers_slim.h"]) ++ AC_CHECK_TYPES(struct ip_mreq,,,[#include "${srcdir}/compat/headers_slim.h"]) ++ AC_CHECK_DECLS(IP_ADD_MEMBERSHIP,,,[#include "${srcdir}/compat/headers_slim.h"]) + AC_MSG_CHECKING(for multicast support) + ac_cv_multicast=no + if test "$ac_cv_have_decl_IP_ADD_MEMBERSHIP" = yes; then +@@ -193,9 +193,9 @@ fi + + dnl check for IPv6 + if test "$ac_cv_have_ipv6" != no; then +- AC_CHECK_TYPES(struct sockaddr_storage,,,[#include "compat/headers_slim.h"]) +- AC_CHECK_TYPES(struct sockaddr_in6,,,[#include "compat/headers_slim.h"]) +- AC_CHECK_DECLS(AF_INET6,,,[#include "compat/headers_slim.h"]) ++ AC_CHECK_TYPES(struct sockaddr_storage,,,[#include "${srcdir}/compat/headers_slim.h"]) ++ AC_CHECK_TYPES(struct sockaddr_in6,,,[#include "${srcdir}/compat/headers_slim.h"]) ++ AC_CHECK_DECLS(AF_INET6,,,[#include "${srcdir}/compat/headers_slim.h"]) + AC_MSG_CHECKING(for IPv6 headers and structures) + ac_cv_have_ipv6=no + if test "$ac_cv_type_struct_sockaddr_storage" = yes; then +@@ -211,9 +211,9 @@ fi + + if test "$ac_cv_have_ipv6" = yes; then + if test "$ac_cv_multicast" = yes; then +- AC_CHECK_TYPES(struct ipv6_mreq,,,[#include "compat/headers_slim.h"]) +- AC_CHECK_DECLS(IPV6_ADD_MEMBERSHIP,,,[#include "compat/headers_slim.h"]) +- AC_CHECK_DECLS(IPV6_MULTICAST_HOPS,,,[#include "compat/headers_slim.h"]) ++ AC_CHECK_TYPES(struct ipv6_mreq,,,[#include "${srcdir}/compat/headers_slim.h"]) ++ AC_CHECK_DECLS(IPV6_ADD_MEMBERSHIP,,,[#include "${srcdir}/compat/headers_slim.h"]) ++ AC_CHECK_DECLS(IPV6_MULTICAST_HOPS,,,[#include "${srcdir}/compat/headers_slim.h"]) + AC_MSG_CHECKING(for IPv6 multicast support) + ac_cv_have_ipv6_multicast=no + if test "$ac_cv_type_struct_ipv6_mreq" = yes; then diff --git a/meta-agl-profile-core/recipes-test/iperf/iperf-2.0.9/0002-fix-bool-size-m4.patch b/meta-agl-profile-core/recipes-test/iperf/iperf-2.0.9/0002-fix-bool-size-m4.patch new file mode 100644 index 000000000..348e316ce --- /dev/null +++ b/meta-agl-profile-core/recipes-test/iperf/iperf-2.0.9/0002-fix-bool-size-m4.patch @@ -0,0 +1,16 @@ +--- iperf-2.0.5/m4/dast.m4.orig 2016-06-15 11:42:03.945581785 -0400 ++++ iperf-2.0.5/m4/dast.m4 2016-06-15 11:42:11.053581641 -0400 +@@ -11,7 +11,12 @@ + + AC_DEFUN(DAST_CHECK_BOOL, [ + +-AC_CHECK_SIZEOF(bool) ++if test "$ac_cv_header_stdbool_h" = yes; then ++ AC_CHECK_SIZEOF(bool,,[#include <stdbool.h>]) ++else ++ AC_CHECK_SIZEOF(bool) ++fi ++ + if test "$ac_cv_sizeof_bool" = 0 ; then + AC_DEFINE(bool, int) + fi diff --git a/meta-agl-profile-core/recipes-test/iperf/iperf-2.0.9/iperf-2.0.5_ManPage.patch b/meta-agl-profile-core/recipes-test/iperf/iperf-2.0.9/iperf-2.0.5_ManPage.patch new file mode 100644 index 000000000..12e8f4631 --- /dev/null +++ b/meta-agl-profile-core/recipes-test/iperf/iperf-2.0.9/iperf-2.0.5_ManPage.patch @@ -0,0 +1,8 @@ +diff --git iperf-2.0.5/man/Makefile.am iperf-2.0.5/man/Makefile.am + index ed97bc6..728873f 100644 +--- iperf-2.0.5/man/Makefile.am ++++ iperf-2.0.5/man/Makefile.am +@@ -1,2 +1 @@ +-man_MANS = iperf.1 +-dist_man_MANS = $(man_MANS) ++dist_man_MANS = iperf.1 diff --git a/meta-agl-profile-core/recipes-test/iperf/iperf_2.0.9.bb b/meta-agl-profile-core/recipes-test/iperf/iperf_2.0.9.bb new file mode 100644 index 000000000..f297f7f7f --- /dev/null +++ b/meta-agl-profile-core/recipes-test/iperf/iperf_2.0.9.bb @@ -0,0 +1,20 @@ +DESCRIPTION = "Iperf is a tool to measure maximum TCP bandwidth, allowing the tuning of various parameters and UDP characteristics" +HOMEPAGE = "http://dast.nlanr.net/Projects/Iperf/" +SECTION = "console/network" +LICENSE = "BSD-2-Clause" +LIC_FILES_CHKSUM = "file://COPYING;md5=e8478eae9f479e39bc34975193360298" + +SRC_URI = " https://iperf.fr/download/source/${BP}-source.tar.gz \ + " + +SRC_URI[md5sum] = "1bb3a1d98b1973aee6e8f171933c0f61" +SRC_URI[sha256sum] = "a5350777b191e910334d3a107b5e5219b72ffa393da4186da1e0a4552aeeded6" + +S = "${WORKDIR}/${BP}" + +inherit autotools pkgconfig + +EXTRA_OECONF = "--exec-prefix=${STAGING_DIR_HOST}${layout_exec_prefix}" + +PACKAGECONFIG ??= "${@bb.utils.contains('DISTRO_FEATURES', 'ipv6', 'ipv6', '', d)}" +PACKAGECONFIG[ipv6] = "--enable-ipv6,--disable-ipv6," diff --git a/meta-agl-profile-core/recipes-test/ipv6connect/ipv6connect.bb b/meta-agl-profile-core/recipes-test/ipv6connect/ipv6connect.bb new file mode 100644 index 000000000..a8b93716a --- /dev/null +++ b/meta-agl-profile-core/recipes-test/ipv6connect/ipv6connect.bb @@ -0,0 +1,24 @@ +SUMMARY = "ipv6connect test" +HOMEPAGE = "https://chromium.googlesource.com/chromiumos/third_party/autotest/+/0.12.369.B/client/tests/ipv6connect" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://${S}/${PN}/LICENSE;md5=b234ee4d69f5fce4486a80fdaf4a4263" + +SRC_URI = "git://gerrit.automotivelinux.org/gerrit/src/qa-test-misc;protocol=https;branch=${AGL_BRANCH}" +SRCREV = "b355b7e1f43a19938895964f314484ffd8a39542" + +inherit autotools + +INSANE_SKIP_${PN} = "ldflags" + +B = "${WORKDIR}/git/ipv6connect" +S = "${WORKDIR}/git" + +# configure script is not delivered, only a makefile. +do_configure() { + : +} + +do_install() { + install -d ${D}${bindir} + install -m 0755 ${B}/ipv6connect ${D}${bindir} +} diff --git a/meta-agl-profile-core/recipes-test/linpack/linpack.bb b/meta-agl-profile-core/recipes-test/linpack/linpack.bb new file mode 100644 index 000000000..84bed0ff6 --- /dev/null +++ b/meta-agl-profile-core/recipes-test/linpack/linpack.bb @@ -0,0 +1,23 @@ +SUMMARY = "Linpack benchmark" +LICENSE = "BSD" +LIC_FILES_CHKSUM = "file://${S}/${PN}/linpack.c;md5=076f1fd8d313056103f98d4253862eae" + +SRC_URI = "git://gerrit.automotivelinux.org/gerrit/src/qa-test-misc;protocol=https;branch=${AGL_BRANCH}" +SRCREV = "920cae73a918d1f516113b0ae967be3ecaba86ef" + +DEPENDS += "rsync-native" + +inherit autotools + +S = "${WORKDIR}/git" + +# configure script is not delivered, only a makefile. +do_configure() { + mkdir -p ${B} + rsync -a ${S}/${PN}/* ${B} +} + +do_install() { + install -d ${D}${bindir} + install -m 0755 ${B}/linpack ${D}${bindir} +} diff --git a/meta-agl-profile-core/recipes-test/linus-stress/linus-stress.bb b/meta-agl-profile-core/recipes-test/linus-stress/linus-stress.bb new file mode 100644 index 000000000..01b3cfce5 --- /dev/null +++ b/meta-agl-profile-core/recipes-test/linus-stress/linus-stress.bb @@ -0,0 +1,23 @@ +SUMMARY = "linus_stress test" +HOMEPAGE = "https://chromium.googlesource.com/chromiumos/third_party/autotest/+/master/client/tests/linus_stress" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://${S}/linus_stress/LICENSE;md5=b234ee4d69f5fce4486a80fdaf4a4263" + +SRC_URI = "git://gerrit.automotivelinux.org/gerrit/src/qa-test-misc;protocol=https;branch=${AGL_BRANCH}" +SRCREV = "87cdfd4626c0cb47fc22f328867e49d6268df85c" + +inherit autotools +INSANE_SKIP_${PN} = "ldflags" + +B = "${WORKDIR}/git/linus_stress" +S = "${WORKDIR}/git" + +# configure script is not delivered, only a makefile. +do_configure() { + : +} + +do_install() { + install -d ${D}${bindir} + install -m 0755 ${B}/linus_stress ${D}${bindir} +} diff --git a/meta-agl-profile-core/recipes-test/packagegroups/packagegroup-agl-test.bb b/meta-agl-profile-core/recipes-test/packagegroups/packagegroup-agl-test.bb new file mode 100644 index 000000000..1c3412e84 --- /dev/null +++ b/meta-agl-profile-core/recipes-test/packagegroups/packagegroup-agl-test.bb @@ -0,0 +1,57 @@ +SUMMARY = "Utilities for testing of AGL" +DESCRIPTION = "A set of common packages required by testing AGL for Quality Assurance" + +LICENSE = "MIT" + +inherit packagegroup + +PACKAGES = "\ + packagegroup-agl-test \ + packagegroup-agl-test-ltp \ + packagegroup-ivi-common-test \ + " + +ALLOW_EMPTY_${PN} = "1" + +RDEPENDS_${PN} += "\ + bc \ + blobsallad \ + dbench \ + ebizzy \ + ffsb \ + interbench \ + iozone3 \ + iperf \ + ipv6connect \ + linpack \ + linus-stress \ + lmbench \ + nbench-byte \ + rt-tests \ + stress \ + " +# to be added, but needs LICENSE_FLAGS_WHITELIST="non-commercial" +# netperf + +# FTBS, SPEC-316 +# himeno +# FTBS, SPEC-1384 +# trinity + +# packagegroup-agl-test-ltp \ +# ltp \ +# + +# Packages for shell commands which are required by LTP +# readelf, logrotate, vsftpd, crontab, sar, arp, ftp, +# host, rcp, rlogin, rsh, tcpdump, expect, iptables, dnsmasq, +# pgrep +RDEPENDS_packagegroup-agl-test-ltp += " \ + initscripts-functions bind-utils binutils \ + cronie dnsmasq expect inetutils-ftp inetutils-rsh \ + iptables logrotate net-tools sysstat tcpdump vsftpd \ + " + +RDEPENDS_packagegroup-ivi-common-test = " \ + packagegroup-agl-test \ + " diff --git a/meta-agl-profile-core/recipes-test/trinity/trinity_git.bb b/meta-agl-profile-core/recipes-test/trinity/trinity_git.bb new file mode 100644 index 000000000..f0f09a855 --- /dev/null +++ b/meta-agl-profile-core/recipes-test/trinity/trinity_git.bb @@ -0,0 +1,42 @@ +SUMMARY = "a Linux System call fuzz teste." +DESCRIPTION = "Trinity, a Linux System call fuzz tester." +HOMEPAGE = "http://codemonkey.org.uk/projects/trinity/" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://${S}/COPYING;md5=96094d47cfbd2cc45eb46ce0fc423c04" + +COMPATIBLE_HOST = "(x86_64|arm|aarch64).*-linux" + +PV = "1.5" +SRCREV = "edc2e693e298e0372010a361354c4a79a3cd93f3" +SRC_URI = "git://github.com/kernelslacker/trinity.git;protocol=https;nobranch=1 \ + " + +S = "${WORKDIR}/git" + +inherit useradd + +USERADD_PACKAGES = "${PN}" +USERADD_PARAM_${PN} = "--system --create-home --shell /bin/sh ${PN} " + +do_configure () { + ./configure.sh +} + +# workaround random build failures +do_compile () { + ${MAKE} +} + +do_install () { + oe_runmake install DESTDIR=${D}/usr + install -o ${PN} -d -m 0755 ${D}/${datadir}/${PN} + install -o ${PN} -m 0755 ${S}/scripts/test-all-syscalls-parallel.sh ${D}/${datadir}/${PN} + install -o ${PN} -m 0755 ${S}/scripts/test-all-syscalls-sequentially.sh ${D}/${datadir}/${PN} + install -o ${PN} -m 0755 ${S}/scripts/test-multi.sh ${D}/${datadir}/${PN} + install -o ${PN} -m 0755 ${S}/scripts/test-vm.sh ${D}/${datadir}/${PN} +} + +PACKAGES =+ "${PN}-example" + +FILES_${PN} = "${bindir}/trinity" +FILES_${PN}-example = "${datadir}/${PN}" |