RFC: remove traceback from "newer branch format than your bzr"

Martin Pool mbp at canonical.com
Wed Aug 12 11:49:21 BST 2009


2009/8/12 Martin Pool <martinpool at gmail.com>:
>> apport works on Windows?
>
> It's pure Python. It should work there, or at least not be too hard to fix.

I looked through it a bit.  There is some Linux-specific code, but
it's segregated and seems to make an effort not to rely on anything OS
specific.  I'm confident the apport authors would take patches to make
it work on Windows - and there are some test suites.

> So it seems to me that if we used Apport it would have these consequences:

Here's a patch that uses apport to get basically the behaviour Stephen
and others describe:

% ./bzr fail
Bazaar has encountered an internal error:
    exceptions.AssertionError: fail
Details have been written to
    /home/mbp/.cache/bazaar/crash/bzr-20090812093730-7185.crash

This probably indicates a bug in Bazaar.  You can help us fix it
by filing a bug report at
    http://bugs.launchpad.net/bzr/+filebug
attaching this file, and your own description of the problem.

The directory is named according to (my memory of) the XDG standard,
which a bug requests we respect.  Since this is new, we might as well
use it.

If apport can't be loaded, we complain and use the previous method of
writing to stderr.

I do think it could be cool to interactively ask the user whether they
want to file the bug report and then automatically kick it off, and to
do this interaction in a way that is abstracted for GUIs. I think we
should merge this first though and see how it goes.

I don't think it's worth worrying about the case of "still running but
can't write to disk".  It doesn't happen often.  We often are still
running but can't reach a remote server, but it'd be hard to get to a
point where local IO can't work.

-- 
Martin <http://launchpad.net/~mbp/>


# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: mbp at sourcefrog.net-20090812093536-vvtmb3cw52bqxfw3
# target_branch: http://bazaar.launchpad.net/~mbp/bzr/trunk
# testament_sha1: 9186d615fe8c427a3011697b11eac0e731f1d0d2
# timestamp: 2009-08-12 17:35:46 +0800
# source_branch: http://bazaar.launchpad.net/~mbp/bzr/apport
# base_revision_id: pqm at pqm.ubuntu.com-20090804052054-yd271soudff1dbgt
#
# Begin patch
=== modified file 'bzrlib/config.py'
--- bzrlib/config.py	2009-07-02 08:59:16 +0000
+++ bzrlib/config.py	2009-08-12 08:33:01 +0000
@@ -821,6 +821,25 @@
     return osutils.pathjoin(config_dir(), 'ignore')


+def crash_dir():
+    """Return the directory name to store crash files.
+
+    This doesn't implicitly create it.
+
+    On Windows it's in the config directory; elsewhere in the XDG
cache directory.
+    """
+    if sys.platform == 'win32':
+        return osutils.pathjoin(config_dir(), 'Crash')
+    else:
+        return osutils.pathjoin(xdg_cache_dir(), 'crash')
+
+
+def xdg_cache_dir():
+    # XXX: this should probably look at some environment variables too?
+    return osutils.pathjoin(os.path.expanduser('~'),
+        '.cache', 'bazaar')
+
+
 def _auto_user_id():
     """Calculate automatic user identification.


=== added file 'bzrlib/crash.py'
--- bzrlib/crash.py	1970-01-01 00:00:00 +0000
+++ bzrlib/crash.py	2009-08-12 09:35:36 +0000
@@ -0,0 +1,140 @@
+# Copyright (C) 2009 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+"""Handling and reporting crashes.
+"""
+
+# for testing this, see http://code.launchpad.net/~mbp/bzr/bzr-fail
+# which adds a 'fail' command
+
+import os
+import pprint
+import sys
+import time
+
+import bzrlib
+from bzrlib import (
+    config,
+    osutils,
+    plugin,
+    trace,
+    )
+
+
+def report_bug(exc_info, stderr):
+    report_bug_to_apport(exc_info, stderr) or \
+        report_bug_legacy(exc_info, stderr)
+
+
+def report_bug_legacy(exc_info, err_file):
+    """Report a bug by just printing a message to the user."""
+    trace.print_exception(exc_info, err_file)
+    err_file.write('\n')
+    err_file.write('bzr %s on python %s (%s)\n' % \
+                       (bzrlib.__version__,
+                        bzrlib._format_version_tuple(sys.version_info),
+                        sys.platform))
+    err_file.write('arguments: %r\n' % sys.argv)
+    err_file.write(
+        'encoding: %r, fsenc: %r, lang: %r\n' % (
+            osutils.get_user_encoding(), sys.getfilesystemencoding(),
+            os.environ.get('LANG')))
+    err_file.write("plugins:\n")
+    for name, a_plugin in sorted(plugin.plugins().items()):
+        err_file.write("  %-20s %s [%s]\n" %
+            (name, a_plugin.path(), a_plugin.__version__))
+    err_file.write(
+"""\
+*** Bazaar has encountered an internal error.
+    Please report a bug at https://bugs.launchpad.net/bzr/+filebug
+    including this traceback, and a description of what you
+    were doing when the error occurred.
+""")
+
+
+def report_bug_to_apport(exc_info, stderr):
+    """Report a bug to apport for optional automatic filing.
+
+    :returns: True if the bug was filed or otherwise handled;
+        False to use a fallback method.
+    """
+    import platform
+
+    # this is based on apport_package_hook.py, but omitting some of the
+    # Ubuntu-specific policy about what to report and when
+    try:
+        from apport.report import Report
+    except ImportError, e:
+        trace.warning("couldn't find apport bug-reporting library: %s" % e)
+        return False
+
+    pr = Report()
+    # add_proc_info gives you the memory map of the process: this seems rarely
+    # useful for Bazaar and it does make the report harder to scan, though it
+    # does tell you what binary modules are loaded.
+    # pr.add_proc_info()
+    pr.add_user_info()
+    pr['BzrVersion'] = bzrlib.__version__
+    pr['PythonVersion'] = bzrlib._format_version_tuple(sys.version_info)
+    pr['Platform'] = platform.platform(aliased=1)
+    pr['UserEncoding'] = osutils.get_user_encoding()
+    pr['FileSystemEncoding'] = sys.getfilesystemencoding()
+    pr['Locale'] = os.environ.get('LANG')
+    pr['BzrPlugins'] = _format_plugin_list()
+    pr['PythonLoadedModules'] = _format_module_list()
+
+    crash_file = _open_crash_file()
+    try:
+        pr.write(crash_file)
+    finally:
+        crash_file.close()
+
+    stderr.write("Bazaar has encountered an internal error:\n"
+        "    %s.%s: %s\n"
+        "Details have been written to\n"
+        "    %s\n"
+        "\n"
+        "This probably indicates a bug in Bazaar.  You can help us fix it\n"
+        "by filing a bug report at\n"
+        "    http://bugs.launchpad.net/bzr/+filebug\n"
+        "attaching this file, and your own description of the problem.\n"
+        % (exc_info[0].__module__, exc_info[0].__name__, exc_info[1],
+           crash_file.name))
+    return True
+
+
+def _open_crash_file():
+    crash_dir = config.crash_dir()
+    # user-readable only, just in case the contents are sensitive.
+    if not osutils.isdir(crash_dir):
+        os.makedirs(crash_dir, mode=0700)
+    filename = 'bzr-%s-%s.crash' % (
+        osutils.compact_date(time.time()),
+        os.getpid(),)
+    return open(osutils.pathjoin(crash_dir, filename), 'wt')
+
+
+def _format_plugin_list():
+    plugin_lines = []
+    for name, a_plugin in sorted(plugin.plugins().items()):
+        plugin_lines.append("  %-20s %s [%s]" %
+            (name, a_plugin.path(), a_plugin.__version__))
+    return '\n'.join(plugin_lines)
+
+
+def _format_module_list():
+    return pprint.pformat(sys.modules)

=== modified file 'bzrlib/trace.py'
--- bzrlib/trace.py	2009-03-24 01:53:42 +0000
+++ bzrlib/trace.py	2009-08-12 08:33:50 +0000
@@ -478,25 +478,5 @@

 def report_bug(exc_info, err_file):
     """Report an exception that probably indicates a bug in bzr"""
-    print_exception(exc_info, err_file)
-    err_file.write('\n')
-    err_file.write('bzr %s on python %s (%s)\n' % \
-                       (bzrlib.__version__,
-                        bzrlib._format_version_tuple(sys.version_info),
-                        sys.platform))
-    err_file.write('arguments: %r\n' % sys.argv)
-    err_file.write(
-        'encoding: %r, fsenc: %r, lang: %r\n' % (
-            osutils.get_user_encoding(), sys.getfilesystemencoding(),
-            os.environ.get('LANG')))
-    err_file.write("plugins:\n")
-    for name, a_plugin in sorted(plugin.plugins().items()):
-        err_file.write("  %-20s %s [%s]\n" %
-            (name, a_plugin.path(), a_plugin.__version__))
-    err_file.write(
-"""\
-*** Bazaar has encountered an internal error.
-    Please report a bug at https://bugs.launchpad.net/bzr/+filebug
-    including this traceback, and a description of what you
-    were doing when the error occurred.
-""")
+    from bzrlib.crash import report_bug
+    report_bug(exc_info, err_file)

=== added file 'doc/developers/apport.txt'
--- doc/developers/apport.txt	1970-01-01 00:00:00 +0000
+++ doc/developers/apport.txt	2009-08-12 09:35:19 +0000
@@ -0,0 +1,83 @@
+*************************
+Bazaar Apport Integration
+*************************
+
+Bazaar can use Apport <http://launchpad.net/apport/> to capture data about
+unexpected errors (probably, bugs in Bazaar) and report them to the
+developers.
+
+This is only active for errors that are believed to be internal errors (ie
+bugs) not user or environmental errors.  (See the Developer Guide.)
+
+Consequences for users
+----------------------
+
+* They shouldn't normally need to see or copy&paste a traceback.
+
+* They will be able to inspect the files before sending them to be sure
+  there's no sensitive data included.
+
+* As at present, they'll need a Launchpad account to report bugs in the
+  normal way.
+
+
+Implementation notes
+--------------------
+
+The use of apport by Bazaar is independent of the configuration in the OS.
+For example in Ubuntu, apport is normally inactive in release builds, and
+normally excludes software not installed from a package.  We'll bypass
+both of them.
+
+Putting in this handler may mean that an OS-wide exception handler never
+sees the error, but that was true with our existing exception-printer.
+
+The user should have the option to: forget about the crash (and ignore the
+bug report), see the contents of the report,
+
+The process is
+
+#. An exception reaches the top-level handler.
+
+#. We log it in apport-format to a file in ~/.bazaar/crash.
+
+#. We tell the user where that file is, and invite them to file a bug
+   report.
+
+This won't be active for bugs that cause the whole Python interpreter to
+crash.  This can be handled at the OS level.  The nice thing is that if
+apport is active system-wide, it will catch either exceptions in our
+in-process apport handler, or errors that crash the intrepreter.
+
+
+Future ideas
+------------
+
+* Capture apport data even for things not believed to be internal errors,
+  because sometimes they are in fact bugs.  Then the user can attach the
+  apport report later if they decide to file a bug.  There may be quite a
+  lot of them so we might need to limit the number that are stored, or do
+  this when a debug flag is set.  At the moment they go into .bzr.log and
+  that's probably ok to start with.
+
+* Raising an error from the breakin debugger should cause this to fire.
+
+* Developers looking at a crash on their own machine will probably in the
+  first instance just want to see the traceback. Apport files may be more
+  longwinded than our current output and might make the traceback scroll
+  off the screen.
+
+* Automatically include .bzr.log in the problem report.
+
+* Ask the user what they want to do with the report: automatically file
+  it, look at it, see just the traceback, just be told where it is.  This
+  could be done through the UIFactory so that it can be done through a
+  graphical dialog.
+
+  However, if we've already had an unhandled error in this process there
+  may be problems in Bazaar that prevent us presenting a clean message...
+
+  Possibly these bugs are better reported in the next time bzr runs.
+
+..
+    vim: ft=rst

=== modified file 'doc/developers/index.txt'
--- doc/developers/index.txt	2009-07-22 13:41:01 +0000
+++ doc/developers/index.txt	2009-08-12 08:03:11 +0000
@@ -70,6 +70,9 @@

 * `API versioning <api-versioning.html>`_ |--| bzrlib API versioning.

+* `Apport error reporting <apport.html>`_ |--| Capture data to report
+  bugs.
+
 * `Authentication ring <authentication-ring.html>`_ |--| Configuring
   authentication.


# Begin bundle
IyBCYXphYXIgcmV2aXNpb24gYnVuZGxlIHY0CiMKQlpoOTFBWSZTWckaNt8AGJV/gETQXgBb////
/+ff7v////VgJf0OvNd1udXmpQPJpd2297T1d833e32fXtS193X2we2CVAlTQ22tBzfLaDNd68ff
a+8Ldyuc7ly++S97nu+9Qdw27uw7Vtm07rsbjPZrtqlreTJ7Pd3bp30x1iL7fWlU9DhJEJomE00R
kxMEp6Yk8k8kn6mU8ppvVNBmjU2ieUHinlA0EyaAhGpI/VPUemiB6IHqBoMQNAAAAAEoBCExJiJk
h6DTVHpAyNHqDCNDQND1AAAJNKQQp4KNGmjKeij9U2jFPUG1AaHqDQaAaaADQESggQmEZAU2mRpN
MUyT8FTxGmkaGT1GgAAeoFSkDQBAgQ0jJiExoo8oB6aahoAAAAN0hM2LAhPEkpOno9NC9fy2fST5
jMoZJZrlqgHrZY8jm/bzPz4+EeaHPzl6yf75YZcNV515y+zJbdKUsMOtCuYWcyX3EN7wJKTI9vq9
7N+w+g/wYF3yGwGyM1I7DUDTLDCCuQaiBSzZmYZlq/XKjtRniO9fslWfKXd0EZN9VT0JVcbr9E8+
Ve2spqZe+odilkH7DE+KcA9LWxl/Yrx/1CGiqqVxkwdypCw7B/IwyT6gWpYszdfNhE00UfGFDG53
Pfsc6NRiueTaueZ/zzJ8dW8sdaWGi7eju93O39qodqjFQojEfd9M0tTTxK3PpPXnLyEuefjS2oH6
6lOqmqJ07eRUQLR3R2QHtswIhoolapvxGA9a1GEW6C9RyyQRXs8vTaMzXxpfBw2HZryR7bo283wP
S/eRFAz83L8CygIcCQ+AYEWQCMMi+loGS1QUBQyR6Uw0EdQbsSLoLghWS+4dm6HfJ4yp8Xj6ZS4m
8fDhhIT/AT3giEERGIxFYsFUnP73+SLtujqFh56JRPR4B6KhK4kktQbZ+z2Z2xjTJHsC+Ek1PiQe
IqA1drhK30w7CpwLjItS7qZuw0gysjIzs1A/Pb4Dn3nYjjqDqB+D2/x9VU3SbmhF+3SuPNH575wK
fbTTzTnxsD+5U25ilvFwVPRKrJEtbHp6Qgj3SeJofUFmCsnShUYc+qScXg/vfsS5Nqg2pFaynU/d
B3ZrpZ6n7Xt2sou48IRja8T6SRthoAj8ikUHIVdG2vlGneCOwU9U7sqcZBnR51o6jUXk0SWmdSO2
Dh5EtNDCC1HED3HNgrnHIZ5QFdpmMmjKNBOml1hVXkIKLTs+76WaOUppFakZ2nj0C6fbRsg/bJX2
q2Ma49SZAkyZSrspLWtea3GkOYizGGcwKW2vGoxnlyq/JTtGPJ9sktWKQ1yiV0R6GPJrtacF8VG6
vViNxnsujuIjGGg1seYe5yvprijIxwwz8hr1kCwQK7Dhw2hGfQHkCLvnREMHKwYUQq8mK0qY+Jk5
YlTjUuKzLkGjs7UUZRRG3O0b5Gy5pgWHqOKCZPCnlNB34Fh9WYtMxznjPJyT/snBdyEaX9RlRXap
i9snOLZQ0VtDa8i9+wiTK94gd1DkDIIohzuPEmmiyr8PeXhMFrtDQ28EX9+q/3DnXBpFpNjEWUay
5pv6diHhbnZl7wLhKFM+MWlOnMRILle6PjJtNmTo2ikAqqFMzMovYidLdeeueXl8V04Q7/gdnLvk
maKKKKKKKKKKKDlt37erhMI8t2eHGvnb46m0xnrx5mOILlmCsk9/QnbqozU14gicNJgUldBn05ZG
Vyiyr0lLE0LvAy2JHMndyup3UhqGFle3S82DnuOxgSlmo3lC61fmSTFxnileAMa+UMzfB0UXsNwQ
mjFEbHPh7KHxNU+sHbZMnbnWFR1LimFFUuvJ9d8y99eg7yY5KQoMpacnmDWB1bA/TB067khZjMIx
3taAgas5dNNM2u7vlW79Y7BgyBkB4i8BD6oMzYjydzHMz951+X6+9sh4fdDfX4WWUEs6FWhWBawt
87YHGHxmSoqi+bXe9jyfjZ0O95vY6qr0eHjXiI443hpPfHWopiUbSbR8ZvF54zVwzjhpq85IG0rH
UL09/gmcdDQQa+wEIqprxkMMMmF70OhOhbNvDfCWwRaAskUJhCCyQiycQOSRkhIQkCJ7lvBS/7Lz
hav/abUao+b9HF8fW/sLNL/+9O0J3aIaKboqArJ4hIWPrH2hSqVTDmc+NdkLkaNR7ors53LWWYbL
6gzDGRvDEnEGvAQTRc4Cn6NKW1rHDKWRx7p9ASZgqPNgZX/DjrjPyzKkNxZn8kA3m9hSv3veiRRO
gvgOLdcp9X3NrpVfVryQqaWIGyTMSMDfxICUSooBm6GWXyHgiqAqCp9J4Y9yt7nxLusW2fdTt1jB
mEgoX6jTvdJR390BkMhCeA62OXSi1OVhQA1vsi9wohAXQ/z/A7PxkkPzlEiUxTx94nzQ5wLJzOzM
KASXIpEh+UVh8Y1/AWhoT9pHX54a52VRWH41R9sTwfQirVGemaPkaIvTn+dMYa4Llx8vHMOJjTt8
W7L9ntr2vG2tOKWGKFK01onDCV/HRbHcYq/442Tko3174cmjW2gfk0NHVQ89HiNpoBgvC9HQdp68
M+rzuOZOuPXhi1XtnqDR+yphzFCmaiB3hmEIYXiK4UlZsoe6MI44hZKjxcFFAukJAYmBg7zwDKkK
fo12kOMpc6IaYmn0EOl5Zui93d3e2222ltttttttttt/jCeNCE39W2+b3eg6g+RzwZ33o6wBFVCX
YB6bwZkQZUR3vSt6mbnZ8hEmgS+JuE0GBVRVXLCJYpD0Fh4+YuRvBi1iWRJDFcxxRS5RY2WZ1vWc
2S80NDIctCE6u5qfMaGEC6FNoiJkgXKcp5WfVMHBWFNRgYA7MzabROg14oaZ5qxYZv2+vSWWaurP
ZiKKrI0Uc3Nbh+rnhJ9rFF8aDfmQyINjeVruxRMHAiqBQ1kQGpOJgq0up1klCIWQGK5fImmJC38n
JoyYuvXV0dXwq5t3JV74a4wo71X83sjo4473qQ9ZRDmVzk6xO5Fpn1NOu3SjBG040nHJXC/TylCE
EIGOXa+fQWtCbkAUKgOfwzFUwe4l87Ibsyw6FULlizpU6jNVAuVOSO/HOmb4PnXfa2jBj3xC6ul2
E4qQKBqKADd+BEQ0FXFbukiefCLXqw7racnRxe6OzhfdDMmykd1TIwcyTBXbQ+2QzcSju1fgqBky
WN9wS3UiCe7uO9k6qOGYquaqMFVWCii14sHOasFFSQxAF2IJDkTQI4CIK3jLdhu4kSZii+18d/E6
RZscVL1T6Ld0Ic1ATCoIIGZsZmu5qkiRapDVSCaW2QF7GP/kVw84U45cWcmTzYPoGrJz5ufJFWLd
hqjZVbzpS55cPNqjOsukbvTixvM3k0TdnflEzbqKtmipxEXM12jCZYIyUaKtlkKJdavrGKMl7eL4
RZo4fojsuUUZMFiZM2bs0VeE5quTFDxE2pEKCeR8jiZTKdCU3V56b2xGurPOcZS0u9gIEMhDLaqz
eNTpi6BzNhCkRNRk1LeeULajh2XNvPm8lUX6NNNGWKOIhiihLmrN1c3uhlijpW94Ojo98OzTPMnS
ScLGiadJNHJ5oojIqyaNlWRVu4ki31SUbM1PmwWL6uFXVY0UepY1eDqwVZr2LROTBV6FV7h4NnNu
7vG9g7I4+tFsNkZctudzpfgrk3nqXWrCFhCyTDF3OYYQamYQF4FkQTrWTHX0LFzhwaXFyJ1m67mx
wnFhCjgIcjIUg7Nlzs55Zt2i9rdDojpMb+1LcXGM72qidFbDEcC5gMY4IhZksxsQYNiHKpyDUSRB
UDkjXC1hc7KLNXN0YsWrGJNHywvWOTJaqsTFe4R2ZrmDGHDhivLmS44Yuna17Ufaju96Nr9NO+zu
XXlabVsjVC6gsxrTuyJWJZfJMXeytjuUc3BDQ0uZuWOWLrtDudmmcratdnPJvoxfIlU64r5qlzlo
6Oa67OUdDByZquWbnR3t2DRmbJtcvzKMG6xgXNTiliiByiDmaqLY9Ah3iDiC40sccDg+4hrCMIbi
ZrY2ZEeikBr4FYcE5QYWtzY7jVY1d/h6I2qo5N3Cx56XRvS9ZsjqojZ3ObMXs9yxeiTIYxBgnA4Y
8hc2Kuchy7kDnMysbsnGt8noU4Yklzo3XMGTN4LTFHDNioqtescjJaydFzZote5F5H1/UjdFu3PN
6aujdC4ccTDHacCm05UWQ5HdMunVcTgDE9Pp5VPB3s1SbOk150Uv5sM1WEmuubO7Vmx3aNfJRqxs
yRgm0LGDd0VvWqJVV07L2S7dg2WLZlwxau1y/d3KvE5Mm68RVRo3aquS1uXnRk6NzZm0WmjVmzeC
MHCjczPADxQOHOZyfq0DQVQLchkEqGve+rrIiWUsNgcyC89DPEsqgXp09ORWGZtHiVMiFFFIJWti
5izYY6aKQ7neuSxRO9bnVs5DbG23EkJyStxcGxNZaiL1jRxUpO6kExAmRkwatGjRe5rlyixO9y5U
p1aM2DRujrDz6ZY9xuy4bal4zflS+GO6FZwUMhNo2QqJnKS+drJeQjh0d0S/SjOrFuw23U0SSlEb
NDzhZai16aLJJRi5KLq4MaNG7VwudFVmRR4tmDVyYVN3ZVk08cZq67OGbCN1jZwth6UWtW69Y2Ua
OGhVzfBGDFe7+FFjZcxaGByfKTtGviOEfL9qPKlGVhZ9tr28NW0nXDzHT8I/Nu5bhGNgOqLoMELW
6QDJC5AEOeA2tIWdAihth2YX/hx5gSubnYeA5f9ghOjEfKCyAj+9GCNH4RE4hyRypAYMigo6kJaB
shKHIMFhLAtrBhYwZacmLFixYjFixYsWKK0YyGOHtR+SjvR5kao4o0Eckb0RqhbpIU9fCouzJkhA
ej4Xev4L3+uMPn8tJFf+ZGVakkKgAsRYR+a4F8L8iHrh8vD6Mpq97T1evdnmmaeb58DQayZaN+o1
w1TIrf5YlFL9NWOD+4+3V8+XtmFynfBHREdVoXTkLeVHuTURwldEN/DHA2NaQt0qKAztJct1O7NA
oLxjEDJtlIUNOW5lvJa9FjSaD3Jkr3sgOwRTGvK9rLGZDA5CEQN7M1WcexhTAPEnFDceEX6iPfDy
fmTq87Xh+KYAxLt+wc9h2MlxJbDYhvDapublPyMJalJHmbUaMhCLzpk3G6EGJMVQj+pwKlJEaoJk
FVKQmmA7CnyBGeqaQnHf8QZqKMVUiqSbgzaOBmtHPt+5olYgSBIyUdZ8TmPxQ/E5hU/W/FsqxWMF
pe8Fj+F5P1KNV7ZevfmoyfmYLFyRTQYsSZDDGYpRBcog3BFPoETuRsycPypX9a9LJN2kNVtGSHdv
GH6bX6shQFjadRpaPnNYUcjBmOIvNpyF9e4M4+9R0ah+M9UDSayRAczGkvHKuC/BgSY5ECNQiR+L
ON37FaXzXKOME9tEV5iHq46yc5szUzKDcsSiAiaF+TQQMwYv0qioKPBAqsWDIFBEPD2t5962wCxV
B0AxIfdQ9QP7We0P0gg2T2Qib972gewhy+Aiy5CkGZNfgAI7cNhGRn/sha46sRWTHaCydhrJhIac
Ty3aAoIsSodjZCYiB6A27rOgrBMkLpntkhgZdd8f3QM24cV37Ao+nIOH9KdaKOOrxpB8H1vS731r
n7D9DHq+K9iufYisWvsbr3NPQxPqRVi1ZN2qwzXL1j0/t4MnD7nC14si5Y6vuTzcJ5vf73ixZNmj
dRR3uujp0q7lU9SOA2dVkeKncuYuH9KOJzr5IocmHYEDth7ouwFA9InSPFHDTl7qDSGcDAhigNDC
esfyTfKGozYh2Lp2DMGUBjpY+LGIQLwZFQH0HTkS0nObTjIpzcSPzEbHiueta6e217GSNXwLlzJa
9z4PMsew4XsmTdwnuKlHSGjr7Z+yk9zo6Nm70/J800ek0UJIOr5uoZ3OIxFhkJBxj4rxOZzMRRms
kCiDJ7vF9kiDTA8JMcj0OHPD5NaxLbBZGRbbCIwDpwohS4aT1iX8qqXCosnonnvPKqapXxyMLGUk
Z6q+RilEiaYYTRr3lPy/8uecOR5A9HfcWvOwqJjv69xP4EPe8ZsDadTuHFG9biexfPQpixisGsxi
pFTAl7KGzEnETYEWM/Tp2lFVAdBznMfwWEBpheUiOckOZxOdQ5gqwLlz51dFMHMk7kehHJzEeT6V
rq4TZmzifwIvc2DxkCk6x9Do0V2eZ7fqbPJq1VKsyC9RcWpZjAYf6co2x31OoPMeGBlGJ5KXOoTI
s9lvOOGLWdiZYu86OjE1Gb7XwQ1GfUo76YUU6wPRHB7ibxPsEyB0LBtSCV2W5IeAFgEki/UIx42s
8oYs4/e49DaWunOU5TYCOA66nKGzLWVcT9MQXSDKHEgZR3GsO5ZcCIvosImDErUwFhZmkxJBeRpM
c9mwc/XB0MKYvkWtK00BmDukwYEBlVQzVlZvHhDg0mnhBytlOIpjL7FGxqIqollvxd8G5txzAynR
XFRV7FRXGNWAbKlvx2dZN3a4hdWQQU7zxPBApvP6/POj7/KreQYgKDzxUdwecNh0DtClRgxcZ4Tf
Rr6LqkPz1rS1eoYZnNafN8OTofK7PB7ni7Ktng4efnTzefpT2JSixfMo+awjyNIIdYyLB7HDwcCo
sQRTc3KNjgWXrF818uDJHM7DrE0JpV7hSYPMXg9B8qjhz72OmZxZlXgyY7SBrDXTwWgxSqr3OYax
UmInzUqAN+Q6fIZThyhmKOKbtiQMhNE2lJ3+lex5yIMnBUnWUh3/Iw8JvkqtkYPurhlkTQbYPXxx
jqoZhtVuPKpmcff+E3R9vAz1g/ufZbgFjo36bpaotGhVUNpWwgHwcjHgWCAyCILIG2TuIbt3Cp0b
/AZX370m/J0LlNLcq0rSUL+q1kbLO5x8oNSIWoOI7k6z3wKfpgOG0DZ+YQWgI6FdNbNhwj0zmp3Z
dV9UzZ0JL1DwTV9IjqL9Tr2BrBTE0dRqRjsoKrugVf46+BrLOjOqqHZDDca3OsYOZfTqogjru3+Q
MOoh3wPozOCCdInIDnR5b+L41aSpBxA7oYYIMnGhDm26dPWuooIUShRRA8R4yS6TrZrmT6Xx+NXt
aPU1S5ksZJqzYPi9yOarhgxYKui9a+eFGjFp1VXr1qx0UXr2b1WdlzP6u7CepHc0ZuSxo7LF69u1
kTPv4eDHBTSaLrWbxkTZ6EarVo49dH5pKFgopD70aC/mQ8YngwKQcVSDQIPNCwk6fbQRVAMTEcz+
ilIQD9isrgrsoUGdCj3il3KwDVlgmMXC29jUwJEUYRMmYwXGJCCk+99UO9GHWkr6JWwbF6M5EPhr
Gbqh2CZDmGYNFQ9W7qQvTewwcHbBy/NGH2EN+109k73LhhS4quMGMFsoYhLUWSafWsJkkhOGaash
QzQEFaCSTNIfrYLCKpKHj1xmMmkXShSpfFATXShmi/VIdprpkuYIKqMi9QhyIdEDuAwaqNpa9iGx
I5BDrANGue9ukRRq2iSHpBdgjSfXOo6+KJvliORyJ2eRKGVP2hbHGyMO3pUA6jQzbuLtnaITENDM
wXJCmf1e9K7MqIenWW2PRCSSOZBC0R8doVxkQ4U4ia/JDqwVbcDaPYdA1GGcJlYeh6wYB2SXRCcW
Ey586G7BSgRRHr+1n9PLaIs1iRjIDK92raAUMGl2eOSAcoOJL4cENbxYSDCB3eCPMjUXHZIjFIEC
CyAqQMDN9MQ6I9KSmvIISCrEVIqwVO7pOXl2QISk9O01A7RIYbJ3JFYVouGvN0sSSt85gKmyjIYY
kkUyOBUPbbbattuRD2kO4h0ENM9KlvkIeLvTwR+uQ6YFOB1nhhyLlkIrkQMFx4fdnPIZZq3ePrhG
N/NF/0w9yPwJhDH8Ue1GUj43xL0qkJE8/0UqyXLWLWQuJwFDDhOPdxrDqf4kjv+es0bxq8oWM5bQ
MaHVwsWykknCjCgkxXfaRONWOnM4VmJokRVPB3HccOrIaRGMTaedQtk6XJzFjlsE1GyGVbwK6YIT
5CaWPnLUKaHBCzuRg6HGkpQgZCe7FTGxQ+WGYManwR4o2xHgq8mJVTDv9WJ0QhIFaX75wmrEspLY
8xaWlrxmEPZClbZe5zrU24sIG2DQ4E8J8/+4T4vOfYBsSg2JQaJQaJQbEsEsSg2JQbEoNiUGxKDY
lBolj7SHPm7wtSChJqNrbnNdZhdMkfsRqjUxoj9olWjvRsTd0AVF9OB4MOMdhtRw4KNP8NZeA0JT
lE+36kYuRLKjWYRGF9sy6KSgzIIr/DHzxEwODDDnbDWGWLguILDGdUcrhsxkW4+iEME9PrcjDmhV
NG4tDFlAYT6hC0kDISCURgBIZBSu7fSgfMIo89+3nw1SI1SyfOGUDGQZDDCGEKDiBDA4ahcBK2o0
W0iYl8tRnJILb6fYj8VRhJH5IijSI5TOFcoZZI8tv1iYGWIY0PjT7ohq1YSTXaXGQKUGbDNLMCQO
dMxMxhkwYoQiIFBvifyCXVC6S2sD5nw6fAEpNqQ9CeUQzZS3OB/JgYxyxLD2H4ugInf1hgIfOeo7
z6SKXon5TswclT+o3GtMhUD9etcdxlHvQipuNvtE+Jp+AkXgGCcwb5qLK9uiYGSNsKrFD4eNmxNs
YENIyAGR5YmI6PJmxVf1YM6s1P3IlJFbrsfoXyLyJaGpsvWzZZYvx6T4soVMitDpwHkIOsCHTu49
1qZcKlAaBBQ2ZDkqLyDlQcUcoq7F8e07MvH6/vlMmxNi8pGXSC+hz0yM/8v8jMxlWblYp5IAzaNZ
BYgpKUhAVqbBEq05/ZE3/T2ZjDFqVSFaqiBkeB5kL8yfuuL4o/ej9wCdH7fmh+8TMT+41KO/qdlH
1B8aKrnyOKm8qEM+THoDyQO4LGe+GJpqH46a7weAywKtYFBBSgpRSgijAEQhSyFEjvD8JGQkVHXg
fwcuk5i0dkQKPn1U1Gz76rujua0HtR7RGI8OfR+snGSQnQ5XLa0JASV0EKEKED74h3iC+IhuJNpE
sWv2V8FzhVEqjPZcN0cCDblbkZW+7GCLklS555Za0omGsRJUyJ4TDLkD/fNt04NDPWm4MjZSy5+m
L2EigXReGS2VJR+8johZWER/U7kfdjU4YX9ynxgAX4QiiBfoE301WqR2FYV2dhVV1RmU5PGVe/nl
Gl0wZDxwOZbbyoJnx1QCFgdUYHvPajasObs6YZZsVfMY7UfwRxF70YqFUeCHA2BTUbfZbQd57QcP
OQyImXkShjYxDDukQWTKyTwjW4g8gD6mmihpq1FR/YRCpCGcoMih/tWqI4QUDCXEao0Ggj+Qc3PU
sLeNIL8kCUhxE7hDD1r9eulfGh4UWRkL/C7ddsvTPD7EjqEwZjgoUeYvdj2HNPnnKyAdGsg0njC6
6Jc50QDMIVSMldzRW6Ky2UbM1GXAKF3DE7RxuRSEIVZ5hrNMVIcqfmjI6M1DOrgwkofmEOIJ1XzN
+2hiLcRiN1pdV6mxNmrHoZfhS5apJC5zXpYMQPHA76hm42E95E9MvnmollHwUddbps/ESlsjlRGJ
AEixUIxGOo/Qhkk/BHr06iOWkkvn3yIPYzrhIO7XbcsssSBpjgjKHtj7M+5ccTToQTFsegStbCRP
evtYGLJ2cNvxmbJuvv7N3ihCiPgXEQWYhH8ZNYg86lhxmFsr2YVULOO6TFlcHlKV8lUs1aXLEM7J
YkYZZYZsduRRNrDfea8DCpS4W0SXManp25pHmR9eOFXPIjArCtnTVmWVCARUS94Ul4AUc5T1iYg0
1I+CNATQR9GlSrSim7UrYqR1gupovec2wSxjUAhm5XzyJQhLcZ2gEbfddVbggmkzfV1CE6zNE7Mw
vkTe93hB0J1NkXSaAksEKhREdKDLRUEQkxQUprlCxFSwYnclbxwwwSgj3bRLnby3YITSScY8znWW
7jrZ4LLbKrLxQT8o92mkAkRZD0BDamqhlQFLo0CIyIrFbnEPM3HnXcmXlrF9+Kwg7TToSysAjKYX
WOjK0N4XHe87hiGkGQ6wp9GnaB1K7EdWyiPYvEe0Tu0E/md2jqumTM0+v+H8oAXS6oUQezK8spQl
Uk6FkNmzi4kSmoaRHa+cySVoo51OI6RRApUN8F1n24rsYBtj2JH9KGmvpoDpnYcsEUh1RPr02SFf
2P5BGcR/RB2ARvGr8jUnUFJJGdyhkqEMDoXvY36xJ6cUxQRngJ9Q7RwO8e4dafQGyibxI117qVE2
RNGhz7etalVK4QszRS6t496N9kaT5EUkjL2TxHyS2Ec1YoPLn8514Fr1aUhY4I112Cx1UvhDNGsP
CmVikxqVlhJmFakghjgLtQ6KIXiZo031Rs09wm8deniL6yNPAMxPFOC8APehvFq71bHgJ0nFHmQ/
oSKHPv7E9n/xdyRThQkMkaNt8A==



More information about the bazaar mailing list