pax_global_header00006660000000000000000000000064137372014720014520gustar00rootroot0000000000000052 comment=7089bab4bf90bb34efbf0df39e952464b8bdb3f0 torbrowser-launcher-0.3.3/000077500000000000000000000000001373720147200155325ustar00rootroot00000000000000torbrowser-launcher-0.3.3/.github/000077500000000000000000000000001373720147200170725ustar00rootroot00000000000000torbrowser-launcher-0.3.3/.github/CODEOWNERS000066400000000000000000000001031373720147200204570ustar00rootroot00000000000000# All code * @micahflee # AppArmor profiles /apparmor/ @intrigeri torbrowser-launcher-0.3.3/.gitignore000066400000000000000000000005461373720147200175270ustar00rootroot00000000000000*.py[cod] # C extensions *.so # Packages *.egg *.egg-info dist deb_dist build eggs parts bin var sdist develop-eggs .installed.cfg MANIFEST # Installer logs pip-log.txt # Unit test / coverage reports .coverage .tox nosetests.xml # Translations *.mo # Mr Developer .mr.developer.cfg .project .pydevproject # vim *.swp .*~ torbrowser-launcher-*.tar.gz torbrowser-launcher-0.3.3/BUILD.md000066400000000000000000000016401373720147200167140ustar00rootroot00000000000000# Building Tor Browser Launcher First, clone the repository: ```sh git clone https://github.com/micahflee/torbrowser-launcher.git cd torbrowser-launcher ``` Then install dependencies, build a package, and install: ### Debian, Ubuntu, Linux Mint, etc. ```sh sudo apt install build-essential dh-python python3-all python3-stdeb python3-pyqt5 python3-gpg python3-requests python3-socks python3-packaging gnupg2 tor ./build_deb.sh sudo dpkg -i deb_dist/torbrowser-launcher_*.deb ``` ### Red Hat, Fedora, CentOS, etc. ```sh sudo dnf install rpm-build python3-qt5 python3-gpg python3-requests python3-pysocks python3-packaging gnupg2 tor ./build_rpm.sh sudo yum install dist/torbrowser-launcher-*.rpm ``` ### Run without installing Install the dependencies: sadly, not all of them are available in virtualenv, so you will need to install (some of) them system-wide. Then, you can run: `TBL_SHARE=share ./torbrowser-launcher` torbrowser-launcher-0.3.3/CHANGELOG.md000066400000000000000000000153001373720147200173420ustar00rootroot00000000000000# Tor Browser Launcher Changelog ## 0.3.3 * Switch to Web Key Directory to refresh signing key from torproject.org, because everything is broken * Use proper version comparison now that Tor Browser 10.0 is out * Fix DNS leak when downloading over Tor * Various bug fixes, as well as AppData and AppArmor fixes ## 0.3.2 * Switch to keys.openpgp.org when refreshing signing key, because SKS keyservers are broken * Use new Tor Browser logo ## 0.3.1 * Ship with latest version of the Tor Browser Developers OpenPGP public key * Fix bug where TBL window stays open after Tor Browser is launched ## 0.3.0 * Switched from python2 to python3 * Switched from gtk2 to Qt5 * Switched from twisted to requests/socks * Use QThreads for async * Removed modem sound * Only refresh gpg keyring on verification error, instead of every time * Updated AppArmor profiles * Updated available languages, and fixed locale detection bug * Fixed false signature verification error related to twisted ## 0.2.9 * Fixed crash issue related to Tor Browser 7.5 changing how the currently installed version number is stored * Updated list of Tor Project dist mirrors * Fixed edge case crash for when stdout isn't writable * Updated AppStream metadata * Updated AppArmor profiles ## 0.2.8 * Update URL to check for latest version, which changed in Tor Browser 7 * Automatically refresh GPG keyring, to prevent signature verification false positives * Improve GnuPG code by using GPGME if available * Updated AppArmor profiles * Added Czech, Hungarian localization ## 0.2.7 * Updated Tor Browser signing key because they added a new subkey and verification was failing * Updated AppArmor profiles * Improved localization, and added Russian ## 0.2.6 * Fixed bug related to fallback to English feature that caused Settings to crash ## 0.2.5 * Fix issue where Tor Browser Launcher failed to launch if currently installed version of Tor Browser was too old * If Tor Browser download isn't available in your language, fallback to English * Avoid re-downloading tarball if it's already present * Verify GnuPG importing keys using status-fd rather than exit codes * Various AppArmor improvements * Removed unused dependency ## 0.2.4 * Fix signature verification bypass attack, reported by Jann Horn (CVE-2016-3180) ## 0.2.3 * Removed certificate pinning to https://www.torproject.org to avoid issues with upcoming certificate change, and hard-coded minimum Tor Browser version in the release * Fix issue with detecting language * Make Tor SOCKS5 proxy configurable, for users not running on 9050 * Improved AppArmor profiles * Added translations * Switched from xpm icons to png icons * Changed "Exit" button to "Cancel" button * New package description ## 0.2.2 * Tor Browser Launcher no longer attempts to auto-update, now that Tor Browser has this feature * System Tor is now an optional dependency * Fix issue where downloads fail because of unicode URLs * Removed window management code that stopped working many releases ago, and removed wmctrl dependency * Removed test code that caused signature verification to happen at the wrong time ## 0.2.1 * Stop using RecommendedTBBVersions and start using more reliable "release" channel XML * Converted settings file from pickle format to JSON * Download tarball signatures to verify, rather than SHA256SUMS and signature * Implemented IPolicyForHTTPS to prevent twisted-related crashes in Debian * Some AppArmor fixes ## 0.2.0 * Fix critical bug with new location of start-tor-browser * Silenced some AppArmor denied events from logs * Print less console output * Remove support for accepting links * Added better support for updating over Tor in Fedora ## 0.1.9 * Added option to disable accepting links, to workaround Firefox/Tor Browser issue ## 0.1.8 * Added new Tor Browser signing key * Fixed removing alpha/beta code due to change in RecommendedTBBVersions syntax * Fixed opening links in TBB if you originally opened TBB without clicking a link ## 0.1.7 * You can now pass URLs into TBL, and set it as your default browser * Hides TBL window before launching TBB * Default mirror switched to https://dist.torproject.org/ * Added AppData file to look better in software centers * Exclude AppArmor profiles in Ubuntu, where they're broken ## 0.1.6 * Updated licensing confusion to just be MIT in all locations * Fixed bug related to TBB 4.0's new folder structure * Updated .desktop files to comply with standards ## 0.1.5 * Split source code into several files * Several AppArmor updates * Prepare for upcoming RecommendedTBBVersion format change * More verbose UI when updating * No longer detaches start-tor-browser as separate process * Temporarily disable AppArmor profiles in Ubuntu ## 0.1.4 * RecommendedTBBVersion URL change * Many AppArmor improvements * Allow installation into a virtualenv ## 0.1.3 * Force installing stable release if available in RecommendedTBBVersions * Removed Mike Perry's signing key and added Erinn Clark's signing key * Fixed AppArmor profiles (thanks to troubadoour) ## 0.1.2 * Updated Dutch translation * Fixed bug with loading mirrors list * Huge refactor of AppArmor profiles * Added OnionShare support to AppArmor profiles * Suppresses output from detached TBB process * Uses freedesktop xdg-user-dirs instead of ~/.torbrowser * Removed all signing keys except Mike Perry's * Made tor and python-txsocksx dependencies to update over Tor by default ## 0.1.1 * Added TBL_SHARE support, to more easily develop without installing systemwide * Modem sound and python-pygame dependency is now optional * Support for updating TBB over Tor using a system Tor * Removed support for stable/alpha preference, forces stable now * Added French translations ## 0.1.0 * Added Polish translations * Version 0.1.0 marks first version in Debian! * Changed GPG release signing key from 5C17616361BD9F92422AC08BB4D25A1E99999697 to 0B1491929806596254700155FD720AD9EBA34B1C ## 0.0.9 * Fixed AppArmor rules that were broken in Ubuntu * Added support for basic RPM packaging * Removed un-used dependencies * Fixed URLs to deal with TBB release filename changes ## 0.0.8 * Removed older code that's no longer used * Updated list of Tor mirrors * Replaced certificate for www.torproject.org post-heartbleed * Fixed URLs to deal with TBB release filename changes ## 0.0.7 * Added AppArmor profiles for torbrowser-launcher and TBB * Removed included libs in favor of adding new Debian package dependencies ## 0.0.6 * Fixed URLs to deal with changes in TBB releases for 3.x ## 0.0.5 * Updated paths because TBB 3.x changed directory structure * mirrors.txt now has local version in /usr/local * Updated TBB signature URL * Made optional modem sound when launching Tor, because it's sooo slow :) * Extra check to make sure the latest version is installed torbrowser-launcher-0.3.3/LICENSE000066400000000000000000000022001373720147200165310ustar00rootroot00000000000000Tor Browser Launcher https://github.com/micahflee/torbrowser-launcher/ Copyright (c) 2013-2017 Micah Lee Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. torbrowser-launcher-0.3.3/README.md000066400000000000000000000042201373720147200170070ustar00rootroot00000000000000# Tor Browser Launcher _**Are you getting an error?** Sometimes updates in Tor Browser itself will break Tor Browser Launcher. There's a good chance that the problem you're experiencing has already been fixed in the [newest version](https://github.com/micahflee/torbrowser-launcher/releases). Try installing from Flatpak (instructions below), or [build from source](/BUILD.md)._ Tor Browser Launcher is intended to make Tor Browser easier to install and use for GNU/Linux users. You install ```torbrowser-launcher``` from your distribution's package manager and it handles everything else: * Downloads and installs the most recent version of Tor Browser in your language and for your computer's architecture, or launches Tor Browser if it's already installed (Tor Browser will automatically update itself) * Verifies Tor Browser's [signature](https://www.torproject.org/docs/verifying-signatures.html.en) for you, to ensure the version you downloaded was cryptographically signed by Tor developers and was not tampered with * Adds "Tor Browser" and "Tor Browser Launcher Settings" application launcher to your desktop environment's menu * Includes AppArmor profiles to make a Tor Browser compromise not as bad * Optionally plays a modem sound when you open Tor Browser (because Tor is so slow) Tor Browser Launcher is included in Ubuntu, Debian, and Fedora. To install it in any other distribution, see the [build instructions](/BUILD.md). You might want to check out the [security design doc](/security_design.md). ![Tor Browser Launcher screenshot](/screenshot.png) # Installing You can install `torbrowser-launcher` from your operating system's package manager, but it might be out-of-date and have issues working. If you want to make sure you always have the latest version, use Flatpak: ## Installing in any Linux distro using Flatpak Install Flatpak using these [instructions](https://flatpak.org/setup/). Then install `torbrowser-launcher` like this: ``` flatpak install flathub com.github.micahflee.torbrowser-launcher -y ``` Run `torbrowser-launcher` either by using the GUI desktop launcher, or by running: ``` flatpak run com.github.micahflee.torbrowser-launcher ``` torbrowser-launcher-0.3.3/apparmor/000077500000000000000000000000001373720147200173535ustar00rootroot00000000000000torbrowser-launcher-0.3.3/apparmor/license.txt000066400000000000000000000030661373720147200215430ustar00rootroot00000000000000TBB AppArmor profiles are based on https://gitorious.org/tbb-apparmor/tbb-apparmor/ Originally written by Radostan Riedel -- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the names of the copyright owners nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. torbrowser-launcher-0.3.3/apparmor/local/000077500000000000000000000000001373720147200204455ustar00rootroot00000000000000torbrowser-launcher-0.3.3/apparmor/local/torbrowser.Browser.firefox000066400000000000000000000000001373720147200256510ustar00rootroot00000000000000torbrowser-launcher-0.3.3/apparmor/local/torbrowser.Tor.tor000066400000000000000000000000001373720147200241340ustar00rootroot00000000000000torbrowser-launcher-0.3.3/apparmor/torbrowser.Browser.firefox000066400000000000000000000120131373720147200245660ustar00rootroot00000000000000#include #include @{torbrowser_firefox_executable} = /home/*/.local/share/torbrowser/tbb/{i686,x86_64}/tor-browser_*/Browser/firefox.real profile torbrowser_firefox @{torbrowser_firefox_executable} { #include #include # Uncomment the following lines if you want to give the Tor Browser read-write # access to most of your personal files. # #include # @{HOME}/ r, # Audio support /{,usr/}bin/pulseaudio Pixr, #dbus, network netlink raw, network tcp, ptrace (trace) peer=@{profile_name}, signal (receive, send) set=("term") peer=@{profile_name}, deny /etc/host.conf r, deny /etc/hosts r, deny /etc/nsswitch.conf r, deny /etc/resolv.conf r, deny /etc/passwd r, deny /etc/group r, deny /etc/mailcap r, /etc/machine-id r, /var/lib/dbus/machine-id r, /dev/ r, /dev/shm/ r, owner @{PROC}/@{pid}/environ r, owner @{PROC}/@{pid}/fd/ r, owner @{PROC}/@{pid}/mountinfo r, owner @{PROC}/@{pid}/stat r, owner @{PROC}/@{pid}/status r, owner @{PROC}/@{pid}/task/*/stat r, @{PROC}/sys/kernel/random/uuid r, owner @{torbrowser_installation_dir}/ r, owner @{torbrowser_installation_dir}/* r, owner @{torbrowser_installation_dir}/.** rwk, owner @{torbrowser_installation_dir}/update.test/ rwk, owner @{torbrowser_home_dir}/.** rwk, owner @{torbrowser_home_dir}/ rw, owner @{torbrowser_home_dir}/** rwk, owner @{torbrowser_home_dir}.bak/ rwk, owner @{torbrowser_home_dir}.bak/** rwk, owner @{torbrowser_home_dir}/*.so mr, owner @{torbrowser_home_dir}/.cache/fontconfig/ rwk, owner @{torbrowser_home_dir}/.cache/fontconfig/** rwkl, owner @{torbrowser_home_dir}/browser/** r, owner @{torbrowser_home_dir}/{,browser/}components/*.so mr, owner @{torbrowser_home_dir}/Downloads/ rwk, owner @{torbrowser_home_dir}/Downloads/** rwk, owner @{torbrowser_home_dir}/firefox rix, owner @{torbrowser_home_dir}/{,TorBrowser/UpdateInfo/}updates/[0-9]*/* rw, owner @{torbrowser_home_dir}/{,TorBrowser/UpdateInfo/}updates/[0-9]*/{,MozUpdater/bgupdate/}updater ix, owner @{torbrowser_home_dir}/updater ix, owner @{torbrowser_home_dir}/TorBrowser/Data/Browser/.parentwritetest rw, owner @{torbrowser_home_dir}/TorBrowser/Data/Browser/profiles.ini r, owner @{torbrowser_home_dir}/TorBrowser/Data/Browser/profile.default/{,**} rwk, owner @{torbrowser_home_dir}/TorBrowser/Data/fontconfig/fonts.conf r, owner @{torbrowser_home_dir}/fonts/* l, owner @{torbrowser_home_dir}/TorBrowser/Tor/tor px, owner @{torbrowser_home_dir}/TorBrowser/Tor/ r, owner @{torbrowser_home_dir}/TorBrowser/Tor/*.so mr, owner @{torbrowser_home_dir}/TorBrowser/Tor/*.so.* mr, owner @{torbrowser_home_dir}/TorBrowser/Tor/libstdc++/*.so mr, owner @{torbrowser_home_dir}/TorBrowser/Tor/libstdc++/*.so.* mr, # parent Firefox process when restarting after upgrade, Web Content processes owner @{torbrowser_firefox_executable} pxmr -> torbrowser_firefox, /etc/mailcap r, /etc/mime.types r, /usr/share/ r, /usr/share/glib-2.0/schemas/gschemas.compiled r, /usr/share/mime/ r, /usr/share/themes/ r, /usr/share/applications/** rk, /usr/share/gnome/applications/ r, /usr/share/gnome/applications/kde4/ r, /usr/share/poppler/cMap/ r, # Distribution homepage /usr/share/homepage/ r, /usr/share/homepage/** r, /sys/devices/system/cpu/ r, /sys/devices/system/cpu/present r, /sys/devices/system/node/ r, /sys/devices/system/node/node[0-9]*/meminfo r, deny /sys/devices/virtual/block/*/uevent r, # Should use abstractions/gstreamer instead once merged upstream /etc/udev/udev.conf r, /run/udev/data/+pci:* r, /sys/devices/pci[0-9]*/**/uevent r, owner /{dev,run}/shm/shmfd-* rw, # Required for multiprocess Firefox (aka Electrolysis, i.e. e10s) owner /{dev,run}/shm/org.chromium.* rw, owner /dev/shm/org.mozilla.ipc.[0-9]*.[0-9]* rw, # for Chromium IPC # Deny access to DRM nodes, that's granted by the X abstraction, which is # sourced by the gnome abstraction, that we include. deny /dev/dri/** rwklx, # Silence denial logs about permissions we don't need deny /dev/dri/ rwklx, deny @{HOME}/.cache/fontconfig/ rw, deny @{HOME}/.cache/fontconfig/** rw, deny @{HOME}/.config/gtk-2.0/ rw, deny @{HOME}/.config/gtk-2.0/** rw, deny @{PROC}/@{pid}/net/route r, deny /sys/devices/system/cpu/cpufreq/policy[0-9]*/cpuinfo_max_freq r, deny /sys/devices/system/cpu/*/cache/index[0-9]*/size r, deny /run/user/[0-9]*/dconf/user rw, deny /usr/bin/lsb_release x, deny capability sys_admin, # Silence denial logs about PulseAudio deny /etc/pulse/client.conf r, deny /usr/bin/pulseaudio x, # KDE 4 owner @{HOME}/.kde/share/config/* r, # Xfce4 /etc/xfce4/defaults.list r, /usr/share/xfce4/applications/ r, # u2f (tested with Yubikey 4) /sys/class/ r, /sys/bus/ r, /sys/class/hidraw/ r, /run/udev/data/c24{7,9}:* r, /dev/hidraw* rw, # Yubikey NEO also needs this: /sys/devices/**/hidraw/hidraw*/uevent r, #include } torbrowser-launcher-0.3.3/apparmor/torbrowser.Tor.tor000066400000000000000000000031151373720147200230540ustar00rootroot00000000000000#include #include @{torbrowser_tor_executable} = /home/*/.local/share/torbrowser/tbb/{i686,x86_64}/tor-browser_*/Browser/TorBrowser/Tor/tor profile torbrowser_tor @{torbrowser_tor_executable} { #include network netlink raw, network tcp, network udp, /etc/host.conf r, /etc/nsswitch.conf r, /etc/passwd r, /etc/resolv.conf r, owner @{torbrowser_home_dir}/TorBrowser/Tor/tor mr, owner @{torbrowser_home_dir}/TorBrowser/Data/Tor/ rw, owner @{torbrowser_home_dir}/TorBrowser/Data/Tor/** rw, owner @{torbrowser_home_dir}/TorBrowser/Data/Tor/lock rwk, owner @{torbrowser_home_dir}/TorBrowser/Tor/*.so mr, owner @{torbrowser_home_dir}/TorBrowser/Tor/*.so.* mr, # Support some of the included pluggable transports owner @{torbrowser_home_dir}/TorBrowser/Tor/PluggableTransports/** rix, @{PROC}/sys/net/core/somaxconn r, #include # Silence file_inherit logs deny @{torbrowser_home_dir}/{browser/,}omni.ja r, deny @{torbrowser_home_dir}/{browser/,}features/*.xpi r, deny @{torbrowser_home_dir}/TorBrowser/Data/Browser/profile.default/.parentlock rw, deny @{torbrowser_home_dir}/TorBrowser/Data/Browser/profile.default/extensions/*.xpi r, deny @{torbrowser_home_dir}/TorBrowser/Data/Browser/profile.default/startupCache/* r, # Silence logs from included pluggable transports deny /etc/hosts r, deny /etc/services r, @{PROC}/sys/kernel/random/uuid r, /sys/devices/system/cpu/ r, # OnionShare compatibility /tmp/onionshare/** rw, #include } torbrowser-launcher-0.3.3/apparmor/tunables/000077500000000000000000000000001373720147200211705ustar00rootroot00000000000000torbrowser-launcher-0.3.3/apparmor/tunables/torbrowser000066400000000000000000000002351373720147200233230ustar00rootroot00000000000000@{torbrowser_installation_dir}=@{HOME}/.local/share/torbrowser/tbb/{i686,x86_64}/tor-browser_* @{torbrowser_home_dir}=@{torbrowser_installation_dir}/Browser torbrowser-launcher-0.3.3/build_deb.sh000077500000000000000000000004621373720147200200040ustar00rootroot00000000000000#!/bin/sh VERSION=`cat share/torbrowser-launcher/version` # clean up from last build rm -r build deb_dist # build binary package python3 setup.py --command-packages=stdeb.command bdist_deb # install it echo "" echo "To install, run:" echo "sudo dpkg -i deb_dist/torbrowser-launcher_$VERSION-1_all.deb" torbrowser-launcher-0.3.3/build_rpm.sh000077500000000000000000000005641373720147200200530ustar00rootroot00000000000000#!/bin/sh VERSION=`cat share/torbrowser-launcher/version` # clean up from last build rm -r build dist # build binary package python3 setup.py bdist_rpm --requires="python3-qt5, python3-gpg, python3-requests, python3-pysocks, python3-packaging, gnupg2" # install it echo "" echo "To install, run:" echo "sudo dnf install dist/torbrowser-launcher-$VERSION-1.noarch.rpm" torbrowser-launcher-0.3.3/makepot.sh000077500000000000000000000001671373720147200175350ustar00rootroot00000000000000#!/bin/sh cd torbrowser_launcher xgettext --language=Python --from-code=UTF-8 --output=../torbrowser_launcher.pot *.py torbrowser-launcher-0.3.3/po/000077500000000000000000000000001373720147200161505ustar00rootroot00000000000000torbrowser-launcher-0.3.3/po/cs.po000066400000000000000000000165151373720147200171250ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-03-23 15:47-0700\n" "PO-Revision-Date: 2017-01-29 21:33+0100\n" "Last-Translator: Marek Suchánek \n" "Language-Team: \n" "Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 1.8.11\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" #: __init__.py:65 launcher.py:470 msgid "Tor Browser Launcher" msgstr "Spouštěč prohlížeče Tor" #: __init__.py:66 msgid "By Micah Lee, licensed under MIT" msgstr "Vytvořil Micah Lee pod licencí MIT" #: __init__.py:67 #, python-brace-format msgid "version {0}" msgstr "verze {0}" #: common.py:100 #, python-brace-format msgid "Error creating {0}" msgstr "Chyba při vytváření {0}" #: common.py:102 common.py:180 #, python-brace-format msgid "{0} is not writable" msgstr "Do {0} není možné zapisovat" #: common.py:177 #, python-brace-format msgid "Cannot create directory {0}" msgstr "Nelze vytvořit adresář {0}" #: common.py:187 msgid "Creating GnuPG homedir" msgstr "Vytváří se domovská složka GnuGPG" #: common.py:254 #, python-format msgid "Could not import key with fingerprint: %s." msgstr "Selhal import klíče s otiskem: %s." #: common.py:259 msgid "Not all keys were imported successfully!" msgstr "Ne všechny klíče byly importovány úspěšně!" #: launcher.py:83 #, fuzzy msgid "Downloading Tor Browser for the first time." msgstr "Poprvé se stahuje a instaluje Prohlížeč Tor." #: launcher.py:85 #, fuzzy msgid "" "Your version of Tor Browser is out-of-date. Downloading the newest version." msgstr "" "Vaše verze Prohlížeče Tor je zastaralá. Stáhne se a nainstaluje nejnovější " "verze." #: launcher.py:100 msgid "Downloading over Tor" msgstr "Stahování přes Tor" #: launcher.py:111 msgid "Tor Browser" msgstr "Prohlížeč Tor" #: launcher.py:128 msgid "Start" msgstr "Spustit" #: launcher.py:174 msgid "Yes" msgstr "" #: launcher.py:178 msgid "Exit" msgstr "" #: launcher.py:192 settings.py:136 msgid "Cancel" msgstr "Zrušit" #: launcher.py:231 launcher.py:245 launcher.py:249 launcher.py:279 #: launcher.py:281 msgid "Downloading" msgstr "Stahuje se" #: launcher.py:238 msgid "Latest version: {}" msgstr "Nejnovější verze: {}" #: launcher.py:241 msgid "Error detecting Tor Browser version." msgstr "Chyba při zjišťování verze Prohlížeče Tor." #: launcher.py:256 launcher.py:357 msgid "Verifying Signature" msgstr "Ověřuje se podpis" #: launcher.py:260 msgid "Extracting" msgstr "Extrahuje se" #: launcher.py:264 msgid "Running" msgstr "Běží" #: launcher.py:268 msgid "Starting download over again" msgstr "Stahování se spouští znovu" #: launcher.py:279 launcher.py:295 msgid "(over Tor)" msgstr "" #: launcher.py:293 msgid "Downloaded" msgstr "Staženo" #: launcher.py:393 msgid "Installing" msgstr "Instaluje se" #: launcher.py:401 #, python-brace-format msgid "Tor Browser Launcher doesn't understand the file format of {0}" msgstr "Spouštěč prohlížeče Tor nerozumí formátu souboru {0}" #: launcher.py:427 msgid "" "The version of Tor Browser you have installed is earlier than it should be, " "which could be a sign of an attack!" msgstr "" "Verze prohlížeče Tor, kterou máte nainstalovanou, je ranější, než by měla " "být, což může značit útok!" #: launcher.py:446 #, fuzzy msgid "Downloading Tor Browser over again." msgstr "Znovu se stahuje balík Prohlížeče Tor." #: launcher.py:516 launcher.py:525 launcher.py:533 msgid "Download Error:" msgstr "Chyba stahování:" #: launcher.py:517 msgid "You are currently using a non-default mirror" msgstr "Používáte právě nevýchozí zrcadlo" #: launcher.py:518 msgid "Would you like to switch back to the default?" msgstr "Přejete si přepnout zpět na výchozí?" #: launcher.py:527 msgid "Would you like to try the English version of Tor Browser instead?" msgstr "Přejete si místo toho zkusit anglickou verzi Prohlížeče Tor?" #: launcher.py:548 #, python-brace-format msgid "" "Invalid SSL certificate for:\n" "{0}\n" "\n" "You may be under attack." msgstr "" #: launcher.py:550 msgid "Try the download again using Tor?" msgstr "Zkusit stahování znovu pomocí Toru?" #: launcher.py:559 #, python-brace-format msgid "" "Error starting download:\n" "\n" "{0}\n" "\n" "Trying to download over Tor. Are you sure Tor is configured correctly and " "running?" msgstr "" #: launcher.py:563 #, python-brace-format msgid "" "Error starting download:\n" "\n" "{0}\n" "\n" "Are you connected to the internet?" msgstr "" "Chyba při spouštění stahování:\n" "\n" "{0}\n" "\n" "Jste připojeni k internetu?" #: settings.py:46 msgid "Tor Browser Launcher Settings" msgstr "Nastavení Spouštěče prohlížeče Tor" #: settings.py:50 msgid "Download over system Tor" msgstr "Stáhnout přes systémový Tor" #: settings.py:57 msgid "Force downloading English version of Tor Browser" msgstr "Vynutit stažení anglické verze Prohlížeče Tor" #: settings.py:66 msgid "Tor server" msgstr "Server Toru" #: settings.py:82 msgid "Status: Installed" msgstr "Stav: Nainstalováno" #: settings.py:84 msgid "Status: Not Installed" msgstr "Stav: Nenainstalováno" #: settings.py:87 msgid "Install Tor Browser" msgstr "Nainstalovat Prohlížeč Tor" #: settings.py:92 msgid "Reinstall Tor Browser" msgstr "Přeinstalovat Prohlížeč Tor" #: settings.py:115 msgid "Mirror" msgstr "Zrcadlo" #: settings.py:131 #, fuzzy msgid "Save && Exit" msgstr "Uložit a ukončit" #~ msgid "" #~ "The python-txsocksx package is missing, downloads will not happen over tor" #~ msgstr "Chybí balíček python-txsocksx, stahování se neuskuteční přes tor" #~ msgid "DNS Lookup Error" #~ msgstr "Chyba při vyhledávání DNS" #~ msgid "" #~ "The SSL certificate served by https://www.torproject.org is invalid! You " #~ "may be under attack." #~ msgstr "" #~ "Certifikát SSL získaný od https://www.torproject.org je neplatný! Možná " #~ "je na vás veden útok." #~ msgid "Error connecting to Tor at {0}" #~ msgstr "Chyba při připojování k Toru na {0}" #~ msgid "" #~ "SIGNATURE VERIFICATION FAILED!\n" #~ "\n" #~ "You might be under attack, or there might just be a networking problem. " #~ "Click Start try the download again." #~ msgstr "" #~ "SELHALO OVĚŘENÍ PODPISU!\n" #~ "\n" #~ "Možná je na vás veden útok, anebo může jít pouze o síťovou závadu. Pro " #~ "nové stažení klikněte na Spustit." #~ msgid "" #~ "The python-pygame package is missing, the modem sound is unavailable." #~ msgstr "Chybí balíček python-pygame, zvuk modemu není dostupný." #~ msgid "" #~ "This option is only available when using a system wide Tor installation." #~ msgstr "" #~ "Tato možnost je dostupná, pouze pokud se používá systémová instalace Toru." #~ msgid "This option requires the python-txsocksx package." #~ msgstr "Tato možnost vyžaduje balíček python-txsocksx." #~ msgid "Play modem sound, because Tor is slow :]" #~ msgstr "Přehrávat zvuk modemu, jelikož je Tor pomalý :]" #~ msgid "This option requires python-pygame to be installed" #~ msgstr "Tato možnost vyžaduje nainstalovaný python-pygame" torbrowser-launcher-0.3.3/po/fr.po000066400000000000000000000174731373720147200171330ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-03-23 15:47-0700\n" "PO-Revision-Date: 2016-12-02 15:16+0400\n" "Last-Translator: Andrey Kunitsyn \n" "Language-Team: French\n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 1.8.7.1\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: __init__.py:65 launcher.py:470 msgid "Tor Browser Launcher" msgstr "Tor Browser Launcher" #: __init__.py:66 msgid "By Micah Lee, licensed under MIT" msgstr "Par Micah Lee, sous licence MIT" #: __init__.py:67 #, python-brace-format msgid "version {0}" msgstr "version {0}" #: common.py:100 #, python-brace-format msgid "Error creating {0}" msgstr "Erreur lors de la création de {0}" #: common.py:102 common.py:180 #, python-brace-format msgid "{0} is not writable" msgstr "Impossible d'écrire {0}" #: common.py:177 #, python-brace-format msgid "Cannot create directory {0}" msgstr "Impossible de créer le dossier {0}" #: common.py:187 msgid "Creating GnuPG homedir" msgstr "Création du dossier GnuPG" #: common.py:254 #, python-format msgid "Could not import key with fingerprint: %s." msgstr "Impossible d'importer la clé avec l'empreinte : %s." #: common.py:259 msgid "Not all keys were imported successfully!" msgstr "Certaines clés n'ont pas pu être importées !" #: launcher.py:83 msgid "Downloading Tor Browser for the first time." msgstr "Téléchargement du Navigateur Tor pour la première fois." #: launcher.py:85 msgid "" "Your version of Tor Browser is out-of-date. Downloading the newest version." msgstr "" "Votre version du Navigateur Tor est obsolète. Téléchargement de la nouvelle " "version." #: launcher.py:100 msgid "Downloading over Tor" msgstr "Télécharger à travers Tor" #: launcher.py:111 msgid "Tor Browser" msgstr "Navigateur Tor" #: launcher.py:128 msgid "Start" msgstr "Démarrer" #: launcher.py:174 msgid "Yes" msgstr "Oui" #: launcher.py:178 msgid "Exit" msgstr "Quitter" #: launcher.py:192 settings.py:136 msgid "Cancel" msgstr "Annuler" #: launcher.py:231 launcher.py:245 launcher.py:249 launcher.py:279 #: launcher.py:281 msgid "Downloading" msgstr "Téléchargement" #: launcher.py:238 msgid "Latest version: {}" msgstr "Dernière version : {}" #: launcher.py:241 msgid "Error detecting Tor Browser version." msgstr "Impossible de détecter la version du Navigateur Tor." #: launcher.py:256 launcher.py:357 msgid "Verifying Signature" msgstr "Vérification de la signature" #: launcher.py:260 msgid "Extracting" msgstr "Décompression" #: launcher.py:264 msgid "Running" msgstr "Exécution" #: launcher.py:268 msgid "Starting download over again" msgstr "Télécharger à nouveau" #: launcher.py:279 launcher.py:295 msgid "(over Tor)" msgstr "(à travers Tor)" #: launcher.py:293 msgid "Downloaded" msgstr "Téléchargé" #: launcher.py:393 msgid "Installing" msgstr "Installation en cours" #: launcher.py:401 #, python-brace-format msgid "Tor Browser Launcher doesn't understand the file format of {0}" msgstr "Tor Browser Launcher ne comprend pas le format du fichier {0}" #: launcher.py:427 msgid "" "The version of Tor Browser you have installed is earlier than it should be, " "which could be a sign of an attack!" msgstr "" "La version du Navigateur Tor que vous avez installé est antérieure à ce " "qu'elle devrait, ce qui peut être le signe d'une attaque !" #: launcher.py:446 msgid "Downloading Tor Browser over again." msgstr "Télécharger le Navigateur Tor à nouveau." #: launcher.py:516 launcher.py:525 launcher.py:533 msgid "Download Error:" msgstr "Erreur de téléchargement :" #: launcher.py:517 msgid "You are currently using a non-default mirror" msgstr "Vous utilisez actuellement un miroir n'étant pas celui par défaut" #: launcher.py:518 msgid "Would you like to switch back to the default?" msgstr "Voulez-vous revenir à la valeur par défaut ?" #: launcher.py:527 msgid "Would you like to try the English version of Tor Browser instead?" msgstr "" "Voulez-vous essayer la version anglophone du Navigateur Tor à la place ?" #: launcher.py:548 #, python-brace-format msgid "" "Invalid SSL certificate for:\n" "{0}\n" "\n" "You may be under attack." msgstr "" "Certificat SSL invalide pour :\n" "{0}\n" "\n" "Vous pourriez être attaqué." #: launcher.py:550 msgid "Try the download again using Tor?" msgstr "Essayer de télécharger à nouveau à travers Tor ?" #: launcher.py:559 #, python-brace-format msgid "" "Error starting download:\n" "\n" "{0}\n" "\n" "Trying to download over Tor. Are you sure Tor is configured correctly and " "running?" msgstr "" "Impossible de démarrer le téléchargement :\n" "\n" "{0}\n" "\n" "Essayez de télécharger à travers Tor. Êtes-vous sûr que Tor est configuré " "correctement et fonctionne ?" #: launcher.py:563 #, python-brace-format msgid "" "Error starting download:\n" "\n" "{0}\n" "\n" "Are you connected to the internet?" msgstr "" "Impossible de démarrer le téléchargement :\n" "\n" "{0}\n" "\n" "Êtes-vous connecté à Internet ?" #: settings.py:46 msgid "Tor Browser Launcher Settings" msgstr "Configuration du Tor Browser Launcher" #: settings.py:50 msgid "Download over system Tor" msgstr "Télécharger à travers le Tor installé sur le système" #: settings.py:57 msgid "Force downloading English version of Tor Browser" msgstr "Forcer le téléchargement de la version anglophone du Navigateur Tor" #: settings.py:66 msgid "Tor server" msgstr "Serveur Tor" #: settings.py:82 msgid "Status: Installed" msgstr "Statut : Installé" #: settings.py:84 msgid "Status: Not Installed" msgstr "Statut : Pas installé" #: settings.py:87 msgid "Install Tor Browser" msgstr "Installer le Navigateur Tor" #: settings.py:92 msgid "Reinstall Tor Browser" msgstr "Réinstaller le Navigateur Tor" #: settings.py:115 msgid "Mirror" msgstr "Miroir" #: settings.py:131 msgid "Save && Exit" msgstr "Enregistrer et quitter" #~ msgid "" #~ "The python-txsocksx package is missing, downloads will not happen over tor" #~ msgstr "" #~ "Le paquet python-txsocks est manquant, les téléchargements ne se feront " #~ "pas sur Tor." #~ msgid "DNS Lookup Error" #~ msgstr "Erreur de type DNS Lookup" #~ msgid "" #~ "The SSL certificate served by https://www.torproject.org is invalid! You " #~ "may be under attack." #~ msgstr "" #~ "Le certificat SSL servi par https://www.torproject.org n'est pas valide! " #~ "Vous pouvez être l'objet d'une attaque." #~ msgid "Error connecting to Tor at {0}" #~ msgstr "Impossible de se connecter sur Tor au moyen de {0}" #~ msgid "" #~ "SIGNATURE VERIFICATION FAILED!\n" #~ "\n" #~ "You might be under attack, or there might just be a networking problem. " #~ "Click Start try the download again." #~ msgstr "" #~ "LA VÉRICATION DE LA SIGNATURE A ÉCHOUÉ\n" #~ "\n" #~ "Vous pourriez être l'objet d'une attaque, ou il peut s'agir d'un problème " #~ "de réseau. Cliquer sur Démarrer pour télécharger à nouveau." #~ msgid "" #~ "The python-pygame package is missing, the modem sound is unavailable." #~ msgstr "" #~ "Le paquet python-pygame est manquant, le son de modem est indisponible." #~ msgid "" #~ "This option is only available when using a system wide Tor installation." #~ msgstr "" #~ "Cette option n'est disponible qu'en conjonction avec une installation " #~ "système de Tor." #~ msgid "This option requires the python-txsocksx package." #~ msgstr "Cette option nécessite le paquet python-txsocksx" #~ msgid "Play modem sound, because Tor is slow :]" #~ msgstr "Jouer un son de modem, car Tor est lent :]" #~ msgid "This option requires python-pygame to be installed" #~ msgstr "Cette option requiert le paquet python-pygame" torbrowser-launcher-0.3.3/po/hu.po000066400000000000000000000166171373720147200171370ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-03-23 15:47-0700\n" "PO-Revision-Date: 2017-02-16 00:55+0100\n" "Last-Translator: Barcza Károly \n" "Language-Team: \n" "Language: hu_HU\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 1.8.8\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: __init__.py:65 launcher.py:470 msgid "Tor Browser Launcher" msgstr "Tor böngésző indító" #: __init__.py:66 msgid "By Micah Lee, licensed under MIT" msgstr "Micah Lee által MIT licenc alatt" #: __init__.py:67 #, python-brace-format msgid "version {0}" msgstr "verzió {0}" #: common.py:100 #, python-brace-format msgid "Error creating {0}" msgstr "Hiba a(z) {0} létrehozásakor" #: common.py:102 common.py:180 #, python-brace-format msgid "{0} is not writable" msgstr "{0} nem írható" #: common.py:177 #, python-brace-format msgid "Cannot create directory {0}" msgstr "Nem sikerült a(z) {0} létrehozása" #: common.py:187 msgid "Creating GnuPG homedir" msgstr "GnuPG könyvtár létrehozása" #: common.py:254 #, python-format msgid "Could not import key with fingerprint: %s." msgstr "Nem lehetett importálni a kulcsot ujjlenyomattal: %s." #: common.py:259 msgid "Not all keys were imported successfully!" msgstr "" #: launcher.py:83 #, fuzzy msgid "Downloading Tor Browser for the first time." msgstr "Tor böngésző letöltése és telepítése első alkalommal." #: launcher.py:85 #, fuzzy msgid "" "Your version of Tor Browser is out-of-date. Downloading the newest version." msgstr "" "A Tor böngésző verziója elavult. Töltsük le és telepítsük a legfrissebb " "változatot." #: launcher.py:100 msgid "Downloading over Tor" msgstr "Letöltés Tor-on keresztül" #: launcher.py:111 msgid "Tor Browser" msgstr "Tor böngésző" #: launcher.py:128 msgid "Start" msgstr "Elindítás" #: launcher.py:174 msgid "Yes" msgstr "" #: launcher.py:178 msgid "Exit" msgstr "" #: launcher.py:192 settings.py:136 msgid "Cancel" msgstr "Megszakít" #: launcher.py:231 launcher.py:245 launcher.py:249 launcher.py:279 #: launcher.py:281 msgid "Downloading" msgstr "Letöltés" #: launcher.py:238 msgid "Latest version: {}" msgstr "Legújabb változat: {}" #: launcher.py:241 msgid "Error detecting Tor Browser version." msgstr "Hiba a Tor böngésző verzió felsimerésekor" #: launcher.py:256 launcher.py:357 msgid "Verifying Signature" msgstr "Aláírás ellenőrzése" #: launcher.py:260 msgid "Extracting" msgstr "Kibontás" #: launcher.py:264 msgid "Running" msgstr "Fut" #: launcher.py:268 msgid "Starting download over again" msgstr "Újra letöltés indítása" #: launcher.py:279 launcher.py:295 msgid "(over Tor)" msgstr "" #: launcher.py:293 msgid "Downloaded" msgstr "Letöltve" #: launcher.py:393 msgid "Installing" msgstr "Telepítés.." #: launcher.py:401 #, python-brace-format msgid "Tor Browser Launcher doesn't understand the file format of {0}" msgstr "Tor böngésző indító nem érti a(z) {0} fájl formátumot." #: launcher.py:427 msgid "" "The version of Tor Browser you have installed is earlier than it should be, " "which could be a sign of an attack!" msgstr "" "A Tor böngésződ verziója egy korábbi verzió mint amilyennek lennie kellene, " "ami lehet egy támadás jele!" #: launcher.py:446 #, fuzzy msgid "Downloading Tor Browser over again." msgstr "Tör böngészőcsomag letöltése újra." #: launcher.py:516 launcher.py:525 launcher.py:533 msgid "Download Error:" msgstr "Hiba a letöltésben:" #: launcher.py:517 msgid "You are currently using a non-default mirror" msgstr "Jelenleg használt tükörszerver nem az alapértelmezett" #: launcher.py:518 msgid "Would you like to switch back to the default?" msgstr "Valóban szeretnéd visszaváltani alapértelmezettre?" #: launcher.py:527 msgid "Would you like to try the English version of Tor Browser instead?" msgstr "Ehelyett megpróbálod a Tor böngésző angol változatát ?" #: launcher.py:548 #, python-brace-format msgid "" "Invalid SSL certificate for:\n" "{0}\n" "\n" "You may be under attack." msgstr "" #: launcher.py:550 msgid "Try the download again using Tor?" msgstr "Megpróbálod újra a Tor letöltését?" #: launcher.py:559 #, python-brace-format msgid "" "Error starting download:\n" "\n" "{0}\n" "\n" "Trying to download over Tor. Are you sure Tor is configured correctly and " "running?" msgstr "" #: launcher.py:563 #, python-brace-format msgid "" "Error starting download:\n" "\n" "{0}\n" "\n" "Are you connected to the internet?" msgstr "" "Sikertelen a letöltés indítása:\n" "\n" "{0}\n" "\n" "Csatlakozva vagy az internethez?" #: settings.py:46 msgid "Tor Browser Launcher Settings" msgstr "Tör böngésző indító beállítások" #: settings.py:50 msgid "Download over system Tor" msgstr "Letöltés rendszer Tor-on keresztül" #: settings.py:57 msgid "Force downloading English version of Tor Browser" msgstr "Kényszerítse a Tor angol változatának letöltését" #: settings.py:66 msgid "Tor server" msgstr "Tor-szerver" #: settings.py:82 msgid "Status: Installed" msgstr "Állapot: Telepített" #: settings.py:84 msgid "Status: Not Installed" msgstr "Állapot: Nincs telepítve" #: settings.py:87 msgid "Install Tor Browser" msgstr "Tor-böngésző telepítése" #: settings.py:92 msgid "Reinstall Tor Browser" msgstr "Tor böngésző úratelepítése" #: settings.py:115 msgid "Mirror" msgstr "Tükrözés" #: settings.py:131 #, fuzzy msgid "Save && Exit" msgstr "Mentés és kilépés" #~ msgid "" #~ "The python-txsocksx package is missing, downloads will not happen over tor" #~ msgstr "" #~ "A python-txsocksx csoamag nem található, a letöltés nem fog megtörténni a " #~ "tor-on" #~ msgid "DNS Lookup Error" #~ msgstr "DNS feloldási hiba" #~ msgid "" #~ "The SSL certificate served by https://www.torproject.org is invalid! You " #~ "may be under attack." #~ msgstr "" #~ "A ttps://www.torproject.org által adott SSL tanúsítvány érvénytelen! " #~ "Lehet, hogy támadás alatt vagy." #~ msgid "Error connecting to Tor at {0}" #~ msgstr "Hiba a Tör csatlakozáskor itt {0}" #~ msgid "" #~ "SIGNATURE VERIFICATION FAILED!\n" #~ "\n" #~ "You might be under attack, or there might just be a networking problem. " #~ "Click Start try the download again." #~ msgstr "" #~ "ALÁÍRÁS ELLENŐRZÉSE SIKERTELEN\n" #~ "\n" #~ "Lehet, hogy támadás alatt vagy, vagy előfordulhat egy hálózati probléma " #~ "is. Kattints az indításra az újbóli letöltéshez." #~ msgid "" #~ "The python-pygame package is missing, the modem sound is unavailable." #~ msgstr "A python-pygame csomag nem található, a modem hang nem elérhető." #~ msgid "" #~ "This option is only available when using a system wide Tor installation." #~ msgstr "" #~ "Ehhez az opció akkor elérhető amikor használatban van a rendszer szintű " #~ "Tor." #~ msgid "This option requires the python-txsocksx package." #~ msgstr "Ehhez az opcióhoz szükséges a python-txsocksx csomag" #~ msgid "Play modem sound, because Tor is slow :]" #~ msgstr "Modem hang lejátszása, mert a Tor lassú :]" #~ msgid "This option requires python-pygame to be installed" #~ msgstr "Ehhez az opcióhoz szükséges hogy a python-pygame telepítve legyen" torbrowser-launcher-0.3.3/po/nl.po000066400000000000000000000134161373720147200171260ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-03-23 15:47-0700\n" "PO-Revision-Date: 2016-12-02 17:40+0400\n" "Last-Translator: Andrey Kunitsyn \n" "Language-Team: \n" "Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 1.8.7.1\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: __init__.py:65 launcher.py:470 msgid "Tor Browser Launcher" msgstr "Tor Browser Launcher" #: __init__.py:66 msgid "By Micah Lee, licensed under MIT" msgstr "Door Micah Lee, onder MIT licensie" #: __init__.py:67 #, python-brace-format msgid "version {0}" msgstr "versie {0}" #: common.py:100 #, python-brace-format msgid "Error creating {0}" msgstr "Fout bij maken van {0}" #: common.py:102 common.py:180 #, python-brace-format msgid "{0} is not writable" msgstr "{0} is niet schrijfbaar" #: common.py:177 #, python-brace-format msgid "Cannot create directory {0}" msgstr "Kan map niet maken: {0}" #: common.py:187 msgid "Creating GnuPG homedir" msgstr "Aanmeken GnuPG map" #: common.py:254 #, python-format msgid "Could not import key with fingerprint: %s." msgstr "" #: common.py:259 msgid "Not all keys were imported successfully!" msgstr "" #: launcher.py:83 #, fuzzy msgid "Downloading Tor Browser for the first time." msgstr "Tor Browser Bundle opnieuw aan het downloaden." #: launcher.py:85 msgid "" "Your version of Tor Browser is out-of-date. Downloading the newest version." msgstr "" #: launcher.py:100 msgid "Downloading over Tor" msgstr "" #: launcher.py:111 msgid "Tor Browser" msgstr "Tor Browser" #: launcher.py:128 msgid "Start" msgstr "Start" #: launcher.py:174 msgid "Yes" msgstr "" #: launcher.py:178 msgid "Exit" msgstr "" #: launcher.py:192 settings.py:136 msgid "Cancel" msgstr "Annuleren" #: launcher.py:231 launcher.py:245 launcher.py:249 launcher.py:279 #: launcher.py:281 msgid "Downloading" msgstr "Bezig met downloaden" #: launcher.py:238 #, fuzzy msgid "Latest version: {}" msgstr "Laatste versie: {}" #: launcher.py:241 msgid "Error detecting Tor Browser version." msgstr "" #: launcher.py:256 launcher.py:357 msgid "Verifying Signature" msgstr "Handtekening verifiëren" #: launcher.py:260 msgid "Extracting" msgstr "Uitpakken" #: launcher.py:264 msgid "Running" msgstr "Uitvoeren" #: launcher.py:268 msgid "Starting download over again" msgstr "" #: launcher.py:279 launcher.py:295 msgid "(over Tor)" msgstr "" #: launcher.py:293 msgid "Downloaded" msgstr "Gedownload" #: launcher.py:393 msgid "Installing" msgstr "Installeren" #: launcher.py:401 #, python-brace-format msgid "Tor Browser Launcher doesn't understand the file format of {0}" msgstr "" #: launcher.py:427 msgid "" "The version of Tor Browser you have installed is earlier than it should be, " "which could be a sign of an attack!" msgstr "" #: launcher.py:446 #, fuzzy msgid "Downloading Tor Browser over again." msgstr "Tor Browser Bundle opnieuw aan het downloaden." #: launcher.py:516 launcher.py:525 launcher.py:533 msgid "Download Error:" msgstr "Download fout:" #: launcher.py:517 msgid "You are currently using a non-default mirror" msgstr "" #: launcher.py:518 msgid "Would you like to switch back to the default?" msgstr "" #: launcher.py:527 msgid "Would you like to try the English version of Tor Browser instead?" msgstr "" #: launcher.py:548 #, python-brace-format msgid "" "Invalid SSL certificate for:\n" "{0}\n" "\n" "You may be under attack." msgstr "" #: launcher.py:550 msgid "Try the download again using Tor?" msgstr "Probeer de download opnieuw via Tor?" #: launcher.py:559 #, python-brace-format msgid "" "Error starting download:\n" "\n" "{0}\n" "\n" "Trying to download over Tor. Are you sure Tor is configured correctly and " "running?" msgstr "" #: launcher.py:563 #, python-brace-format msgid "" "Error starting download:\n" "\n" "{0}\n" "\n" "Are you connected to the internet?" msgstr "" "Fout bij het downloaden:\n" "\n" "{0}\n" "\n" "Bent u verbonden met het internet?" #: settings.py:46 msgid "Tor Browser Launcher Settings" msgstr "Tor Browser Launcher Instellingen" #: settings.py:50 msgid "Download over system Tor" msgstr "" #: settings.py:57 msgid "Force downloading English version of Tor Browser" msgstr "" #: settings.py:66 msgid "Tor server" msgstr "" #: settings.py:82 msgid "Status: Installed" msgstr "" #: settings.py:84 msgid "Status: Not Installed" msgstr "" #: settings.py:87 msgid "Install Tor Browser" msgstr "" #: settings.py:92 msgid "Reinstall Tor Browser" msgstr "" #: settings.py:115 msgid "Mirror" msgstr "" #: settings.py:131 #, fuzzy msgid "Save && Exit" msgstr "Opslaan & afsluiten" #~ msgid "" #~ "The SSL certificate served by https://www.torproject.org is invalid! You " #~ "may be under attack." #~ msgstr "" #~ "Het SSL certificaat geserveerd door https://www.torproject.org is " #~ "ongeldig! Je bent misschien onder aanval." #~ msgid "" #~ "SIGNATURE VERIFICATION FAILED!\n" #~ "\n" #~ "You might be under attack, or there might just be a networking problem. " #~ "Click Start try the download again." #~ msgstr "" #~ "HANDTEKENING VERIFICATIE MISLUKT!\n" #~ "\n" #~ "U wordt misschien aangevallen of gewoon een netwerk probleem. Klik op " #~ "Start om het downloaden nogmaals te proberen." #~ msgid "This option requires the python-txsocksx package." #~ msgstr "Voor deze optie is het python-txsocksx pakket nodig." #~ msgid "Play modem sound, because Tor is slow :]" #~ msgstr "Speel modem geluid, omdat Tor langzaam is :]" #~ msgid "This option requires python-pygame to be installed" #~ msgstr "Voor deze optie moet python-pygame geïnstalleerd zijn" torbrowser-launcher-0.3.3/po/pl.po000066400000000000000000000121701373720147200171240ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-03-23 15:47-0700\n" "PO-Revision-Date: 2016-12-02 15:35+0400\n" "Last-Translator: AreYouLoco? \n" "Language-Team: Polish\n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 1.8.7.1\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "|| n%100>=20) ? 1 : 2);\n" #: __init__.py:65 launcher.py:470 msgid "Tor Browser Launcher" msgstr "Launcher Przeglądarki Tora" #: __init__.py:66 msgid "By Micah Lee, licensed under MIT" msgstr "" #: __init__.py:67 #, python-brace-format msgid "version {0}" msgstr "wersja {0}" #: common.py:100 #, python-brace-format msgid "Error creating {0}" msgstr "Błąd przy tworzeniu {0}" #: common.py:102 common.py:180 #, python-brace-format msgid "{0} is not writable" msgstr "{0} jest tylko do odczytu" #: common.py:177 #, python-brace-format msgid "Cannot create directory {0}" msgstr "Nie można stworzyć {0}" #: common.py:187 msgid "Creating GnuPG homedir" msgstr "Tworzenie katalogu głównego GnuPG" #: common.py:254 #, python-format msgid "Could not import key with fingerprint: %s." msgstr "" #: common.py:259 msgid "Not all keys were imported successfully!" msgstr "" #: launcher.py:83 #, fuzzy msgid "Downloading Tor Browser for the first time." msgstr "Ponowne pobieranie Tor Browser Bundle" #: launcher.py:85 msgid "" "Your version of Tor Browser is out-of-date. Downloading the newest version." msgstr "" #: launcher.py:100 msgid "Downloading over Tor" msgstr "" #: launcher.py:111 msgid "Tor Browser" msgstr "Przeglądarka Tora" #: launcher.py:128 msgid "Start" msgstr "" #: launcher.py:174 msgid "Yes" msgstr "" #: launcher.py:178 msgid "Exit" msgstr "" #: launcher.py:192 settings.py:136 msgid "Cancel" msgstr "" #: launcher.py:231 launcher.py:245 launcher.py:249 launcher.py:279 #: launcher.py:281 msgid "Downloading" msgstr "Pobieranie" #: launcher.py:238 msgid "Latest version: {}" msgstr "" #: launcher.py:241 msgid "Error detecting Tor Browser version." msgstr "" #: launcher.py:256 launcher.py:357 msgid "Verifying Signature" msgstr "Weryfikowanie podpisu" #: launcher.py:260 msgid "Extracting" msgstr "Rozpakowywanie" #: launcher.py:264 msgid "Running" msgstr "Uruchamianie" #: launcher.py:268 msgid "Starting download over again" msgstr "Ponowne rozpoczynanie pobierania" #: launcher.py:279 launcher.py:295 msgid "(over Tor)" msgstr "" #: launcher.py:293 msgid "Downloaded" msgstr "Pobrano" #: launcher.py:393 msgid "Installing" msgstr "Instalowanie" #: launcher.py:401 #, python-brace-format msgid "Tor Browser Launcher doesn't understand the file format of {0}" msgstr "" #: launcher.py:427 msgid "" "The version of Tor Browser you have installed is earlier than it should be, " "which could be a sign of an attack!" msgstr "" #: launcher.py:446 #, fuzzy msgid "Downloading Tor Browser over again." msgstr "Ponowne pobieranie Tor Browser Bundle" #: launcher.py:516 launcher.py:525 launcher.py:533 msgid "Download Error:" msgstr "Błąd pobierania:" #: launcher.py:517 msgid "You are currently using a non-default mirror" msgstr "" #: launcher.py:518 msgid "Would you like to switch back to the default?" msgstr "" #: launcher.py:527 msgid "Would you like to try the English version of Tor Browser instead?" msgstr "" #: launcher.py:548 #, python-brace-format msgid "" "Invalid SSL certificate for:\n" "{0}\n" "\n" "You may be under attack." msgstr "" #: launcher.py:550 msgid "Try the download again using Tor?" msgstr "" #: launcher.py:559 #, python-brace-format msgid "" "Error starting download:\n" "\n" "{0}\n" "\n" "Trying to download over Tor. Are you sure Tor is configured correctly and " "running?" msgstr "" #: launcher.py:563 #, python-brace-format msgid "" "Error starting download:\n" "\n" "{0}\n" "\n" "Are you connected to the internet?" msgstr "" "Błąd przy rozpoczynaniu pobierania:\n" "\n" "{0}\n" "\n" "Czy jesteś podłąćzony do internetu?" #: settings.py:46 msgid "Tor Browser Launcher Settings" msgstr "" #: settings.py:50 msgid "Download over system Tor" msgstr "" #: settings.py:57 msgid "Force downloading English version of Tor Browser" msgstr "" #: settings.py:66 msgid "Tor server" msgstr "" #: settings.py:82 msgid "Status: Installed" msgstr "" #: settings.py:84 msgid "Status: Not Installed" msgstr "" #: settings.py:87 msgid "Install Tor Browser" msgstr "" #: settings.py:92 msgid "Reinstall Tor Browser" msgstr "" #: settings.py:115 msgid "Mirror" msgstr "" #: settings.py:131 msgid "Save && Exit" msgstr "" #~ msgid "" #~ "SIGNATURE VERIFICATION FAILED!\n" #~ "\n" #~ "You might be under attack, or there might just be a networking problem. " #~ "Click Start try the download again." #~ msgstr "" #~ "WERYFIKACJA PODPISU NIEUDANA!\n" #~ "\n" #~ "Możesz być atakowany, lub mogą być to tylko problemy z połączeniem. " #~ "Naciśnij Start aby pobrać ponownie." torbrowser-launcher-0.3.3/po/ru.po000066400000000000000000000211461373720147200171420ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-03-23 15:47-0700\n" "PO-Revision-Date: 2018-07-07 19:50+0400\n" "Last-Translator: Andrey Kunitsyn Sergeevich \n" "Language-Team: Russian\n" "Language: ru_RU\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Gtranslator 2.91.7\n" "Plural-Forms: nplurals=3; plural=(n % 10==1 && n % 100!=11 ? 0 : n % 10>=2 " "&& n % 10<=4 && (n % 100<10 || n % 100>=20) ? 1 : 2);\\n\n" #: __init__.py:65 launcher.py:470 msgid "Tor Browser Launcher" msgstr "Программа запуска Tor Browser" #: __init__.py:66 msgid "By Micah Lee, licensed under MIT" msgstr "Написана Micah Lee и распространяется по лицензии MIT" #: __init__.py:67 #, python-brace-format msgid "version {0}" msgstr "версия {0}" #: common.py:100 #, python-brace-format msgid "Error creating {0}" msgstr "Ошибка создания {0}" #: common.py:102 common.py:180 #, python-brace-format msgid "{0} is not writable" msgstr "Нельзя записать в {0}" #: common.py:177 #, python-brace-format msgid "Cannot create directory {0}" msgstr "Нельзя создать каталог {0}" #: common.py:187 msgid "Creating GnuPG homedir" msgstr "Создание домашнего каталога GnuPG" #: common.py:254 #, python-format msgid "Could not import key with fingerprint: %s." msgstr "Не удалось импортировать отпечаток ключа: %s." #: common.py:259 msgid "Not all keys were imported successfully!" msgstr "Не все ключи были успешно импортированы!" #: launcher.py:83 msgid "Downloading Tor Browser for the first time." msgstr "Загрузка Tor Browser в первый раз." #: launcher.py:85 msgid "" "Your version of Tor Browser is out-of-date. Downloading the newest version." msgstr "Ваша версия Tor Browser устарела. Загрузка новой версии." #: launcher.py:100 msgid "Downloading over Tor" msgstr "Загрузка через Tor" #: launcher.py:111 msgid "Tor Browser" msgstr "Tor Browser" #: launcher.py:128 msgid "Start" msgstr "Запуск" #: launcher.py:174 msgid "Yes" msgstr "Да" #: launcher.py:178 msgid "Exit" msgstr "Выход" #: launcher.py:192 settings.py:136 msgid "Cancel" msgstr "Отмена" #: launcher.py:231 launcher.py:245 launcher.py:249 launcher.py:279 #: launcher.py:281 msgid "Downloading" msgstr "Загрузка" #: launcher.py:238 msgid "Latest version: {}" msgstr "Последняя версия: {}" #: launcher.py:241 msgid "Error detecting Tor Browser version." msgstr "Ошибка получения версии Tor Browser." #: launcher.py:256 launcher.py:357 msgid "Verifying Signature" msgstr "Сверка подписи" #: launcher.py:260 msgid "Extracting" msgstr "Распаковка" #: launcher.py:264 msgid "Running" msgstr "Запуск" #: launcher.py:268 msgid "Starting download over again" msgstr "Повторная загрузка" #: launcher.py:279 launcher.py:295 msgid "(over Tor)" msgstr "через Tor" #: launcher.py:293 msgid "Downloaded" msgstr "Загружено" #: launcher.py:393 msgid "Installing" msgstr "Установка" #: launcher.py:401 #, python-brace-format msgid "Tor Browser Launcher doesn't understand the file format of {0}" msgstr "Программа запуска Tor Browser не понимает формат файла {0}" #: launcher.py:427 msgid "" "The version of Tor Browser you have installed is earlier than it should be, " "which could be a sign of an attack!" msgstr "" "Вы установили новую версию Tor Browser раньше, чем это должно быть. Это " "может быть атакой!" #: launcher.py:446 msgid "Downloading Tor Browser over again." msgstr "Повторная загрузка Tor Browser" #: launcher.py:516 launcher.py:525 launcher.py:533 msgid "Download Error:" msgstr "Ошибка загрузки:" #: launcher.py:517 msgid "You are currently using a non-default mirror" msgstr "Вы используете нестандартное зеркало" #: launcher.py:518 msgid "Would you like to switch back to the default?" msgstr "Хотите вернуться к стандартному?" #: launcher.py:527 msgid "Would you like to try the English version of Tor Browser instead?" msgstr "Попробовать загрузить английскую версию Tor Browser?" #: launcher.py:548 #, python-brace-format msgid "" "Invalid SSL certificate for:\n" "{0}\n" "\n" "You may be under attack." msgstr "" "Ошибка, связанная с SSL-сертификатом:\n" "{0}\n" "\n" "Возможно, вы под атакой." #: launcher.py:550 msgid "Try the download again using Tor?" msgstr "Загрузить снова через Tor?" #: launcher.py:559 #, python-brace-format msgid "" "Error starting download:\n" "\n" "{0}\n" "\n" "Trying to download over Tor. Are you sure Tor is configured correctly and " "running?" msgstr "" "Ошибка загрузки:\n" "\n" "{0}\n" "\n" "Не удалось загрузить через Tor. Проверьте, что Tor запущен и верно настроен." #: launcher.py:563 #, python-brace-format msgid "" "Error starting download:\n" "\n" "{0}\n" "\n" "Are you connected to the internet?" msgstr "" "Ошибка при запуске загрузки:\n" "\n" "{0}\n" "\n" "Вы подключены к сети?" #: settings.py:46 msgid "Tor Browser Launcher Settings" msgstr "Настройки программы запуска Tor Browser" #: settings.py:50 msgid "Download over system Tor" msgstr "Загружать через Tor" #: settings.py:57 msgid "Force downloading English version of Tor Browser" msgstr "Загружать только английскую версию Tor Browser" #: settings.py:66 msgid "Tor server" msgstr "Сервер Tor" #: settings.py:82 msgid "Status: Installed" msgstr "Статус: установлен" #: settings.py:84 msgid "Status: Not Installed" msgstr "Статус: не установлен" #: settings.py:87 msgid "Install Tor Browser" msgstr "Установить Tor Browser" #: settings.py:92 msgid "Reinstall Tor Browser" msgstr "Переустановить Tor Browser" #: settings.py:115 msgid "Mirror" msgstr "Зеркало" #: settings.py:131 msgid "Save && Exit" msgstr "Сохранить и выйти" #~ msgid "" #~ "The python-txsocksx package is missing, downloads will not happen over tor" #~ msgstr "" #~ "Пакет python-txsocks отсутствует, загрузка не будет производиться через " #~ "Tor" #~ msgid "DNS Lookup Error" #~ msgstr "Ошибка запроса DNS" #~ msgid "" #~ "The SSL certificate served by https://www.torproject.org is invalid! You " #~ "may be under attack." #~ msgstr "" #~ "SSL-сертификат находящейся на https://www.torproject.org недействителен! " #~ "Вы можете быть атакованы." #~ msgid "Error connecting to Tor at {0}" #~ msgstr "Ошибка подключения к Tor через {0}" #~ msgid "" #~ "SIGNATURE VERIFICATION FAILED!\n" #~ "\n" #~ "You might be under attack, or there might just be a networking problem. " #~ "Click Start try the download again." #~ msgstr "" #~ "ОШИБКА СВЕРКИ ПОДПИСИ!\n" #~ "\n" #~ "Вы можете бы быть под атакой, или имеют место проблемы с сетью. Нажмите " #~ "кнопку Пуск и попробуйте снова." #~ msgid "" #~ "The python-pygame package is missing, the modem sound is unavailable." #~ msgstr "Пакет python-pygame не найден, звуки модема недоступны." #~ msgid "" #~ "This option is only available when using a system wide Tor installation." #~ msgstr "Эта опция доступна только при установки Tor в систему." #~ msgid "This option requires the python-txsocksx package." #~ msgstr "Эта опция требует пакет python-txsocksx." #~ msgid "Play modem sound, because Tor is slow :]" #~ msgstr "Играть звуки модема, если Tor слишком медленный :]" #~ msgid "This option requires python-pygame to be installed" #~ msgstr "Эта опция требует установленный python-pygame" torbrowser-launcher-0.3.3/ppa_release.sh000077500000000000000000000014161373720147200203530ustar00rootroot00000000000000#!/bin/sh # This script pushes updates to my Ubuntu PPA: https://launchpad.net/~micahflee/+archive/ppa # More info: https://help.launchpad.net/Packaging/PPA/Uploading # # If you want to use it, you'll need your own ~/.dput.cf. Here's mine: # # [ppa] # fqdn = ppa.launchpad.net # method = ftp # incoming = ~micahflee/ubuntu/ppa/ # login = anonymous # allow_unsigned_uploads = 0 VERSION=`cat share/torbrowser-launcher/version` # Make a source pacakge rm -rf deb_dist python3 setup.py --command-packages=stdeb.command sdist_dsc # Sign it cd deb_dist/torbrowser-launcher-$VERSION dpkg-buildpackage -S #dpkg-buildpackage -S -pqubes-gpg-client-wrapper -k927F419D7EC82C2F149C1BD1403C2657CD994F73 cd .. # Push it to the ppa dput ppa torbrowser-launcher_$VERSION-1_source.changes cd .. torbrowser-launcher-0.3.3/screenshot.png000066400000000000000000004213531373720147200204250ustar00rootroot00000000000000PNG  IHDR9Bd sBIT|dtEXtSoftwaregnome-screenshot>-tEXtCreation TimeTue 06 Oct 2020 04:47:58 PM PDTe~ IDATxy_eyyɬ7ke hA\mzm]޶Vv{z֋[Z[qA@PYuf2]Nf I&03g}}w;ҳE=""* ?Tӯ yD AQţ ".QATŋs@|xBN#ZǴ75 8*CUCq+W"R%&@4.Gј.bH(t*uLBLUh,Qy+/|(XgB=i"2Ї(#4F lf(WՔ؜Cmmh|J C.tXfι(G7HbxRN|Pg\Z+T1?⢈|20qxBwt 128/=Y.D@%Qb=i͕(ԯքpb.c9,XhQfo\V8;yxć 含4JgtBH 8 *xK%=O% A@p1?CUpQi>& g UӠb},IqUki uI:(OJ~q dIJEZ;MY4k]PNP.ꑘP)3/+PI.hMGFGs>"I#*PL\e}qZ=ޥOzg.*itd=Շ:PgxXϨ5슋$*xu1M;U]4 Th.nuC5{v3G\Ԫ| +̺P}|Cm+}%ó z$6XMvR%k(k yPUi&Sv(h%a >/KoHƖZsQy vq9aAshtzE>@|Vv#aU>*IԄ*A| mo:/~ iVTb{ ʉϩM*@#4N"lfL`eU2ւ8rxBwXϊe>6Sk4Z`5dߤ(?4 >>A(/Si(ȎjЋ.ׁJUQ&qAuMU&?+ϊ0&~v2s qN~'-Ig&?B}?IV޶k5l`tX>xR{D_V yj%'9sQjeETB)LD5l`SM]2кWVJuW|o}o+Ӕ*Ly9{5^ju*$9g7G[~֜M**CJ-ʠ$d_e 4F緞7z&*YH䬺JMX|;%'Ix]Uhp4ct³PSZSA*۠OJTF) KY3Jb_ Rr%j ŧi%5\ѫT?K9$I|^HԦ}K0LMk(IQƃhp s'F_S vHpRF5)1B$55v@bd<\T'{MD4NUjIIViKA6<@D}P潏2SdOch.z~-STPzfNm4_'ňJ$YPCM %v 22)j2Ss$c*799d+G"w":J{ vޓ8w1'^rѺ!ЬJ: &h\1S[+/PpPXujE|W2",Src9-d$%Wdt5uHQWΌjbRK$I;4K:Β"iD9u[R]*(L )uYK|, 1,85 =[vGpJNc\"Y%=UФbs]֜$6*YGJ?U[@}%T\ԭR$H2>vK,FEl'VVTeKL(A$z;HT hZDLD[\\3uYVQN(dbPSۯq" BЂ*RTNlA.۬Hi'Nf/5Tv.eyHmHcgDD OemJ9[.UU'=XS Ug sSY|Bl_C%1=HJe" x1,$+ѱYԃaZY%YPnv;IƈET`p.ȯ'tA: A&-NÀt$;gMi2#P4:^J2 Z Ey 6G* LUNFܩTn.˔bUd%F ef{ntid|URwWF̧+t QTP1FdH*OHWr: X┚U]|&$Ò3OYg \Qx-I:땘>bJU]s1r!. 6Z^sYi=)Υ_d:颱F%ׅV,ԆHrY4JqY-et\==bz~s쓆`MKY&- TOsU#Ilby8E'_Vi΅e0SR]4 FSɧ,MU/u0SN»%N?uujԩT4jG'k*[NK޲O%/j 2ܗW3`U'WF>Uu,XRuWύ2\N6׵fGNq.S+xKR`sYvh\{k+qZ]ޙ#GHU5VJjNm87º9Hs9 e0I4 p}R@wKDAܕޞ4B-YR\rRW2jq9V41JFɩߛl@U5[ u)niLI^]%IW"Lꠇ47ݛ@jzWzN }T -;yHE49!xuz^[cޒEs򙺼hk!2pVZKurlKbʏ$'u_%PJhOf);)ho P9.FfE2 *qFɁ::-aH$N NKG_ 0ӫS@բO{)[hMI DEQ ykׅ )H}ATa|x_A#[;!Ir SjXuުUJ${Z%%BmCVUo^-z AzpwjUJxlO{Tr깮S9W rWg9rIJɉB$fgC 5\v|H 7 2\18DRTS+W[Ġ̽#ɡF!T~T `Cv S}֌1OJuG9Ȏ2H&*ÇtjF2I ͨHD7!rϧ2M#YB%ERۨdL1 W%^='#k.,e,iH5 pёJk2DQ+ݐ&IDõ.4MUgyVHrũ2D}[ӀqFÑFs &e;t_0)֔,!Шӂt4YEa&Y %֎/Ղ Xx MFF&NzwH.dOȶ"_\TUPϬ24*㠲F"r!x՝&iqqFSI.kYTIX -N(5mr|dvQOQ.ڤGcVYȹV!YCiZ;Ul(!@Iȓ>Hh04$E'ˈĄ~n]%gu$"⁂4%Eõ~s:E纍:* T54/kH,-Hn7FJ{]Ҝ=嵦+qRDӾmG}&j^DzVpsrC+K*%TRUg؋h<3/U[8 Qɝu9j)Krʪ4[5<8ϖj:RUK_R Y$PU;\V˺a֮S= w$?Ke/L$$lh(jvJEk.ܖ$ʌ$EfUw?ZOPy^=8Lk%(|_K\ <Xf2Yr)d}H0M{ JdžPv-dHt>yk^=e,^M7s40K:bU!9 EŒtT25&#Iv~ɵ*J2uPjZ'ojWl6Yy*N>X~tÏx|(iDߑ9!IFsZޢMI2w6\uauŀPt*YՂyKU?gʤE=I*Bu& Ie?5y5 J>U-XGq(#^Z$`?Q-9T8 yons#iEM'DY";9SI|mxfTkͤ'9PS& OhihUفkZBboONAcu.]72c5ё:]io+#\/iahmAv.}Ⱥ rʆDz."]snc␴Cm7yFh1e9xW+zKetuRId3SH $ۙuJUBj(*HKSGu]½w@IO$AQҀpŒg\fju4+{_,F*C'Qe48\8Qx;V KVILCM jMuLjVKOZ*_^+$2A@\@ 6Lf)QJ-3-!58$[rhRZ$eHS)Ak+n22|dk"JvGLSh%ny9>&OZWiiGli[hBuzB_ Դ!NwL)w#7j3 &U9Gz3*TR+r8)NbYRIAј\ Tjc,R~u![U_s R Z@kNS]1.kjqyHʲ*0IhKTZ3Dq9} H_gI6kC']I PzD )kHA8 OIDfܲNUsXJzeTJ*&1隚NT3h|tJk@㧌|=vBG4Q|V >Y1#p'G}iP}B &YVUnق?l6nqd*e Wu'<*|nuD5>!B^c: A29/i&fWX% 1UN%;U[J58MuXOX Ux \jZ=EgJ.}qr$[zeh-i rbciJ|-Q>Z*Ї苉O)QSVuSQ>\ni'仧Rr>-*FMm80;ۑrL[k%!] 4}J Йpel5$֍VUGfd+/nL64ug}VF?5ӲP((}3ϖ 5O雡sDW>4i[ރ!'3sئr'Z^Z5d$U rZlSd~tp-|gwE{GTIKg}~g?*΄?搮G(6r XSM eN[A[[A5f: :P .rrzt>U|o3^}=V'?^9-O'D΅/x*穎Oʓ&~)BsD+o:Nj%{_tZܒIޫ㴉׍}N 'rgZݻ-ݔO#dL/Te~l&5I~ ǎ[/VY&(ьslv˱ pR!3xV˥O$ V2DDs d}NVY6cOL[De"i2 Ε32Z242HfF84۷SkdhK}i8mI4;-\@OwwXnaaa^,Kزe}}}H *f0f"1iUyV0 0 0 0&c޼ytuuMZaܹEΝ;4>'" N$WA}aƓv.;UAf 0 ={ .*? u_n0 8p)rҹpsp׾wUaa< (ޖcM\oo/EQLmak|œbxqsB!Dix(a8?-7 0Ys%,m_]ǿGiVZWrΫpw^šC&6~IGzXv #m]v^aOi7Nz+i E|tM?hse͚5|Cʛ؋Ӟ/q}p$nGC !>Q{0 ctu}dD#ޓ6WPOC~*NOyt!ł+Y [ܸvh/0 0*& 9stMoh[V/ui܋8<pqS=4??PaƬ8Y+.Z~_lk\UVC:9̋XMϦ?ֲ/[} <wof=?g=FW I²3^b?Z-┗S0ʃ?2PpȚWs6Wn\GTi^?=h1{;irwogn0}k^YurȡK)֮y:YZ:8Wr抂曷nB{O%/;ȕ?\h9i?O^0;?GB*'s ;#Xwm~6Fj=aO5wJ}[ @́} {ԟ c p q˰4|w.2 0fÎNhj:w_m^wNH<>lΕ!cƲ^ Vϣ)iw<{ |}id~`d4qч0lЦ# A}16(ö>>olcã[(W,kB:e%KXn-,fa:G/8m,r#1ߧOQӿks (↵s_ԃadbc/|ic5upx{!B1_wC bahcMxpq4p>g ޕp폱}%8fG㦵C{/9`>Ⱥo&[s?uO#M@?7{s}`Mz z%wܹCdh=EZ(2-\¢Ưh.[BH:v-^L(#9iEu$'3>wnt}.=g}]ˮ ҹ/0 0C.'سRòAU q4Bp Wmoa&`%C<~tkq3rQӽ1SqO+81=#iQ_7v> O;Cxo-F~c T_n^?{/=u-lT\[su{4g8sb:iٲ;OfѼ,Y]:FGh6li/17`x+9rݯ箻yhXE %r8*v 0 اi53yVB!+o6 sP| aA+' +9VuKWq&9QiqΚ8 75|la=vsxyGӳXwO#q: Q.;+gtqȆhnⶫf'z!,]Lvw\= )GձobmAd1-fc,)ŗ)c/aj*X)x<ԄLa>Gt#xFv|BV~exGbʖ~ŏnfksfap,?CR^}0`N[?7Va2 tuuoݫ*wo9 L}^ _ S}9qdaƬ0GBc#۳uT9ri~͏ld[0褳 n[=?r{jwA5hx/Qd6 0 0 0 c,{31x0zڋ" 0#_w 0 0 0 8@~Z7DJ]8_߂|0 0 0 8`V+ NihҰaaaa"/oç( 0 0 0 @"ك"x#"8'8oaaaz.N){qG?0 0 0 08^\xi}M|?5 0 0 0 c BxTAxiBq~ߴi,%0 0 0 0$}.-Wā_Ƒ{(i~`ѢE0 0 0|pmw.|^|Uh@>ޢ޷<;6 >d`aaCA5nG _^+0 0PTm_0 SDѮ5'"qy'xJa1)0 c 0 0>'KЯhO zu4>WToaaW,7 0c>P}6p UE M7 0S0 0&fO}=^@]UGC;~'aiPnAaa̜1 ? )My a^Es 0 c_0 F 0 czI=i z6 i$^~7g0 0&{30 0*k' ̧v S;$}J< ϥ^WWx31yoag:dOwlLc쎋燝Ja)zl'0 ,ߛaa_ VyGgg'W]uո/B6lmݶSfl2|ztaӉF' ߉ ;i|H}ȽH4Yg}6wq}=?ø{=sNv @YرM6OM:;;9묳k_Z˹K.SN9kvRgl0Q=UD| 0 #S}o:Aؠ}Qk yc`/BPO4ۗ2,XN8.?|.][;vpWsuk^V^MGG6l_:smmm?';pqO~^s=}3Jdg?>9.n?䪫SO= )۳e}OM0 0&0^?Q}/݉sqqͽ=\{g=܃uV>l\w/}|3~odÆ }ݼ0<=yٰaä>r 7;-*&{uꫯfڵ3~+>W\z饓n}ncDŽa;3>Q>ߧ0 x2Q=vDl>x3݀oo Zh*F7/K֬Ymݖ [o3FK'wu_=/zы8Sعs'{,Їضm\s /x 83w$؛Xbw[UK 'c)hOqfTAa,ȟ,CٽN'AhT =X,Y-ܒr-9X~}˽7of…,]{ƍYd4Ci7_^:4b7y0Iப OY;0 0$[[===tttOφ>Q Upai}.}{w;f͚ݟl6Ďi$fdL>E}=|0dj͖-[PUz{{ioohTal6~-Z3 m>bBpO{i#|;|o9= .˗\dbpHzTQEݎ瞽f'0;Xhߟ6ڛh=0]k?:n6Roai@tnc؞kټc$=:a}t|08,7g&>mkaEUq%}o8P c*cwATUCC(b%0 0BLO;aa.+om;˞t%hc#F0 0'dGEda1{x[Og WyDP '!W3aa<}1{aA卒E0V:k{҈b`? aSF-7 0'ΒFŽ8kEL]s./|yfO;_/P߹w Gi80 S&?uaa̜.ӅA^3ėw;c`}O҈=*8)g=UixѼ{0 7؈aa~oa NvQ޲ewY/gHO92mR0]? x0 0ft׏Yoƴ=s274׹w=J/6ц3pNADsoaS`aSx/kdC>38u*\O%ƓEIƘs={>C{_20e9qa>Ɓ@dƍ 0`뿏v7& ?].}nWA.g!w0GyiX0gqg\⺵|I;\qo?w!Ʋ3yi s+11\O_O2>rեk˷N)_Fc99s@_7#m Nûygs₾?/}Wڣ|OD bn#Xk~o?})_2@;N{,aǿ~njGC^~a,[0;?}{Hj@r;~:9mǧ߼N<}XN(q4lۥ,\q2#_͇~kѧ\q'sؽ7`#q#~_amx|l'-LOq^qEU~X0_%/H' &Y+?6S4: ?~:R8'>x'! >O,aJYeCEw( O Nt-q.Կ3'[(b*9M˯˖IUgM>!KNfB 9aSNWW }}}8,ȟ!Ry衇`ddd 0T߼l3E80hr?'G9OOּ/.=^rt/~x֚׳90x#7C󩷿_xEkxo>Q @5r#}{ɕ~޻7_p;U}=6ۦ7G"w)pyJ7ǽ︊~t%,~9]z:ioo(2 .gSe`hop)1c?мNE-mx '7_>4,]<~M7-]Cy9 @]ņ~sRq q\{OѼ_':/\}7_3Ӿ|fC7ЎAWm<ݯ =6{XOZՖI8K8i^~ nj=#S00^,wp%;︝_oE9ۆ47OBrVك<i4OvnW<|1'.8~A-l]h( ]ʄ_Q& ,}N+"̝;mFѠ =LQ\v- ,,7 06M -N9EC+ڔﺂo޻8ɿs#&h2{7QP>t37?83לI١X;\Wѽq=9hUϣR>r_Ϋ/:pﻘ3ķB=-8_﬎h߷ӿ-$>/zY[sG7>^|x*ȷo_9y?1^^{MY(KJ 'zFnN}ͻ]7Ʃ[F6wQksPB ū^۵^koEŮł4E@( l9qvH|ٝs{3WARMy/\3#c89Rgfp^`ѵΑG'VZpl+oUgSWYNJi̳螸P@CBMa:###O8/jԮ((& YڿHJ+ofz'wJY%SBF2\"X+"m*f 7>85umֵ-n\R'm2v%YLKsI|,m ߦ?ȋr2naCJ.n{(!6黷gZh477~ii)6;]^QEQEQһr^eI>Hqq1$*ut}`.]4Nܬ(YEQF`γ73ۡ4,ƻ9A [&/ۭqe:r*x.,o{Itn#һ}+NݙL&Zn ޽{v!/o]}]n3x`:wLll,lٲ 6PZj,-rw[o5z,7v= WC4/0]4| EQEQE9-H e"ןn}RzkƄ{&f>I&{5xU1g@.Ýkmt%ޛs3ڳL3u,̨װϤˆ9)yYF۰ n5RWiU޽9묳Xx1tbۉyMܟ?l(((JՄ-'4 !Y=sgH#* nT_U6nwvcw߱~z߶Rn֭[ݻ7&Mj#d*Ju(q&uC?Ofߺ4ƽ܏O!~W*=U (qRmvtE<'O]@\H'bv}aÆ&l+**C5u3{((g3f4RxRS4!ЅY^`LF\{:7ʉ뤔u #ci"AWo%44&V%-Q_ǘ\1c33w2NysK.SUXM~I6X5+eYlJ[̑"cd偟5W GVUY5IٜFއ-g|#Ď$/hڕQ.R o8ܥ}7v-ۣ!)`c"26V(L&S]gM||Z˫Kj; >(Xl1ڶWՆݱcGKHHN,Y:UvEQEQK.$k!4ti3ßMZq\׸iiӦ{0..p}򲳳 ߟ\@PP_}q7#Gv̶ ֻC՚ !5pݸqUu9>B`av<ڟ?>D-kNe[Mv:E'9w3yj8+җc&ǡ5 [۳ְ7'RWQrۅ.`NO=6:EE8nUUSVpF D]WpYvװo:8$ڄu%¯ v0$R̚$)}9BGrNNQ}-N-ݻ7:u" M(**B׏]d̘1f~'_p}y}v]tDDD0`6n@bb"lڴm۶QRRرc47Ҽysz͛} gݺu,Y!Cسg%%5^|l6_M&G&99*PQmHtttmڰa:ubƍ/u.6vl/25k۷o_~{nrrrj^UjjfK/eɒ%,X۷ӱcGbbbHNN&((J)oj6akEQE"<<ͩoKݞB||$BHiB%*̻u؃ы֡C:7lfRR]y@y-[N|[J\\_~%̛7Rv˵gMXXYYY&a&IsoGW3-_Vmud)VY0kVRRrѯhLLt@k8ؖW[NZ>RUb\ E0*=HxtRXUm۶$&&2~x>3Ȑɓ'Wzmff&͛7'11fSb^748W%']  7| mPQ]>mky5 j>AAA $p1m{UmlذK.,RRRسgo@mEQEQ$Ҙcˆ1^K$F|#GH؞Mp\X,jڷo_ w\hZ\էd2DKll)@ZQmp??cFοm0 i),%h;ֿNoﶗ&r p7_:f{36Wgߥ;,>Dt@V#pI'D &5 .3>u2VԖA:J[–Ln}7벯'-[ΕW^ILLo3*͙R_͛;woQ$.N4HEM _[~ֵWSj;)NڶWՆ{ٲelذ֭[DŽ Xzoڶ+C4PEQI'A.Bn70Itn unݺZU`P"֏13g6H'~'m7,ƹۈvv ׃M 㐥կ.j"h k8>x .p&OrNE)4 lM6lL[I)v7/Etϖ0h dž t]FFFrJm֬kDﴒxˌ%i;p|{:Q~WCW۱idnSTT[W^ݛ?JYfMS7AQEQ  HtfB$RJfHlt*^*/)++5%+`=XRtB>}}ޠAN2x.@)Jpʷ+?/cv_ۏ/ln^^~Y9?s &ak@-Awn֬XBd EPcGQt¼`Q-hK^t ZC}ŅtfL DDa3МOBG.w;\Zsq׾ևngĉ 4h &>>ѣGNZZyyy$''3dBCCBТE &OLTTȇ-ZitWGUrss9p&44ɓ3CJJ $ L߾} `۶] m?tnoj;iiiѿ_Rϳ:w.msWi(PvEQEQ &$ȐϏ1ڬ:&LH*ֹ7LPku!{"Ac`5>g&L ܹ3 . w0V ЄЖ!l8YT˷4; IDATg,uIFO>eUߊ?|u)%9iy D\H'ttMR?$NCQB=qA#9w3 s.Ha +R.{=_YX(t5c%i@JKKYd } .n:޽M6zϟСC1~z22<k֬aĈL&RRR;w.FbرoU?| ĉ8rs=&ϟgؕɬYm?kyfL֭OOZO?ù(**bҥDGGc2us222 dԨQt:9ty-vQvEQEQj'+M[HaFx#=چ dwd_\zM9qu{*Ҵ*^̪xn. i3%%%lذd5[QEQ:JLL]v=_t9|xzc>-5}ABw!&:ñ='Az˗؁=ٺu+ K.,uVEZȞeE7RMQNk&0EQEQEQjsrIH0iRxR{fDW^kX(,,߿΍rcFGaa!6(!ֱR.\… OjBIg' KI~-p/&K((()F:сs/5/y1(,, }* ; Hų*(((&kBƒxBMJ4DGJX^VH[,q8tIqq1REQEQEQS8Gzxh:]jHU:Frj^{EQEQEQoO'C@yKO~Mf3fF n7999Mwd2 g)_QEQEQI5R{zUxt$n4Mh@u(bi :Dp!T* (((MH c;R3 !44 @Hc/.rFz؋_Pwp7ȗRv)** L&O`*EQS\gjSXXHbbb]n]pm^N漗wM#/aIP{E9eS<>m:/|S:'S5#45c4zQf$F|%'Vfl6vݎ?߽ʉEQ(gzNW}6,37i?/VwI8BXwip=+WAрNښy>=伨f뼿B3ǘ`o ԗhbB$p}rЗMMԭioo:%6;-#'* am2smz=&)w1s+;K0ª5>iNR+8mbnNClq{guRK*>Ѳ$=^RL& L͍p@&sZ%QͽWEQSM|%D}}Qbqt epk2u^"X9=*iMnǐk@+*J#@ncz=hۄ\ 1Vjv+()tϖ/{Zj#K[xr^@Y^|>_Ksz#=y5򿿞&G1n$-&gRc|y2 pj! ~i\}s /:HFt 3,%Y~[V&akٛGjX}o&T7x&o\76l,>&WEw3Pw|Wnaoz!r-(eWqK߳f8z22|ZNUnbb<[0%H@;=7#S<]ͳ-ȼ |Գ7o{m =;L=}+(tۈy7_ۅ}?}okvE$/t=+)EH; n9|fjݗC:Kw Yq_](>;hsxjTF0 ȚYuhUmY\7C_>!o^R{CtFM#=yTcyUo治iުMӣw_@ R,@Hc+TEQoĿ'};z.݈^Ỽ<&59 I(a9_|8n(tyՔL_Jm'ԺkK|;Y˗5`y4bf@`(I,Bb!ݵa|(BEx^H-|?Gt1w:?3̳bΫ7 y,fVAC~'~]D?&JEwZî`jzg ?8Yxacge*z2`!z]/QDy9hAO_ê z'ɔDư~=z Dh\':w>z1=XٜN6=w[\_=+]Y7g9?^a=;ZLٕ|,Z[o'9O?C !Ռ'Jd] :+ѷ3m[mwRR&tZO:wCZs.t reK([Ytbڙv?eb| 1114'(N%5n߳,Q/' 伛CzEeNNpr a@? )HBWfm YSM:II9ʹ-=퍡嘷H#50ۂ(Be[xٔ=ML mSMO}.Ư%1WLهSfɪwqٽߚvn\RG{֫QA=Z>ކ++Zz%N .c(K~~&dnf_&k 6f.Yҥ^yQtk{!esx~ gtoCO߳Q+pXwyO<_V Zn\{.g?xnYƥ{b t.I hӎ-^s.aٻ3! )Inzr9ߘ ;T jbZ?dδ [_4|om#iCJINn.CVGFJ FR|] 0I9JMHEQoG}v .4@lṭ_0;2F^ sqK8/߼5CG?y{9riB'CWoߗGh2.Kgzvd!sWr;K/a0>NtI#!!ܭ!$.| O&w! =1s~YXG; #ԯYݴ<?~_~Y1]wPio{b{m/j_y9X MNC&bCWS1{RqWs{cmq׭c߭]zuU@T:›{.&U9h /-QEt䖿P9 zbs۞t cłu~IGn~>.Mn~>9yḙBCzֻ&LH$f !;;K'tipMۂ0A0}^E/ׯW2AdS`r˛&[h)3tL+{ Is Luo9yha5w2x;){<)<_P.t~et֊@M~={7?}{x{iaљX?'J6!"ѽy),_%2o/eb̀}W~2\V= bџ)gpa=;%pg?쳼|Y% ƤKZ}3nw7'x{8Lyjii #>z}g#u;?z{ռzwg7paF)LxLg7>'޳͸Տ8d,7'~t j@ݳF'k">}a>!HxoMd o#/>==U_Iڍс2sW?M G>rVbmݧ|͏a1i4=2SqѷZerUcR1!<“XܬYsnB !{hcC *x-G4RxZWkv"??^- &!!^QN/2}&Wv/g {/PEQOD3NRx))U!>.wG>d;}}h}B`u ]z; Nke\>~<. #T(ɦtGOg,Ǐ>æ*WE9 o<"fƱĤf)$h"MT< =y_QEQEQ$ߞ)Ѕ@q#,ƃ|z h:hQr܄&&<: ((('#A҈݀.AӅqGQK] 08ȨrOR$ }D|LTʧ(((Ұ<ƌ{Mt_izƲzy o=߰|OJtL 앆#1-Gs(((MH] !#D5Y[_aFB=ICP| M#,2st(((rzx}4R| x;Or^'X-5u3THx0fɓȢ[(((ʙ͖֌wnY3{$%s*D-S.-++vE~~>999ME9텅Bk|ݻ)(( ++$LQ'""ڶm[2q tX IDAT` _3 bfOyzQX[]8MI5&I. ؟̂ڟ(4vd2ѻwn1ٽ{wݻBp9܆)J=_={Ю]:=.#S^ :o[Z )) !0K{6O1ػGJZ$~""8dz>z&cwDTP~?!1M RbFHT(JSgȑM E9`j0l0zrݻ7K,s5FqV=WDwIlZha~-'S?+9ユIeWf<I,A((M~[N> r0?h;=')2d4SQLhₒc+-'?taɘ_~ TM,&mhoDP,,0#]"sI2l.\rd"L/agZ2W:}ȫq/c[u%_?[z odg_ȈJ^V!K~X/7uEQEQxen.x6|B ˍޝ̞Ss5όxIUN]8IFx׼gƺ渶ؽkFoVżW4L$ڙ"w.&͂UؐHtܾJ 6Ѣ[ Lf䥸[?>@jR6@ 탰@*]W57jNAkŎ/*wx-_6Cz>ݿ s]{`&[ Svk]/O#l^hh2sW$o=H͸mgz_M\tGz=I)$"6S/c}2R'[Ǐk1SS7MQEQ!t{lԣ}m,߿NÅ-}OT6Οa"ezV~z.eԯu;[]]n¢ =־GdF$5#ȗ_z!В3 @X|Ixҋ21 ::.1{tnpNRHݜ͖2|:~9؍>ӞS"$,VN5׌o]wx+KpJ/O_=vh?^\>TD5#Tf_92/O\0~t>^]V}|-̸</]ܩ,:Vˆ0R%`#3nJp35Vr|GPh;2vz)bmnNlB?s?,{0M ])s[hj~ޜL?l6lU_8$-fЦYv;~DʐSx{E:S o^%U@ZmwahHqw'1S}t14ý}l†[te3slKpYlu~uf,DKHzq<<_5ofF7N)&A3 }a;?x[4#B}Ìyv^]PVf&}]F|v;<%F - ̠m| bdzY[gq}Gj1xq _Dk"$.7u7min*7yWQt7B Bz/"( vTDAAA@TARH]Wi !߻;ߏ[CQ3zwvwfwϜ3gn_9OT, ~D>گ>etC$J&.ϘNL\ kaVx/?[A R҄"TF3"Rc5l) :Y-j$̨Z:8htYg4BжT1 .CvspeHJHERڱ}Yk"8 m6ʒ_vY9Qc8Vs( @eٶb?RG.aJ+vв$s܊ToPϯ5߱ 1Iy>x4BWg(b2yw7rf,no]Byc7OWF> ͮ5tttt&UFXXCj@1R0K^:]\SD E֢3i?k\[=^-BP"T9٬ZvlJ)K#X~VF:W6Lb`PRzK|(|=# ?EPߟ/#c̑ :i/_C,AF}k:Eܥ15Hϳy{1,-`B!?NlI),dZ 1UPfMj֬IU(fyn|i;y9{8w)6<\;l+zU/ <Z.ÚӱY&6ͲsVrLw" 8j'v!ݼSsUҏ󠥿̧~`XzT,^7O* [J==Q"i6x:#TLerWtk}S|۬})1!u=J)K|3KKJἶ!*]^u݄$~{ÛK-'hꇷD}y8aw͗6-bhWXs.!1Pt-)$f&h҄ -[R 3f-jt/Jo:8x(g[f^ &'Ix;KugVLXP3N>nz1qh{ )'t(BHNH( $8 'cn$&eKKs[./:"?naSleWz'6潅#79U+ e{=r}t<Ȩ472E8eEL[ILЈ8-W:gV7x]7f򌞿k2eT-l-FͯՐؗ?ߴU{1_M{lV9dszfKx6nISGgW[^~/>쳖NVHy,]yQn-& Ň¡)qp$!AcYJb3g\i&jѮb%l5Pʤg,SxC~a߾Ҝ9K$僴8bsujW\%$QYMm4mAu;YZ0jtjE ǚ }=>Ş7PH5{^br"#yt{9gK OE&56cok& ֬fb{/,ncol=_qMi~Y'F]5^'^JgfEʭ[m<^Ŧ*tp` ^nDFUl}9SRX3nI+ֆطeRnƟS?3˿睦q0 C]9ݍݧ,m ~HϪ9ܿY:{]4͢_ΊmI;~]&7h~㥶}s>}şOvv0 ]fhwd:7Y"{8ܐuX43Ąlٺ*y7ń,͵(p9?c ҌDHMj((y{X}53WUE(ސEoCFqa v:MP,e'fiXۦk-w;m+iHsTѼ?\ωzd$vg]&84nw">:W!1Bݔszn&meW_rB]˩8uFBy^|VgxRo-FKr0 nrKqxsበ:StxHJS(ݨ+95%we޿Q땵[}֞™}Pߙ6C3z84C! d.ǺM `D4sT^_nL[GS&G_ iՊFg}ϱ-e Дdg}<Ḋm;Uޟp =r~DhIs)hFHkYk|pH!R̽jw`9R&2⢸&>^ÌINH%>*CM \t^l&d*ǧ\!Rq1(]^˟ wP)zpE<|ܨZ߲3cfU_&ܩs#>:'%1ګ'旡:VhDT:Y<|a=xuNZM8v"^R@ ,RSP#׵s.tucFk8ъM1_8Ɖ4vJ@k{09%_am1?Nf嬟 uzCDQ717ΎxUlg8ؔlC 7}{0%$s~^y}eݔEQ ڄD-z˱WLtKǾĦe9OA;Rѽَq1% q)H!nハo9M|w 1R.4J-Tp5ѭ% {|~y;~AjQE:ԯBbE(QyVh+|/H `>4jZ![бڽ={mRf2DCR9zj3{*6&H*GBmFۺoH=xx>EyG"`Tji0P(zmⅺayc'Z_Ə BC-%D(¢ M wFTLHH4S] FIF$3FRb KDkjt*8"i7se@z\?.}}-$)G(K=kpwv4a\:yҕk\˗Rr`qF~6s7e^zG oCTܱ$wrBjdŋXF$o_o_n 0ahFrB _yL⌛Ú?=ttt?Ҟr3+=$A(+AFV-&4}Y܍x gȌY߆29<ynoR* 1WSbxެb~DRiLs!e~%~1SKРn1-tTp*L)E氒K[42Js,Oӝ˘ Ƶ)aa]],K{%? ش,;wru'SdN)tԲd/&s9H(T!8sT_6,viѮ6&cGlqvm1h3f1xNb`ct kUb.3wc6k m~WM : }c_Owg8).@RXUX,'AQhV]<ݽX6v]'v*>34z`xi@I8&jncS2 NJ}Τ IDAT*]xaMVm,\zWbWZ URB{?T1Frz) 6W|! MӐR+iQCٚTwe֣6 hvl=Vf U=@&\rn@K$.^''s 'T=JX=Ukcb;SI,Ѹ&:Zc|鴛X2Hhqv}f}0lbN{E/'@H5Ӵz2!*}PqD:4[;[ݰT3~:_v]NK锪Sz:bH Z*էS0e:{yL{Je9Sy>m+T/99|q޾??c`>OP%3iߟ&e A=3|m ZW2vo VC2AMaG90/ *íG,K[?LٱOShj ;N[j#T bI)=OFrrzkLHdĆY^PMw~E&ng򈘋;}K'v,hYx'kHB>8ػ'Mt2>P ^^fxq_i͌AT7dR *9{j*9j_mwNW,.Y @!hț}_<S8St)Eӭ;2<|O#Wp L+/SSh0#Ņ;~`Yd ByĝdߕT >޸+~"a a gٰ.9ݤofPhH2-zO(<{4Xr??%Bīx+DP~CfƠ:QsTЖi!|HО#E0:|ufsZ[e4gNG Jtn.6T _G0zZ?vT3|G4ˬw&K| eXmƫl5h ELDgFLz(J3mJg,a҉'fɄ ј})ҊȘ.wY#LyvD Jw8PX4oNOOicV- y'S3Ƅi{y3Q*nԄWN'@=F*~͈s0Wmh{s.aghp7MKBu2~xvGNL~6t`I{:R,sywg4<6WxG{][ҿL@U{asR5L_9%HԵ{D -;iߣ \ޡ0?-M.ŬjD‚yFş2sr?+k\P| xK bGCo3ݩ,4V&-eIud!&1:+ˡc|3"Ν#!!۷CGGGG ___<==)[]_F[0cﺣ-/&xɏb1] a7b Ŏ-QWrgVdI!7@()5-#B lJFLEGX}D Br/&TTU#MMAڢ[ rK58:1ugn‰P ^~\9}aX{!M4yآr!Ο?Orw6K)U<\KԎoyv$M ; -A-VCQ1KiqǗnQz9Ң#5hd&52Y\sڔxK՚o]OS5ifowHr|*]BU?CS5ȯǨ@ƍ٩u:::::7!!!lݺ߿7i+WVYjWzgu!0Vđc'Pe]VoLц9w(eHkf@w1n8l2[uttttrrm]y˴p~wMY,B s]®Q :E f lUV|YKyͪ{ <\t^GGGGxjz oGg%GbMM!lP,~l5_cH͌)6w|iZk!}4䄔-#h,[%tiT&e4tɈGѹ[Xe_ =yUO@t>j`9Q?/,NO>IԮ|'}AK^yuEWB(VX k~Uj}}@ZCX 5)=-cJ|Lt{d uƕHTm)Hn ^bOʴf (T<1u}h2?no/\ M&gX;G݄1g- |q֨e1ap=I )e:bjA"o3a 5HOVDQ1#f4vv;:::8nFBI_@D¬S(_Bpm434rzHGV-K[RQ..T@JxQ0sҲ)Y9&2][=^-BP"T9jvٳEn YR;ƯH@ :K ~K;tl6&/nI_'J֩{+7H;^es6'-v#Par"3ͧfɯ7й3U X~"N,%R&qrX )Eb`GR" LoI6Xڗ~ouv)_=|)V)6}$}+ZĵM3Q<jHr9z͖IhZ ^ч0%nQ6ow7BJd_,~+uYbi5gYy/IOzRTT+W3EEEyn6^XBIE %IP(nI"ASIlt=k|F% V}y*r!>mЈ8-WxmT{ 8l1m)y0a v`rS3&n. /;HԼobӾtN]@rFo^l!L~fbgo"mX<׹"=̱8]S9"FQ<9x%܏+yESgg;WF3xuzL[jn$}5%ri_oSˆC,ݓ"[1<$|] WoWpvIl/kf} H (=:hA_bC[E+x.ȀvVlK1復͝}jic'uLOÄc_~رwM._#;cP #\|ڞ=q}zf`?H=:*}۾+ GRJVZc_ǎ+SυPPP,KK[|=)(*RGQ-Fϴĸd.%Oa<<niչ3R&cwGZ8Zѭ:::=*QGAyj2͞+Eܺ/ -lJOHI\Q(^s?BZ$UQ0ue/d64~ՔJXhҺ!w>w^\=5̮/vMqXJTOG摟.%(~Tk֒w> IDAThܜUa/l0k[Mi\:@ 빸d,&mjS MGX%LDX:c)Q'tgE/,edUHIs)hFHkeSˮK ՟(a5}2 _cW,װYc G7▾w*N q`Xh[Z4qмYiRfW;?%bR iՊFmMߩΒo닄uLyZofr(@j9'KWŗ=e.T=sG>i=Ӡe;´ol.1P}!{}OD:tCر=qD %DHbM{H4q@=_ ,RXZM`NWɅ3qdꭠ󯣩i$%$qN]&ZI˸{L"&ք748f'̵.}i>?SZ Opk7Lp^u/4"⊡-;q5ǽ@ر#;vDB"Q DQba@ F .BHli _J{LkΊfE'`=aHe`OCZy۶t<0d3F鸛?Q_ͣo{g 𙐛槞nhM3#mtY{zk0"WjG:lbYքϿ'#g%lZP^{ey3ػl%WKu ixa&ObO1sW=_nv[&SaZ3^hZNYU v,=e'[eY5t=}Wqr7zUڞ/$&Af{i߹ ::::Lpp'KMCjB D۳f 0Y&K=C^j> AjdX3% =uZ-(S5O\jvDͪF.e{<;sVTfM ndөspq ㉉ӲW~vKJ.F8RJY˜y)p/߂!k˔<>9sʧŰaJ"#?e7V 2+RlLz9^@BM*3sʜ2'gd|,q+R۸d\۶3JUjV12gN>ĮxWlMK]RJ eRPOP,( {*Oi?g!j\޶5Swh{t}! t{ܟd>6{AOzMAAAw}lE/fQj",+dФ]9LXH)-e# οG" 7|qbI$$J\\]O"GB{1q;(\k,kZ$ ʽ˨grQ.vzT'x|\e-+X+נ"o)ի)()_|?wOW>̧uWk:׷ /| hqx 6-p,۔FQTHh);[d%}*s<]?W=F GYڦE 7JI]I;yɉ4-geQ j p=҃f]e@:/9F/5.{-g ML_CāogҌ^ ?y70$=LSHtkŰ!i?}1i9qh3H]4HHUD!k+Dn n<'Nwq9't#%ݹ 1/~)[0&ek]E >ˊGFO1;XzMjcFԹ-,7n$!] n,3'Ѿ)A`o|؟&7J5M >,1K$ҷMc[YaZU;·p2J_}5Vnw3.2q<;#ٟru3(gx5Ī3;$7eF͎Tȵp6r5xe7>b؞LMr _A{M( (@S,z(!xK np"CɮgFWutt2n@c@ZI ͺ!ФFt:v7!qFڴil7bsٿK%pe zq G>Ma q Ckݬ{,"y:h,vt\m*@}8mXjw=3*p}/49Yb|.C{O^~a |w|_5p@Foለ[n2p}(s=s!ǂp$1=n Z؇ ""h-F2x|ڞ`Fӎ2NW^!8FY~<+̿`n8!mL.zHs#EDDDDDDC6FHFHI <䖤DDDDDDD*+ӆBێH$i>Biph@p0'ʂ[Wh/""RmFɓ,zAmm-+lVz4u[,i oy70`@>szV1-\2ǰxvz"""Ud :wCTuYg}>szV?=[ֲ-wg;kDDD?A ͮ^[(O17 5|=0,ӳ\J_DDD9?6y4ee7琵cʒFgGk,ӏ.C6b`4$ @H1sdz2`YKo$"N$j,`Y:p^\ߑ{ā_;ܤ_Y*]m=^WȃN` ~l仛b E+oy3Ϲ渵H,fVfj=7,7Y /#&q$4v91x᳗9wE\y Syԍ9੝03yOn -m]_\9& /~s9xT,;76:zj)a#X!"1f"y,N"""($>ʕK nyN>~Dn?Iwߐ{wcn!;{3\?wq[ݩ ۜ|#f6sZڶm~s ]JKpgd\v?Hޒo-T;o<6ֻѨM'.?7@ڎt֏?ڃ*YgVb( \*eÝ}rnur=U[mVl䇻ٰopٮo~n;o^hhWmb<:Yw@ j@(-'3DDDK ;Q_>}y]ՖVOv?fM絯6suײ7pv;ϑg 9irtTKd?k-ߥxSںw׹ĝ``ou_w9{>4 ^m3Cg_) `g7aM_nSx>E6ͤ8}aLuvΚԮ}.3k ЎvQ-lf~u&?_Z?ap =`?=`\ /v/37/;_ܛc?/;v߉v?]p-71mܩ{Uۉ=c_J瑳wa5Vwtғۃ 3w'7e`Zj{.j]K*͙{m*}ӭߪl{516#Җ/ 6jXw759ކv7ϏG`Z WljOYw'9awP-9Vw~5NKS_uzl IG0K˶՘qM&vԯeչq@޺02/>ǨO寗s[^.>,8y >ߜW9/ji|='+$Nv}1q.=x/%L`sh}@DA&m;Q("""UGA=:Ip9.a+5n4}릗lo?SNfW>pӚ=r]on΋؋W^F+q_eqGgGy7­3K KsWs k#9q:xcN+weC kc~u-jfS.}qNX>@9NG>w.z^d:b*Y6@A\4[lhۻl9?߉G0JsFYߦ_z/rhGǹl:+olǷ9MIV;~ 2_}_} j|?3x-L =Yܗ5k8L =Sai[fcBb!FO;Yi1YX,rϻ7}<~>$!a;fnilf6X{Y{c89k\=}}-/۷\^҃'{9?luُGل3@~m=Sy'pk<9 هCwߍI7[ B& NC=wM.ff_оKG}>;H3;e龅2m=lQ nY!ϗ[=`&>BɼNof7Ȋ]#.}]:׸x#\zYw<+]<'3$wOc+U܉~?n>ůW@壘*˗ at8 DHQP7(Cfwogg@[Z>>9Mxi+)Ⱥ P7e;?؇͸;ciq^lro矰3extJs&;WE_}glzݍ^NIe4]suz+?zwca'0 |vL6d2n>m6f=ۮ׶:ݏ{7? lz?]gaؾ8/k˪kQ[1zO;`eRx1Z^J9i` -&}?$f#nY&i6ʊrRQPj8x}wu夯!kˠpw߹ k ]vƦ|K#dM2ӕhs\׍9f1cPvќkߑ3Cl|'lr'g'txv\6~4ZcZ֗ͶZ)Cƿy'85;f3{R G#ҩdMqa,A G}Nd)Fϧž;A' pOg{N)_~b ;cVKnVgUi_ͻe3Nxn˕s͏Y"5/ywސ1c^9rt 9w酡L7zL/+~7 oםk 緞/vݦWѧq凱w3v]g0[.۱pwu{ڷ/Г[Bd%a\{qLj/:%Ǜ?ߝ׌F \tcov=b IDAT$xWe:v;dƹW0rzb@~o|CokڔE\EN,/Xe9$f}S^|Ywц%cs[şK9?0:{5t͙l/o g}5mе'+5K55͵':.ن^+΅[՗ޗ\|\fQv.dΘbNWl͏߉-EhNa!G0ܱn}{tuL׶ΠqCA,*DBtw̍:=Cks'|v؁]wNKiȮYt^!k9FL."-Bcmx^%W3 %Yہ{dT9nf!Wo/ xflgK/_5d-<?1п5YqSi>WaItBeDDDNknjB¯7%ww?~_M c貛rj{2@uu4y|$>d7S_xPt_:n!]ٙWzRs|6|N/e%9$sM*֟V>JEdf >뤅}i*t_=`{B$5dQR"""2CmZ HuQ^dף]` >81wϕtl׆={0m n,ʹ5ԭ[7bT1Fu6z݊Tn\CӅ{ O,СsgB0v;yDYsux"""Zr or{!oAZDdVdq//`?v-@?價=s)[Wm,"""ۥA~6 =$!="""-Sy <}z!w2W/""RޫsZ}Qo4·O88I:i`a<ӊ"""[r=c'I(=+y-m'""" ^+uԯ&]f3L-܌BJ$̥H5+.\jCn{ϥfÆȼ5 EDDUC־u|N&>aV3s'QHK7km??]H˅f-߸L4KA>1G;NLLP#^_!DDDD ~y>0+_"""ծq!~Sʺ' fV3K#?(Mi N E} Xw roN.""K; We+ ֶ,bε77lĺ\~È """M]q]\ Mp mqa_1(%˜0ߢ݊)oV|J7ȹ:Oϊ>fF!f ^DDJg[M}}!J[o]Z_/ڒ›}Y/]g,|I`_gKM|7KE7oc u81+th~39 $mH6Xz,&Eb\G_4XY޼pcBҙj+ډRH])_GmgBt݇cR7u*멏I?u$|С,sF߼0"z#%Qs7+V2P)o=9r>k O35L+ +]WWӑvӯ.l+ J*ꚮ}RXI&s>I1,*Oi*xB|/nNЋȒlҍ77|}9߇v"""Һf䧗J rEDD5iئyoMD0,m[}j:xEOlSY4Uk7{sg/c'-J;뢟ӵ"̽܋uo][DDAKZ5v[-XiBZ#'q|"""fKoP)oDDDdZG`fG;n,8H25$/Y,\vߛព׼,IB>?ri}im3^DDDHzb㈥r}bLW 1$fI7'H~dCDDd hW"""nngW" 5Hi` R""" AS*LHY4U##<` B$xZvʏ EDDԢ!DDDDZGr!dI&:2YpGDDDDDDDD˝M苹D@5s"""""""R-I K˻G HR6r2p/""""""RM8y$xHi%<*b :A&wM I}>u1"""""""RܳE, y31'C0Y܋T <өdIfc ]OEDDDDDD93 BbxL%1-=Txf!Ct' EMۋT؛4[o`.g@,-ŏ1._DDDDDDzK5{$X 1ۋTg͈^Y$WOB ?FߋTyia_> q F $5mQt/""""""RMc!s-dHS~6Ff&I""""""",ҧ=i$K-Y,"""""""E#F t;{2D dɭGVEDDDDDDH&8fY #I@A:%_i{j鿙!݉1 Hbd1s#!HODDDDDDDE 5djjnfx $0Bzjd$deDh½HUq"xe10K%YEj'""""""RM,r{4b4'n,._DDDDDD#fzs @?!݈ wODDDDDDDy.[iJۋTljj> #Năq0/HDDDDDDDFfrS1Fb[>HU4w"O!kEDDDDDDxL9|9I3 EDDDDDDIn}.[@x:|nĢB-m&Yfn@3k葯DDDDDDD{+sNGVSYH5 V;׹8IErNY VsUn$PYnT^6oi|8`t}bwnFbjx8Ie ?E' ߉z"""""""UŜܜ|jw!IkъH93rӬw`u=2."""""""Uq"oeqK{["/^DDDDDDDPd1M[=?GZ^DDDDDDywri~ps/""""""ReOK$TLM 1:!G,v7#Wj0̌Xn~@IpOz\:_{jRG:w{v9S&3.2!,/|Hu0,u^rlջ+tp:ңO?YG,"""""""EG)S0#43ܨ%hN :g\,"""""""E̝ 0۱{gR7i:S"LGf͜N]6K:v"""""""U%X/ !Cb7'qY@FEDDDDDDד]#fDwI NFODd wƵGC }i'oxD$:r x=N҅xDRY i1#x4^#I 1K'|%;N$8DN,zYD+ٯ|6?o#uL<)1 xk41/ N>TDDDZE`D[H/"""K3ctҞ`m1m&/7^7qa+8i|_v"Y>a)}pSx/"""vڲCl7܃{G M^2+n|" "]N 0DDx.eH` 6]h+"2/F:542/[ijԵCa<w?ˑߴJU[4d fgsBn.~i`j'"""G_s˅szg럔\d8ґ-9o0`aT#=>uZ^DDD7_&\2ɏסgRŒl EDY>X/ Cf$gсWDDZKCXg,3j;P?M⋑cx߯܃2yr<;cWg`uWggBF&ıOxxw>eFomwl:Y'u3yw!W$CVabѭW-]GgInw{7yl}UyQ1yT#J7~-k^j{ cCo0/Mמ]Х=uL8_>浧ƽe呭[Dd"1K K'1L#c_DDr֍DZ.gl gfϯo?d??ugY2vٿڛZ|eqfߓw$dJnS&}v[mG/מs'-RӶݏކNۅ.;Uܦ]Ƕ^+5~?=I̺99ϖ{m\|>-ŕ9$ܶ}[9d9q),7>'1˰{;}/N^z~Umk .v`Gg~c]u]ztk_ެk.;qcgqE77u\\??+:w8gM/=оc웎kqxθ(.IM>]g|Z.B7kg_9{gqOnViԱm!kY_a0IЖea]֣gv|9)˾N<}{qN޻+k YMw\]]uÁ鱳0s&k֌FAclzfW26} 竼=C}3&gnԴ)lChס"YN>7ftooӶMm[qje%' {c)[io>l/ŅZco_3u4ڴ=`5Yy ۙG_|~b؎n#{*Ԁċ9O'"艸 םMܝ$ t}tâAEDf/w-t<ïz[ );ʷiߓ÷\w%G_Ƿ_Pvϸ~0;Eѿۏެ28}Nb>Kp5GkWXu;gi f5:ѮC[8v[ ~ŋLMYyNO*ѳo7~u1%S$!#s Mse˲M{fy/);bUĤ4{?]{va-W+k:,|>Ϳw߀_^ m7XSh IDAT9y7涏xS|؇o:K?1FP}o~0cXnï6 Cvݠdۇ*"K xt,箋f<1b30G)"\x2a5mNQMЖ_\Ӓyn4VYoE:uȷ>P14{zI7Z;4:0Vx;:dgYǼ[dQ??hy,{}ɶ]wb- (E[qޭmk(駑k{ͺ S'N+[wjMl=o=qdk%cG$5Q>;?Qq,zҮ,22qDRE""RW7}WU26xkvc/[?9~fwqxiRV^RgȮ ̞}oXv5}WF5d6dғ^D:hokUBT6vlV2WO*n?SK4βnw4HoҸ) k(|=Maf֕TFfݶ%ЍI=;kbR;cS267sED %z=ql+?Iۅ0ːSY,Vd%|k[Myoϲk|jס-]SN }_,|5Oz͸x}6ݩ 8dX~eJp[bMWMAAs;J˽A=+fO+y}_+boU LņwX_^LY{_mo}c/ڿsΪ7n7u&\s4~>hUw}MsxвiC ukNƳv""$8ɐC6DvӋYãbiNc.fv˭tO6{m? c Z{w^yQecl~Vʻ7euW,Z8T}]g{]ں0l{3+ܬ}N; ۢ~a%}=Yw՚lظ${UCDdQeC0K!DY  ZPj'""\q-\y%?<֌ˀΚ^Wܷnf6͘:$on Q?e 3T[qSV%ݙ9}'LeOQLVp g͚'0, _'~7-*}+]`Y V9EURX&ѱ|bތ$5wqz?T #y+flk7C<_JoY%[_/Fn}‚G_sW,Ø>xc1eW[j˶ݦQI+yg"VXu.4:6ʎϚQˏ{/Oe1u&uuee3wcpC7 -\tuңSYURҢeDDGi}.!u0pKOЇy``Q{yŞO*վo;:XkɥZi^0[w}=)H߰fShA=ٓν%mD|Ar}o޸O_KN?|yNhݹyY4DD7 u {]y~+a| z""wc͉ =>.}5;)}5](m~ ;&=nܪNI]~UTP*I ;_'#Gnzv%`oUeyӤnE=-9%g1 13\`]9qPu7p_Fpe's dfdV)wߨe{…c娪TMߩBc5* vY%}qӪѼCwJ%=>^3kdSW7,\Գ];t}ϞY'mC@| |""WsF bF(p<=ȍREDʣ^-Ӓ?xD@y+yגtYlo eaօUE< *mN..+އwEK*o4mېV=̙~. LYhuڴ>mhڶa^3*nCO vNQYF""9bJ$J7=y㟾>oG%g1 7/Gv/{@oZ0a6%}}~G'ˬ٘Km+) X,+i[eѺssFLqFo/kk6ƾtR>WbsZxgU&$ hޡ13Nsr̢@ c88Vs니H\3 ?e\_rwՂ~zSPa2[~M3<)^BE;'7.9rB #G٥v$<=uц TO/͹7HM8/'p˳Wf.br wYؖ'~Y[1qQSIsEȽ mO(ahZ+u6>~e|Ҷ#9߄Yx |<yJ̅؛A`pIsòT-_Dt=݋.=cۖmcrp}~y|1{NH>lOJ|ɟOgՒہN=~O 35D-iѱ;k|ӓVjzζ -=+>Vs{BQߓp >xyf)J}V<~c~լ[$ ǯ|+8o Ł'~03l[3дm#:7C_Cck֛\"_xhe‡SJ}X8s >>g]{|b[:b؟O(MAF3lT\v_KPa-61/J^"g_w|XRje$ے3dʲ}?|DⱙqraEN!Z=nWK{.IoBAu 1?7%Vl9'L`x>|NUEDv 0G >q#4p8Ի"",ZlTZ%5^@Ƶ,_C#=OLwbzksr+389sތ}[~8LEǦ 8m4Ozm^nBYN̞-9s~G)[,֮XOioR^ueú53捯wkۊGѣ}Bg Lz_}8VmKנc6x¾Ԫ_#8fqU,ыn:m}˚f2O1wI[ا O{'>sL^nuբK>T t"ГzYjVM1+e V%=;ɟO'w[Z xO[ٮw$G> /=wV|ÙO@5TtED~%[͎\X'`Ȟ`8a~>rA@5""),>)("kkҺN 3GsNkY n/kgD1gOH$^7FrX{4^DDDD~00|D""0_z O ً/{pۧzyw+E"".^"`$*>a oofiZ禧/K|N+:5UDDp;<.phbDQnJ&u۲7lћ^V>#|<#9 ]תS3λyo/1oTVo9|,ÈD}_N}}[Hx"X{##IO'Y6tJ6EzFldU{>|a,l&T"V ?D{ ){+>'~SDDDDDDDvC㮦iBڴl[N׾{3fDsr1yМ{]<A=趭yx3EDDDDDD$a΁x03{D,^uNH10>0A.B4b{0SEDDDDDD$xS-,/ÓQ*QyX_{"bّ]$Lk ߑ '{?I)f8JjD0s-8ow\ OHJ/G$nۇ=91;潁ws/""""""R<>MyO0t'J{ރgܛ"{ ĴzxY|O8>|:m$7||pν#,g EDDDDDDRJ9fKqDI1f-1cEph /oa1p<o>1^DDDDDDDRKuO4pH?H0w㉆\|C'""""""Z\w?s EDDDDDD$XX- >/G50+""""""" ,L73<>\b*"""""""EĈaA3yg 9WEDDDDDDUyXXN{>/"""""""pD©Nx\Z ODDDDDD$䗾`px`DE+WS|/"""""""`3 莛0-/"2?kFA=[zUfzo#Jl|/=qLqI;'ߏp7wp[@G/ͅŏtݯcmޙcܜaoE޲xptڷ]Vq<'8?- ~qR6н ?#oS0rҼ>,v4!:+d^Uq^\b?qx|dt;Sbۥ>aoJ&r>%7$_3NǓ妧L:Պ<W?ɀ1!|I<=vǸKqn{!Χ633>,G۟{޻V=A_~| EIlԲ>l|m,.}mTaoO{8JlI}Z뭴k`4W?I+^ܜF ey;޿ o./ڷ.;c?F.F-'/⑱ /((K: kqsWxgɣu4o߸l, 0D%7lf _ʈfxU&~Vc1Xkլ\3]urws}wLkJ:Pg{O 8y79H͡WƳq=D#mڗ0HIwQ+w+Wsս%n.<[yX^c8MEwW֯Y]Nso8jW LI}+_|Nrj_by2}}}J{}IpRz?Ƭlny2_D7xjx Dü»`EJ;Hݖ<éW偿 WsY|:~&<9~XDvwtza\҇ϩƼ9o>mħbԴ'SfF;0ت^;v][2q]>{G59ccfrsX4O/{~⭉|6ĸw&Ѩe}e6ďfxrZthRggPzc"SD-ħ,ۧ󿯩Z=#)KS2믤뻠΅} >M6a8a"_Zzۙ$d[7'/:jGua&/\3~3Iy#hwkÁ\ا뻠-$ VҰY/O2_o@iEhy+Ϙ8㔥6=?]fQ-/gQܵQۅ;_D3\X+paqqx¾L'_YyRJxNe>d1}T~ްe:QV&Sm,.;нg&[Χ,7ȫO#a]ypPԑ cI?iC!ȉg@ɟsCM{c9]wPaHKo1}Z뭼_\Kg;gP9mĖMhԼժ5{[7.ؐ/6ҊzkEDa%.^\{p1нTFDڛo9#QP>S#JmlA ~Z cO22o%ѽgׯZ&&ٳE{~!,Srȩ}/q%/agOmN8xO&rO=w{.L=uOY;_Z47Úyͯ0Êgv> '/Ekگޟ @p}s]w`nXlrz۝eY4n^mݿ,}ռCc.4v=Z:qw߮~hӥ/r|c"DbyO.h'p`_DLG.45MFfκx5G/{Ϣ9Rv&MZ7W/>̟8"{нn9F~ңg"gsk7Ɍo撵r=iXmrM'+P`k1 t-:4ዷm}XV[lE&Ԫ_#v}Ro>^};е_Dg߱Ьm#&>}OYzȸgD"Ԯ_=zM%CiS6pz?:jG$M ejcnN_5Ӯ:&`/XS߹svD"qؤ);a&p TA&u8/{qcϙ,"\=Sgvg/1?r?ϤE&4mېkL 量H*3 pƋ;p8PZH%pEpg?n¢Q\3#ysWpOӽg"Ѳ2ǹ?Ƿx=eAX1-}BҪDiz΃ n} n`87t?~kc^dmPhWŧM`mŴhaY :u/\y&ͣZLV/buL'ZwiMpλr>y27GѠY6ofr%>QRPٲikxQ\p˩٧k?W:Ǽ+paj3Q>޼ ;#dkT]TD2ߴO+/H%2zy+C~iU0a: k܇[ًw5M[`ElrrzK֖tp>`x^4>xpF2ED*(uG/ai E*GZ}Ky,""z<8ށ K އLuGDD*335{w_xE7GDvx`1w_i!-1pTJ%?-'뷄%νwfHG00g_DDDDDDDRLX3?AJ~|sô|DU_Gs>=\> 7@_ ދ 7 ^EDDDDDDRXX?iވDEq}ڞSZHJ1, 'yo>"""""""B,# 0ϫ…܋HX/{"¹sA{IsF |0GGă """""""""| ̬ .Zm>4sDpxdgo${& r5r/""""""* 0g8 fA8ޅ9 \~]=paE|x< ׶ϯouSd/""""""B =07 G_/Z ODDDDDD$xC >"bDp{}.'""""""")"s 35>ރ/""""""JֹI!x4OwA7 Wp;3DDDDDDDRFX%p}½a>ü5sDyHq8,H+9sCHj1|}8>>>,?0畖/""""""B@X7 G4y>Kk^DDDDDD$ Á\|ވ~)I1 {퐎Cjz`>a>AǃA4 |g 4t/""""""Bʽ?c0wzΡz""""""")^)Y( {AI"""""""0ѻyOԈyo5d/""""""j,qGafD=׹JI){,no>,x> sH6WDDDDDDD +ax 0ouDDDDDDD$e$sx|"=ߛ,>oaW-"ϻ {p!>FxuEDDDDDDRXμgJ{a/""""""")ă1sᠼ7xj>D()_DDDDDD$0Xdux _qODDDDDDDRߡZ>/7Å|""""""" A=!oD,^EDDDDDDR>iy xa|͹I)tA|p;P=q2EDDDDDDR=U4^DDDDDD$%׹so|T)[8*|<po//"""""""!x y㉆# fb""""""")%WsF ypΑ""""""":kIi,XnMH޽;v , n:sk~:,Ip7"/{\#J#8y^gk%ۻ'#Fv)Aڵ1b:'ҊnwxaxƂ|,"]|;,X""""0bZn͡-`-@Y^/EeK ǃx91UtwΌWt3Dy [|?0# FDIn""""""""Ey3O|{Ǜ'𞴊n k5|Ɩi_[5+dSh5mM՞٭/WtsEDDDD*xb>1 pA3G4{TIu9f҃l70 Rj5bג3Ys~3::'_UQ{`uN73z"R {#k?~KSh=,֮$w""QM'vއZǜM^jֽ9ڧUT:c9"x074^D[ew]Mn}hzLcG1IJVzMz=jr"/dCə?zhH ^Lby<8p*v y;6c78"{?,˼O7\oVwDp8s{ 7sp2[!{92uϻ=ߒM+/l_ƪf晻3\<0>p>f3o,0,|oT{ƲWdo R.=޺5:fwD?O~bud'Mip2c >W<J<!f0gx\~ ^Dߎ!auθ% XD*}lj 9 @xҦMx:g\U^1/b7`i4߬}!ض<-J)-Źt|pb_R+U7%{h{>Bқ4"kR{4,=n[ֿ"-Q[?֏|8 1tP ֭[WMJ[8Zo>qp>(f]"o[&̚dv˦F3fuϽhyw^P']"qh4ΣIs;o &frrrȠiӦ 0֭[1woO>=zc_s9tuw,XDȠq>+qfw9쳋lw`֭|deeF_>/}٭߮u1m4Oڵ+I"RI9{<k'@XmLjRC IDAT*]2s;X,ƀh̜֬9w}%Kp)*m_f Edx<.bAH< p`Iyނ j͓RuYA΂ԨMFпo 63UTsXd۟->ߩvN:=zгgOԩCjhРCM۷zҥKwxԩSuҢE =P Ĝ9s;v.2gӦM\~ٓƍӢE ?p8 ,XƍHUvm~ڴi/";%^C!| 3.p>x=ӨYi 񳷊neT͏൏?OjFZ೉~l"mT͛أ;^{dZZ5.]J^^h6o{nj3ӨQ#:(ڴiyXx1AФI;8Zh)ܧvcƌVZ\xlܸ~YfafjՊN8o?mx5kUT_~ 0PN9W_}[oŠAh۶mا#Gl2.DZ_͜9s;w.&Ln(iӦtޝ'rAM7OΝo1,}{ϫʲe4hUVM1e: UVhnݺѭ[mٌ99s搓C 8ꨣh׮]]D~|Ȯ. ^/X,Ɯ9Gz"z֭"Z+[@ӆh֨Ɂ'c?H0r1w[KݣSp'f [zzA|r^>~'rrr ꫯyf>ÓO>9yש^:C aС4k֌gy 3"cǎcW^a۶m <뮻L^x~tܸqݛo0j(/_^};vd޼ysΥI&̝;7i{.ur'oiڴiի-e||?3^xa}EeժU&n?OVV_~97tݻw'-"۠|U o 9! s=E~߂kAyl]A?ޢ}OPJrrD?&f0FXqbX*tA,kNm۶\s5?ӧ3fҥ G}4ua̘1!CPF _ͤI0`W\qEq{ʢ^zmڴW^ZٳgsUWQn]O?G}kUV0lذBmҤ O?eŊ&Fww%10^:Q^֠AfF$)r}lڴիWm6222֭o6̛7ڵk'owoi6n܈sU&S>6mSN嬳΢N:)ٖL֯_O;D?Kl_&d)ԯ_?񜈈Ȯ恀/1CPDʢ~Z##m??ض<ۖfT|H֭&R)իӻwo5kƃ>ȢEEnBfyꩧӧ{.X{7iߴ4 **Ż"##-[2ob8gFZ$Bz$Ek7 om8ڝְt%yG}pi0oօ<&(iR},2X}gsD5"h'se˖K13/^LNN Hl .,Evf{q:v3gN[6m;wna̘1}a\R@~VO;8>ly7R-9zW_}ڵk .''_؊+ۼ^"W0WA=)|{3bf"<FXh F^N9ٛª"#w2vWNޓ|Q5֤7B+uhu4{!iwp)̓>|ŋYnk׮e+4k֌-[R^=:wȑ#YjA0w\ ƒ%K7oXӧ3y{AoߞUVfx RSƋӱcG.\Ȃ ۴iYfMUYj;=RCVVYYY,Y>znݺѳgO aR~}&MĖ-[Xv-|Ibsh4g͌3S-Gq7fL0e˖tR&LO 6lH裏ذa9993 6$,"o 88yi" (T-&QbD#6&Q$E%FJl AA }azKvX6yյN,3_4` q1V $.*?4{?o QN=Pz- ¢EHR4lؐ]s9^|E^-[FƍӧZ`};%%%lVx< :tI=Xy@6mo~;jݺ5K,~ԯ_H3g[v8$_~e&L_N;v,cǎf͚4mڔ_ٳq~8Æ nI&~|WymڤYfz 6mrJ]jԨgo/ $?8ٳ'[{,/"wy'fF-83h֬Z Q`/"닙8x&'ɷ[ɰ|OKwzתWwo3Giy̓,pf}*uλ6_OUiN=Zxx!386 :DDo߾L0ʁw߬ډHulLY16ľSy )t:[o{Y?'!z fIB=H%xt<" 9O4=l:̜F\ s?r~v#5XZH__ip F{/{y$s'f!m $zf JD~^j'?ܧyŐ)ۯy{?u6ׁԘ]k*kČ& 2j/M7kC n/cݗsf~K/ܒAò듩;$^Hl"4;&7~f!ԩۿH$Qs'2yxYwW*I%Ojnݝ=Bۀ^&Sw_n HE5Bdƽ;$k>@D̒L+܋ N}>z'G>&]vC,k5dl|sNmw.w9P'ԦѱТ}XZlzev_c@:FRX6>$nh҆كpР|)MZ^0z˧~EΡnX7t7l-fjΟ3q(X̾?mͦtg-IDmc13RcuIZ/"jފ?AΠfmiEm RajS(79’F3|5"""""20 BwF=۳<f!o{YYS&I_0׻c7joߛI5jJS̼)v2˾ѣX>eu8w=թWݗ!""""q2) 2fc!EtY2,_E"5L+#ΝâѣXdg,"ՠ1E64ZڵkG&xꮖT3<ѝK'}ꭷD_̢n~z}$_;tuv~xc9$"#LvY!f[ ݋-f6MhUwꮎ>k""%#X f#$Y1"""""""#s;fIJ4ǰ|) ˍ݈$|<7"""""""ܓ{O͆ofC̡l勈 7ǬtZ}{L DE"""""""R͜d@eX3F '{"""""""R "z8F4`yN:`sܓib{BB.vNH:ꝤKSN=!3?flٿ'^DDDDDDDsHθ\EDDDDDD Nf/]β]I*}K2dB|‘,k_̓Dz]>]o@K^{/ EDDDDDDp$z6gy6~'d~rVr*"""""""{%ꓠ$lϽA$V[]EDDDDDDdU!ɔGm諾@:{dӰ|a@LϮso!ϊ_DDDDDDD C$Od*~@T/""""""R(xIg ϭfx0 ) N$qb:/{@$ Q#EDDDDDD [9/NEd"4[>lȊzT'ַJgG{!$$ws/""""""R0 $ܒfcw )٩Mf`޳䋈se!!"""""""Hz-I`qwPu\!H0p!Y=f=ַQV_YUē HH|s_DDDDDDD {x|{3c$'D܋3I"Hғ-ɪBbvH{㐉1Y>-17dc=}vFi 7Lv ʥ3u܋/ tm4^:W@DDDDDDD B2ޒ~zK81>/ 9I? Hf1-/ɜi$_d+) xBw'H%Ngт拈7#z5,ۃIɁ8l|LjfҰ>f0s e뉈HAp$zHx'""""""RJ׵K'}$E>@C|{ǂcQ=""""""" <>;ߞntt{O2狈HA0cv}s> !|:_kቈt`$S'M&CܝTuVZDDDDDDDV00y2Hќ,Ƃ⋈"2!D4w')#@B$^JHDHd9M14d|eDDDDDDD ees`deP|’K}I|0rKN."""""""4'=Y>GOsZ ODDDDDDx]`?OEKL"""""""<2IF{v={w8d>PJSfꭴfswB6WNH!`-M5BQڄ{`! hFDhC1g%|^Nv=I"|7K⇀!H̡8{`EHGDRFIp1Y7ύꭷanXܓ?!1s;fdB$7G 'q,"Y ϒE!`L5XDDDDDDDI:`p dۃc 'e!2&EDDDDDD08PR!eFK=$B fd2NHd|׸|f8FI `.|'e H!/ 'Z*oyi3!&A} Wx/""""""RH$^H$X?/ZaModHJ'""""""R̓z%BB I'K`Ha`s/""""""R0d {K{tҤ0RU]YdL$CB 6'-'""""""R rgLV'tdpWh/""""""R(/,fA [L;db=VgEDDDDDD,O~3yfN:xd|4^DDDDDD0Ai]>aHgz8'""""""RX<!q7<:H222,ə_UbiGX&b8#` $M]RCwo9F.BvZ϶9}|~ZU.?G=s.LuaUޏ/ٲ^x #?SW' ܈ x?}Zgs=UCDDMeR0 X mh1 ] :U 66y/7fO`f4lRޖ3o:~W'bf$]ߣ,,ſu=LDD$_Fp'F'`d<12XH|p'/;{>'bY̜2fmU>GocޜzoY0wcnO:U 66y/7%2sf|3N/{nQ>GHюq=HDDdm9%$tχr IDAT2xp,8ʭ'NoZ~Ni8*?xx:ՖQv>C+⹯劇Ϣ^:ܝ/]JCvd#wЮK՞^:\2/}s//LĀӵVr*_mc}rGqwe,b!r`ܶ UkSR7:=}߼kԬW?~/N6ߢskn{O?_IWVt?V̬m=J^}|/sa;qx櫁xɡyꞯGUS_icvxf<9O8~.{LBX(23c!>KyeC {'_ʞOeW)w#u^=*wzm7`V10w9{mwh]qMSThUt-wƾ;6&5~垅` |3[̋δ3+-uamx蚧lN>gk`".*!oҸymcѺf<~0_¼9yr?ȷ_żdJ2\^U=O~[}&3‡4߼ |/d{ tlQxƼ3E3/ɷk*~X#ڟ}ŇY?yd2=۶ב;_xAV=˔d%LVW_ٵ9&nftݙgynڴ9 m+Lp?|Ϙͧ[~Mn&"1PrH%IӔ,/! F7W:=Yg7`+}W3hٮyIV]|3/cҸ|4jo|V*{Ҁa;V=nJW&6Wemz從,j\iy'￝4sewmkN!Қаf]*Y'ﻯgM|/wgyq j'^U=O~[W,(C]WwM^i3iڲg8:be{ޓ=ɍܗi.)^ן7؇M[5sw0OF3?,d]:UUgX>~sμx?U֮2Ъ}sj׭sp'QV{wf9L]es .߳ G?TiEDd#Fw1̒}3#K$3`(/[,<=ez;ە;_̻1aEVUI/IYQTv=kJ24w/.lҲ7?(9n.*mV<c$?=t&N/zqɼنMo3诘;GN5k@-+ SY/W^P*)ޯ="+wjO*bwc[ [5_ֺkcdyr?r`\u=KagK-xkڠߠӹk+MԢMhy:nז/7Ќg{6iФb|elKG4OՖW{۵3#򮳈l̜H$F ctNڢC0̒o/Us Ooţ3)2aZ5whҪ1>xR>}{mI{?OFƛ5}`X"""9pMt!p'!k޽/9F`?}TUEݰh# v&] 1qD٭.""""""򳳶~G-, 7=Ҭz"""""""#] |R锧q;%|"""""""RlE|[vbg!ۍoٹAH1l< {, Iį{L7%ON71#1"""""""ZtI< ,{'d{k9{MWcbGO/E0 lj EDDDDDD Niw#''9DDDDDDDPXidvCH _MY] /UoB26?es9;+*NDDDDDDD6.$O~HXȐNd~2A_EDDDDDD ÒyI 0%9"""""""&:f=Q n'""""""",zKWw{ًA,`ٿ'}I'ɏ$^O2S^e/3e+"""""""Ygs-<$g^tVWT;3'cD<豈HƓK׽ EH'c5pDDDDDDD ~z0 N 4`!}Ufd! s3ݔ/_DDDDDDx67#Iib6W9n~"""""""#`Ingg֧Yko$ًOBvb67ܜ^^ON}Ȏlֶ K3i`$o ]u`fG9_76ͷf_a3>T4_0wK3<ˆI>|ޣ\?W*ѳ]ָS۫1lV_·_{^eRمZw }陋W㪡*gRDDDPD 2xn[^u8*0zLjծ؞:mw݊{/iWKxpnegSTি_DZE}c|UA`"9*}ukk,0NݳscvL9X^ 2z"1?Ĵ/~ʇAay{| .٪G;~%Lw@evYmpЬvKqo/{^e$%,ΞȔD~1f,YSt9';gqxOqJgr8'_\dcvO+2 |4'Y/V_}ePNM:rgr}O_L @Q"F..vRܶzp<ͽ0m^O^+Ns̮$ :' bȫާKWCne-߶Gg;yețk![C`O~P˪G*{w{^ {۰6nT\Uvo׶-G<.ԃowa,hcZnA,yeț4nހmY|_ | NA}˯""""|{Jd}t~0cf刔* hpRMZ4dᏫ]Y-:UM;|3/cҸ|4jov]ΟOo<>\<آs+κ:؞;yheUvoFf hվ9bᏋy8Q;3k;SsUٽ]kǓ9e݉{+m9ЮKkjnR#׳_V1kz_O]lgFˇɗΕ)ϋlmq,KoI;$p׬{7㿥x2٥#jjvLhHB1;qvғ}]W2=ߎ ĝ/W镒҅`̚|}){ޫ1l~zw{6XYePWkyqGkxJ*Tq[Z͹U5;{%ϧ%ʍP9efƍ!7cִ\οhމ j[tQ1_.=;ҽOg>xmLs=W^kO˾_bfW9IFãĻYZW@W;r/(|o.GL:!Uz؊Tx2ytա{ޓ-iËdY 1ɊҞIX 6mXST&-y2M;)ou:q̃/u͘J?6Ļ+,/F'I뎫&amiveUnӾJ]B{_{Y9Uܖ窪꽬L*ȱtۭ=܆H.ә}$칪ޮOK: aU&CnEI.mv9*{ZgOݶazl_d^xDDDD6v^#{6n2DlO q{ -5]ѯdp_[I3u uo6M-Ken,ǜu ٪!ާ CA[=lKGE)6;l ^.)M4hR\)qvlYCjծM[4l IDATWיϹKֵye~gi9t֖mviW͍^EyLiݦMGofܲ}*CY.yY˹?ˁט>WUUeYԩE͛|&_1/85!1mwH]uڲynKeUev]f6>a}]m>YS =t&N/zqI>MWzʞq~ݱ{a>~s`D~ """QdF e);<$k 9'D*ϵ_Grx{o" ^>S 傻N/2Gާs3[~WQv OS^f'_3iҪ1>xR>}{8޼N}5etq.dƽ7ɟ:>WUUeY})Tb$o~ʐ'|8: j3g\1N`.aٕy*bSpeѨV-øhiL3zX>n. ~\n'แ{Y@Lu[DDDDDDDDzx|,g!>ČLcEDDDDDD a :;)R ?iNw3M)(FtBv=x`601Fp'8l"""""""qInDwH'~װ|a$,ɦ#$c@D1%-_DDDDDDCcpJ,&`xpggnj3+ ҩTۜ䖮w @Ĉ٘>;pK!z"""""""?:u묺Ϊے,b$ES3"=E,x4%5E I`ߨAr8N2x<2iKQgE@f^$3q4npRXqSRDɠ"""""""%1B@H0#Zd}N$@H0 FOz"`r fX*GsEDDDDDD ݉f_܇`7C5?q/""""""R@`,gۓX3нH1N;Ly ,3`o\.=;`f;S;fUsEDDDDD6)lj`)i #7{\G;/{!B!e@+7Zi\^O+} _@xB]s2 NKs1r B!Be2 FAΟpZXXƍ1{ Yr/JA7ᮋXr]\Wι4^zp:nl(B!Sh۠=W`_w8phvc0J B""*пq1^~#DTL$Ւ1s!L!B!BeFܖ(o,mq`#d%T%/ZׇfY ғ3ф/x%DFcO*G;B!Bq\RSkJ4ƍs>.ÍViO)ڲ@Ƶxuo}-:. TIJ\߫= G5e!k\XdA!B!+<޲,68 1hq[ Ɓz_!/š}iD>| RGNb疽T^;xÿЛlY18YB!Bv5(~y;2ˠg3=p/T%w#a=T>?_ɩe뉌`4mѐأ|!B!8e(QV{JiVhJ岽Arh_6ߡmsޯR7ضa7\ߤEC"˟-ѹckpgy$Nyu\\swM.Y| M]eEO_G3oT5}L0hz/LOgw%kGۗ!nǣpʫ"⧙ko4fmُqj˓aӱV}hWb7|.C4Qs!PR`aP  NogHZ6#IJ+0^xg)˽懮WdՏ븧Փd̤{ռLfO_ )N5~Ltl$?ޣsrgZr#Gҳ94uZ*RKᦓuLc36tUjҼ'}V~W,kFG%=sWUn{%?q=cI巯Wu$ gn̪Wʺ~c׌*BϷ3(, mhsxg~`²4(d|E|Ϫso>Q0T晷$1%> em%>_go&Z7},?sד\-{_3b隰7,:)!9-Ezmqp}eg:;69ji(:ej%OǛpXso`_; ;T}hO^k﹄6a'?iB! ƞ{۷k3{VX2a>̫_ =x߻sݳl\)>"%7 M-Z ,4OHc{el+q'0tnzY5X|ޏM}{ 6kC:_0axD>9 9 %ع.S=ǼSyON丐}SiשCv^Y5=ez*gi}z(E8w m;E7]S8i~nnʹF0jc$V{xw|m"LvM Z1;7ͩ-O[td>.٠\Tu+@ ߒ]I^?04kהٛ'pqIS2*hBTOb79ӂ驴xЅ^ N W>b?{^gƊKJ]g)T?7cf7Cq8>VTځ qQÅBs`eT/|6y{2cty|gU\׀qբQy{z3 BQ>mF{i8PhAhF,?c 6Ͼ_~/AD-kWs=&Ɛ0^S⹫-?@:hvn˛?S.v;ӿ:rwM=_0Mit?:7_71~h|%й׭)1}Gtݓ{*7kvY9N_ 'ן3 |<]S6Yx_k֮)?=hZzH~>5amqc+`4]їйQҟ_~t9AlϓSV'soA y.ܒVW| v~_i.$u+@ ЌgеC8낦Aӻq{vlۘ:d=q@f4aڲMtc Pc{e.}^MA~iY0e֊9uXE_iCg1^TswFKN/BMp`F)Bv4cV[I %0h;vxn??ߵc׌ۣ8'Q1%>OL|S=Wh//VՕg1 9L^Ϧ}Ŗ;[cep%ٙ9|".7*z_ #HL3sITWX`J֊GuoAzXy]r~r%GO_^QJѬmf_B+X`EX߮a^6MpfLv$7;^Ϯ-kkq_Y_6v , UԻ`ض~uOV!h*I3vդECJfv ][s]%ˣ q-.\kp^1&| V'#Aơ#|:uMsBJ֖_ׇϖ5;BJkq|?Wο9#g?-xT[P@T_n/ehOfxX\Wm[zUc y9.cJ}3Z-vĦumDEA$عYg㪭*5?o-[ו,_OJ$j7Nl|4d2p4kۄ=[yEZ7gGmvQش#9$БBP_0Ejd_We/'+EŌoZ;&6bg 7>Չ/Hk cN )i2x a~_^Vvn˄o\5Vӽ hޟ s6Ycn*>-,ю/W\Wj*:_ؔd?xÊG!D^r(i,0F2EjXq ⻹2Tr*|x_:n%5سuX۱qi28S_ /He7O]l%c;4R+=gӾc̡^LiD+sg`o<3_4x&Jt~c 34&>)߾^Mvfl'Ѭ]_=,Қ["i mW^J.| r~i.$R0pU/V2|.NKQ^Uv<߭e"Q0(}Ɛ[pRnPשLt\ٙ9i|>}1~o68 s ʼ͂J.`JώviFpFƅSEW{ů_IM8x*ߟKB!ʗhQ@Ba|B+MmK^$^=1},ôx!f_xwKYqQ_]jpj],UOyx_DcH9\QT]gSKYy˕Ѻ1g]x*~'+]YЬ]S-GZP9u`]%h,%voAjggU2Z:-[_+ׅ ݉Q%Ө9j֯ƞCjcȍ<n?@Q$Mʢk˺ ZE˨ UByyſcf}W?uPᅵ3Z°SJbғ}_!DߍeYX4a c?^ۋQx"}Thx a8tĔxwo뽍?To Mʂipj]Qk) iعiGBݓkf2c Ԭ>Y9=&IU+B9?_djAⲛ5&Kˮ{ea$*UI䔳m?_H[I•$Nou2%t whNuj`WTQ(>r k&z,Xy)EҮ^t{#1TLGy֟pֿvN_LR|='uh߭-bY*qɍ-iҢ!҆'dѬWk{2%/^x~C+{xg|7r<=CpJV25UUg1pJO-e /MZ4tpY֜pJ-!h3?&J-$=j?'Y{v;&p`aMͯKV񔅥ʷBq+nm@)P4J9p o=y⹻'rS7оҁ}swO #9k?νs]s̀}c=q9n}zƸdǦm3N]Da73cded:_ v>Fq=r• >'d[0׊%й*S8'Uk's$=ߗaԽhK׵7˾ٿ+[KuI=K(mдĈ'yc(eΞceo B!Bq+,ܩ xsB!B -€0+{c,g/B!B!*'zeߦ8}< B!Bm$(얯=h}!B!BT L-@)m5x.{cd!B!Bd Xe<{SysoB!B!Dd#OzN^?~+18Z_ݜ>/Vq~:|m"c=K൯5g|F~MzuZÅ^޿#7.:0++X9 aeWT&L6`ׯ?JfV;=,/30HnEϿ(i"mXξo ¼g= g3a(U؈Gxx]48.~c>#"#{$.1ӿ⛏Wdt'ރ֚X濳}GkΥrdF?<>m2ILV'yy6SxujA>ӛȨHb⣘3i;iNÝ2s5o5GҳILžضn7\>v; i3ضn؊ۚ==_~;? hֶ o_3w;`&MZ4aJ\_)}8/v{Ïr0# {rM߃aV}=AX_>IH齋yQưnhI3N!+^S׵ 3ߤ>'2m,6;|T,Gjԫ;/|7]WDc߂ Ϙhbc  8=[, zb{ /I^7-kSA5N-R;t|+{_}4<_uoV~y.j]_yKg(cωM{y~cՂbe^~?զen#*&]Z({ P`pPB7_XTLcN#2:?`ϸ[vm Wwoˮ-x}DD:IyG,E)kcRٶ n= s7^~K~ {xG]A/:72m,j5օ׾y5Eo krv Fs]˹NIfdv+bܼ* P~w8 v8d<_v9(U?[Ao|/}jIoz'bm,qQpfo ˲T%!Uc=iaHmcsu>#ﲇSP ڳ5 gm̕]o•p%nNt\>2>*\mX_l5㼷.yhK>sIm|yQ01DF9yTZ]u]@Ҭ]S-?~{(^ujAzUW ۗh, T균ͽp煾XcsjeoE~y9Xtb=wmg:W %W_-M.:_]@e_2)6ZLy?y-3{Sp [r sW 6v|7ᬀeMcrg?4L-(Yt/JnlnvNѦ1`[M&3-o<Wc㪭8?䪉l^TNO`,{y onP{\>q[:jkd7>DTL$Q1ױr]DFGz-*&CGزf/?4'uqо4~x_:iөT%'z'؃}{Lv Jq{Mfrw'> _Ԗv[A;|W{.ܒC{Ә?s)WlrspoIF(BiU/Xl M+k\[^#F`Y&Jyխ̆<~5.xFΦUgO`}1ʼ(_cX [W|gcnߣ#KUP| `.X+7c\mz VVo _=~ѱQ}/V2X%W<_yN}}+L*i-}<9P[U?1,}(p?|p%ظ DYs+ נ x9|"t[x}a}nN8Q$s`a,?Ǯc(7~:^3bpy'1/kRGᲛ[sc+H+W>vZܨe=&Uj%oAbiye3F3W76M0^/k>3o|NC""/%ˁ݇? YwT1~0fz' =/^QZ1kp幉~`uWԇ _ kp:T%ҁm#zR}(TW&-Ǿ=&.vZ/+#Q='38"*&Ydževκ)c&HQ3BW^OA)/KVsg]ĦumT[W:./fF|h4=!P(|=iue3cxkrrˢBnX_\W߹iϺ%3e[}hpj6_{!dOyӽsR,xl[[R'sWs)#eۣ߮0hz/6s3I_JZemϟ7h,w@4~X9WImqY)++>;;V|:+fzXeN?/UeB(:&羿q8P*clG9kE˳߻w->_G9d<M+_xeZeߍegݟrM~^2ncmu .wqY{:)SgΤ^{q_ѫGp$=;`X_SsY EJ$N<.A)<=/zX'_P<N8 _HCfdX(X x9,ˠAy~⿦^Ztp-SX'{m ܓ-+}!yO@a}ẞqɔ!ۿ y8U,^NJ1Q(y\V  Q`YUr^!B!(_?t14F18,pjeڽB!BQqٷڻQJ} ,KB!BQسv(e<~^s0Nd/B!BT4N½eR`AJ{}!;Ɣ踳/>-DMnNo+u<:aW˧:_SE/ײN_Ig0 ־_cQ/U6WzV]8^_iƸK?.x(XG=6\ϴҪH5?-Qać0vSLX OKrŕX9~Vu_QF1Fc) ze0ƍɽ/ZbJ<',U>GC:(|0ꩢv(}jeXW<*UMD)0—o%טV.*8#QcKYs\R,Ͼo>7 CXwnɸ)ˡ=_WFa4hc18Fi{%Q1Cg5Wwഺ+8'2,|;o:S{v0mvq񍭸cN{i>izƑlx4>|=4<^>ڡn9auu*Xׇqҙp煤̤IF/< *XHr/y7)ܴnh\{|;nv nyodo UMpvжJ}98侘_>`NŀIj7EwRJ7vio}-|ց?^Gոٲfϴ_wEǾk8ibbuqVh/&`;)/ϙc>>WseR4ūX|\o. q}/o: }1^=ğI\r:a3y^ u<-'!Mko3W{p:R yҽf΃ <`?b!.)!gϸkVo>7zkqmӲ,*UI`-p:xgfOZ嶨R3~ퟥ]ԨWyo}ͥ]Zs6|i6l_7{:}1}˻i %8"}c1][2}GDFG0,dx[_ݜFdtS1-۲k>^>NR>/چ߮aO8mbyy6>SY|#ӆ΢Vhq8a֝`]dq1sXLN-@QNՓr@B/׾|<r_ /'@TLzN.n)X.Uژzywsu>#._wE>GեL{~sw{>i/_^Ci7npʴK V2RDVk巴y }:_fr%VW0Tv?nCnv^`ٵ) X8-r,XW4A8Q1DDy۲vٙ9h=!V2V ֿv"~.7T9M լ)9VW[<7MTgc'n{:chyE3^6^6׸6JlBx6󟛝τWԪ_G^3 ~:)&V/P<ө?0iл~NX_w^u]r V'VPނ񔦮_\O+jVo`|U 3-gG3Ek_T~쫾@C@c1?} Vy }sˣˢq./0usA _i5};I<7gޢQ?B,ˠ(c_ǾwWs}!{[~w>vZfߎjP Mk7RK*2gedtyjV,]KNV4m߸M:r[,zƊoۺ~nC/Wھq7'\ S9p>LzUhҢa.hʼԯI1nn͍}d#>vy' |'PIB՝; A0#[AE"@Nvr O8u hZ|Pr(_ /'@F5$U'_ 1X._CVwzCI;_}Ɨcݏ}צU['ܴCϖh>X(e1k(Ws˻/ pΜV|{\|Rp>c5>|&s鴸t&>>_ɳwL '+Dxcgi|m~ν28-1Ba/w#WE`4>k~HL\4:r oVf]Gv?@KLw2`ҽ {qQ{s fSb/qO'ŽsӐ.:ф/x N}5WM9>勷؄ILzr& vy68Wm+V Y3nrxq1Mbx&,~?R(_aAGa^lZ#9!]׃hܼ'`9+m[w<~-߮ X.F]ܼ7`|߾3h[ X IDAT__)jJ)\.o`케cA}vy]WfuX(ʷN8q?U_~RO< `cuSiwlP*ؘ[}{~\- 3->3-ǯwa7poA.߼7Uts1JJ~r%tv8)0e/mPe{[봋Mf&=9Sjq<ţrR=OEPv OC)q|w ̴J|;ZuZ!ok.m?v![-}Zu-40gA S)@c2ܖ/nz*Z]y/~X'D2se\DF2exPuyܷ~XZҏ|{i% $Q,mO5zJlrQX` rr+B!B!D9(ɕtRph'h ,1x?NeYheuR+B!B-yžroy"PZdg !B!|h@,XXQg=-_!B!H,V߇, Zk7ҳk'B!BT(81FuoQe0D2< Yu/B!BTcxV C 8( ȵ{!B!p*{6D+'PƠ, '2J9B!B!DNhܖ+߉ž@2cd!B!Bd,(RXnF),A+`p8}þ1rKB!BQ(QZc, aӭX-J/B!BT(n4`_(P~('~FBZB!B!Db 0J0D:XQh zyB!BQgnovawܯ(<B!B!DA6J;aߪo,7m/k, !B!v rc@tzkoY(cB!B!D=Su {=`(QO!B!X<{Yrea082Fie0yB!BQX`8A{W+ (B!B X V(@9зܻBaPh1_!B!@R_,`^lN [= !B!0ieo?8{4q*cPJ0sA_. !B!;j1 ,pj6|Yk/B!B2ƞ{2RZ+犾B!B!Dš1he+-F+/7#{ !B!eTZ{wo܀}WeamB!B!DbϹ7`~.g+=cPF !B!\7(R A9N 1 # !B!ʟ{=cٗqV4~hӞB!B!*؏3{Q8hثRŞzڡDFéq84JiCp:pXn1neGnOv[(+J)"#riQD(: wv2mGnḌBQ *6Ȩc#qD8[ie3r%7;\\yc#e,,<>h8Á6(WA;bM!6>g3cE'+ő,dd%_~M\b qDFGuvhp#Q(rs: HN+'X9'&G/YXfbG\BQ##$zHzȯ!*'_)w)$GơLO_HL<|ZB?n$DC^[b ֪gN\R,&@F s"u|IH uK뤾OZ+RM!&6E򢴲>@0+c⣩Q|> uM/$yUA;aڕ8|CjOP{F~h `JMrD$xWJٷ&Pv spo6VФTO"rB+.79y \fvqϚ`fXi{S?D91&Vޫnۮ=w[H}U|]!ML|4T޴xK^b MIr$r\H/v|{VmM[k)HyYU*`x#O<5 &5B{`ǀ'ef͓USEFZ;J RD߅nMDz/q}Da&iZy^ f˕>9Q3)F ț1Sarԍ^OKk&080P0֠u";­VBNݓȿޞ@пA5rGx\x_M172?J9"խ7cM=D:uR(Pta5Cg|UѨ9̄gK? 8uв?l#nxgd&TvuM>;:ﻷW?m!*F_3G*rz=-V|t۟ {qzП5!Dpsk[-Zي/ %Z/G8;|4DNWJ_e㯂6 siyDT0;?ՈmX!pggSc~a׆^O 7BtvTZۣS힦>5B]wN7>^j_Oc|HeCp J@tAM0Se}]5h.rXr<*: j.I+)NΧUz{ٲZ31_<OF5 WN~bե v*Ҋ{ /{K'rz=-[8?H˒V3M]4.'fBmŵ|:?xhTz:(`D'_BuO>)*8lZ' #G+buAbɦ絳 I`vvE:ɓJcivc֠O96_M]I'=)~wKQ?|ԨPq}|rg\zZ [߭xeT+X\o;L wN3auk)}ܥSd4 Nqxw.Wl)9-iZ~k`߁?Ox@֔kK"8=zcP@_'_EJ˛ 5dNAe)-)8_ /~DTU͌' cᚍ&>=ui+GJ Vd$?Luc=\_5'xw9Xgi` (D" ޮ{`r;OpcΎX{pT]ӈ^OoXX@in_~ߛ2ŵZA}R\Nϱ4ٛ5i4}UAq0S c5&5hMB`~wO}R>{FԞgGu~8{=*8{| ZZ=Zi4c✖є#I+uCKTΏ/ހW@Tpxv3TOӭ şbT Ͽ:a0QD}NSP 3{Ry/~؜ڟ?l lU?Sw'zgl}Ry뵅*bw{twq* (ώm|oU+O/>zEo^ ݞ ~׉s̔(WJ^~Q`8*2.덩nt>f-[_u}wuΨ.UpUotxf IFgo0W-X*bcT`*Lickf썯C0LJ ތ)`^ z0 By~9>3Uffz>>qDlvvBh]L/ߘU]OO/ҨC *FXX͟^O҈بFz) Ad3aJژ,`VJx_<*z1[K]͸lumxz_ԫ>{ խ%xDuj/a/jeshzлsO HggDVWY  w֧^.UH9'kw ilb‹60W9S!0[)a} <^ă ?AHxԷ]<5uZ񃦬2^V]Vn3voC3izU*XXd&WMqzAc^(F(#g(3_pgTiWЮzSY`&Ӌ4"rSmC>;o;]|lRj>t8 ϗqϿHixW >2/rOWTpXyFϙPX1C:5/ x= ceN#F z0 ǃGqr^óc³n@X#C5LU/zf@a&o}Pk3|?pRrVc'>}y~5p UߣKk+@#\v>4z9wQ1i@TcǠWh4cZZ7U>c\}mh6Zv_"]{IE+2Wt8"rGs& +Ҙ#_Gj:m XZju zϬb8?\ׁ,`"\IЋb[K72PK\_5'^p}%N4A]1KίU.=6,\r(L1*2 oxcfvxؗ^P 3v;y5f+%Npz0{ npQEZTp(A/Om5-|eIt(4W-w938ǸDek0W;`qv/Mj>~yt%n|mO ?_H$赺t㨔:#v?np?eFgOx00eZƛ|>RǤTʙ ߾|=cC?d&l͞?˕ qA,,Ld|Ѭa V\hGB1f]yJ^c>I"<{v/TJ/f« j6ΣF"oZūe^뇢r~7 lZ(c&,װRŌ*ke;]1卤z}+@D891#h''2 ni:xn{R}Wz㾴w8rw45sxO8ҟFD#<BxZך7=2m"l}~/Ӎ ϲ&py<@^![}ou,^^sfm 13[b@_ \_5՘yuwWH,׳:R~J7cǾ/"Jz#SmCk9F1M z~,B4RYG~Xz YTj+$$NpzxDuB܌7cN$vUӃܰ>8=8{=^>h^lfl:k(Ϧ=4.Gw=4/g0:gV/n4ĄĝSޮ8@ϊqjc*`^8!k * _9Gy~sl, IDAT^Ax+u7+Mt] ϟqrp6OϟR/~lP'* |^1)~\itgt}8ǥWTp.U>.N/hj"pvT>M7 MA2\q]?G;'xsغnϟqs3\xip:_7q+FÝX=!B D mMOn'O?li`TVT}2kc4.+뵉DpBL^ϟ3P\QxH}+w򻀫vtwkع8 ~Ӌ6[)͟^` ^5mc!wN6Fɓ_[TrL^ytT||h= "3 `YXe1b卅Imu7h6y3ڿF|.^:W/wquavT ʕ 3 h`@+\pYo){=\ 'M>9ScQz9]\)=>+f+%lXz;;Fy~6s&}+GI2Ry.b!\*8A'HIѸ&Ɨf %qO=.uŏC߻zӝ&K >&N B" (ܖX f w V898ʳž/M־Yc!6_GnQ] :. [oٝ<̄j7!2?U?%'c1:ϰcl^͔6Iz U߽~77j&^QwU*t+So SύF{#i\ 󋃧YD="&W+o;yϬиƗwsv?uB1B=pVoOfL]H,}sdm;idIaq9=8ϙQ?Ky\y8Vwŏ5w1죂KS]_LdGVq:>~wπb L^Ka 뜞#m[:9w{3fWFps_h~ۙ&9rL d} ݪKLcYaPA.cfv^%K J DžAHg@Ŗ@$3,oE +yRiTڋ$Npi=%~kukaRh4*:R^Ҋtsel#PDX*fVJ/vssHX*`iU~Q]`iUÝ PAu_wzʝnMKL$.ZXSARa,z\z/=(W#co&qhd=&u7 4Y3(:Q{!HAv#F"nߋŵjתvX*M-8>ΛnZ-ueV,Tul^sr_FGrjTq3e&MM fJE̔(WJ7֦W*8;poj㮌*.덡J]鵼1ayc!**~OKSEuu=_\dqL.~uUhǎuk-Gwz+7}kbregGe]襙-쨎/y=E+%z1gE/V@lG:/8|8NjHZI/+89\O6/Υ=5י3]BsV3kԃRV"BSMfMGrz”;D{ <¼50GĄ7OaW#F<5x/}u< L#ƥ>ݑ38hr܌SpN`QdKőv;j.ҫXyt7"]!SG#̎CL_g'ͽIb?>^9Ϟecmǰx^00^o ּI4Iqw ^R_ugo>QgGM[cxf-snR%ӜqG5^nǡ|ėw{x瑜ЫuwMѽ7fu_랙:'l<\z-պ8I+&:?6NΑt8ԳfC)坸<Ε2^N-f2X'4X /08=8H)p\z!A;g= d5Kӑ)SB $̖0=Jyャ4[Dfvpnsd}s^F':/;Q?Ļ||z峣:]Lprpf[_{>)ͨ .SEȣR?5]~hV#]kVw?uf~wvTOiC^v(9޵eCgK]^aq#f{~L YAgo2:Sl@`X Iƪ.MI ·|)8? vuH ЫTkP)G&~=^n/f>TQw< j6l2cX|hMX\H3;WJd$'rtCy欴q\_aafp +վ?c4~c>| :A'}M\+z\1u4KCuEO ̄A${1 ` 0 wG3B4ys /]^ngGis6k>Σ*m'gNBr%SJU˒8 * ü5;(G{,]z:D罌Y! =?x;vѻ淥CAeY<8՞,92l/gG>Y患 @gbP^DV ^' "ND&!<L(NI ·RYG59ͽ}^#&'8?Vv\_:O<>=5W>ݧn\TֻQ1B/ft0`f897ß_OFj^c`&~k<~J/f:^}w>h~z_>Q?DK( kn?<Ύ{By`qŎdd2L/2y~ҧOlZTջR2 z`L×@""(Skv~6OL) :$,GeߘAq赸=;gnyޗw{S}h)[߭lJ ,}z^t6N2lP]O_}{F׳X\"n%S_ƮgЫ8ץ㵮c4Fc2h\tO&Ы^1!{/+<_Jބg`P^U+f(xHh{"mOH;_s蘝RzR)Z8?R*>9*gB-o,}vPͥFl>i7%#788tbI;KO;>ZJ Q a\)ud Әs(fzuN2# *8T*(brvT0[)avn&v5 ڜ]@0Yc U\_~r1^{h`ar_۰no?ƞ`JB1RFIjƨ^j@k}:L~mV)_,'gh\dsne0vOps ^k\cՌo_VCj%hg~81[)h \r~YEDC3YЃ~~n{HدBO&AJ^fB+G6ޮ#*F8?gNn-aa#tf(^"[Qk\}qcyzOf،.Y5479Ͼ}xo5B.|zC"`<ËODg?l/䍥i2ջ+mJJGdxfFHO楮n-w6pbo`uk z@d!P] mW?Q16znzU1ںv6H^\LjΎ] xTHQ1rۃ'>sk#Ǵ deAlŧ!_ͳ>%`NڕӧLFIGD $C@"`~( h\^^qu@nQTQU驟^f2{˸g3_ 霭fkx/`&̔gP(F~vaag8;cyc˱0,zR: sCoWqV?FmycѺw? A>7 ʕ9쟡4[DK$qfb9TLZvЫ"?z{0<_J3V3g{a8ŏ^DAN30 brUWs`8Cٞ, 8Kɰ?;c@{(|QVjej6;']5yZ=ٽ7͗ۯsr~7=aԛcz06ҫX* nc8n%w }} vl{g츕`תh\5w(|(!u"@~r<& 맾>nʯBېz<`Eg'0CHAy x!e<55((tG֭Qf Z>nSVv/NlgoQ?t7+GaQg㢷S/ ꍩT(@ $q@Z&ix@k]ռx8f!"}s닥7L\qհ7M3}uaiHoM^"n%ݳf1|\M *F:*h)9kT t^R!u,>^tK|O/TJS,f /WG+|ފs|O/o",VSgnVtAʑ#%"SAGř~~zf~huҗf݉cz/nߢb4425N$wŜhhW V쨎?hLh*s'E7It~}q:L~A&=^9r?ȁyϬŐ3wCJ!1f݃=#"@;Ep A/- 3~c}= g+CD+'xq;>lpvT2תC.{䕭&S:to(  =9 1#ŨI`V?3d,M?޻Z3>_Jc:qfb7,ADh]h5} D_Τ$R`A5۾;G ^Z{ZL z g0zEQ =`JM*2J{uVm\3dN3 k@j:7DyϬA[\,p2D;{xhG!}7|i)08[^|W*7 2{ik6^}!WD7uڭ*do{cu|N{&`KF^۠[[h'C+&y~4ĠXw}z\ '+ |A<􊠓 x5}>1Fׯ ^f`;"O]^@" h@_<:  *m5lI$|L O?B&"G"P= c+H>NfD"DtA H @)_5@ |z"rpuXm :@ħ6<Q ײBF#oE:z$>CwL" "60ļG8I59U0>H5[yx  "x[3}^l$ˈts{]cfh 8>O}i }tl֘ÿly&Ɇ]9TH<` <lj=Ǚ 3<@Zm-C (o`!e^a$>G$ O 3eF蓱q#ALz(5!YN30wC=)ȮgBXzDB7!b$!ᄵ?  o{S&W X`\_xcIb}𒀅A|3:=IʫDT $k"Oi ߦ9}'ḴϾ6Re9b]S?aKIb:"qB8wĶGSwuIc^8JL' 8@ཀm#IYx=9ffPG@T=aS+Tґx虃Xx&!29bSP$z=H|{9+9ta3$3'v(@k! Op8]l۶&"rЈ:umm*|X$_׷~q^چo%؁?qM "2Vċ*f}hM{x$i 4mtpޤog)e>3x6rVtk'o#4zF|<6r!"H"v'(ρom(uSLIzqBfQ^$HϨ'0P(X,׺feaiS⭗7ۺJZx5![m2^,^M`8gk+8f StEQb WWYݱGT3.O`&W{af@}S,0~.G _MQR>er)/ "7]HlR&Mgp'5U{h47!dg-ACpn"q`w^ػA 3 &;u)"1mI OTwWQL*OV#ޚ'gNasEٳOF!vۅͺgƧ=e;bރR4PHZDmSr"ƷU>2^`]#2-ψ$̴Hd d Ĕlmu*ENf$ $&Ta`ӭ 1}"vd H"&dL-:sT ~}jS֘ͰTĊ~v! P$H }8" Th8 k{Mn3ǬH(R"1^H&)<ɛ3I90D`qBK Zo 3A%] .aQe:g݃`iQ3T*OmCz-SB #%0yUF$r*&s Emi` LK6HāW?wmcϯ9$&4g#!63FKp0T( QGۙTQҳ"q &fP''9}&j@e; H;C?'x(CVX甾dB;0Í^3H`Mv3!ߓX!>6g\}Deo҈:C_AS &Dt]J(LT}`2N\A] '^~] RvbgS/1H|\ gX #3"ßIu1BBC%=TsPAR9d{5 PA7Ib3p(1kl!:_ag88'3L-, i;Q50g, u06 }t})DwhtԶUG 2@yo؈fR;zNLۇٙΧ%d6x4P;DW߫%\ tщ,m;<!=7>wOE >X0ǺgH1'Xe R dyhI{\HKϙ֌wdzKwo9skIfypG8u~:4HICՙt0 !Nc5ĕy1mgXٌ3;+վpvT)=>SXpiPR 8a|Зu+LTP0 $Yvd&пocx@4i_K01є:.0[ Ţf Vf^9E՛ӓKXJ Z5؃E7;U ![)fm/oȠN!8iQ/̀ѐ Λ'o#;Arux{p[ Z(Bct{ 9Ae16 N3 ;ST.dĜȔ~.LbSffe6DU1 :Ép3LpN^K얝$ IbA#΅ֈy Vy~7dzҨfh)*?v zbY'f@>uH\mi;œ,aJxuliI H{&cgP`$$!K#dJ۫o{C?ڿ'DȀ!JUXpf%Gu76Ψ #J^b-PGCH E7 uK&]Ϡz9=AKY*P{%dYyCv;k}LL Apf'H'a#I<"-8͓`b2ց&Tj&eKCw*Is*JoԎIlG8/>Sd]Gp'=#>@;X%9AxD1y?9U;1@"ppi+0qL 8ݸfb0E`؍!Uz;NE$Y#J03ALT ]85haۼsPZjS*jR4!"z|0/M8'\hTy1Z^(ck+!n^{hH:D,ռaFv]*12@&KM2&(X(b{8;뺽\L| (?"V4Ī0Rߙ=zZ 6gA%+(504غ1"&uJ$z#sT&]X U2 h,Z [zB3#!2&_&"8l 1b3T'`j"c!:۲ bEk[[D:p;Zn rqs`sFF#)iINYe'y5Q2PΚ 52| LWL2"M2t]TOxRGaǀЅOB!:yS@A԰t\؜)3DI*[t9ѳfǖm|v4ng{(s)brѲN2Cd$mp[1YS-UM=ohTGIuvϖa Zd_ti]VM2j:|b;` x=,k2B잙|p7j:fhZd]lӵ,HrE{ sXRՎ`rzDsDH!1S!I#܄!boHR;\-X),}1i{ϋi'>lvnj HۿaoF{"=YsV= ,^$tHX"Il6ov$ĮlB: %սa쀕9$F4 #KG8l8EؗFP>t#&0Q2("%Ma#c! ڙ4MBHL`DH`+"q٘aR\-\!FDz5zX=aAAPiꇨ¹"o[11V>[l"#hd̛ N25(XZ A7uBB*(A$Ǥ`|lYټZoG*0m"j'[rmE%8rXDӕY`uf@zStPĘ2 Pƪ*Ԕ7.LYKGpBmd``[Y3';&Qp ۆӶSآ a?H:U%rf0%IPYr }"ޖ•u)yyټNx(EhI`*H+BjOJBA9U,(HȖFYU̓^!KQGj/x  K(J6 lɃӨL A&t}0ڳ)qnFVwbbSp F Mǖ9 yu%!52`4*倱 HUV QXKs ;b*jsV2fi̓:I4 #uh$xA!1(X؞sDAj*@HDTt d&ҪOo0%Zs%D#5rv]+ c|P^at|[W H΁=Bd78B9.2Nab[ fߦU]˒7 IoJE@\YoOK"LG#g@b,ި O9DraD'`(D>E]Ggwdޗ^T\|_5]L9w_(>{@iV9 @:N#% b4%gD H lzN;w}513IF!&\$oM KUcLc;ϑ;>c} Qy*+jW[xD^lõV7 xTt>4ʵcdl0.&T8˽ÑŚDȝB& <m܂&AlcE"t28Ԟ-.. šWtG$_Dcu; wK}}vpY1vohyPt)/1N[>R$R/#=GHcd}!Ɩ@)h.tկMLJm5#7xOEHWBD^BK20Q6Gn}"nA˓O 4W}na{ۊ IL&3g}i "H*1E@9r86H"@y%_vnrcUܜ4^Jf0RIZdfO 8ְ0/j8Q}2G]$,zDayE1A`; yvuZgL{L>Ҹ\} -',t&&V#BoeQϙs/5F5>1 ̫8`޵zh/t9luMKۊ},3$sx.f vko̤{[ 3!k@k& 5ظg\Bʞ%+^ZTtBM0X8DrDOhw[rr 57Vݴ2J>U"x8$  u\`Wb=UחjA__H䒈رmrkys~E"JTt:yN^AKPV*0/BBZ"|~s J>ϰ@WJ$VEw>ͳJomUŵf#xdé|d$"4Cu4!gnt0^xDHp1hڑXAT;7 " FE,H ̲si 3@I6QLH9RydE 7X +pL@9M ⼹FQҝ&,8[X^foϋU [ ϟRH0Rh,FUK]!řlLSD?1Ӗ899睇 Yd"(CS2\) J88zx?p< {h "WY5u84Nm&4$z_c9K_ȏV\4k*`os %NIaf'5ujHWiU.iV$iwQt,Yb+ qRoab3Ab 8ԌD`nCbvI{?IxIDATYXA:^$pM)TsSHcf7&2_&"=3Rh4x%XYx `*yGC+5D:XPTzWNC ,n}b9\M|%\dĪ"{@1E9{搠K买ȕE1K"?"Yj>U} Aq-^³;W]-T$1tH#h <%DdGx4 8BٜtqcיoFm=bFS_A^K*!;@*yM &MSE`8,UP^;|dMVa0Bw쪱}IENDB`torbrowser-launcher-0.3.3/security_design.md000066400000000000000000000060131373720147200212540ustar00rootroot00000000000000# Tor Browser Launcher Security Design This document could be improved. At the moment it's copy/pasted verbatum from a post to the [debian bug tracker](http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=752275). ## TLS/x.509 security torbrowser-launcher doesn't rely on the CA infrastructure. The only TLS it does is make HTTPS requests to check.torproject.org and (if you haven't set a mirror) www.torproject.org. When it connects to these hostnames, it uses a hardcoded certificate. So none of the TLS PKI issues apply at all here. (And I took extra measures to make sure the .pem included with torbrowser-launcher is valid. I downloaded the cert from several different internet connections/ISPs and compared, and when I had one I thought was correct I sought out Tor devs to verify I was including the right one and not a malicious one.) ## Downgrade attacks Downgrade attacks shouldn't be possible, unless they're committed by Tor devs themselves. If an attacker captures a valid old request to https://check.torproject.org/RecommendedTBBVersions that claims that the current version is an older version than what's currently installed, torbrowser-launcher prevents it from installing. (And by "installing" I mean extracting to the user's home dir.) However, there is the scenereo where the user has set a third-party mirror to download from instead of the default. The third-party mirror could serve a tarball and sig that have filenames of the latest version, but are actually an older version. This attack is mitigated by the fact that all mirror options use HTTPS -- though none of the mirror certs are pinned, so in this case it would rely on CA infrastructure. This is an edge case, and would only work against users who are using a non-default mirror, and who also have access to a trusted CA signing key. ## Installing Tor Browser system-wide You cannot install Tor Browser system-wide. It's released by the Tor Project as a bundle. There's a lot of code in there that specifically prevents it from touching any other files outside of it's own directory. All files need to be owned by current user, and it's designed to be runnable off of a USB stick. A long time ago I put a bunch of work into tearing apart the "bundle"-ness of TBB to make it installable systemwide, and concluded it wasn't practical without the Tor devs releasing it as such. If you could install it systemwide, there would be no reason for torbrowser-launcher -- it could then just be a normal debian package. ## What secret keys/access attackers need to succeed Yes, attackers that 1) have access to the trusted keys included with torbrowser-launcher and 2) have access to modify files on https://www.torproject.org/ or have access to its TLS key are able to get arbitrary code exec as the current user when they open Tor Browser. This may or may not include any of the Tor devs whose keys are included. But like Holger said above, this is a feature, not a bug. This is the whole purpose of torbrowser-launcher, so users can automatically install TBB updates that are signed by Tor devs. torbrowser-launcher-0.3.3/setup.py000066400000000000000000000102611373720147200172440ustar00rootroot00000000000000""" Tor Browser Launcher https://github.com/micahflee/torbrowser-launcher/ Copyright (c) 2013-2017 Micah Lee Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ import os import sys import platform import subprocess from distutils.core import setup SHARE = "share" # detect linux distribution distro = platform.dist()[0] def file_list(path): files = [] for filename in os.listdir(path): if os.path.isfile(path + "/" + filename): files.append(path + "/" + filename) return files def create_mo_files(): po_dir = "po/" if not os.path.exists(po_dir): return [] domain = "torbrowser-launcher" mo_files = [] po_files = [f for f in next(os.walk(po_dir))[2] if os.path.splitext(f)[1] == ".po"] for po_file in po_files: filename, extension = os.path.splitext(po_file) mo_file = domain + ".mo" mo_dir = "share/locale/" + filename + "/LC_MESSAGES/" subprocess.call("mkdir -p " + mo_dir, shell=True) msgfmt_cmd = "msgfmt {} -o {}".format(po_dir + po_file, mo_dir + mo_file) subprocess.call(msgfmt_cmd, shell=True) mo_files.append(mo_dir + mo_file) return mo_files with open(os.path.join(SHARE, "torbrowser-launcher/version")) as buf: version = buf.read().strip() datafiles = [] for root, dirs, files in os.walk(SHARE): if files: datafiles.append((root, [os.path.join(root, f) for f in files])) # disable shipping apparmor profiles until they work in ubuntu (#128) if distro != "Ubuntu": if not hasattr(sys, "real_prefix"): # we're not in a virtualenv, so we can probably write to /etc datafiles += [ ( "/etc/apparmor.d/", ["apparmor/torbrowser.Browser.firefox", "apparmor/torbrowser.Tor.tor"], ), ( "/etc/apparmor.d/local/", [ "apparmor/local/torbrowser.Browser.firefox", "apparmor/local/torbrowser.Tor.tor", ], ), ("/etc/apparmor.d/tunables/", ["apparmor/tunables/torbrowser"]), ] datafiles += [(os.path.dirname(f), [f]) for f in create_mo_files()] setup( name="torbrowser-launcher", version=version, author="Micah Lee", author_email="micah@micahflee.com", url="https://www.github.com/micahflee/torbrowser-launcher", platforms=["GNU/Linux"], license="MIT", description="A program to help you securely download and run Tor Browser", long_description=""" Tor Browser Launcher is intended to make Tor Browser easier to install and use for GNU/Linux users. You install torbrowser-launcher from your distribution's package manager and it handles securely downloading the most recent version of Tor Browser for you, in your language and for your architecture. It also adds a "Tor Browser" application launcher to your operating system's menu. When you first launch Tor Browser Launcher, it will download Tor Browser from https://www.torproject.org/, verify the PGP signature, extract it in your home directory, and launch it. When you run it after that it will just launch Tor Browser. """, packages=["torbrowser_launcher"], scripts=["torbrowser-launcher"], data_files=datafiles, ) torbrowser-launcher-0.3.3/share/000077500000000000000000000000001373720147200166345ustar00rootroot00000000000000torbrowser-launcher-0.3.3/share/applications/000077500000000000000000000000001373720147200213225ustar00rootroot00000000000000torbrowser-launcher-0.3.3/share/applications/torbrowser-settings.desktop000066400000000000000000000014631373720147200267670ustar00rootroot00000000000000[Desktop Entry] Name=Tor Browser Launcher Settings Name[fr]=Tor Browser Launcher configurations Name[hu]=Tor-böngésző indító beállításai Name[nl]=Tor Browser Launcher Instellingen Name[pt_BR]=Navegador Tor (Configurações do Lançador) Name[ru]=Tor Browser (настройки запуска) GenericName=Tor Browser Launcher Settings GenericName[hu]=Tor-böngésző indító beállításai Comment=Tor Browser Launcher Settings Comment[fr]=Tor Browser Launcher configurations Comment[hu]=Tor-böngésző indító beállításai Comment[nl]=Tor Browser Launcher Instellingen Comment[pt_BR]=Navegador Tor (Configurações do Lançador) Comment[ru]=Tor Browser (настройки запуска) Exec=torbrowser-launcher --settings Terminal=false Type=Application Icon=torbrowser Categories=Network;WebBrowser; torbrowser-launcher-0.3.3/share/applications/torbrowser.desktop000066400000000000000000000005701373720147200251270ustar00rootroot00000000000000[Desktop Entry] Name=Tor Browser Name[hu]=Tor-böngésző Name[pt_BR]=Navegador Tor GenericName=Tor browser GenericName[hu]=Tor böngésző indító Comment=Launch Tor Browser Comment[hu]=Tor böngésző indító Comment[pt_BR]=Navegador Tor Exec=torbrowser-launcher %u Terminal=false Type=Application Icon=torbrowser Categories=Network;WebBrowser; StartupWMClass=Tor Browser torbrowser-launcher-0.3.3/share/icons/000077500000000000000000000000001373720147200177475ustar00rootroot00000000000000torbrowser-launcher-0.3.3/share/icons/hicolor/000077500000000000000000000000001373720147200214065ustar00rootroot00000000000000torbrowser-launcher-0.3.3/share/icons/hicolor/128x128/000077500000000000000000000000001373720147200223435ustar00rootroot00000000000000torbrowser-launcher-0.3.3/share/icons/hicolor/128x128/apps/000077500000000000000000000000001373720147200233065ustar00rootroot00000000000000torbrowser-launcher-0.3.3/share/icons/hicolor/128x128/apps/torbrowser.png000066400000000000000000000214571373720147200262350ustar00rootroot00000000000000PNG  IHDR>asBIT|d pHYs[tEXtSoftwarewww.inkscape.org< IDATxy|T;d'dI@ADqTJ#.ZnjmڟOU[)TmRÃVPMv!/d23%3r'D?ds{{|EPLZ3.SWL @R'Z]ͬWw}q/ x2D+y.GP dW EPb7RّRrKia{/$a@9۳]P $᎑Ȁea8Ae R?rRQ!FlKy%0(+9Z@] )WI!V]>i{L'?Ixz1SY cwpͯ!~HϱrxMs^jꡘ-Xe^)vt]./{Ƞe-ŧmC>R>W[ټYΞ ;<6^ [һ*\"AJ~=2DV@o]8LZŸu[nb0yȤbBT}@/N W1}uBC<;|"}*$f)HL:MPh*:/m܎-߅*m}q>!LB)9޻.w( B_^L^haȨ4, , 4 MP!jF*4RekRO ةH{9U/ (ȿHzyUyof4'윲0Gs&9Bt:[)khO By p/zS_Guz::*&,7/ .&?:eֱ>Ņ@,lqOB`^ӧJ\]ץ{bAE zD:F%;_kZ23o**7>qFQֺd.G0ǻ߷ǣ|go4aeDi F/m.drZNtbtuӛ$-5;M1L )@XQ7:]wxrYYɖblRϪf0^}r>ڹ҅EX$ONoG ztդp5ù~TE(=V GlȎ5 Yj1[׹F`HG:f,Ø0`I$1ɂ59$$QDF~Y%cNR=U8M~QsAO*bY\]|B"^ ^hzC@EdB FL`9ihC$eI)Ճ}yE% zE) ƻ.{-TJ=0$@0 eܼ\FNS,ZϚKĮ?!Y9Ꞵ(EH}rw,JR_ 7t6x2:C@ ޮdߪJ\:COMA5`R'2vn.5i,-+ᴺdkZۋc@h[t^L`B fOUFB5=论эuZ^Ӯ5.-!jK{CUcsg'}Z~! ;|NV>Y:|k=; 9g([b Y7Xײpsa/(f^!:%GwT4joifrǦ#FsfY\ ,|&mYՓ>_G  OOaj\|YcuObgz33pH3P2%@4_gDGo|3>4SfDſ܂%|qrI"uk-.~عBD€h>sJʷS_f٪<4ͬqasD|C{S͕mtD}LEІʨ H׭m;?j-{$_g`{IKI:zV_{umZA6U;%yѷ 砚6W19i(#B56+0R"ck/rWe#w'57Ъ7yTO6!HtUԶuJ хRyk:^R+ Q* gFd׿Ik.z}ŞU= zK}K:(Ggg"?m*v1%ϋVلNhāN=2lhJv"VǶG鰻HL571/ ޵G ˗x}WY990o[7ÛGѩ|pX ? @Jy/2ޏ} 2rb6#A|u G[hM(ooHwKq:Bw˟&s2cU{OtMLjS>Iǒ9*F-m15w[:F;,>Ycٶ8.䒑vUc2ZȚ}p*J{x ZQ< z)Lz,<W=~!iy)1곥i|&8chC2K7тF䙚lyuYwΉ skfܬ<är:\lx$ΚWhH-}ƮR,Ʉ:?`j\Lν-wۊa#9f5:5jy%tI=np3$igS7X&NɮJ.8wX\N=2F 4C*@JY7Z\ȅdL1D +wTcշsLB$#: `D sonQUav$cqĆG_P(ҤT拯F-tQ-fM`bZ^MYYf 0eQ(99CJ`.A~ǩ8%F-HxX-FMiN6D8L.k 3ۙv{s,8L!D * 5;̂4GmX61-#>ĜdZV ]&H_ӟ_3 9VNno:N=dgRU3F]1kZ!e%ZMHP3ɐ,4'ya@~zʱx5+QtZop=6Wۢ>Μ>0t ЙVc]v i/@ q4T5GrXRR[;eha: vhR6@G.qCcU eQ?!ya6E2 lT Π'#8-Hhv4H-rPЍTC)a% '8q.jyCF&6#צg5+E9%0ƎptwUԲMP8ixX5׵F-/+59QV} Y[DvQ,Ctt: w7`yL>E!yY P}.zyRO Yo  uCQcvN7.BYr:\V4F-OGyXmTAtLd}`,g95>7ZawzhX#.c< -Wv[/j5?fVu˔l}{딩ya!y%vewj.U@Éz/='O!='%vSg{ Z;*6vGˎÌwHv|0Xd#6hi ! #bȈ4q۹abњfpbÚjmT۹/n;t j b`gh„W\LU?Kc`9f=JG R*$x .ϒ_M@'(b#`e&a1g]}09A"'~b!oO`cu :2Ckr:\ kԷnt9S}+\O?dHk +wG-?ZJ<#A+Io2Lt>,{xnvzyɐȌk&g; Dif pƳ'V.%R ֦Pij ٷomj?[i,R̼a Z7zuoxd/pZgVtBK1FFK>u, \|C`'_4F%aM ),Hwf'ɬ1̹ xnAb%v{k_d k܅˥*CB\,&.fo9` y+6&Y Lx+V#bu'ʋ+ƢC7P gİrdZͤ2f(;IsNǒyWOxB BB/C Tv؝ &IW* ^߭R>`Ǘ"A &I"9%$rFe1\ Ə$X͆'Œdc.7`wbԂ| kc(tn P(WH + @.Xm_EN~v#xQgklV1]Kv{`n}Zע V7_݆nr=ENgw((4Ds ~{ 9v|/d"G3#5+ZCKcy2t[] EYC5켹h^; ~:>q$$$wH-Nj8QZGkc{@L=p-dݥĭ`fY.Z_D1;\˿wx+nAz#g"l73M2lϋW}^9/5hz0 p $!SEA,dָs};+/˩::ڝ~z(|#{T&>&]:!s=*sIĭ+b{oq%@vg@Bο|2w/#DuUy7c/]njax&F]i)@P'JTi`C܂,n| &?>x3^zteAa7\;Ĥ??]f :k^($hͨhOHL/_Eo`W,z71|>OYVteO`X5ݱ@6ne.b 3$F}Y }כJ,HCWOȨ'u@E"-r utf-8&%n1<R>b=Sy^"n]O% 'U%Zw0$rά )L~jL{AK4T!I:)"bntRkJ͑0 ~b!RG r)>+ 2S9eb)Sgwy5:{^gjJ'ʇ8ˇ&nWpu- {MϋV>I#؜u2O>Neu5}wkj ;N |}n;I-u,v[n769] OMmzOPQJf\ $C`3HK 7Fvo {زv;m-QmyǪvoHŪEK%߹E 5gz{iT5) 'e;x=[RqL4,Xռ8&gM/yw]`翧Xps/os&%;$CEkcUGj8~+dIDATǀg[YbVey Of+=DzkgK1(^Q%띖IA]gXSWhS4PAKLiyfK_s#Ue1^+7"~okwv_"i >P!Hw֕88խKMo1CJ~$U9rfqL6R[FL=ʇ~kwnmoq&$rӳ:E0SxapDA Vu[ޣo̬;S c냉o-IoBhJ>~sq ^̤H3']!!lHdZ݂ x- HH2ZW.c1, sꎦ  @@IK0 I7)/sUe7H ~~$.$r|}] %?pǥ)7e"9D0 +`@NۄdhmZRg41 RgPY( 2W8Џ R)9 R4^B{EbP ̔3!ap${">qU]-WWkQS IENDB`torbrowser-launcher-0.3.3/share/metainfo/000077500000000000000000000000001373720147200204365ustar00rootroot00000000000000torbrowser-launcher-0.3.3/share/metainfo/torbrowser.appdata.xml000066400000000000000000000035541373720147200250100ustar00rootroot00000000000000 torbrowser.desktop CC0-1.0 MIT Tor Browser Launcher A program to help you download, keep updated, and run the Tor Browser Bundle

Tor Browser Launcher is intended to make the Tor Browser Bundle (TBB) easier to maintain and use for GNU/Linux users. It downloads the same TBB from torproject.org that everyone else uses, and it doesn't alter it in any way. But it does make it much more usable, and it makes the task of keeping it up-to-date more secure.

You install torbrowser-launcher from your distribution's package manager and it handles everything else, including:

  • Downloading the most recent version of TBB for you, in your language and for your architecture
  • Automatically updating (while preserving your bookmarks and preferences)
  • Verifying the TBB's GnuPG signature
  • Includes AppArmor profiles to make a Tor Browser compromise not as bad (in some distros)
  • Adding a Tor Browser application launcher to your desktop environment's menu
  • Lets you set Tor Browser as your default browser
  • Optionally playing a modem sound when you open Tor Browser (because Tor is so slow)
https://raw.githubusercontent.com/micahflee/torbrowser-launcher/master/screenshot.png Window to change Tor Browser Launcher settings https://github.com/micahflee/torbrowser-launcher micah@micahflee.com
torbrowser-launcher-0.3.3/share/torbrowser-launcher/000077500000000000000000000000001373720147200226435ustar00rootroot00000000000000torbrowser-launcher-0.3.3/share/torbrowser-launcher/mirrors.txt000066400000000000000000000022761373720147200251100ustar00rootroot00000000000000https://dist.torproject.org/ https://tor.crazyhaze.de/dist/ https://creep.im/tor/dist/ https://tor.ybti.net/dist/ https://tor.0x3d.lu/dist/ https://www.it-sicherheitschannel.de/dist/ https://mirror.freedif.org/TorProject/dist https://tor.secure.voyage/dist https://tor.127001.ovh/dist/ https://mirror.oldsql.cc/tor/dist/ https://mirror.torworld.org/dist/ https://tormirror.tb-itf-tor.de/dist/ https://tor.zilog.es/dist/ https://torproject.ph3x.at/dist/ https://www.torservers.net/mirrors/torproject.org/dist/ https://tor.myrl.net/dist/ https://tor.stalkr.net/dist/ https://tor-mirror.cyberguerrilla.org/dist/ https://mirror.velcommuta.de/tor/dist/ https://tor.eff.org/dist/ https://tor.void.gr/dist/ https://www.moparisthebest.com/tor/dist/ https://108.248.87.242/dist/ https://mirror.ntzk.de/torproject.org/dist/ https://www.eprci.com/tor/dist/ https://sela.io/mirrors/torproject.org/dist/ https://tor.ccc.de/dist/ https://tormirror.snydernet.net/dist/ https://tor.calyxinstitute.org/dist/ https://torproject.mirror.metalgamer.eu/dist/ https://nl.mirror.babylon.network/torproject/dist/ https://fr.mirror.babylon.network/torproject/dist/ https://cyberside.net.ee/sibul/dist/ https://tormirror.tb-itf-tor.de/dist/ torbrowser-launcher-0.3.3/share/torbrowser-launcher/tor-browser-developers.asc000066400000000000000000000153441373720147200277750ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- mQINBFSOr7oBEADQMs+Q5cAshRhj3YkKgCBKyrjFWMZqVhlf9Y3ePtFQ9kFEnYIS G9rzMhFC6KMXPn9bgg6OBPPUnnJ29UsKvAk+qa8F35R+s0ZXmPRfmv5/6PqxLOn4 G733K67K0/eXYW1mTkz9sjY8u9E3T10JNT0zE/60WihuZGKZQDIqqig0fOsdvdGa g+srAW91T56kAT+y59VcvqVCQNjS897E3T9hsUNkQNCdOitQcnN8/5VNQUL0SjyD BV0y5ry+pUt1rnojj82KQ3WzZuD+XsDE+w2JSGqhcqf9b7D6puy1smhCNwZJ9L1l pJlrCap6YQN8TPFTkf4aFBctxonAdQDDxbON6sPJALc/myPwTVTxD3nJJhv12yft 2iwZLaCJcdq6tp96re1dwaETpvvKeWqhWGVkmNaAPhShcCKpVYC3+Jil6nTqN6LI hKD0ILBGOT/2/Rxd4kj1uDzvc2RVHe6LKLc5EQYO80/wSIL8LMdqZSX2R/AnhcNg G/k7yOQWWNY7RPU1cV+E9QKNwqS4Zj2VyU6s6ikaPuUnjW59iMkSGUuS+gJUR2hp jOKjNzu8vxbotBgZ01upDUdl69OnR1dv9X+bMzGWUyOjAjK6SP8rFtWFBjWgWcED OHu51YpicSdN3uf7lppEXGx91n45xVMhL9d2KNp3DhWkKDuWhdliWC/r1wARAQAB tEBUb3IgQnJvd3NlciBEZXZlbG9wZXJzIChzaWduaW5nIGtleSkgPHRvcmJyb3dz ZXJAdG9ycHJvamVjdC5vcmc+iQJUBBMBCgA+AhsBBQsJCAcDBRUKCQgLBRYCAwEA Ah4BAheAFiEE724obdqF6ipLp95oTixuh5MpgpAFAl8XqaAFCRPu+2YACgkQTixu h5MpgpASEQ//fiGjtuwF+xAB5366e0ciTXKTKq2ar2uBgeKnAl7h862ePLE8MwIN 2d7t1eGBdyr1B+CK6XRkeHtRjN5feOLOKQYy6UkPfSZZnSt/pXqH9bCZWIlejpFl HaNAUGFMbmtHzJb4ZEto3B0/HGAAx/1xiHP5GspdEj99H2T710axz5mCqbt6BRv4 twZCEWQ4LE1GGn1NoBaf0STmF7luKC3IQi/H2VSc2LTJLQoo5Lnmr/w+jZ4N9S/J QKfeYQmXplbHWtG+AQh9VxDJxfK8z85zwvosR0LuUpbvn9Jsn8sFwB2TA9jLzPNr trBeotx5kcQm1ae+ETiNQdtJ8JzFHm5a5UmViZy6/zyK0T4PisKu7J10mZ9bBBro RXuqmxWqnD4GV/knKECE7K2DUeS7HsJin/hVc2OaHckII1i2Ced64tVfP9I1H/QX HXeP4AVkeDnwPTVDB/1R3RCBguqm0fkqGBW9HNTQz8ju6hiNdtTtLBFQ8rYaMO8U YVfQBFtuh7zKwjSnt0gsN3J/FEcHMIDto5mkerL3GrEnBZeXV8M14BdBOKiw2swK ibVuXhmW8nWdKO7evK8O+xE7W6wE+fWCghW3VLM8tnVlpMkmTTxQATbZ74Fhfor2 DT8Obn8D+IK7Vzv2NJbtX9j1S8bz9t0JCuKIHRClF7ijJ0NyQEM6xbK5Ag0EVI6w 6gEQAOSdq/N0T8db8PTutfkBRVtkdVpvhumkKWbjBoN4CwA8BVZSAfdgNCE74tyP +k7Pa802eQBUE6f0j4rD8E7ohGO61vo3ZLIIMPGCQOLtvOThNKU8ZBnCPdUbk6ms bPmnfh9Khz33zGkjozzr3uLkRDKqgwCu22sgxMMa+Szs2yBpejab4mSRglNgEgm1 sLxoIUBX2DzuV6jh4+J3jCCSOSUDSl8HF3ELaBebNo2VegGdvOqTOKPLZp+8d//8 ezi/W62wUhxJltJsFPRKw3rFkIeGgSUog5ooX/V9V9YO0UsDmCO3Vgy5s4byctgC uEbxa2ZPabwrRgpaXUgOGu/a5PDO1veesCJhKbAuHvwgntaODpY6PjmnNA/9QzrK hUpAYp4jeSANxtd2tLFM+n/HwK4n8yxnBcM2dqc2WebfZDHNzNyqCGv+3CugTouq W97cgJPbS7IkEMAVm2zygMezx3y3p7bVC502SxkGsnLcw9H+qbBSg01v8hiKVtI/ 7jFRQxAHSmpQOtk+Y7jApxox123BGOtJKjsxkUo1GEk+rIpCkun+Dk13NlYw4DNt IKPQBngx+OBNi9XLS0s5ZslfOwk4fxTdJlmNAGLmXvsVyoOAsJo+Kt7HH5KKKJL7 YUrE7a658G/6ZuiYy9XbWI40tLpKrArFodTON9W6+AeqG1bRABEBAAGJAh8EKAEK AAkFAlXdoO0CHQIACgkQTixuh5MpgpCV3RAAizJNW4PdKa90EiAVL63tTlz4+L4a hPFNXYeB5WXt/2fZS97B8kr3uFP7GnGj7ojj4/+9x6vTWiFguHw3ZGpJRkWeoHRL ge+eAxl9AXXtMDdeJk0hzqd14Nj23eRmssoqeAtQm1zXPvmmC0ybfm7CxnAIdvZN CITt4J0g6bMqyerR2550+ZY6mAlN/x65JNfmG3XJ3Xo6WKCGy8haOjaWrcTM9BR1 wM8266raCJakjZXLhOLJWMRAvcYIwpCdKKATe+AcoDT5N8gQJmgDJjXRfstGLPkJ kmu9hmo9AfLjrZhtqRGexmaPnqb2eQSvlzuADZuuy9GyIx5+t85q7OHs77pyYBm8 8so2LkJbwhL51XNJW6z6j1jX9ubbLgZmJlAkx8nNmVMWPexKHr2aE+nHkRmuS9e2 TIK7o5cutlt0MuIRjBz5SLrB6m7TH543/Ym+h/vWxjXSGFOeMfVx6e8zpNDu4WmR PmR8QlHXrnOhlWuwFY3kIGaEWtWIxalKz1XyZijaWnZ+AIbAnfLhVPTjcwaky2Em 0NDQqCLwk4jwuWUByzwVurNJkwAwlhXVh3cAyV8fiwDXopI4RzyrgcuW+yLyCsXT F0Fgp7KzYkfLo5M9OGlKvPVvLmCzu+oRif2EGVBdGj7+65pV4E3/YTdzsw8EdYBZ KKfetxATY9ZJcBOJBD4EGAEKAAkFAlSOsOoCGwICKQkQTixuh5MpgpDBXSAEGQEK AAYFAlSOsOoACgkQLQAJiFiYOaO2UQ//cmWSSkfbgSPwAT5cFnC3ipqcFvY+L+/O Dcp723unIwfslaSDssUZKlBMgbj8c59EZqEbrxJA0rI9L4xTCG2pCusR84aeZd/5 NLYXVOopUYiwWk2I1KLnNbhDYYGWHANOw8Y6ycACOWxGOSDDB6CrpQQMlhPPdfW2 RtjaIUfihKv+F2mA54jhnasdCaAk0aGkdJmJ04/2BhkwWpBepFpl6+WMwe1oA0lN Cg/eXhoxW8BT5ExK6w0lzp2/4P9wZjVtAYpOOU9SdHj7g1XpH6vavapQlcz8Nfw+ ByX6ZLIr1YaQpOsOr/EBcjyw02LCPiP+tIo/Bw4o8jm8+OIt/qnrEqlwBLBFlQO5 Nisy6Dr7uyqEALv7MGbExJm33jnCSyHR5oyRDFI4BYip2PdFZ5WAUKZvlq5+lh+Y d3Bf8uC2ljMZD6Ed6rAp00M4MWLnzUmrPg/4JzWc7S+V5dBZEhEWJesPU8T7xr8u tG7b2LxFXYzZRq5jSyr62WPMbLHzlRTIdzsBdNsBnJLgo5PCbHwIQxGXeJoHWd+Y THtMORBF3uCpC/AgHKioU551ipcx1e8aFypskMxZZRHllTObwKexeO8c2fT1V9Gv QnEn572l0QpY9zz3duB83s80rpHnl6NjRowEbPuqBKpLIxw3a7Wo319qRQDYOFm9 TXrO0CDZ8MY7+w/8DSi8KSDRNxrMbhME1R/CcSNoBQrQOoGSJLdBhW9QSEjMP+6h ATkenbGmrVxl1mICzHuqXgr+JW92DbPwR8z6A1k5SO8V1xOesX7zgt2sy5RvfNZe 9mmiaa0CxeY6YG0NaqF2+OA5vvpHXh3vwGOcN481rTLdKF4lQhzvpzdHlYUTYwtf 3MIwAOJdzsZB+jGJphRh6XS+mTABtAigXFAP901sRfiL+41Zo1nQtm7sjBVhHVEI SObFZLTdXwvTn5ufw+3rmY5X5n8A2QK1V9j4y0DYFk1P4dW9OoanWU/kLRyqPDsP jr8Ey0UeZyEur4HXBdFucy1Fn2/EtUFTYWaPOqyVl0/IlKTlfGY0566l/n48kwOx /P4PHIVr36tE6XHPRB1d6ui6fpzjm2FgC7odjna2gD9IhHAeLfjG1wvXXHcFCeZH df1B0nicivxYAGb0Nc8ICl89WMfKp+/LMzD08Alzz26Mfmglv6zJx2J0b8puMEtT iM4ESrDVrMxewibZ4cI9e1g86WXGPlIZ0ApicFlr69bTIPzIYNmYwWqab2tqm0MQ VRpNDWMIkWJ/r3TTmNN+Fqv827Fo7qR8zjPVi8DyoKmFzfgya2ZoE7od5bGg7lcM 7UhzEPfwZUMqKaawlrnzqy1sGLJi0QZErUhHo3tU9sHYqAtUENvs4LC7dEG5Ag0E WwnQdAEQAK8MRUxjsvvZFGt3dScnI20cvlL4LM3ReesedqrFEOcZP8q5kVxiu3n1 zT64BXRza2EiYPttymbh56ynLk/SxxcM1qdGhn1qwdCEav//TYJK4eE0ZRPbdOL6 YY9hkfBPZUONBD+YYnohsOUnAYRNaRsSjlAwsaoDauJMSOGl7Fam0E2GDvzAYeCE jE9SYFwW1jGGmvEKjAV9zqjeMwH0A7NWYuTo9VXmCyxRPPhAKw/3XsMuJ1WOnL9r Pz4yo2ZQlyLf342IFKpvQLw+H3NqRYpJa8P5bi1cKYGHP97UZFHLOu5rzvoyFmTU 82H0oc2BQDIacZzwmVVwyM0wOg4evdRXmv/2KvtuwxosF58kXZTtCQ7miWRWUPGM X4PR71I70KBBDcLWZMptmW8Ey+oE7DjOUMv77sGeBZdF/pBW0Oy4qgNF/tX//Nko I2dKBBuEQMikQLgfuEoGF/5zueWJdLjEDESeZB9nXgWEaADwiH+nzcuUYivCYR2y szRpRTv2GwcUoYbT1Cb8L3Qy77xq21BiOxs5OWylfUS0yLZN9XOP/qwa5MDPmpS1 kAw3IcBf9MA825PFxXQY/mv9rvd5gmip+vfwBT8F3ZvXzQHAWBF0bXTONmp/Cxuj jE1PkJBQ+mOg5x/wyYEVw+HkfZgSIwfVFFJ+MXkKYeXXVHg5+lubABEBAAGJBHIE GAEKACYCGwIWIQTvbiht2oXqKkun3mhOLG6HkymCkAUCXxep8QUJBNOafQJAwXQg BBkBCgAdFiEEEQd1tdEB+za8bJEb63dEkdn/BuIFAlsJ0HQACgkQ63dEkdn/BuLX vQ//RG+DS4F2seyco6N+rA9nqTgjVbDHa2mSuxvjApVXGhFNkU6IXUMTfeBnUOR/ WNzN/B2kFlBsLvSCRovPZaltsFG2DpEhlA7nemwz7CZhE7ULg/4HIwn1t/xXbynM pOwFXeNTcAKna41Z+3vAjNSr/oAcd/pGBW+KSCUL5FxTEts4d1fMumAzwi3Oi0Pd QGr6Dru6bdUbUcLf/VFoD62q+uD+56ESOGILvnddiDPZWQeVFVWgzvgqhcLccrEK HACulPmUB+rBTC9y+86I8vhmwGK+Xjna1A4995/1cGBXstJCdLVbLzHQv6dwKU/w 6IR0LcOllKBkp4UnVX7GyKz1XQHOz8+/hUf6zuym+bUCXsHCQ1dCTGfZyxrCzWUi 5Ltx8Hqxt2Q00bEB5BI58Is4JYlTTWeLL81VFCIQSNuEJIwfCPUAR/oH6waCGaPk ER8J18Hbujh4Ku//FAImuLuDQWVgXKmdrFz+UeiM1BlkIAcDcC/9EJxsSgFDUkF1 HZ/2hRDzpkm0dVtQpTiTf2NID9vx6pJBAHrL/Z2Q11bZWdeIz8CLxqPUUlBNfgr6 PmkIbL/4BHbjWp94iavcm0xq/ZKuR+4PvZ1Q9sqjAV4qrczSnf3Xal6gfzY9WcuC wPu6FFNhuEtQ559gbwm+ii+eFAfpf1G8wRDdpnK9F+CQ3JEJEE4sboeTKYKQXBYP +QEP09XFYVMjc03VyBDLcBBPqUHcPYoX/J/tfq9f0IylwE1wPNA8PobHi99eKqQi ahxkeZgUujaDTDOGpsFKLCFFyXvEPwBv5iuvDrNRXLhwIXNFdpvz6gjo6kI2Sn8c THfX1wbGyN9GvtoI96agmLtv6jgmLC9j7Hf+gPM/VhybbL2MCFPG70B0kxnEyEFx j64e5kHKZLRzCOl+fiwTsaEX9L9z74Otx8uXOzh1ZHKtCpPk4N/Xfq99XgzmXVvU aH6FDSiado6GN+W08zCczPTlhBHFpVRQXSbexw/mSgq9E+FpihqLOmrQdAy2b6Qz 36X8EVHy2NbNJbrjM9wzLxcxfjf8aeF9yS6/CDAdHiPRQKNLr+btFCAT3XZ9TYBC wT7YPduK1pXsLvj4xbS+bOZ67YXTNFUXLLPNehcnwID4vbpg6ybm1VT6+i3Mz7em 6jYEgtZe0cO8S9AjxLHnsTIbak8lfGUtjuAl3j0mpRjc34tDLNiC7OmMTS4lJUDy nelBL8UX5qHmR/0q70PljoGScWRPz3200i/f46idUInEPw2F/A1jPH+EgOnVCXjF im4sXI02h3vYPcc1KoFIpAbEE9vJ/7ROoC8V65mIkBAKx/84LX89jy9mWBIx7rHU US1tzdMLm/wtVT8TAm3xciJOxq6lOdfosxhTnm1v5SVE =ODNf -----END PGP PUBLIC KEY BLOCK----- torbrowser-launcher-0.3.3/share/torbrowser-launcher/version000066400000000000000000000000061373720147200242470ustar00rootroot000000000000000.3.3 torbrowser-launcher-0.3.3/stdeb.cfg000066400000000000000000000004301373720147200173110ustar00rootroot00000000000000[DEFAULT] Package3: torbrowser-launcher Depends3: python3-pyqt5, python3-gpg, python3-requests, python3-socks, python3-packaging, gnupg2 Build-Depends: dh-python, python3-pyqt5, python3-gpg, python3-requests, python3-socks, python3-packaging, gnupg2 Recommends: tor Suite: bionic torbrowser-launcher-0.3.3/torbrowser-launcher000077500000000000000000000023251373720147200214710ustar00rootroot00000000000000#!/usr/bin/env python3 """ Tor Browser Launcher https://github.com/micahflee/torbrowser-launcher/ Copyright (c) 2013-2017 Micah Lee Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ import torbrowser_launcher torbrowser_launcher.main() torbrowser-launcher-0.3.3/torbrowser_launcher.pot000066400000000000000000000102721373720147200223510ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-03-23 15:47-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: __init__.py:65 launcher.py:470 msgid "Tor Browser Launcher" msgstr "" #: __init__.py:66 msgid "By Micah Lee, licensed under MIT" msgstr "" #: __init__.py:67 #, python-brace-format msgid "version {0}" msgstr "" #: common.py:100 #, python-brace-format msgid "Error creating {0}" msgstr "" #: common.py:102 common.py:180 #, python-brace-format msgid "{0} is not writable" msgstr "" #: common.py:177 #, python-brace-format msgid "Cannot create directory {0}" msgstr "" #: common.py:187 msgid "Creating GnuPG homedir" msgstr "" #: common.py:254 #, python-format msgid "Could not import key with fingerprint: %s." msgstr "" #: common.py:259 msgid "Not all keys were imported successfully!" msgstr "" #: launcher.py:83 msgid "Downloading Tor Browser for the first time." msgstr "" #: launcher.py:85 msgid "" "Your version of Tor Browser is out-of-date. Downloading the newest version." msgstr "" #: launcher.py:100 msgid "Downloading over Tor" msgstr "" #: launcher.py:111 msgid "Tor Browser" msgstr "" #: launcher.py:128 msgid "Start" msgstr "" #: launcher.py:174 msgid "Yes" msgstr "" #: launcher.py:178 msgid "Exit" msgstr "" #: launcher.py:192 settings.py:136 msgid "Cancel" msgstr "" #: launcher.py:231 launcher.py:245 launcher.py:249 launcher.py:279 #: launcher.py:281 msgid "Downloading" msgstr "" #: launcher.py:238 msgid "Latest version: {}" msgstr "" #: launcher.py:241 msgid "Error detecting Tor Browser version." msgstr "" #: launcher.py:256 launcher.py:357 msgid "Verifying Signature" msgstr "" #: launcher.py:260 msgid "Extracting" msgstr "" #: launcher.py:264 msgid "Running" msgstr "" #: launcher.py:268 msgid "Starting download over again" msgstr "" #: launcher.py:279 launcher.py:295 msgid "(over Tor)" msgstr "" #: launcher.py:293 msgid "Downloaded" msgstr "" #: launcher.py:393 msgid "Installing" msgstr "" #: launcher.py:401 #, python-brace-format msgid "Tor Browser Launcher doesn't understand the file format of {0}" msgstr "" #: launcher.py:427 msgid "" "The version of Tor Browser you have installed is earlier than it should be, " "which could be a sign of an attack!" msgstr "" #: launcher.py:446 msgid "Downloading Tor Browser over again." msgstr "" #: launcher.py:516 launcher.py:525 launcher.py:533 msgid "Download Error:" msgstr "" #: launcher.py:517 msgid "You are currently using a non-default mirror" msgstr "" #: launcher.py:518 msgid "Would you like to switch back to the default?" msgstr "" #: launcher.py:527 msgid "Would you like to try the English version of Tor Browser instead?" msgstr "" #: launcher.py:548 #, python-brace-format msgid "" "Invalid SSL certificate for:\n" "{0}\n" "\n" "You may be under attack." msgstr "" #: launcher.py:550 msgid "Try the download again using Tor?" msgstr "" #: launcher.py:559 #, python-brace-format msgid "" "Error starting download:\n" "\n" "{0}\n" "\n" "Trying to download over Tor. Are you sure Tor is configured correctly and " "running?" msgstr "" #: launcher.py:563 #, python-brace-format msgid "" "Error starting download:\n" "\n" "{0}\n" "\n" "Are you connected to the internet?" msgstr "" #: settings.py:46 msgid "Tor Browser Launcher Settings" msgstr "" #: settings.py:50 msgid "Download over system Tor" msgstr "" #: settings.py:57 msgid "Force downloading English version of Tor Browser" msgstr "" #: settings.py:66 msgid "Tor server" msgstr "" #: settings.py:82 msgid "Status: Installed" msgstr "" #: settings.py:84 msgid "Status: Not Installed" msgstr "" #: settings.py:87 msgid "Install Tor Browser" msgstr "" #: settings.py:92 msgid "Reinstall Tor Browser" msgstr "" #: settings.py:115 msgid "Mirror" msgstr "" #: settings.py:131 msgid "Save && Exit" msgstr "" torbrowser-launcher-0.3.3/torbrowser_launcher/000077500000000000000000000000001373720147200216235ustar00rootroot00000000000000torbrowser-launcher-0.3.3/torbrowser_launcher/__init__.py000066400000000000000000000057601373720147200237440ustar00rootroot00000000000000""" Tor Browser Launcher https://github.com/micahflee/torbrowser-launcher/ Copyright (c) 2013-2017 Micah Lee Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ import os import sys import argparse import signal from PyQt5 import QtCore, QtWidgets from .common import Common, SHARE from .settings import Settings from .launcher import Launcher class Application(QtWidgets.QApplication): """ Qt's QApplication class. It has been overridden to support threads. """ def __init__(self): self.setAttribute(QtCore.Qt.AA_X11InitThreads, True) QtWidgets.QApplication.__init__(self, sys.argv) self.installEventFilter(self) def main(): # Parse arguments parser = argparse.ArgumentParser() parser.add_argument( "--settings", action="store_true", dest="settings", help="Open Tor Browser Launcher settings", ) parser.add_argument("url", nargs="*", help="URL to load") args = parser.parse_args() settings = bool(args.settings) url_list = args.url # Load the version and print the banner with open(os.path.join(SHARE, "version")) as buf: tor_browser_launcher_version = buf.read().strip() print(_("Tor Browser Launcher")) print(_("By Micah Lee, licensed under MIT")) print(_("version {0}").format(tor_browser_launcher_version)) print("https://github.com/micahflee/torbrowser-launcher") common = Common(tor_browser_launcher_version) app = Application() # Open the window gui = None if settings: # Settings mode gui = Settings(common, app) else: # Launcher mode gui = Launcher(common, app, url_list) # Center the window desktop = app.desktop() window_size = gui.size() gui.move( (desktop.width() - window_size.width()) / 2, (desktop.height() - window_size.height()) / 2, ) gui.show() # Allow ctrl-c to work signal.signal(signal.SIGINT, signal.SIG_DFL) sys.exit(app.exec_()) if __name__ == "__main__": main() torbrowser-launcher-0.3.3/torbrowser_launcher/common.py000066400000000000000000000342211373720147200234670ustar00rootroot00000000000000""" Tor Browser Launcher https://github.com/micahflee/torbrowser-launcher/ Copyright (c) 2013-2017 Micah Lee Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ import os import sys import platform import subprocess import locale import pickle import json import re import gettext import gpg SHARE = os.getenv("TBL_SHARE", sys.prefix + "/share") + "/torbrowser-launcher" gettext.install("torbrowser-launcher") # We're looking for output which: # # 1. The first portion must be `[GNUPG:] IMPORT_OK` # 2. The second must be an integer between [0, 15], inclusive # 3. The third must be an uppercased hex-encoded 160-bit fingerprint gnupg_import_ok_pattern = re.compile( b"(\[GNUPG\:\]) (IMPORT_OK) ([0-9]|[1]?[0-5]) ([A-F0-9]{40})" ) class Common(object): def __init__(self, tbl_version): self.tbl_version = tbl_version # initialize the app self.default_mirror = "https://dist.torproject.org/" self.discover_arch_lang() self.build_paths() for d in self.paths["dirs"]: self.mkdir(self.paths["dirs"][d]) self.load_mirrors() self.load_settings() self.mkdir(self.paths["download_dir"]) self.mkdir(self.paths["tbb"]["dir"]) self.init_gnupg() # discover the architecture and language def discover_arch_lang(self): # figure out the architecture self.architecture = "x86_64" if "64" in platform.architecture()[0] else "i686" # figure out the language available_languages = [ "ar", "ca", "da", "de", "en-US", "es-ES", "fa", "fr", "ga-IE", "he", "id", "is", "it", "ja", "ko", "nb-NO", "nl", "pl", "pt-BR", "ru", "sv-SE", "tr", "vi", "zh-CN", "zh-TW", ] default_locale = locale.getlocale()[0] if default_locale is None: self.language = "en-US" else: self.language = default_locale.replace("_", "-") if self.language not in available_languages: self.language = self.language.split("-")[0] if self.language not in available_languages: for l in available_languages: if l[0:2] == self.language: self.language = l # if language isn't available, default to english if self.language not in available_languages: self.language = "en-US" # get value of environment variable, if it is not set return the default value @staticmethod def get_env(var_name, default_value): value = os.getenv(var_name) if not value: value = default_value return value # build all relevant paths def build_paths(self, tbb_version=None): homedir = os.getenv("HOME") if not homedir: homedir = "/tmp/.torbrowser-" + os.getenv("USER") if not os.path.exists(homedir): try: os.mkdir(homedir, 0o700) except: self.set_gui( "error", _("Error creating {0}").format(homedir), [], False ) if not os.access(homedir, os.W_OK): self.set_gui("error", _("{0} is not writable").format(homedir), [], False) tbb_config = '{0}/torbrowser'.format(self.get_env('XDG_CONFIG_HOME', '{0}/.config'.format(homedir))) tbb_cache = '{0}/torbrowser'.format(self.get_env('XDG_CACHE_HOME', '{0}/.cache'.format(homedir))) tbb_local = '{0}/torbrowser'.format(self.get_env('XDG_DATA_HOME', '{0}/.local/share'.format(homedir))) old_tbb_data = '{0}/.torbrowser'.format(homedir) if tbb_version: # tarball filename if self.architecture == "x86_64": arch = "linux64" else: arch = "linux32" if hasattr(self, "settings") and self.settings["force_en-US"]: language = "en-US" else: language = self.language tarball_filename = ( "tor-browser-" + arch + "-" + tbb_version + "_" + language + ".tar.xz" ) # tarball self.paths["tarball_url"] = ( "{0}torbrowser/" + tbb_version + "/" + tarball_filename ) self.paths["tarball_file"] = tbb_cache + "/download/" + tarball_filename self.paths["tarball_filename"] = tarball_filename # sig self.paths["sig_url"] = ( "{0}torbrowser/" + tbb_version + "/" + tarball_filename + ".asc" ) self.paths["sig_file"] = ( tbb_cache + "/download/" + tarball_filename + ".asc" ) self.paths["sig_filename"] = tarball_filename + ".asc" else: self.paths = { "dirs": {"config": tbb_config, "cache": tbb_cache, "local": tbb_local,}, "old_data_dir": old_tbb_data, "tbl_bin": sys.argv[0], "icon_file": os.path.join( os.path.dirname(SHARE), "pixmaps/torbrowser.png" ), "torproject_pem": os.path.join(SHARE, "torproject.pem"), "signing_keys": { "tor_browser_developers": os.path.join( SHARE, "tor-browser-developers.asc" ) }, "mirrors_txt": [ os.path.join(SHARE, "mirrors.txt"), tbb_config + "/mirrors.txt", ], "download_dir": tbb_cache + "/download", "gnupg_homedir": tbb_local + "/gnupg_homedir", "settings_file": tbb_config + "/settings.json", "settings_file_pickle": tbb_config + "/settings", "version_check_url": "https://aus1.torproject.org/torbrowser/update_3/release/Linux_x86_64-gcc3/x/en-US", "version_check_file": tbb_cache + "/download/release.xml", "tbb": { "changelog": tbb_local + "/tbb/" + self.architecture + "/tor-browser_" + self.language + "/Browser/TorBrowser/Docs/ChangeLog.txt", "dir": tbb_local + "/tbb/" + self.architecture, "dir_tbb": tbb_local + "/tbb/" + self.architecture + "/tor-browser_" + self.language, "start": tbb_local + "/tbb/" + self.architecture + "/tor-browser_" + self.language + "/start-tor-browser.desktop", }, } # Add the expected fingerprint for imported keys: self.fingerprints = { "tor_browser_developers": "EF6E286DDA85EA2A4BA7DE684E2C6E8793298290" } # create a directory @staticmethod def mkdir(path): try: if not os.path.exists(path): os.makedirs(path, 0o700) return True except: print(_("Cannot create directory {0}").format(path)) return False if not os.access(path, os.W_OK): print(_("{0} is not writable").format(path)) return False return True # if gnupg_homedir isn't set up, set it up def init_gnupg(self): if not os.path.exists(self.paths["gnupg_homedir"]): print(_("Creating GnuPG homedir"), self.paths["gnupg_homedir"]) self.mkdir(self.paths["gnupg_homedir"]) self.import_keys() def refresh_keyring(self, fingerprint=None): if fingerprint is not None: print("Refreshing local keyring... Missing key: " + fingerprint) else: print("Refreshing local keyring...") # Fetch key from wkd, as per https://support.torproject.org/tbb/how-to-verify-signature/ p = subprocess.Popen( [ "gpg2", "--status-fd", "2", "--homedir", self.paths["gnupg_homedir"], "--auto-key-locate", "nodefault,wkd", "--locate-keys", "torbrowser@torproject.org", ], stderr=subprocess.PIPE, ) p.wait() for output in p.stderr.readlines(): match = gnupg_import_ok_pattern.match(output) if match and match.group(2) == "IMPORT_OK": fingerprint = str(match.group(4)) if match.group(3) == "0": print("Keyring refreshed successfully...") print(" No key updates for key: " + fingerprint) elif match.group(3) == "4": print("Keyring refreshed successfully...") print(" New signatures for key: " + fingerprint) else: print("Keyring refreshed successfully...") def import_key_and_check_status(self, key): """Import a GnuPG key and check that the operation was successful. :param str key: A string specifying the key's filepath from ``Common.paths`` :rtype: bool :returns: ``True`` if the key is now within the keyring (or was previously and hasn't changed). ``False`` otherwise. """ with gpg.Context() as c: c.set_engine_info( gpg.constants.protocol.OpenPGP, home_dir=self.paths["gnupg_homedir"] ) impkey = self.paths["signing_keys"][key] try: c.op_import(gpg.Data(file=impkey)) except: return False else: result = c.op_import_result() if result and self.fingerprints[key] in result.imports[0].fpr: return True else: return False # import gpg keys def import_keys(self): """Import all GnuPG keys. :rtype: bool :returns: ``True`` if all keys were successfully imported; ``False`` otherwise. """ keys = [ "tor_browser_developers", ] all_imports_succeeded = True for key in keys: imported = self.import_key_and_check_status(key) if not imported: print( _( "Could not import key with fingerprint: %s." % self.fingerprints[key] ) ) all_imports_succeeded = False if not all_imports_succeeded: print(_("Not all keys were imported successfully!")) return all_imports_succeeded # load mirrors def load_mirrors(self): self.mirrors = [] for srcfile in self.paths["mirrors_txt"]: if not os.path.exists(srcfile): continue for mirror in open(srcfile, "r").readlines(): if mirror.strip() not in self.mirrors: self.mirrors.append(mirror.strip()) # load settings def load_settings(self): default_settings = { "tbl_version": self.tbl_version, "installed": False, "download_over_tor": False, "tor_socks_address": "127.0.0.1:9050", "mirror": self.default_mirror, "force_en-US": False, } if os.path.isfile(self.paths["settings_file"]): settings = json.load(open(self.paths["settings_file"])) resave = False # detect installed settings["installed"] = os.path.isfile(self.paths["tbb"]["start"]) # make sure settings file is up-to-date for setting in default_settings: if setting not in settings: settings[setting] = default_settings[setting] resave = True # make sure tor_socks_address doesn't start with 'tcp:' if settings["tor_socks_address"].startswith("tcp:"): settings["tor_socks_address"] = settings["tor_socks_address"][4:] resave = True # make sure the version is current if settings["tbl_version"] != self.tbl_version: settings["tbl_version"] = self.tbl_version resave = True self.settings = settings if resave: self.save_settings() # if settings file is still using old pickle format, convert to json elif os.path.isfile(self.paths["settings_file_pickle"]): self.settings = pickle.load(open(self.paths["settings_file_pickle"])) self.save_settings() os.remove(self.paths["settings_file_pickle"]) self.load_settings() else: self.settings = default_settings self.save_settings() # save settings def save_settings(self): json.dump(self.settings, open(self.paths["settings_file"], "w")) return True torbrowser-launcher-0.3.3/torbrowser_launcher/launcher.py000066400000000000000000000574441373720147200240140ustar00rootroot00000000000000""" Tor Browser Launcher https://github.com/micahflee/torbrowser-launcher/ Copyright (c) 2013-2017 Micah Lee Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ import os import sys import subprocess import time import tarfile import lzma import re import requests import gpg import shutil import xml.etree.ElementTree as ET from packaging import version from PyQt5 import QtCore, QtWidgets, QtGui class TryStableException(Exception): pass class TryDefaultMirrorException(Exception): pass class TryForcingEnglishException(Exception): pass class DownloadErrorException(Exception): pass class Launcher(QtWidgets.QMainWindow): """ Launcher window. """ def __init__(self, common, app, url_list): super(Launcher, self).__init__() self.common = common self.app = app self.url_list = url_list self.force_redownload = False # This is the current version of Tor Browser, which should get updated with every release self.min_version = "7.5.2" # Init launcher self.set_state(None, "", []) self.launch_gui = True # If Tor Browser is not installed, detect latest version, download, and install if not self.common.settings["installed"] or not self.check_min_version(): # Different message if downloading for the first time, or because your installed version is too low download_message = "" if not self.common.settings["installed"]: download_message = _("Downloading Tor Browser for the first time.") elif not self.check_min_version(): download_message = _( "Your version of Tor Browser is out-of-date. " "Downloading the newest version." ) # Download and install print(download_message) self.set_state( "task", download_message, [ "download_version_check", "set_version", "download_sig", "download_tarball", "verify", "extract", "run", ], ) if self.common.settings["download_over_tor"]: print(_("Downloading over Tor")) else: # Tor Browser is already installed, so run launch_message = "Launching Tor Browser." print(launch_message) self.set_state("task", launch_message, ["run"]) # Build the rest of the UI # Set up the window self.setWindowTitle(_("Tor Browser")) self.setWindowIcon(QtGui.QIcon(self.common.paths["icon_file"])) # Label self.label = QtWidgets.QLabel() # Progress bar self.progress_bar = QtWidgets.QProgressBar() self.progress_bar.setTextVisible(True) self.progress_bar.setMinimum(0) self.progress_bar.setMaximum(0) self.progress_bar.setValue(0) # Buttons self.yes_button = QtWidgets.QPushButton() self.yes_button.setIcon( self.style().standardIcon(QtWidgets.QStyle.SP_DialogApplyButton) ) self.yes_button.clicked.connect(self.yes_clicked) self.start_button = QtWidgets.QPushButton(_("Start")) self.start_button.setIcon( self.style().standardIcon(QtWidgets.QStyle.SP_DialogApplyButton) ) self.start_button.clicked.connect(self.start) self.cancel_button = QtWidgets.QPushButton() self.cancel_button.setIcon( self.style().standardIcon(QtWidgets.QStyle.SP_DialogCancelButton) ) self.cancel_button.clicked.connect(self.close) buttons_layout = QtWidgets.QHBoxLayout() buttons_layout.addStretch() buttons_layout.addWidget(self.yes_button) buttons_layout.addWidget(self.start_button) buttons_layout.addWidget(self.cancel_button) buttons_layout.addStretch() # Layout layout = QtWidgets.QVBoxLayout() layout.addWidget(self.label) layout.addWidget(self.progress_bar) layout.addLayout(buttons_layout) central_widget = QtWidgets.QWidget() central_widget.setLayout(layout) self.setCentralWidget(central_widget) self.update() # Set the current state of Tor Browser Launcher def set_state(self, gui, message, tasks, autostart=True): self.gui = gui self.gui_message = message self.gui_tasks = tasks self.gui_task_i = 0 self.gui_autostart = autostart # Show and hide parts of the UI based on the current state def update(self): # Hide widgets self.progress_bar.hide() self.yes_button.hide() self.start_button.hide() if "error" in self.gui: # Label self.label.setText(self.gui_message) # Yes button if self.gui != "error": self.yes_button.setText(_("Yes")) self.yes_button.show() # Exit button self.cancel_button.setText(_("Exit")) elif self.gui == "task": # Label self.label.setText(self.gui_message) # Progress bar self.progress_bar.show() # Start button if not self.gui_autostart: self.start_button.show() # Cancel button self.cancel_button.setText(_("Cancel")) # Resize the window self.adjustSize() if self.gui_autostart: self.start(None) # Yes button clicked, based on the state decide what to do def yes_clicked(self): if self.gui == "error_try_stable": self.try_stable() elif self.gui == "error_try_default_mirror": self.try_default_mirror() elif self.gui == "error_try_forcing_english": self.try_forcing_english() elif self.gui == "error_try_tor": self.try_tor() # Start button clicked, begin tasks def start(self, widget, data=None): # Hide the start button self.start_button.hide() # Start running tasks self.run_task() # Run the next task in the task list def run_task(self): if self.gui_task_i >= len(self.gui_tasks): self.close() return task = self.gui_tasks[self.gui_task_i] # Get ready for the next task self.gui_task_i += 1 if task == "download_version_check": print(_("Downloading"), self.common.paths["version_check_url"]) self.download( "version check", self.common.paths["version_check_url"], self.common.paths["version_check_file"], ) if task == "set_version": version = self.get_stable_version() if version: self.common.build_paths(self.get_stable_version()) print(_("Latest version: {}").format(version)) self.run_task() else: self.set_state( "error", _("Error detecting Tor Browser version."), [], False ) self.update() elif task == "download_sig": print( _("Downloading"), self.common.paths["sig_url"].format(self.common.settings["mirror"]), ) self.download( "signature", self.common.paths["sig_url"], self.common.paths["sig_file"] ) elif task == "download_tarball": print( _("Downloading"), self.common.paths["tarball_url"].format(self.common.settings["mirror"]), ) if not self.force_redownload and os.path.exists( self.common.paths["tarball_file"] ): self.run_task() else: self.download( "tarball", self.common.paths["tarball_url"], self.common.paths["tarball_file"], ) elif task == "verify": print(_("Verifying Signature")) self.verify() elif task == "extract": print(_("Extracting"), self.common.paths["tarball_filename"]) self.extract() elif task == "run": print(_("Running"), self.common.paths["tbb"]["start"]) self.run() elif task == "start_over": print(_("Starting download over again")) self.start_over() def download(self, name, url, path): # Download from the selected mirror mirror_url = url.format(self.common.settings["mirror"]).encode() # Initialize the progress bar self.progress_bar.setValue(0) self.progress_bar.setMaximum(100) if self.common.settings["download_over_tor"]: self.progress_bar.setFormat( _("Downloading") + " {0} ".format(name) + _("(over Tor)") + ", %p%" ) else: self.progress_bar.setFormat(_("Downloading") + " {0}, %p%".format(name)) def progress_update(total_bytes, bytes_so_far): percent = float(bytes_so_far) / float(total_bytes) amount = float(bytes_so_far) units = "bytes" for (size, unit) in [(1024 * 1024, "MiB"), (1024, "KiB")]: if amount > size: units = unit amount /= float(size) break message = _("Downloaded") + ( " %2.1f%% (%2.1f %s)" % ((percent * 100.0), amount, units) ) if self.common.settings["download_over_tor"]: message += " " + _("(over Tor)") self.progress_bar.setMaximum(total_bytes) self.progress_bar.setValue(bytes_so_far) self.progress_bar.setFormat(message) def download_complete(): # Download complete, next task self.run_task() def download_error(gui, message): print(message) self.set_state(gui, message, [], False) self.update() t = DownloadThread(self.common, mirror_url, path) t.progress_update.connect(progress_update) t.download_complete.connect(download_complete) t.download_error.connect(download_error) t.start() time.sleep(0.2) def try_default_mirror(self): # change mirror to default and relaunch TBL self.common.settings["mirror"] = self.common.default_mirror self.common.save_settings() subprocess.Popen([self.common.paths["tbl_bin"]]) self.close() def try_forcing_english(self): # change force english to true and relaunch TBL self.common.settings["force_en-US"] = True self.common.save_settings() subprocess.Popen([self.common.paths["tbl_bin"]]) self.close() def try_tor(self): # set download_over_tor to true and relaunch TBL self.common.settings["download_over_tor"] = True self.common.save_settings() subprocess.Popen([self.common.paths["tbl_bin"]]) self.close() def get_stable_version(self): tree = ET.parse(self.common.paths["version_check_file"]) for up in tree.getroot(): if up.tag == "update" and up.attrib["appVersion"]: version = str(up.attrib["appVersion"]) # make sure the version does not contain directory traversal attempts # e.g. "5.5.3", "6.0a", "6.0a-hardened" are valid but "../../../../.." is invalid if not re.match(r"^[a-z0-9\.\-]+$", version): return None return version return None def verify(self): self.progress_bar.setValue(0) self.progress_bar.setMaximum(0) self.progress_bar.show() self.label.setText(_("Verifying Signature")) def success(): self.run_task() def error(message): # Make backup of tarball and sig backup_tarball_filename = ( self.common.paths["tarball_file"] + ".verification_failed" ) backup_sig_filename = self.common.paths["sig_file"] + ".verification_failed" shutil.copyfile(self.common.paths["tarball_file"], backup_tarball_filename) shutil.copyfile(self.common.paths["sig_file"], backup_sig_filename) sigerror = ( "SIGNATURE VERIFICATION FAILED!\n\n" "Error Code: {0}\n\n" "You might be under attack, there might be a network problem, or you may be missing a " "recently added Tor Browser verification key.\n\n" "A copy of the Tor Browser files you downloaded have been saved here:\n" "{1}\n{2}\n\n" "Click Start to refresh the keyring and try again. If the message persists report the above " "error code here:\nhttps://github.com/micahflee/torbrowser-launcher/issues" ) sigerror = sigerror.format( message, backup_tarball_filename, backup_sig_filename ) self.set_state("task", sigerror, ["start_over"], False) self.update() t = VerifyThread(self.common) t.error.connect(error) t.success.connect(success) t.start() time.sleep(0.2) def extract(self): self.progress_bar.setValue(0) self.progress_bar.setMaximum(0) self.progress_bar.show() self.label.setText(_("Installing")) def success(): self.run_task() def error(message): self.set_state( "task", _( "Tor Browser Launcher doesn't understand the file format of {0}".format( self.common.paths["tarball_file"] ) ), ["start_over"], False, ) self.update() t = ExtractThread(self.common) t.error.connect(error) t.success.connect(success) t.start() time.sleep(0.2) def check_min_version(self): installed_version = None for line in open(self.common.paths["tbb"]["changelog"], "rb").readlines(): if line.startswith(b"Tor Browser "): installed_version = line.split()[2].decode() break if version.parse(self.min_version) <= version.parse(installed_version): return True return False def run(self): # Don't run if it isn't at least the minimum version if not self.check_min_version(): message = _( "The version of Tor Browser you have installed is earlier than it should be, which could be a " "sign of an attack!" ) print(message) Alert(self.common, message) return # Run Tor Browser subprocess.call( [self.common.paths["tbb"]["start"]], cwd=self.common.paths["tbb"]["dir_tbb"] ) sys.exit(0) # Start over and download TBB again def start_over(self): self.force_redownload = True # Overwrite any existing file self.label.setText(_("Downloading Tor Browser over again.")) self.gui_tasks = ["download_tarball", "verify", "extract", "run"] self.gui_task_i = 0 self.start(None) def closeEvent(self, event): # Clear the download cache try: os.remove(self.common.paths["version_check_file"]) os.remove(self.common.paths["sig_file"]) os.remove(self.common.paths["tarball_file"]) except: pass super(Launcher, self).closeEvent(event) class Alert(QtWidgets.QMessageBox): """ An alert box dialog. """ def __init__( self, common, message, icon=QtWidgets.QMessageBox.NoIcon, buttons=QtWidgets.QMessageBox.Ok, autostart=True, ): super(Alert, self).__init__(None) self.setWindowTitle(_("Tor Browser Launcher")) self.setWindowIcon(QtGui.QIcon(common.paths["icon_file"])) self.setText(message) self.setIcon(icon) self.setStandardButtons(buttons) if autostart: self.exec_() class DownloadThread(QtCore.QThread): """ Download a file in a separate thread. """ progress_update = QtCore.pyqtSignal(int, int) download_complete = QtCore.pyqtSignal() download_error = QtCore.pyqtSignal(str, str) def __init__(self, common, url, path): super(DownloadThread, self).__init__() self.common = common self.url = url self.path = path # Use tor socks5 proxy, if enabled if self.common.settings['download_over_tor']: socks5_address = 'socks5h://{}'.format(self.common.settings['tor_socks_address']) self.proxies = { 'https': socks5_address, 'http': socks5_address } else: self.proxies = None def run(self): with open(self.path, "wb") as f: try: # Start the request r = requests.get( self.url, headers={"User-Agent": "torbrowser-launcher"}, stream=True, proxies=self.proxies, ) # If status code isn't 200, something went wrong if r.status_code != 200: # Should we use the default mirror? if self.common.settings["mirror"] != self.common.default_mirror: message = ( _("Download Error:") + " {0}\n\n" + _("You are currently using a non-default mirror") + ":\n{1}\n\n" + _("Would you like to switch back to the default?") ).format(r.status_code, self.common.settings["mirror"]) self.download_error.emit("error_try_default_mirror", message) # Should we switch to English? elif ( self.common.language != "en-US" and not self.common.settings["force_en-US"] ): message = ( _("Download Error:") + " {0}\n\n" + _( "Would you like to try the English version of Tor Browser instead?" ) ).format(r.status_code) self.download_error.emit("error_try_forcing_english", message) else: message = (_("Download Error:") + " {0}").format(r.status_code) self.download_error.emit("error", message) r.close() return # Start streaming the download total_bytes = int(r.headers.get("content-length")) bytes_so_far = 0 for data in r.iter_content(chunk_size=4096): bytes_so_far += len(data) f.write(data) self.progress_update.emit(total_bytes, bytes_so_far) except requests.exceptions.SSLError: message = _( "Invalid SSL certificate for:\n{0}\n\nYou may be under attack." ).format(self.url.decode()) if not self.common.settings["download_over_tor"]: message += "\n\n" + _("Try the download again using Tor?") self.download_error.emit("error_try_tor", message) else: self.download_error.emit("error", message) return except requests.exceptions.ConnectionError: # Connection error if self.common.settings["download_over_tor"]: message = _( "Error starting download:\n\n{0}\n\nTrying to download over Tor. " "Are you sure Tor is configured correctly and running?" ).format(self.url.decode()) self.download_error.emit("error", message) else: message = _( "Error starting download:\n\n{0}\n\nAre you connected to the internet?" ).format(self.url.decode()) self.download_error.emit("error", message) return self.download_complete.emit() class VerifyThread(QtCore.QThread): """ Verify the signature in a separate thread """ success = QtCore.pyqtSignal() error = QtCore.pyqtSignal(str) def __init__(self, common): super(VerifyThread, self).__init__() self.common = common def run(self): def verify(second_try=False): with gpg.Context() as c: c.set_engine_info( gpg.constants.protocol.OpenPGP, home_dir=self.common.paths["gnupg_homedir"], ) sig = gpg.Data(file=self.common.paths["sig_file"]) signed = gpg.Data(file=self.common.paths["tarball_file"]) try: c.verify(signature=sig, signed_data=signed) except gpg.errors.BadSignatures as e: if second_try: self.error.emit(str(e)) else: raise Exception else: self.success.emit() try: # Try verifying verify() except: # If it fails, refresh the keyring and try again self.common.refresh_keyring() verify(True) class ExtractThread(QtCore.QThread): """ Extract the tarball in a separate thread """ success = QtCore.pyqtSignal() error = QtCore.pyqtSignal() def __init__(self, common): super(ExtractThread, self).__init__() self.common = common def run(self): extracted = False try: if self.common.paths["tarball_file"][-2:] == "xz": # if tarball is .tar.xz xz = lzma.LZMAFile(self.common.paths["tarball_file"]) tf = tarfile.open(fileobj=xz) tf.extractall(self.common.paths["tbb"]["dir"]) extracted = True else: # if tarball is .tar.gz if tarfile.is_tarfile(self.common.paths["tarball_file"]): tf = tarfile.open(self.common.paths["tarball_file"]) tf.extractall(self.common.paths["tbb"]["dir"]) extracted = True except: pass if extracted: self.success.emit() else: self.error.emit() torbrowser-launcher-0.3.3/torbrowser_launcher/settings.py000066400000000000000000000154711373720147200240450ustar00rootroot00000000000000""" Tor Browser Launcher https://github.com/micahflee/torbrowser-launcher/ Copyright (c) 2013-2017 Micah Lee Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ import subprocess import shutil from PyQt5 import QtCore, QtWidgets, QtGui class Settings(QtWidgets.QMainWindow): """ Settings window. """ def __init__(self, common, app): super(Settings, self).__init__() self.common = common self.app = app # Set up the window self.setWindowTitle(_("Tor Browser Launcher Settings")) self.setWindowIcon(QtGui.QIcon(self.common.paths["icon_file"])) # Download over system tor self.tor_download_checkbox = QtWidgets.QCheckBox(_("Download over system Tor")) if self.common.settings["download_over_tor"]: self.tor_download_checkbox.setCheckState(QtCore.Qt.Checked) else: self.tor_download_checkbox.setCheckState(QtCore.Qt.Unchecked) # Force en-US, only display if language isn't already en-US self.force_en_checkbox = QtWidgets.QCheckBox( _("Force downloading English version of Tor Browser") ) if self.common.settings["force_en-US"]: self.force_en_checkbox.setCheckState(QtCore.Qt.Checked) else: self.force_en_checkbox.setCheckState(QtCore.Qt.Unchecked) if self.common.language == "en-US": self.force_en_checkbox.hide() # Tor SOCKS address tor_addr_label = QtWidgets.QLabel(_("Tor server")) self.tor_addr = QtWidgets.QLineEdit() self.tor_addr.setText(self.common.settings["tor_socks_address"]) tor_addr_layout = QtWidgets.QHBoxLayout() tor_addr_layout.addWidget(tor_addr_label) tor_addr_layout.addWidget(self.tor_addr) # Settings layout settings_layout = QtWidgets.QVBoxLayout() settings_layout.addWidget(self.tor_download_checkbox) settings_layout.addWidget(self.force_en_checkbox) settings_layout.addLayout(tor_addr_layout) # Status status_label = QtWidgets.QLabel() if self.common.settings["installed"]: status_label.setText(_("Status: Installed")) else: status_label.setText(_("Status: Not Installed")) # Install button install_button = QtWidgets.QPushButton(_("Install Tor Browser")) install_button.setIcon( self.style().standardIcon(QtWidgets.QStyle.SP_DialogApplyButton) ) install_button.clicked.connect(self.install) # Reinstall buttons reinstall_button = QtWidgets.QPushButton(_("Reinstall Tor Browser")) reinstall_button.setIcon( self.style().standardIcon(QtWidgets.QStyle.SP_DialogApplyButton) ) reinstall_button.clicked.connect(self.reinstall) if self.common.settings["installed"]: install_button.hide() reinstall_button.show() else: install_button.show() reinstall_button.hide() # Status layout status_layout = QtWidgets.QVBoxLayout() status_layout.addWidget(status_label) status_layout.addWidget(install_button) status_layout.addWidget(reinstall_button) # Top layout top_layout = QtWidgets.QHBoxLayout() top_layout.addLayout(settings_layout) top_layout.addLayout(status_layout) # Mirror mirror_label = QtWidgets.QLabel(_("Mirror")) self.mirror = QtWidgets.QComboBox() for mirror in self.common.mirrors: self.mirror.addItem(mirror) if self.common.settings["mirror"] in self.common.mirrors: self.mirror.setCurrentIndex( self.mirror.findText(self.common.settings["mirror"]) ) else: self.mirror.setCurrentIndex(0) mirror_layout = QtWidgets.QHBoxLayout() mirror_layout.addWidget(mirror_label) mirror_layout.addWidget(self.mirror) # Save & Exit button self.save_exit_button = QtWidgets.QPushButton(_("Save && Exit")) self.save_exit_button.setIcon( self.style().standardIcon(QtWidgets.QStyle.SP_DialogApplyButton) ) self.save_exit_button.clicked.connect(self.save_exit) # Cancel button self.cancel_button = QtWidgets.QPushButton(_("Cancel")) self.cancel_button.setIcon( self.style().standardIcon(QtWidgets.QStyle.SP_DialogCancelButton) ) self.cancel_button.clicked.connect(self.close) # Buttons layout buttons_layout = QtWidgets.QHBoxLayout() buttons_layout.addWidget(self.save_exit_button) buttons_layout.addWidget(self.cancel_button) # Main layout layout = QtWidgets.QVBoxLayout() layout.addLayout(top_layout) layout.addLayout(mirror_layout) layout.addLayout(buttons_layout) central_widget = QtWidgets.QWidget() central_widget.setLayout(layout) self.setCentralWidget(central_widget) # Install def install(self): self.save() subprocess.Popen([self.common.paths["tbl_bin"]]) self.close() # Reinstall def reinstall(self): self.save() shutil.rmtree(self.common.paths["tbb"]["dir"]) subprocess.Popen([self.common.paths["tbl_bin"]]) self.close() # Save & Exit def save_exit(self): self.save() self.close() # Save settings def save(self): # Checkbox options self.common.settings[ "download_over_tor" ] = self.tor_download_checkbox.isChecked() self.common.settings["force_en-US"] = self.force_en_checkbox.isChecked() self.common.settings["tor_socks_address"] = self.tor_addr.text() # Figure out the selected mirror self.common.settings["mirror"] = self.mirror.currentText() # Save them self.common.save_settings()