Code review comment for lp:~jelmer/bzr/foreign-tests

Revision history for this message
Jelmer Vernooij (jelmer) wrote :

On Thu, 2009-09-03 at 00:24 +0000, Martin Pool wrote:
> 2009/9/3 Jelmer Vernooij <email address hidden>:
> > On Thu, Aug 13, 2009 at 05:09:06PM -0000, John A Meinel wrote:
> >> 3) I would also like to see things like:
> >> class ForeignBranchFormatTests(object):
> >> format = None # set by XXXXX
> >
> >> def test_foo(self):
> >> self.format.x
> >
> >> It makes it easier to figure out where things are happening.
> >
> > This should work well for foreign branch formats. It's trickier though
> > in the case of foreign branches, where there is custom code necessary that
> > creates a branch. How would the adapter find the code that creates the
> > branch attribute that is used by the member methods of a testcase
> > class? This seems a lot easier with a MixIn, but I'm probably missing
> > something.
>
> I might be missing the point, but I think you'd have
>
> ForeignBranchTests(TestCase):
>
> branch_factory = None # set by scenario
>
> def test_log(self):
> branch = self.branch_factory.make_branch_with_crisscross_merges()
Yeah, that makes sense. What about something like the attached patch?

Cheers,

Jelmer

--
Jelmer Vernooij <email address hidden> - http://samba.org/~jelmer/
Jabber: <email address hidden>

1# Bazaar merge directive format 2 (Bazaar 0.90)
2# revision_id: jelmer@samba.org-20091011013123-zbcruv13w8q2h6r5
3# target_branch: http://people.samba.org/bzr/jelmer/bzr/squash-xml-\
4# invalid-chars
5# testament_sha1: 32984381e00180079b59a5192388743b5ddf002e
6# timestamp: 2009-10-11 03:33:30 +0200
7# base_revision_id: pqm@pqm.ubuntu.com-20091006204548-bjnc3z4k256ppimz
8#
9# Begin patch
10=== modified file 'bzrlib/foreign.py'
11--- bzrlib/foreign.py 2009-10-06 14:40:37 +0000
12+++ bzrlib/foreign.py 2009-10-11 01:31:23 +0000
13@@ -36,7 +36,7 @@
14 """)
15
16 class VcsMapping(object):
17- """Describes the mapping between the semantics of Bazaar and a foreign vcs.
18+ """Describes the mapping between the semantics of Bazaar and a foreign VCS.
19
20 """
21 # Whether this is an experimental mapping that is still open to changes.
22@@ -122,6 +122,8 @@
23 class ForeignVcs(object):
24 """A foreign version control system."""
25
26+ branch_format = None
27+
28 def __init__(self, mapping_registry):
29 self.mapping_registry = mapping_registry
30
31
32=== modified file 'bzrlib/tests/__init__.py'
33--- bzrlib/tests/__init__.py 2009-10-01 14:44:43 +0000
34+++ bzrlib/tests/__init__.py 2009-10-10 22:28:00 +0000
35@@ -3650,6 +3650,7 @@
36 'bzrlib.tests.commands',
37 'bzrlib.tests.per_branch',
38 'bzrlib.tests.per_bzrdir',
39+ 'bzrlib.tests.per_foreign_vcs',
40 'bzrlib.tests.per_interrepository',
41 'bzrlib.tests.per_intertree',
42 'bzrlib.tests.per_inventory',
43
44=== added directory 'bzrlib/tests/per_foreign_vcs'
45=== added file 'bzrlib/tests/per_foreign_vcs/__init__.py'
46--- bzrlib/tests/per_foreign_vcs/__init__.py 1970-01-01 00:00:00 +0000
47+++ bzrlib/tests/per_foreign_vcs/__init__.py 2009-10-11 01:02:28 +0000
48@@ -0,0 +1,47 @@
49+# Copyright (C) 2009 Canonical Ltd
50+#
51+# This program is free software; you can redistribute it and/or modify
52+# it under the terms of the GNU General Public License as published by
53+# the Free Software Foundation; either version 2 of the License, or
54+# (at your option) any later version.
55+#
56+# This program is distributed in the hope that it will be useful,
57+# but WITHOUT ANY WARRANTY; without even the implied warranty of
58+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
59+# GNU General Public License for more details.
60+#
61+# You should have received a copy of the GNU General Public License
62+# along with this program; if not, write to the Free Software
63+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
64+
65+
66+"""Tests specific to foreign branch implementations.
67+
68+"""
69+
70+from bzrlib import (
71+ foreign,
72+ tests,
73+ )
74+
75+
76+def vcs_scenarios():
77+ scenarios = []
78+ for name, vcs in foreign.foreign_vcs_registry.iteritems():
79+ scenarios.append((vcs.__class__.__name__, {
80+ "branch_factory": vcs.branch_format.get_foreign_tests_branch_factory(),
81+ "branch_format": vcs.branch_format,
82+ }))
83+ return scenarios
84+
85+
86+def load_tests(standard_tests, module, loader):
87+ result = loader.suiteClass()
88+ per_vcs_mod_names = [
89+ 'branch',
90+ ]
91+ sub_tests = loader.loadTestsFromModuleNames(
92+ ['bzrlib.tests.per_foreign_vcs.test_' + name
93+ for name in per_vcs_mod_names])
94+ tests.multiply_tests(sub_tests, vcs_scenarios(), result)
95+ return result
96
97=== added file 'bzrlib/tests/per_foreign_vcs/test_branch.py'
98--- bzrlib/tests/per_foreign_vcs/test_branch.py 1970-01-01 00:00:00 +0000
99+++ bzrlib/tests/per_foreign_vcs/test_branch.py 2009-10-11 01:20:37 +0000
100@@ -0,0 +1,151 @@
101+# Copyright (C) 2009 Canonical Ltd
102+#
103+# This program is free software; you can redistribute it and/or modify
104+# it under the terms of the GNU General Public License as published by
105+# the Free Software Foundation; either version 2 of the License, or
106+# (at your option) any later version.
107+#
108+# This program is distributed in the hope that it will be useful,
109+# but WITHOUT ANY WARRANTY; without even the implied warranty of
110+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
111+# GNU General Public License for more details.
112+#
113+# You should have received a copy of the GNU General Public License
114+# along with this program; if not, write to the Free Software
115+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
116+
117+
118+"""Tests specific to Branch implementations that use foreign VCS'es."""
119+
120+
121+from bzrlib.errors import (
122+ UnstackableBranchFormat,
123+ )
124+from bzrlib.revision import (
125+ NULL_REVISION,
126+ )
127+from bzrlib.tests import (
128+ TestCase,
129+ TestCaseWithTransport,
130+ )
131+
132+
133+class ForeignBranchFactory(object):
134+ """Factory of branches for ForeignBranchTests."""
135+
136+ def make_empty_branch(self, transport):
137+ """Create an empty branch with no commits in it."""
138+ raise NotImplementedError(self.make_empty_branch)
139+
140+ def make_branch(self, transport):
141+ """Create *some* branch, may be empty or not."""
142+ return self.make_empty_branch(transport)
143+
144+
145+class ForeignBranchTests(TestCaseWithTransport):
146+ """Basic tests for foreign branch implementations.
147+
148+ These tests mainly make sure that the implementation covers the required
149+ bits of the API and returns reasonable values.
150+ """
151+ branch_factory = None # Set to an instance of ForeignBranchFactory by scenario
152+
153+ def make_empty_branch(self):
154+ return self.branch_factory.make_empty_branch(self.get_transport())
155+
156+ def make_branch(self):
157+ return self.branch_factory.make_branch(self.get_transport())
158+
159+ def test_set_parent(self):
160+ """Test that setting the parent works."""
161+ branch = self.make_branch()
162+ branch.set_parent("foobar")
163+
164+ def test_break_lock(self):
165+ """Test that break_lock() works, even if it is a no-op."""
166+ branch = self.make_branch()
167+ branch.break_lock()
168+
169+ def test_set_push_location(self):
170+ """Test that setting the push location works."""
171+ branch = self.make_branch()
172+ branch.set_push_location("http://bar/bloe")
173+
174+ def test_repr_type(self):
175+ branch = self.make_branch()
176+ self.assertIsInstance(repr(branch), str)
177+
178+ def test_get_parent(self):
179+ """Test that getting the parent location works, and returns None."""
180+ # TODO: Allow this to be non-None when foreign branches add support
181+ # for storing this URL.
182+ branch = self.make_branch()
183+ self.assertIs(None, branch.get_parent())
184+
185+ def test_get_push_location(self):
186+ """Test that getting the push location works, and returns None."""
187+ # TODO: Allow this to be non-None when foreign branches add support
188+ # for storing this URL.
189+ branch = self.make_branch()
190+ self.assertIs(None, branch.get_push_location())
191+
192+ def test_attributes(self):
193+ """Check that various required attributes are present."""
194+ branch = self.make_branch()
195+ self.assertIsNot(None, getattr(branch, "repository", None))
196+ self.assertIsNot(None, getattr(branch, "mapping", None))
197+ self.assertIsNot(None, getattr(branch, "_format", None))
198+ self.assertIsNot(None, getattr(branch, "base", None))
199+
200+ def test__get_nick(self):
201+ """Make sure _get_nick is implemented and returns a string."""
202+ branch = self.make_branch()
203+ self.assertIsInstance(branch._get_nick(local=False), str)
204+ self.assertIsInstance(branch._get_nick(local=True), str)
205+
206+ def test_null_revid_revno(self):
207+ """null: should return revno 0."""
208+ branch = self.make_branch()
209+ self.assertEquals(0, branch.revision_id_to_revno(NULL_REVISION))
210+
211+ def test_get_stacked_on_url(self):
212+ """Test that get_stacked_on_url() behaves as expected.
213+
214+ Inter-Format stacking doesn't work yet, so all foreign implementations
215+ should raise UnstackableBranchFormat at the moment.
216+ """
217+ branch = self.make_branch()
218+ self.assertRaises(UnstackableBranchFormat,
219+ branch.get_stacked_on_url)
220+
221+ def test_get_physical_lock_status(self):
222+ branch = self.make_branch()
223+ self.assertFalse(branch.get_physical_lock_status())
224+
225+ def test_last_revision_empty_branch(self):
226+ branch = self.make_empty_branch()
227+ self.assertEquals(NULL_REVISION, branch.last_revision())
228+ self.assertEquals(0, branch.revno())
229+ self.assertEquals((0, NULL_REVISION), branch.last_revision_info())
230+
231+
232+class ForeignBranchFormatTests(TestCase):
233+ """Basic tests for foreign branch format objects."""
234+
235+ branch_format = None # Set to a BranchFormat instance by adapter
236+
237+ def test_initialize(self):
238+ """Test this format is not initializable.
239+
240+ Remote branches may be initializable on their own, but none currently
241+ support living in .bzr/branch.
242+ """
243+ self.assertRaises(NotImplementedError, self.branch_format.initialize, None)
244+
245+ def test_get_format_description_type(self):
246+ self.assertIsInstance(self.branch_format.get_format_description(), str)
247+
248+ def test_network_name(self):
249+ self.assertIsInstance(self.branch_format.network_name(), str)
250+
251+
252
253# Begin bundle
254IyBCYXphYXIgcmV2aXNpb24gYnVuZGxlIHY0CiMKQlpoOTFBWSZTWVqfm5cAGnX/gE5QAQBY////
255f/ff6r////pgInXdzFr7nA8PDpml9zJfc73vS9PSa7m9toG2Cq06A6DqtNCg3uea7R1udnvNxpPI
256ZpneYaD28rr3e6zEt5OcUddenlO93Tt06vLvDe9uR2wBhJIjIGgCAmENER4Umyj0mRmo009T1B6m
2571DR5QSQgBAgmiTIo8o9RtIA0ZBoAAAABpkEFFDQBvVGgANAAAAAAAAEmlImmUam0BU800EhvVPUe
258ptQbKD0IAaD1PUA2UEUgqehppqan6jTEFPNU2nqanpHlNHpNqegTTRk0ANNARSBCZNNCnimnoCno
2590xU8KeptQANNGhoAAKiPVXQm9hxAIcW+fu/igFST0YTsDN5LW9C+LQhHiTR3ceT+U726IlUfn2M4
260C7+UEseV9Hxpmf/mqhV8mM8guGKBqwKi9KeDOZQ37dHW+3Et9415hvvkIQ+iJv0ESR8Rd6MnWNva
261eBsbLuRpqMw6sRw4l7+vcu3wH3kfZWKElxLXMPJxOy0wsWm7fJN89Y2VEjdtj5n9V5S1b7ds1kuG
262tDkNmEkbrTNQaUIdDCcBlTDmYLJjGKHb/7Hn+B7OC7+fnnKf2E+Q8fPyB7j0kpyHMHyw6xNDwQqM
263aCocBdnyN3Xscp34mMd18zjdr4tLmARZsyoZshKwkr4gKMJI7EprAYZ2vD2YVTH12Gs08XnGqRTW
264RVBVVPNIKg9EG2pgRGWFjTwIVWAwKIqLMTxQxi73lKs6MUZmC4icE2Zg8pCSNbER7eMHhvsAqmpB
265eBAABwneVAtE6BcTQ/fw2z+bXyyQ9wTsgaMsgIwUEUYKsFgiQBQPwZ957whOrxdfHfrDaUWK+LCO
266yMPBiCzvDjBYkYLRSFFpK0NGmsZbRCxqBLMBaap0kRJIhhuBT6aB9y+qb3KSZALKBszTJyrC41zd
267wWEQhRkxgBBWQMhJysG5aMDXTzNk7rKESqLXZ8WjJGWMODLi1LhAtkzNnpWwnic3dhEKCsuE98Xm
268Fqy0CTLuhRzEG0C11ktc2IsRikTX1DDYbb4vLZyRu4AYD3HgbjvO3UbvgWnM7hjrIFhCi4UYlZqG
269Ace8VJ58hTnxJiA37sGBwh1ZDsMygXeUhOHaOFEtJplcI+BtIlqhrWXoHtXvZ7k95PEndVN35Efy
270sOBApHz7bFWZFG745VDBF325XCnMpyBbkQLidTsbw/5Pn/327mz1DwR1/KPLTbcFb7omDDAoTD+7
271yeeXtc9m/Nj2MiGdX0AysaVtikRUIghz/ivFpFHGJKtbx3DT0PPkgrfcid/YjJzsVKozaR0PDn8j
272H1JIv5mZLXKkYJTd8uOfjJKho+hSFI0QLrx457QEtpgbdZlBy0gBlvccc4piwTOOkh4sfI+3nVqH
273xsWl5oOkV3LIzbsgPqJHifQAakyYYaunLGx7DisVYq/uDxwMQSybyTwiZv4yMSCcmdkMSkGJlEiS
274tOofecc3vsHzkw80EHhu+mu4d4T+Xiefhbc6rdAqH+KJBYegF1Em2tOPNnKq2tfVgWPKQ4nPs8Kd
275/Py5Dg59TflXxq3w0o3toZCDtR9a+71/teAzJ45MMgeNOkGlLMufHe5zqkIHOZr9NuttlR1bpIK0
276MgYR5DE+oLD9IhBGAGDK0SKSdBOgQwIwEiQv9XZaHd2XGINzAmS2341nKSJBC+KOqdSdaNEM8N7S
277PeBnOzLJQdVAYCDwjFVBgGmYkWhzhzVVbGmazTVLA5lFYSgiSfUW/EHa792Pi5djtvsTGuzDNyVy
278VqZooKVrNU2x9WCVVzoLk3ErPRtyn8jq5jSTgnvZbxgnITyZVaGHdftMbIlt+EMkES9HU/45Y8S3
279n2io2wFvuNiRYPwmewGRzWZlCcwPTZhykEoO2mOQ5NIGac5pqZl8nw9LPsVWljZGQ5Rk/ROwLwgf
280ANqskTxFSlAkgxLSTNBfN+4GRB6Q8QWZCQUANjVWSPTNGBKiWiYhTq1CdQJPGOvdExCUQrkVgden
281H0S1Tu/cwTFP+cdOTduvL/+SPg44qzcM3Z/FfnyD/QSDQyQDhk86eLj7QNbLeUaUu+Q7s5z2LXFV
282gPHFdMwbZyGTIKwibT7Wh6yEAwbTfxEFVMwmMlmLlAGq03uU/EblSpf92/790vtLBqnTjbfz9IW0
283tpbbbLaW2W2W22/Icmuw6a67e6Tt+697ng0xxCAvduoZoSC5oCzck70sHXAhdfBcJp8AkTUsLci3
284dsSK91EYHfOcWDkUkGkkoqSNNNlpUSzIWNCBEiBW0Ca6SGhK/NZl7dsulDA6BsIEvoIlfdg45aq2
285yewlOiEeSsGOFcybgKJFzpu9SFcCxXpI4kS3DcgwfZegbXwG4OsBcSLwSqVC9ZBZulAolhgAz0cC
286DfBl7BLi4W7WwExRJqwiptWWIgbILFNWygpSUgRxuIZIZIg88tMwlktZOMHCvXHKVzejub0ZvjpO
287GeZDm5Vi0CJaEXxQKFOcqP0ELpJejrkhfvoN3vBz1ympSsAJvVlEQRPLK+EoiUqd6Kaer8yVWgeT
288EEmKyneliQxhJHnNxPmIJdlIxkLJEkgwO1JgNCEHuhzSC8I+AJtz+wS+phhIwKCsrDBUceVClYbM
289F0GAmoTltpiXoSJDGsdwekm6MML83me486lukH1Z9RttaM5Ld7FGx2l1KUCKFS+/sPLiIs0BaYZg
290i3Wa08rcy6xExnlj3ihbZUwC3CJF9VkjQhGRdam+vWJLoEg2nerW5R8aOhHT0En7u27sbgXXwkqc
2913MzLECdqnnBxPKDhaXzzkSvd1VBYl2yxLyw3G/O4wxyl1FirnBGgD5YLFCeiir4vyOSV9zZcGplM
292GDX0nQoJFTKe+hzngnxk9fRZK03mkOwDSZwKzyOcUz1UT5cGvEnu8yeQoOGUlUV5RRWqgHGSBIkI
293kuMoKKW9wj0ZoakEzlW3gRkqKLzJsYwU4lhEjBVIuiiE6SkCg3sKQBCQ4d6FepItRpQt4JXypq0D
294nRwAOjTpx6nUjIytBfJ1QSNCUjQgrBnKmPMPepYMRCjlHIoDE1ZZFt6sZgf6AlMX5k79loJFhzQu
295q8jG1jxouaVtXi0jg6KkGNosZPJ+wL8ADfHdLPGzQkSeUn53h3iUgR+SwoN5iXkc+TEG5PKkd9dk
296QJybpJyXS27JLPdYNwB0sFsHQ9yCKCJNwSkVYOvIht4BhHFglmXH1zwCLHNgsQTJvafS2CZzzs6R
297ZEmSYZY5HkkpOY+aQ6UxtIQs556SJ1UKaV0HsWXl8yklEwqEY9s8c+RzkmcEi86TJlVlvBkoIvvP
298lT2YrjQxUlVfdVHK2KFtQOD3elCkK8AoW8M9Vemf0jTU4eIAYt4nSljvJpY5eaGMp2CmT1Rs6gqX
299JcWFJsCBiQInAguOBwyosXBq9PKlAFxgRSiiFjaF4YXGFepJkKY+/RKDgEWmMpnNDZ34riP0qLjn
300p9bwU8Ba+TiSscu8264oU5EjadNTjNurfy7pnzdFNB6eTo88nawWCgsFikWDMmPOL6VjhbhPOItP
301cRAhqMkVEBuN9q8JPZBPk3ioU9iR6g7uFi2w1i0za8e2RsHzX3h3SPohbpLg+s589fJQHLQtpIwN
302eu71d3s9nJ/L2uSq5nTNOYi8pUyUQlOnuRoFAePgMA69rG4Zyhz0fDy9J9MdG6GOxgR2t1Y5v3hD
3031+UGOCZ3wbrxffK7c/fnbABYSZDNtrfYeKXok2S5ulF51KkoVrYazPxbkzZCo7GNL5txL7gRQtMR
304uqodhppNc7QkZVBTyBD3ATHAvSV6KdJ4U2G90r+mIPlxo1c1BQkTJW9tnQvGzBFHfqaTytmpcpVp
305dUCdLAXok69ZRyXOqmcZznfCCxuplGuVopMFwjooeWOElUblTLpixuYEiUEj1KsivPVuld7Ged7G
3065is7JhzPCu1DhcjeXKTpWu3uI3QB4ODniIScjsceuYpxoZijrDnJwKBM1dW9oTLzyV7A0V4Nwp1j
307zFv1I6j2ywt+vYY9Wb3jqzRJnu9QkJEJDUF2klzSVMwYkpEeVaz5cs6G/uFM8Qv5HP2ib56HM23N
3088BQvM1Q19Ou4fDyse1rIzEYGmomXXySNiyu/rWMdqs+oyWV97zlAiWNbDZsmINg6+MZjOebUOIAG
309XERyIRSoTiffC3LnVSOzxYksPPGL7pLaxl17fiQvQlZJaPXbBIczEpvMxJezJsRXsaCjq6FZWVr+
310BRS2e3EUTDlNd+anQhslneMyFcChNPytKfnbycnFX8tw1Cly88mTWTOwWVL5JEqb8q2xmREDmybv
311HBImbLPxbGQoU6MhsceOxI1PgMpYKQk0z37LcvmgiEIVfcQ/RC5Y4PBHgJHOdyFo9BuRrv3ta55t
3129ghuY0zm9HrybEG42BcCTR+Y+Q3iXbNuRtI45pmUdGJITtS0TJ7RAzPEsFn8S60rasIMacNMCALJ
313aO4vViaMjIEvLJV2lvORIsVnBctxltVN5iXBll8vfR47BfpTxgERhUsaoWOQ3Gt2NUwOk/btY5Tn
314RaRB7E9Nx3YzncL0go3TK2J3NFDhj3BF+dJ7m2kuvHjkzQtfR4z8hI80K7E5duu2iM5Pg198a8zf
315ckr+sRWCOQhweaSX6FhsY9Bis26JJQv35UoJSN6l8E4GYkGkSBLBNQnASLCSRGkrhKABMSQiQiXC
316SlQAMFEteJAkvA7T6zgflQDrUWScRIZwVUWIIzxQpELGJbCMZvgooqxRYsVWpGRk6g6ofjgDBJ6i
317G5ouU5fmEQJ9h8C89J/Z7SYdp/p8TwNDeE4FRFYIEWey2As/qdZn9LOqZ0Sk9pwPhP5kDgimh449
318I1uZoQqEPPaORaIqQcVWLwraY/AojN7ICQndAP3nEaiDsM6b6cJ/hxkGZyFoL8XgLWImzPgbhkUo
319mBfMYho3d1IxOQfIXIo7HTHOYW8ZImBMZAM4+RSYIxEaG4tEdCkkQHATDx5zKRHuRrGEMThsW048
320BicqLk1HRrE6CD2WS4hO8vNCCx5pgkypJeJ6ohxf2DMdJikHnQoFgMiY2DFo0a8HrFDCXAuMZpCj
321og95Lj72tXYloltao+qNA8DATnX2xEMVRFURZIoqlhDcmrMiE++w8MgY9MpqMmIvNsG/AaQGIyDN
3225ChYEkmjOaiQWH6g+LiSbdJYCAhWkVhfraUshoKFj563kEi2TUvmBBGYHybgiBHph+yZin2XCJ5T
323y4EwDk9RkPP3Fs5Wk1gDGjWmDBH5zQ9xz84ZI+o2xASDOOcMPIgcwbTGGtLZoESkgJ5T+RZ8rz+E
324xo21UGWBiSvUj79oF/62ZkzJLI/BcTeFow5S5ay9sx0TZWtpeS25pchHIomB2kj6XOHoKKpvlRj3
325EL7F4OuCi6g9lw6xEDtAD4xsEvMSQBYFRmhIyGZ8yFlBQ85vpDpOrxCZ9gXQdwqGsDS8oUq3GSR9
326ZyxA1ihC6080hgggiL4PmTRbM44RhigwByNUw4CnycFQTK/32m5B5cvH0GfceSz8NxdwL6HrLBXh
327oAeNtUX2hcPAqntseYTCZs7CxnoSycTy1GmBthIimGulQTm7REC48z4mhwpr1HtDSmYvWBh5i02Q
328IMxQUgFiVJoTwLMoN34m6YjTqig8IhYrktYGo18ACPrBBJB/XtJId87xEVyb4SGxcC6Z0XDX7Grp
329CFqua6+UzykmDBYXOSjl5SQ8EhgOwloE40UykfeCClkICKR10CRtN2zt3+pC4lHX2nEh1FA3I50D
330njYGrpeoPTXkjoa+NmWHWksiswWSSniYlZ2vK5wzeFxnChjyBicK6wnTfRUtq7gZcByDLQlCo1F7
33177bSYpz1pBnsN76dJFP1AZATzcTbYlSC9ERtv7DtotxpbhMggiSSlISGYHNHsG7yQ6NQOJ0iQG0O
332A/DXAObRGNYyMIOW7Ux+FOIg8+DEpTAUwXcFp0nk56iYYbshM+g5WeeRXp7MXJbqlSWwTq6y1o02
333oBlVpoImG4x0hdWrpDETQsVM1Bm7OkkE38Byt5bkqDOIViYrybAdhUr5j2qJYY24y0M+wSG1b8Ss
334OSeO4kjZfjbJP+oANx8kolZIW0AcYCYhLGvi4jqPkKJyzKECUtCJ8WzcobNuShg+01LBPqwBdbGz
335KsyhA5ipaQzGhq3e5pOQU7jTMmTGjzyXNG47Bkj9mCTBUR+qQE2iYwil44mH2PGcJHeO6KRtOxXT
3366TPxuzzl06o44bbDuw5GRSUrIi9qyLunVkWTFk0KyHfKQTA0aYD9TjS/Nh32Q02bXZn9oz6bNsNt
337D2jU6iMX4GmOJuS02DysuSjqLtsidm1vh3NQNTuN81zH06G5GsAYQUCMhh5YgIhIElELDpZzlrK8
338SKTVNCibxpcbi823AbTGjYMqcCBsORSj606ZJzdho6cqedo2o3DloFlAvxYYYwxil6DiyPoGnNBF
339Tdd2erGW/hKkRwEeJA5gLeGLo6JYZ38KHVlVMMRDxJK89JE5CUxPRpnnoVbhFs+Xa0OemRQI1w0G
3407atJ4foIYEcsQEB8xHYIQGx/RI+43h5AB0q2Hcnagd/1koHd5iA8KQKQ6bvJJiwCbSkN/MWlCUQ9
341+QlRECqcwy7ravAHvE23UhKihmahMNZa0mtLNaHw+df36PMSxu+RYT611CQkKhISBksARCRClF+A
342ek+XE9wmhDEMEMQNxAG0UicRiU2q4FjY8jVVDPLWInb57RNwWiNBghAkBBUAAwPeeXjP0+A/to8c
343WLZ9Q49nreqavNy83PTy0p2SHU3k5cmYtIyvNmupTwN4puka/FWKlM3EmbDUjasLbLeX7NTjsxmo
344xI/D4YQcapYguOdpuNwUklTcPBwXZgAkY70LSVpwABVWD6wDximdU43UWHx/N7cfEZDPL6SwnlIZ
345WYjPEHqyu5sSYViJCQ2EiU4P1bZaw7gNDtGpgJ7Roc0dyT5QAB0QoTyQhEk4TwSIoo8GhSGItski
346hjUsxjXtR3OsA6jYiHhOiQEEpQRMiAhRWA7BcaHOj0DkE5gsRxEIuAxAiyB0dckXFPXHH9N4XlLE
347fkJFF+JJgIDz0yLwoeKu0X4HccA9odqClym8TmhIF9XahCwOTkcyQfrArMAsfMOYnaoMoYkJjNlR
348KYB84AaT1ki03QB1qwL5kNQnFgitTnOJXMCXC6mHOQmRRNO8VnuuDYUI5Tsjex7DIxonn7hPoEzE
349xxMYYRRQUEkEZIDJQEZ/jrOyTrPYcsUGAtQ+0xAA9kQ7KAOKFYUNlsXwLRxAWB7PWwh3sAIF/tSG
350FMAN3CM5VgFQeo9ImDcAliUiWJSJRsEoMpEsSglBlkSgykSjQSjfGQ17YTTSefmJPOLHEd9LpMgY
351IE8jUeQKtB1IzDcIRSYSO+hsUSfALyDrOvIiVRxgd5iJyiINORgAkw6EBsJMBIssdVrx98dlDMgk
352X2DtyAOLOJCmTJnNU9inRcAgbELDQ4GyZjotMCR6xMTh9RITIEQmsQ6YB4BDuGIXKZDwmY+PSKUW
3538gLRuXcEgnhqcDAsSoSCQPsUk9QalewSxVS20N6kECMMPWPCfrOgEZPYAYCIHfGBEQxBmEAMF84E
3548PQCIWswJsBKKWB6DUN5cJcAEQPemFMCDXId6gRgaQVo07EhjmIcWUKRSlKEGAziZVmlrR2k0ZwH
355sJKyBgRPRSGeCFklpCWAgCwQeJzx87JCTgBTaexzAMwhQFrBmokHWMDcIGgYQ0xdBioKYyqDDkC7
356iISCxJz8ezARiKQ1JCSHcJabEQFsQLL/JmGwGiEoASVJABOFEyUmerXUV4o5gmNjrVr9HNsDdhlC
357TJIcCnUCZKuhMDKaXfoicYUj0zOUqjlFPOF5iXpQ9eUT0IToJeMJIGLF0a6A7xxIENDIkql8IHIL
3585/uGsKPWJnJmPEOgmJQszbCQlhcdZIMT4yAlAVwIN1RPIHeJVAHqQhOcRAmbRJhlGKCrAEZJp6JJ
359mSSdElPrPN1HYAxVhb5gjmfmaguB5ulMa79pLUWWCJCNwZEfVFdI+8SQhAiRcAGBoaHx5W8eZ+id
3604mQBLJsG1HfL5kwjKsdJ0dDD0h6FMFKuVZCRUMTMjEEKBrGhoqkGofcPiGsUw+lTYKfahsLh+QJJ
361qfpMUmJpEhMjUUnEFBtYchu3UChuZDdQ773CaabzIxjIJ4IUGwUDHBiUT3YTHwDqQTbBECqwjAId
362xcH4M3QqDLATOTnF6vZ5SEvE73GiBiQaF8Y7zhzCrO64EL4ETmPGWZTRGjZEmURJiSVay5JByifa
363JRUnAlGRKUgq5hEDWcKscdw29hYnohV9xd32DgrA9IdiMgRqTWA2ikCSDmw57uHSPQJJOTOYVE4g
364iZbzt18LAsAJSBJd5wGSIa4EfMztSkeI0O9ipNiC70ITTd9rupkoj0QJ6ldoGetqGbsml51Y0tSD
3658gUNJmIHpCPyplsTGmEEli7EbMWgnk/UAQE8QTDXOzEMhOIiB2n0Rxe+8LkJhEjIYMfsmNDMGU5g
3664vERH9gkViQMA8Cv9EMDJMKLECPeHziY5fN1EgcZ3nSjuMcAN3rEUFFigoMQmYBkZnK8Z3hfHM5I
367jAJ3GNADpJ+dBYoLFiwUFFiw5j8RDOc78OXuweGTAGhBJA90lFksE3EKzEmAS5RRzzNyiURmERYq
368HHYaJrU3rJOLWLwjqi7QNC8KOovJkiA/suOSZVtQhFxMNsFCBi1IExUYsAw95SOxgq3tjAJFlMKS
369vKllgL0dXQJQSibSG+MhMGNYRgSzYLDYgIUiyRIfOAFJQEQkwSgUNx+49ehqPIbGxCNUzKTPxbE+
370oSm4rceYTIDjI6l7lhZK84KQSDnDKUTJ9wkwA5CXmKTUSCFgzE28RSY6cFPUCbg5XgbyCCAiByPk
371jeZA3tiKdsGgSokXEBISFYEtPNAFVNDzampkGY6PKyuyOKAbMnMkMyEMyGgdZcJRSlFJhCu4E3jJ
372NzYhANhUMlLwD86EsX+Y3HJTT8Ip27Tl7wTTI9OXyR3nHcGJ6Cgll1FQ5H4w2KVCw1ZPEOCmNJBe
373+gC8oQecDvGyu46e4e9HXi6zqkSCHpekwfQK7KmcFqpSLQghrBPpvRnVyGo3vahIkZqwtAClSdWA
374O0Wiv4EcATQWPzKSHFRPR1+k3HGcne5tFDUVJk+RK1pgFBhVgTCBHzQ2C8FIvADApt7B84BJBU1H
375rDHLNXBB4vXtRqbHiMNCACI3q8wBAvhtExhvhcEIaM58D/xdyRThQkFqfm5c

« Back to merge proposal