Merge lp:~sinzui/launchpad/distro-modification-pages into lp:launchpad

Proposed by Curtis Hovey
Status: Merged
Merged at revision: not available
Proposed branch: lp:~sinzui/launchpad/distro-modification-pages
Merge into: lp:launchpad
Diff against target: None lines
To merge this branch: bzr merge lp:~sinzui/launchpad/distro-modification-pages
Reviewer Review Type Date Requested Status
Henning Eggers (community) Approve
Review via email: mp+10206@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Curtis Hovey (sinzui) wrote :

This is my branch to update distro modification pages to 3.0. This effort
started out as a simple set of mechanical changes. When I realised that
two of the forms did not have views, I decided to extend the
LaunchpadEditFormView to to provide all the features needed for UI 3.0.
I did not update LaunchpadEditFormView because I am unsure of the
consequences.

    lp:~sinzui/launchpad/distro-modification-pages
    Diff size: 568
    Launchpad bug: https://bugs.launchpad.net/bugs/414043
    Test command: ./bin/test -vvt "distribution-views"
    Pre-implementation: no one
    Target release: 2.2.8

= Update distro modification pages to 3.0 =

Update the distribution add and edit pages to the new UI.

== Rules ==

    * Some are simple and can be deleted; use generic-edit.pt
    * Update labels and page_title
    * Add cancel_url as needed

Addendum

    * Some pages are using ZCML editform that must change to a view.

== QA ==

Get admin powers on staging
    * Visit https://staging.launchpad.net/distros/+add
      * Verify the label and page_title are the same.
      * Verify there is a cancel link back to the /distros page
      * Create a distro
      * Verify that you are on the new distro page.
    * Choose Change details
      * Verify the label and page_title are the same.
      * Verify there is a cancel link back to the distro page
    * Choose the edit link next to members
      * Verify the label and page_title are the same.
      * Verify there is a cancel link back to the distro page
    * Choose the edit link next to mirror admins
      * Verify the label and page_title are the same.
      * Verify there is a cancel link back to the distro page

== Lint ==

Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.

Linting changed files:
  lib/canonical/launchpad/pagetitles.py
  lib/lp/registry/browser/__init__.py
  lib/lp/registry/browser/configure.zcml
  lib/lp/registry/browser/distribution.py
  lib/lp/registry/browser/tests/distribution-views.txt
  lib/lp/registry/interfaces/distribution.py

== Test ==

    * lib/lp/registry/browser/tests/distribution-views.txt
      * Added tests for add, edit, edit members, and edit mirror admins.

== Implementation ==

    * lib/canonical/launchpad/pagetitles.py
      * Removed old page titles.
    * lib/lp/registry/browser/__init__.py
      * Added the RegistryEditFormView to make the conversion easier and
        all edit pages consistent.
    * lib/lp/registry/browser/configure.zcml
      * Converted editform to page directives.
      * Switched forms to use generic-edit.pt
    * lib/lp/registry/browser/distribution.py
      * Updated the label on the views to use the distro name.
      * Added page_title and cancel urls (often via RegistryEditFormView)
    * lib/lp/registry/interfaces/distribution.py
      * Updated a field description so that the page template did not need
        to explain the purpose of the field.
    * Deleted the 4 templates

Revision history for this message
Henning Eggers (henninge) wrote :

Very nice branch, thank you. Extending LPEView for your purposes is a very efficient approach; I wouldn't have dared either to makt those assumptions for all views.

Just one issue: There is copy&paste error on line 407 where you mention mirror_admin instead of members.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/launchpad/pagetitles.py'
2--- lib/canonical/launchpad/pagetitles.py 2009-08-13 00:39:47 +0000
3+++ lib/canonical/launchpad/pagetitles.py 2009-08-15 13:37:48 +0000
4@@ -459,8 +459,6 @@
5
6 distributionmirror_review = ContextTitle('Review mirror %s')
7
8-distribution_add = 'Register a new distribution'
9-
10 distribution_allpackages = ContextTitle('All packages in %s')
11
12 distribution_archive_list = ContextTitle('%s Copy Archives')
13@@ -469,21 +467,13 @@
14
15 distribution_upstream_bug_report = ContextTitle('Upstream Bug Report for %s')
16
17-distribution_change_mirror_admin = 'Change mirror administrator'
18-
19 distribution_cvereport = ContextTitle('CVE reports for %s')
20
21-distribution_edit = 'Change distribution details'
22-# We don't mention its name here, because that might be what you're changing.
23-
24 distribution_language_pack_admin = ContextTitle(
25 'Change the language pack administrator for %s')
26
27 distribution_members = ContextTitle('%s distribution members')
28
29-distribution_memberteam = ContextTitle(
30- smartquote("Change %s's distribution team"))
31-
32 distribution_mirrors = ContextTitle("Mirrors of %s")
33
34 distribution_newmirror = ContextTitle("Register a new mirror for %s")
35
36=== modified file 'lib/lp/registry/browser/__init__.py'
37--- lib/lp/registry/browser/__init__.py 2009-08-06 19:11:58 +0000
38+++ lib/lp/registry/browser/__init__.py 2009-08-15 13:48:33 +0000
39@@ -8,6 +8,7 @@
40 __all__ = [
41 'get_status_count',
42 'MilestoneOverlayMixin',
43+ 'RegistryEditFormView',
44 'RegistryDeleteViewMixin',
45 'StatusCount',
46 ]
47@@ -16,9 +17,12 @@
48 from operator import attrgetter
49
50 from zope.component import getUtility
51+
52 from lp.bugs.interfaces.bugtask import BugTaskSearchParams, IBugTaskSet
53 from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
54-from canonical.launchpad.webapp import canonical_url
55+from canonical.launchpad.webapp.launchpadform import (
56+ action, LaunchpadEditFormView)
57+from canonical.launchpad.webapp.publisher import canonical_url
58
59
60 class StatusCount:
61@@ -120,3 +124,22 @@
62 for release_file in release.files:
63 release_file.destroySelf()
64 release.destroySelf()
65+
66+
67+class RegistryEditFormView(LaunchpadEditFormView):
68+ """"A base class that provides consistent edit form behaviour."""
69+ @property
70+ def page_title(self):
71+ """The page title."""
72+ return self.label
73+
74+ @property
75+ def cancel_url(self):
76+ """See `LaunchpadFormView`."""
77+ return canonical_url(self.context)
78+
79+ next_url = cancel_url
80+
81+ @action("Change", name='change')
82+ def change_action(self, action, data):
83+ self.updateContextFromData(data)
84
85=== modified file 'lib/lp/registry/browser/configure.zcml'
86--- lib/lp/registry/browser/configure.zcml 2009-08-14 00:52:28 +0000
87+++ lib/lp/registry/browser/configure.zcml 2009-08-15 13:37:48 +0000
88@@ -1964,23 +1964,21 @@
89 class="lp.registry.browser.distribution.DistributionEditView"
90 name="+edit"
91 facet="overview"
92- template="../templates/distribution-edit.pt"/>
93- <browser:editform
94+ template="../../app/templates/generic-edit.pt"/>
95+ <browser:page
96 name="+selectmemberteam"
97 for="lp.registry.interfaces.distribution.IDistribution"
98- schema="lp.registry.interfaces.distribution.IDistribution"
99+ class="lp.registry.browser.distribution.DistributionChangeMembersView"
100 facet="overview"
101- fields="members"
102 permission="launchpad.Edit"
103- template="../templates/distribution-memberteam.pt"/>
104- <browser:editform
105+ template="../../app/templates/generic-edit.pt"/>
106+ <browser:page
107 name="+selectmirroradmins"
108 for="lp.registry.interfaces.distribution.IDistribution"
109- schema="lp.registry.interfaces.distribution.IDistribution"
110+ class="lp.registry.browser.distribution.DistributionChangeMirrorAdminView"
111 facet="overview"
112- fields="mirror_admin"
113 permission="launchpad.Edit"
114- template="../templates/distribution-change-mirror-admin.pt"/>
115+ template="../../app/templates/generic-edit.pt"/>
116 <browser:addform
117 name="+linkbounty"
118 for="lp.registry.interfaces.distribution.IDistribution"
119@@ -2037,7 +2035,7 @@
120 class="lp.registry.browser.distribution.DistributionAddView"
121 facet="overview"
122 permission="launchpad.Admin"
123- template="../templates/distribution-add.pt"/>
124+ template="../../app/templates/generic-edit.pt"/>
125 <browser:menus
126 classes="
127 DistributionFacets
128
129=== modified file 'lib/lp/registry/browser/distribution.py'
130--- lib/lp/registry/browser/distribution.py 2009-08-05 01:49:41 +0000
131+++ lib/lp/registry/browser/distribution.py 2009-08-15 13:50:42 +0000
132@@ -12,6 +12,8 @@
133 'DistributionArchiveMirrorsView',
134 'DistributionArchivesView',
135 'DistributionBreadcrumbBuilder',
136+ 'DistributionChangeMembersView',
137+ 'DistributionChangeMirrorAdminView',
138 'DistributionCountryArchiveMirrorsView',
139 'DistributionDisabledMirrorsView',
140 'DistributionEditView',
141@@ -67,7 +69,7 @@
142 IPublishedPackageSet)
143 from canonical.launchpad.webapp import (
144 action, ApplicationMenu, canonical_url, ContextMenu, custom_widget,
145- enabled_with_permission, GetitemNavigation, LaunchpadEditFormView,
146+ enabled_with_permission, GetitemNavigation,
147 LaunchpadFormView, LaunchpadView, Link, Navigation, redirection,
148 StandardLaunchpadFacets, stepthrough, stepto)
149 from canonical.launchpad.webapp.interfaces import (
150@@ -78,6 +80,8 @@
151 from canonical.launchpad.webapp.breadcrumb import BreadcrumbBuilder
152 from canonical.widgets.image import ImageChangeWidget
153
154+from lp.registry.browser import RegistryEditFormView
155+
156
157 class UsesLaunchpadMixin:
158 """This mixin is used for the overview page of products and distros."""
159@@ -776,12 +780,22 @@
160 class DistributionAddView(LaunchpadFormView):
161
162 schema = IDistribution
163- label = "Create a new distribution"
164+ label = "Register a new distribution"
165 field_names = ["name", "displayname", "title", "summary", "description",
166 "domainname", "members",
167 "official_malone", "official_blueprints",
168 "official_rosetta", "official_answers"]
169
170+ @property
171+ def page_title(self):
172+ """The page title."""
173+ return self.label
174+
175+ @property
176+ def cancel_url(self):
177+ """See `LaunchpadFormView`."""
178+ return canonical_url(self.context)
179+
180 @action("Save", name='save')
181 def save_action(self, action, data):
182 distribution = getUtility(IDistributionSet).new(
183@@ -798,10 +812,9 @@
184 self.next_url = canonical_url(distribution)
185
186
187-class DistributionEditView(LaunchpadEditFormView):
188+class DistributionEditView(RegistryEditFormView):
189
190 schema = IDistribution
191- label = "Change distribution details"
192 field_names = ['displayname', 'title', 'summary', 'description',
193 'bug_reporting_guidelines', 'icon', 'logo', 'mugshot',
194 'official_malone', 'enable_bug_expiration',
195@@ -812,6 +825,11 @@
196 custom_widget('logo', ImageChangeWidget, ImageChangeWidget.EDIT_STYLE)
197 custom_widget('mugshot', ImageChangeWidget, ImageChangeWidget.EDIT_STYLE)
198
199+ @property
200+ def label(self):
201+ """See `LaunchpadFormView`."""
202+ return 'Change %s details' % self.context.displayname
203+
204 def validate(self, data):
205 """Constrain bug expiration to Launchpad Bugs tracker."""
206 # enable_bug_expiration is disabled by JavaScript when official_malone
207@@ -821,10 +839,27 @@
208 if not official_malone:
209 data['enable_bug_expiration'] = False
210
211- @action("Change", name='change')
212- def change_action(self, action, data):
213- self.updateContextFromData(data)
214- self.next_url = canonical_url(self.context)
215+
216+class DistributionChangeMirrorAdminView(RegistryEditFormView):
217+ """A view to change the mirror administrator."""
218+ schema = IDistribution
219+ field_names = ['mirror_admin']
220+
221+ @property
222+ def label(self):
223+ """See `LaunchpadFormView`."""
224+ return "Change the %s mirror administrator" % self.context.displayname
225+
226+
227+class DistributionChangeMembersView(RegistryEditFormView):
228+ """A view to change the members team."""
229+ schema = IDistribution
230+ field_names = ['members']
231+
232+ @property
233+ def label(self):
234+ """See `LaunchpadFormView`."""
235+ return "Change the %s members team" % self.context.displayname
236
237
238 class DistributionCountryArchiveMirrorsView(LaunchpadView):
239
240=== modified file 'lib/lp/registry/browser/tests/distribution-views.txt'
241--- lib/lp/registry/browser/tests/distribution-views.txt 2009-07-27 14:08:17 +0000
242+++ lib/lp/registry/browser/tests/distribution-views.txt 2009-08-15 13:37:48 +0000
243@@ -9,7 +9,7 @@
244 country.
245
246 >>> from zope.component import getMultiAdapter, getUtility
247- >>> from canonical.launchpad.interfaces import IDistributionSet
248+ >>> from lp.registry.interfaces.distribution import IDistributionSet
249 >>> from canonical.launchpad.webapp.servers import LaunchpadTestRequest
250
251 >>> login("foo.bar@canonical.com")
252@@ -227,3 +227,176 @@
253 >>> for pkg in search_results:
254 ... print pkg.name
255 mozilla-firefox
256+
257+
258+Distribution modification views
259+===============================
260+
261+
262+Registering a distribution
263+--------------------------
264+
265+The +add view of the DistributionSet allows admins to register distributions.
266+
267+ >>> distributionset = getUtility(IDistributionSet)
268+ >>> view = create_view(distributionset, '+add')
269+ >>> print view.label
270+ Register a new distribution
271+
272+ >>> print view.page_title
273+ Register a new distribution
274+
275+The view provides a cancel link.
276+
277+ >>> print view.cancel_url
278+ http://launchpad.dev/distros
279+
280+The view accepts the basic fields to register a distribution.
281+
282+ >>> view.field_names
283+ ['name', 'displayname', 'title', 'summary', 'description', 'domainname',
284+ 'members', 'official_malone', 'official_blueprints', 'official_rosetta',
285+ 'official_answers']
286+
287+ >>> form = {
288+ ... 'field.name': 'youbuntu',
289+ ... 'field.displayname': 'YoUbuntu',
290+ ... 'field.title': 'YoUbuntu OS',
291+ ... 'field.summary': 'summary',
292+ ... 'field.description': 'description',
293+ ... 'field.domainname': 'youbuntu.me',
294+ ... 'field.members': 'landscape-developers',
295+ ... 'field.actions.save': 'Save',
296+ ... }
297+ >>> view = create_initialized_view(distributionset, '+add', form=form)
298+ >>> view.errors
299+ []
300+ >>> print view.next_url
301+ http://launchpad.dev/youbuntu
302+
303+ >>> distribution = distributionset.getByName("youbuntu")
304+ >>> print distribution.name
305+ youbuntu
306+
307+
308+Editing a distribution
309+----------------------
310+
311+The +edit view allows an owner or admin to change a distribution. It provides
312+a label, page_title, and cancel_url.
313+
314+ >>> view = create_view(distribution, '+edit')
315+ >>> print view.label
316+ Change YoUbuntu details
317+
318+ >>> print view.page_title
319+ Change YoUbuntu details
320+
321+ >>> print view.cancel_url
322+ http://launchpad.dev/youbuntu
323+
324+The view accepts most of the distribution fields.
325+
326+ >>> distribution.official_malone
327+ False
328+
329+ >>> view.field_names
330+ ['displayname', 'title', 'summary', 'description',
331+ 'bug_reporting_guidelines', 'icon', 'logo', 'mugshot', 'official_malone',
332+ 'enable_bug_expiration', 'official_blueprints', 'official_rosetta',
333+ 'official_answers', 'translation_focus']
334+
335+ >>> del form['field.name']
336+ >>> del form['field.actions.save']
337+ >>> form['field.bug_reporting_guidelines'] = 'guidelines'
338+ >>> form['field.official_malone'] = 'on'
339+ >>> form['field.actions.change'] = 'Change'
340+ >>> view = create_initialized_view(distribution, '+edit', form=form)
341+ >>> view.errors
342+ []
343+ >>> print view.next_url
344+ http://launchpad.dev/youbuntu
345+
346+ >>> print distribution.bug_reporting_guidelines
347+ guidelines
348+
349+ >>> distribution.official_malone
350+ True
351+
352+
353+Changing a distribution mirror administrator
354+--------------------------------------------
355+
356+the +selectmirroradmins allows the owner or admin to change the mirror
357+administrator.
358+
359+ >>> view = create_view(distribution, '+selectmirroradmins')
360+ >>> print view.label
361+ Change the YoUbuntu mirror administrator
362+
363+ >>> print view.page_title
364+ Change the YoUbuntu mirror administrator
365+
366+ >>> print view.cancel_url
367+ http://launchpad.dev/youbuntu
368+
369+The view accepts the mirror_admin field.
370+
371+ >>> print distribution.mirror_admin.name
372+ name16
373+
374+ >>> view.field_names
375+ ['mirror_admin']
376+
377+ >>> form = {
378+ ... 'field.mirror_admin': 'no-priv',
379+ ... 'field.actions.change': 'Change',
380+ ... }
381+ >>> view = create_initialized_view(
382+ ... distribution, '+selectmirroradmins', form=form)
383+ >>> view.errors
384+ []
385+ >>> print view.next_url
386+ http://launchpad.dev/youbuntu
387+
388+ >>> print distribution.mirror_admin.name
389+ no-priv
390+
391+
392+Changing a distribution members team
393+------------------------------------
394+
395+the +selectmirroradmins allows the owner or admin to change the members team.
396+
397+ >>> view = create_view(distribution, '+selectmemberteam')
398+ >>> print view.label
399+ Change the YoUbuntu members team
400+
401+ >>> print view.page_title
402+ Change the YoUbuntu members team
403+
404+ >>> print view.cancel_url
405+ http://launchpad.dev/youbuntu
406+
407+The view accepts the mirror_admin field.
408+
409+ >>> print distribution.members.name
410+ landscape-developers
411+
412+ >>> view.field_names
413+ ['members']
414+
415+ >>> form = {
416+ ... 'field.members': 'ubuntu-team',
417+ ... 'field.actions.change': 'Change',
418+ ... }
419+ >>> view = create_initialized_view(
420+ ... distribution, '+selectmemberteam', form=form)
421+ >>> view.errors
422+ []
423+ >>> print view.next_url
424+ http://launchpad.dev/youbuntu
425+
426+ >>> print distribution.members.name
427+ ubuntu-team
428+
429
430=== modified file 'lib/lp/registry/interfaces/distribution.py'
431--- lib/lp/registry/interfaces/distribution.py 2009-08-09 18:01:59 +0000
432+++ lib/lp/registry/interfaces/distribution.py 2009-08-15 13:12:34 +0000
433@@ -182,8 +182,8 @@
434 vocabulary='ValidPersonOrTeam')
435 mirror_admin = PublicPersonChoice(
436 title=_("Mirror Administrator"),
437- description=_("The person or team that has the rights to administer "
438- "this distribution's mirrors"),
439+ description=_("The person or team that has the rights to review and "
440+ "mark this distribution's mirrors as official."),
441 required=True, vocabulary='ValidPersonOrTeam')
442 lucilleconfig = TextLine(
443 title=_("Lucille Config"),
444
445=== removed file 'lib/lp/registry/templates/distribution-add.pt'
446--- lib/lp/registry/templates/distribution-add.pt 2009-07-17 17:59:07 +0000
447+++ lib/lp/registry/templates/distribution-add.pt 1970-01-01 00:00:00 +0000
448@@ -1,28 +0,0 @@
449-<html
450- xmlns="http://www.w3.org/1999/xhtml"
451- xmlns:tal="http://xml.zope.org/namespaces/tal"
452- xmlns:metal="http://xml.zope.org/namespaces/metal"
453- xmlns:i18n="http://xml.zope.org/namespaces/i18n"
454- xml:lang="en"
455- lang="en"
456- dir="ltr"
457- metal:use-macro="context/@@main_template/master"
458- i18n:domain="launchpad"
459->
460-
461-<body>
462-
463-<metal:leftportlets fill-slot="portlets_one">
464-</metal:leftportlets>
465-
466-<metal:rightportlets fill-slot="portlets_two">
467-</metal:rightportlets>
468-
469-<div metal:fill-slot="main">
470-
471- <div metal:use-macro="context/@@launchpad_form/form" />
472-
473-</div>
474-</body>
475-</html>
476-
477
478=== removed file 'lib/lp/registry/templates/distribution-change-mirror-admin.pt'
479--- lib/lp/registry/templates/distribution-change-mirror-admin.pt 2009-07-17 17:59:07 +0000
480+++ lib/lp/registry/templates/distribution-change-mirror-admin.pt 1970-01-01 00:00:00 +0000
481@@ -1,29 +0,0 @@
482-<html
483- xmlns="http://www.w3.org/1999/xhtml"
484- xmlns:tal="http://xml.zope.org/namespaces/tal"
485- xmlns:metal="http://xml.zope.org/namespaces/metal"
486- xmlns:i18n="http://xml.zope.org/namespaces/i18n"
487- xml:lang="en"
488- lang="en"
489- dir="ltr"
490- metal:use-macro="context/@@main_template/master"
491- i18n:domain="launchpad"
492->
493-<body>
494-<tal:tag condition="view/update"/>
495-<metal:heading fill-slot="pageheading">
496- <h1>Select this Distribution's Mirror Administrator</h1>
497-</metal:heading>
498-
499-<div metal:fill-slot="main">
500-
501- <div metal:use-macro="context/@@launchpad_editform/editform">
502-
503- <p metal:fill-slot="extra_info">
504- The mirror administrators are the ones allowed to review and mark this
505- distribution's mirrors as official.
506- </p>
507- </div>
508-</div>
509-</body>
510-</html>
511
512=== removed file 'lib/lp/registry/templates/distribution-edit.pt'
513--- lib/lp/registry/templates/distribution-edit.pt 2009-07-17 17:59:07 +0000
514+++ lib/lp/registry/templates/distribution-edit.pt 1970-01-01 00:00:00 +0000
515@@ -1,23 +0,0 @@
516-<html
517- xmlns="http://www.w3.org/1999/xhtml"
518- xmlns:tal="http://xml.zope.org/namespaces/tal"
519- xmlns:metal="http://xml.zope.org/namespaces/metal"
520- xmlns:i18n="http://xml.zope.org/namespaces/i18n"
521- metal:use-macro="view/macro:page/default"
522- i18n:domain="launchpad"
523->
524- <body>
525- <div metal:fill-slot="main">
526- <div metal:use-macro="context/@@launchpad_form/form">
527- <p metal:fill-slot="extra_info">
528- The branding images are used to throughout Launchpad to represent
529- <span tal:replace="context/displayname">Ubuntu Linux</span>.
530- Changing them here will affect every page related to
531- <span tal:replace="context/displayname">Ubuntu Linux</span> as well as
532- listings which include it. You must use <strong>exactly</strong> the
533- correct size of image.
534- </p>
535- </div>
536- </div>
537- </body>
538-</html>
539
540=== removed file 'lib/lp/registry/templates/distribution-memberteam.pt'
541--- lib/lp/registry/templates/distribution-memberteam.pt 2009-07-17 17:59:07 +0000
542+++ lib/lp/registry/templates/distribution-memberteam.pt 1970-01-01 00:00:00 +0000
543@@ -1,33 +0,0 @@
544-<html
545- xmlns="http://www.w3.org/1999/xhtml"
546- xmlns:tal="http://xml.zope.org/namespaces/tal"
547- xmlns:metal="http://xml.zope.org/namespaces/metal"
548- xmlns:i18n="http://xml.zope.org/namespaces/i18n"
549- xml:lang="en"
550- lang="en"
551- dir="ltr"
552- metal:use-macro="context/@@main_template/master"
553- i18n:domain="launchpad"
554->
555- <body>
556- <tal:tag condition="view/update"/>
557- <metal:heading fill-slot="pageheading">
558- <h1>Select distribution members team</h1>
559- </metal:heading>
560-
561- <div metal:fill-slot="main">
562-
563- <div metal:use-macro="context/@@launchpad_editform/editform">
564-
565- <p metal:fill-slot="extra_info">
566- Select the Launchpad team that defines the members of
567- <span tal:replace="context/title">Ubuntu Linux</span>.
568- </p>
569- <tal:XXX condition="nothing">
570- # XXX 2006-02-20 mpt: That blurb is not useful, and should be replaced by
571- # an explanation of what the distribution members team is for.
572- </tal:XXX>
573- </div>
574- </div>
575- </body>
576-</html>
577