← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~wallyworld/launchpad/duplicate-picker-info into lp:launchpad

 

Ian Booth has proposed merging lp:~wallyworld/launchpad/duplicate-picker-info into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #806785 in Launchpad itself: "Person picker displays duplicate info when selecting recipe owner"
  https://bugs.launchpad.net/launchpad/+bug/806785

For more details, see:
https://code.launchpad.net/~wallyworld/launchpad/duplicate-picker-info/+merge/67118

When using a picker with a UserTeamsParticipationVocabulary (or derivative), the launchpad id was displayed twice for each picker entry.

eg Fred Smith (fsmith) (fsmith)

== Implementation ==

The UserTeamsParticipationVocabulary overrode toTerm() to use person.unique_displayname for the term summary value. This override was simply deleted to restore the default behaviour.

Also performed some drive-by lint fixes.

== Tests ==

There were no existing tests that I could find specifically for the original subclassed behaviour. This branch simply deletes the method override to restore the default term generation strategy for the vocab. So no new tests are warranted.

lp was run up locally the correct behaviour verified.

== Lint ==

Linting changed files:
  lib/lp/code/browser/branch.py
  lib/lp/registry/vocabularies.py

./lib/lp/code/browser/branch.py
     843: E261 at least two spaces before inline comment
./lib/lp/registry/vocabularies.py
     639: E261 at least two spaces before inline comment
     835: E261 at least two spaces before inline comment

-- 
https://code.launchpad.net/~wallyworld/launchpad/duplicate-picker-info/+merge/67118
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wallyworld/launchpad/duplicate-picker-info into lp:launchpad.
=== modified file '.bzrignore'
--- .bzrignore	2011-06-30 23:12:06 +0000
+++ .bzrignore	2011-07-07 06:39:25 +0000
@@ -82,4 +82,5 @@
 run.gdb
 lib/canonical/launchpad/icing/icon-sprites
 lib/canonical/launchpad/icing/icon-sprites.positioning
+lib/canonical/launchpad/icing/yui
 .emacs.desktop

=== modified file 'Makefile'
--- Makefile	2011-07-02 15:40:24 +0000
+++ Makefile	2011-07-07 06:39:25 +0000
@@ -18,7 +18,6 @@
 
 ICING=lib/canonical/launchpad/icing
 LP_BUILT_JS_ROOT=${ICING}/build
-LAZR_BUILT_JS_ROOT=lazr-js/build
 
 ifeq ($(LPCONFIG), development)
 JS_BUILD := raw
@@ -27,10 +26,9 @@
 endif
 
 JS_YUI := $(shell utilities/yui-deps.py $(JS_BUILD:raw=))
-JS_LAZR := $(LAZR_BUILT_JS_ROOT)/lazr.js
 JS_OTHER := $(wildcard lib/canonical/launchpad/javascript/*/*.js)
-JS_LP := $(shell find lib/lp/*/javascript ! -path '*/tests/*' ! -path '*/app/javascript/lazr/*' -name '*.js' ! -name '.*.js' )
-JS_ALL := $(JS_YUI) $(JS_LAZR) $(JS_OTHER) $(JS_LP)
+JS_LP := $(shell find lib/lp/*/javascript ! -path '*/tests/*' -name '*.js' ! -name '.*.js' )
+JS_ALL := $(JS_YUI) $(JS_OTHER) $(JS_LP)
 JS_OUT := $(LP_BUILT_JS_ROOT)/launchpad.js
 
 MINS_TO_SHUTDOWN=15
@@ -178,16 +176,12 @@
 		${ICING}/sprite.css.in
 	${SHHH} bin/sprite-util create-image
 
-# We absolutely do not want to include the lazr.testing module and
-# its jsTestDriver test harness modifications in the lazr.js and
-# launchpad.js roll-up files.  They fiddle with built-in functions!
-# See Bug 482340.
-jsbuild_minify: bin/jsbuild
+jsbuild_widget_css: bin/jsbuild
 	${SHHH} bin/jsbuild \
-	    --builddir $(LAZR_BUILT_JS_ROOT) \
-	    --exclude testing/ --filetype $(JS_BUILD)
+ 	    --srcdir lib/lp/app/javascript \
+	    --builddir $(LP_BUILT_JS_ROOT)
 
-$(JS_YUI) $(JS_LAZR): jsbuild_minify
+$(JS_LP): jsbuild_widget_css
 
 $(JS_OUT): $(JS_ALL)
 ifeq ($(JS_BUILD), min)
@@ -486,4 +480,4 @@
 	reload-apache hosted_branches check_mailman check_config \
 	jsbuild jsbuild_minify clean_js clean_buildout buildonce_eggs \
 	build_eggs sprite_css sprite_image css_combine compile \
-	check_schema pydoctor clean_logs 
+	check_schema pydoctor clean_logs

=== modified file 'buildout-templates/bin/combine-css.in'
--- buildout-templates/bin/combine-css.in	2011-06-30 10:25:29 +0000
+++ buildout-templates/bin/combine-css.in	2011-07-07 06:39:25 +0000
@@ -25,18 +25,18 @@
 # list seems like the best option for now.
 names = [
     'style.css',
-    'lazr/build/yui/cssreset/reset.css',
+    'yui/cssreset/reset.css',
     # Use the old cssgrids instead of the new cssgrids.
     #'lazr/build/yui/cssgrids/grids.css',
     'cssgrids/grids.css',
-    'lazr/build/lazr/assets/skins/sam/lazr.css',
-    'lazr/build/inlineedit/assets/skins/sam/editor.css',
-    'lazr/build/autocomplete/assets/skins/sam/autocomplete.css',
-    'lazr/build/overlay/assets/skins/sam/pretty-overlay.css',
-    'lazr/build/formoverlay/assets/formoverlay-core.css',
-    'lazr/build/picker/assets/skins/sam/picker.css',
-    'lazr/build/activator/assets/skins/sam/activator.css',
-    'lazr/build/choiceedit/assets/choiceedit-core.css',
+    'build/lazr/assets/skins/sam/lazr.css',
+    'build/inlineedit/assets/skins/sam/editor.css',
+    'build/autocomplete/assets/skins/sam/autocomplete.css',
+    'build/overlay/assets/skins/sam/pretty-overlay.css',
+    'build/formoverlay/assets/formoverlay-core.css',
+    'build/picker/assets/skins/sam/picker.css',
+    'build/activator/assets/skins/sam/activator.css',
+    'build/choiceedit/assets/choiceedit-core.css',
     GALLERY_ACCORDION + 'gallery-accordion-core.css',
     GALLERY_ACCORDION + 'skins/sam/gallery-accordion-skin.css',
     'build/sprite.css',

=== modified file 'buildout.cfg'
--- buildout.cfg	2011-07-05 00:06:40 +0000
+++ buildout.cfg	2011-07-07 06:39:25 +0000
@@ -30,7 +30,7 @@
 
 prefer-final = true
 
-develop = . 
+develop = .
 
 [configuration]
 instance_name = development
@@ -42,8 +42,8 @@
     rm -rf ${buildout:yui-directory}/yui-${versions:yui}/*
     tar -zxf download-cache/dist/yui-${versions:yui}.tar.gz \
         -C ${buildout:yui-directory}/yui-${versions:yui}
-    mkdir -p lazr-js/build
-    ln -s ../../${buildout:yui-directory}/yui-${versions:yui} lazr-js/build/yui
+    ln -s `pwd`/${buildout:yui-directory}/yui-${versions:yui} \
+        lib/canonical/launchpad/icing/yui
 
 [filetemplates]
 recipe = z3c.recipe.filetemplate

=== removed symlink 'lib/canonical/launchpad/icing/lazr'
=== target was u'../../../../lazr-js'
=== removed symlink 'lib/canonical/launchpad/icing/yui'
=== target was u'../../../../lazr-js/build/yui'
=== renamed directory 'lib/lp/app/javascript/lazr/activator' => 'lib/lp/app/javascript/activator'
=== renamed file 'lib/lp/app/javascript/lazr/activator/tests/activator.html' => 'lib/lp/app/javascript/activator/tests/test_activator.html'
--- lib/lp/app/javascript/lazr/activator/tests/activator.html	2011-06-29 14:56:15 +0000
+++ lib/lp/app/javascript/activator/tests/test_activator.html	2011-07-07 06:39:25 +0000
@@ -1,29 +1,26 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd";>
 <html>
   <head>
   <title>Activator</title>
 
   <!-- YUI 3.0 Setup -->
-  <script type="text/javascript" src="../../testing/config.js"></script>
-  <script type="text/javascript" src="../../yui/yui/yui.js"></script>
-  <link rel="stylesheet" href="../../yui/cssreset/reset.css"/>
-  <link rel="stylesheet" href="../../yui/cssfonts/fonts.css"/>
-  <link rel="stylesheet" href="../../yui/cssbase/base.css"/>
+  <script type="text/javascript" src="../../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/javascript/test.css" />
 
   <!-- The module under test -->
-  <script type="text/javascript" src="../../activator/activator.js"></script>
+  <script type="text/javascript" src="../activator.js"></script>
   <script type="text/javascript" src="../../anim/anim.js"></script>
   <script type="text/javascript" src="../../lazr/lazr.js"></script>
-  <script type="text/javascript" src="../../testing/testing.js"></script>
 
   <!-- The test suite -->
-  <script type="text/javascript" src="activator.js"></script>
+  <script type="text/javascript" src="test_activator.js"></script>
 
-  <link rel="stylesheet" href="../../testing/assets/testlogger.css"/>
 </head>
 <body class="yui3-skin-sam">
-
 <div id="log"></div>
 </body>
 </html>

=== renamed file 'lib/lp/app/javascript/lazr/activator/tests/activator.js' => 'lib/lp/app/javascript/activator/tests/test_activator.js'
--- lib/lp/app/javascript/lazr/activator/tests/activator.js	2011-06-29 14:56:15 +0000
+++ lib/lp/app/javascript/activator/tests/test_activator.js	2011-07-07 06:39:25 +0000
@@ -1,7 +1,12 @@
 /* Copyright (c) 2009, Canonical Ltd. All rights reserved. */
 
-YUI().use('lazr.activator', 'lazr.testing.runner', 'node',
-           'event', 'event-simulate', 'console', function(Y) {
+YUI({
+    base: '../../../../../canonical/launchpad/icing/yui/',
+    filter: 'raw',
+    combine: false,
+    fetchCSS: false
+    }).use('test', 'console', 'node', 'lazr.activator',
+           'event', 'event-simulate', function(Y) {
 
 var Assert = Y.Assert;  // For easy access to isTrue(), etc.
 
@@ -77,7 +82,7 @@
         var custom_node = Y.one('#custom-animation-node');
         this.activator = new Y.lazr.activator.Activator(
             {contentBox: Y.one('#example-1'), animationNode: custom_node});
-s        Assert.areEqual(custom_node, this.activator.animation_node);
+        Assert.areEqual(custom_node, this.activator.animation_node);
     },
 
     test_unhiding_action_button: function() {
@@ -268,7 +273,20 @@
     }
 }));
 
-Y.lazr.testing.Runner.add(suite);
-Y.lazr.testing.Runner.run();
+// Lock, stock, and two smoking barrels.
+var handle_complete = function(data) {
+    window.status = '::::' + JSON.stringify(data);
+    };
+Y.Test.Runner.on('complete', handle_complete);
+Y.Test.Runner.add(suite);
+
+var yui_console = new Y.Console({
+    newestOnTop: false
+});
+yui_console.render('#log');
+
+Y.on('domready', function() {
+    Y.Test.Runner.run();
+});
 
 });

=== renamed directory 'lib/lp/app/javascript/lazr/anim' => 'lib/lp/app/javascript/anim'
=== renamed file 'lib/lp/app/javascript/lazr/anim/tests/anim.html' => 'lib/lp/app/javascript/anim/tests/test_anim.html'
--- lib/lp/app/javascript/lazr/anim/tests/anim.html	2011-06-29 14:56:15 +0000
+++ lib/lp/app/javascript/anim/tests/test_anim.html	2011-07-07 06:39:25 +0000
@@ -1,25 +1,23 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd";>
 <html>
   <head>
   <title>Anim</title>
 
   <!-- YUI 3.0 Setup -->
-  <script type="text/javascript" src="../../testing/config.js"></script>
-  <script type="text/javascript" src="../../yui/yui/yui.js"></script>
-  <link rel="stylesheet" href="../../yui/cssreset/reset.css"/>
-  <link rel="stylesheet" href="../../yui/cssfonts/fonts.css"/>
-  <link rel="stylesheet" href="../../yui/cssbase/base.css"/>
+  <script type="text/javascript" src="../../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/javascript/test.css" />
 
   <!-- The module under test -->
-  <script type="text/javascript" src="../../anim/anim.js"></script>
+  <script type="text/javascript" src="../anim.js"></script>
   <script type="text/javascript" src="../../lazr/lazr.js"></script>
-  <script type="text/javascript" src="../../testing/testing.js"></script>
 
   <!-- The test suite -->
-  <script type="text/javascript" src="anim.js"></script>
+  <script type="text/javascript" src="test_anim.js"></script>
 
-  <link rel="stylesheet" href="../../testing/assets/testlogger.css"/>
 </head>
 <body class="yui3-skin-sam">
 

=== renamed file 'lib/lp/app/javascript/lazr/anim/tests/anim.js' => 'lib/lp/app/javascript/anim/tests/test_anim.js'
--- lib/lp/app/javascript/lazr/anim/tests/anim.js	2011-06-29 14:56:15 +0000
+++ lib/lp/app/javascript/anim/tests/test_anim.js	2011-07-07 06:39:25 +0000
@@ -1,7 +1,12 @@
 /* Copyright (c) 2009, Canonical Ltd. All rights reserved. */
 
-YUI().use('lazr.anim', 'lazr.testing.runner', 'node',
-          'event', 'event-simulate', 'console', function(Y) {
+YUI({
+    base: '../../../../../canonical/launchpad/icing/yui/',
+    filter: 'raw',
+    combine: false,
+    fetchCSS: false
+    }).use('test', 'console', 'node', 'lazr.anim',
+           'event', 'event-simulate', function(Y) {
 
 var Assert = Y.Assert;  // For easy access to isTrue(), etc.
 
@@ -181,7 +186,20 @@
     }
     }));
 
-Y.lazr.testing.Runner.add(suite);
-Y.lazr.testing.Runner.run();
+// Lock, stock, and two smoking barrels.
+var handle_complete = function(data) {
+    window.status = '::::' + JSON.stringify(data);
+    };
+Y.Test.Runner.on('complete', handle_complete);
+Y.Test.Runner.add(suite);
+
+var yui_console = new Y.Console({
+    newestOnTop: false
+});
+yui_console.render('#log');
+
+Y.on('domready', function() {
+    Y.Test.Runner.run();
+});
 
 });

=== renamed directory 'lib/lp/app/javascript/lazr/autocomplete' => 'lib/lp/app/javascript/autocomplete'
=== renamed file 'lib/lp/app/javascript/lazr/autocomplete/tests/index.html' => 'lib/lp/app/javascript/autocomplete/tests/test_autocomplete.html'
--- lib/lp/app/javascript/lazr/autocomplete/tests/index.html	2011-06-29 14:56:15 +0000
+++ lib/lp/app/javascript/autocomplete/tests/test_autocomplete.html	2011-07-07 06:39:25 +0000
@@ -5,20 +5,17 @@
   <title>autocomplete unit tests</title>
 
   <!-- YUI 3.0 Setup -->
-  <script type="text/javascript" src="../../testing/config.js"></script>
-  <script type="text/javascript" src="../../yui/yui/yui.js"></script>
-  <link rel="stylesheet" href="../../yui/cssreset/reset.css"/>
-  <link rel="stylesheet" href="../../yui/cssfonts/fonts.css"/>
-  <link rel="stylesheet" href="../../yui/cssbase/base.css"/>
-
-  <link rel="stylesheet" href="../../testing/assets/testlogger.css"/>
-  <script type="text/javascript" src="../../testing/testing.js"></script>
+  <script type="text/javascript" src="../../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/javascript/test.css" />
 
   <!-- The module under test -->
   <script type="text/javascript" src="../autocomplete.js"></script>
 
   <!-- The test suite -->
-  <script type="text/javascript" src="autocomplete.js"></script>
+  <script type="text/javascript" src="test_autocomplete.js"></script>
 
 </head>
 <body class="yui3-skin-sam">

=== renamed file 'lib/lp/app/javascript/lazr/autocomplete/tests/autocomplete.js' => 'lib/lp/app/javascript/autocomplete/tests/test_autocomplete.js'
--- lib/lp/app/javascript/lazr/autocomplete/tests/autocomplete.js	2011-06-29 14:56:15 +0000
+++ lib/lp/app/javascript/autocomplete/tests/test_autocomplete.js	2011-07-07 06:39:25 +0000
@@ -1,7 +1,12 @@
 /* Copyright (c) 2009, Canonical Ltd. All rights reserved. */
 
-YUI().use('lazr.autocomplete', 'lazr.testing.runner',
-          'node', 'event', 'console', function(Y) {
+YUI({
+    base: '../../../../../canonical/launchpad/icing/yui/',
+    filter: 'raw',
+    combine: false,
+    fetchCSS: false
+    }).use('test', 'console', 'node', 'lazr.autocomplete',
+           'event', 'event-simulate', function(Y) {
 
 /*****************************
  *
@@ -564,7 +569,20 @@
     }
 }));
 
-Y.lazr.testing.Runner.add(suite);
-Y.lazr.testing.Runner.run();
+// Lock, stock, and two smoking barrels.
+var handle_complete = function(data) {
+    window.status = '::::' + JSON.stringify(data);
+    };
+Y.Test.Runner.on('complete', handle_complete);
+Y.Test.Runner.add(suite);
+
+var yui_console = new Y.Console({
+    newestOnTop: false
+});
+yui_console.render('#log');
+
+Y.on('domready', function() {
+    Y.Test.Runner.run();
+});
 
 });

=== renamed directory 'lib/lp/app/javascript/lazr/choiceedit' => 'lib/lp/app/javascript/choiceedit'
=== renamed file 'lib/lp/app/javascript/lazr/choiceedit/tests/choiceedit.html' => 'lib/lp/app/javascript/choiceedit/tests/test_choiceedit.html'
--- lib/lp/app/javascript/lazr/choiceedit/tests/choiceedit.html	2011-06-29 14:56:15 +0000
+++ lib/lp/app/javascript/choiceedit/tests/test_choiceedit.html	2011-07-07 06:39:25 +0000
@@ -4,23 +4,22 @@
   <title>Status Editor</title>
 
   <!-- YUI 3.0 Setup -->
-  <script type="text/javascript" src="../../testing/config.js"></script>
-  <script type="text/javascript" src="../../yui/yui/yui.js"></script>
-  <link rel="stylesheet" href="../../yui/cssreset/reset.css"/>
-  <link rel="stylesheet" href="../../yui/cssfonts/fonts.css"/>
-  <link rel="stylesheet" href="../../yui/cssbase/base.css"/>
+  <script type="text/javascript" src="../../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/javascript/test.css" />
 
   <!-- Dependency -->
   <script type="text/javascript" src="../../lazr/lazr.js"></script>
   <script type="text/javascript" src="../../anim/anim.js"></script>
-  <script type="text/javascript" src="../../testing/testing.js"></script>
   <script type="text/javascript" src="../../overlay/overlay.js"></script>
 
   <!-- The module under test -->
-  <script type="text/javascript" src="../../choiceedit/choiceedit.js"></script>
+  <script type="text/javascript" src="../choiceedit.js"></script>
 
   <!-- The test suite -->
-  <script type="text/javascript" src="choiceedit.js"></script>
+  <script type="text/javascript" src="test_choiceedit.js"></script>
 </head>
 <body class="yui3-skin-sam">
 

=== renamed file 'lib/lp/app/javascript/lazr/choiceedit/tests/choiceedit.js' => 'lib/lp/app/javascript/choiceedit/tests/test_choiceedit.js'
--- lib/lp/app/javascript/lazr/choiceedit/tests/choiceedit.js	2011-06-29 14:56:15 +0000
+++ lib/lp/app/javascript/choiceedit/tests/test_choiceedit.js	2011-07-07 06:39:25 +0000
@@ -1,7 +1,12 @@
 /* Copyright (c) 2008, Canonical Ltd. All rights reserved. */
 
-YUI().use('lazr.choiceedit', 'lazr.testing.runner', 'node',
-          'event', 'event-simulate', 'widget-stack', 'console', function(Y) {
+YUI({
+    base: '../../../../../canonical/launchpad/icing/yui/',
+    filter: 'raw',
+    combine: false,
+    fetchCSS: false
+    }).use('test', 'console', 'node', 'lazr.choiceedit',
+           'event', 'event-simulate', 'widget-stack', function(Y) {
 
 // Local aliases
 var Assert = Y.Assert,
@@ -522,7 +527,20 @@
     }
 }));
 
-Y.lazr.testing.Runner.add(suite);
-Y.lazr.testing.Runner.run();
+// Lock, stock, and two smoking barrels.
+var handle_complete = function(data) {
+    window.status = '::::' + JSON.stringify(data);
+    };
+Y.Test.Runner.on('complete', handle_complete);
+Y.Test.Runner.add(suite);
+
+var yui_console = new Y.Console({
+    newestOnTop: false
+});
+yui_console.render('#log');
+
+Y.on('domready', function() {
+    Y.Test.Runner.run();
+});
 
 });

=== renamed directory 'lib/lp/app/javascript/lazr/effects' => 'lib/lp/app/javascript/effects'
=== renamed directory 'lib/lp/app/javascript/lazr/formoverlay' => 'lib/lp/app/javascript/formoverlay'
=== renamed file 'lib/lp/app/javascript/lazr/formoverlay/tests/formoverlay.html' => 'lib/lp/app/javascript/formoverlay/tests/test_formoverlay.html'
--- lib/lp/app/javascript/lazr/formoverlay/tests/formoverlay.html	2011-06-29 14:56:15 +0000
+++ lib/lp/app/javascript/formoverlay/tests/test_formoverlay.html	2011-07-07 06:39:25 +0000
@@ -4,26 +4,24 @@
   <title>Form Overlay</title>
 
   <!-- YUI 3.0 Setup -->
-  <script type="text/javascript" src="../../testing/config.js"></script>
-  <script type="text/javascript" src="../../yui/yui/yui.js"></script>
-  <link rel="stylesheet" href="../../yui/cssreset/reset.css"/>
-  <link rel="stylesheet" href="../../yui/cssfonts/fonts.css"/>
-  <link rel="stylesheet" href="../../yui/cssbase/base.css"/>
-  <link rel="stylesheet" href="../../testing/assets/testlogger.css"/>
+  <script type="text/javascript" src="../../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/javascript/test.css" />
 
   <!-- dependent modules from lazr-->
   <script type="text/javascript" src="../../lazr/lazr.js"></script>
   <script type="text/javascript" src="../../overlay/overlay.js"></script>
-  <script type="text/javascript" src="../../testing/testing.js"></script>
 
   <!-- The module under test -->
-  <script type="text/javascript" src="../../formoverlay/formoverlay.js"></script>
+  <script type="text/javascript" src="../formoverlay.js"></script>
 
   <!-- Testing helpers -->
   <script type="text/javascript" src="../../testing/mockio.js"></script>
 
   <!-- The test suite -->
-  <script type="text/javascript" src="formoverlay.js"></script>
+  <script type="text/javascript" src="test_formoverlay.js"></script>
 
 </head>
 <body class="yui3-skin-sam">

=== renamed file 'lib/lp/app/javascript/lazr/formoverlay/tests/formoverlay.js' => 'lib/lp/app/javascript/formoverlay/tests/test_formoverlay.js'
--- lib/lp/app/javascript/lazr/formoverlay/tests/formoverlay.js	2011-06-29 14:56:15 +0000
+++ lib/lp/app/javascript/formoverlay/tests/test_formoverlay.js	2011-07-07 06:39:25 +0000
@@ -1,8 +1,12 @@
 /* Copyright (c) 2008, Canonical Ltd. All rights reserved. */
 
-YUI().use('lazr.formoverlay', 'lazr.testing.runner',
-          'lazr.testing.mockio', 'node', 'event', 'event-simulate',
-          'dump', 'console', function(Y) {
+YUI({
+    base: '../../../../../canonical/launchpad/icing/yui/',
+    filter: 'raw',
+    combine: false,
+    fetchCSS: false
+    }).use('test', 'dump', 'console', 'node', 'lazr.formoverlay',
+           'event', 'event-simulate', 'lazr.testing.mockio', function(Y) {
 
 var Assert = Y.Assert;  // For easy access to isTrue(), etc.
 
@@ -498,7 +502,20 @@
     }
 }));
 
-Y.lazr.testing.Runner.add(suite);
-Y.lazr.testing.Runner.run();
+// Lock, stock, and two smoking barrels.
+var handle_complete = function(data) {
+    window.status = '::::' + JSON.stringify(data);
+    };
+Y.Test.Runner.on('complete', handle_complete);
+Y.Test.Runner.add(suite);
+
+var yui_console = new Y.Console({
+    newestOnTop: false
+});
+yui_console.render('#log');
+
+Y.on('domready', function() {
+    Y.Test.Runner.run();
+});
 
 });

=== renamed directory 'lib/lp/app/javascript/lazr/inlineedit' => 'lib/lp/app/javascript/inlineedit'
=== renamed file 'lib/lp/app/javascript/lazr/inlineedit/tests/index.html' => 'lib/lp/app/javascript/inlineedit/tests/test_inline_edit.html'
--- lib/lp/app/javascript/lazr/inlineedit/tests/index.html	2011-06-29 14:56:15 +0000
+++ lib/lp/app/javascript/inlineedit/tests/test_inline_edit.html	2011-07-07 06:39:25 +0000
@@ -1,25 +1,23 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd";>
 <html>
   <head>
   <title>Inline Edit</title>
 
   <!-- YUI 3.0 Setup -->
-  <script type="text/javascript" src="../../testing/config.js"></script>
-  <script type="text/javascript" src="../../yui/yui/yui.js"></script>
-  <link rel="stylesheet" href="../../yui/cssreset/reset.css"/>
-  <link rel="stylesheet" href="../../yui/cssfonts/fonts.css"/>
-  <link rel="stylesheet" href="../../yui/cssbase/base.css"/>
-  <link rel="stylesheet" href="../../testing/assets/testlogger.css"/>
+  <script type="text/javascript" src="../../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/javascript/test.css" />
 
   <!-- The module under test -->
-  <script type="text/javascript" src="../../inlineedit/editor.js"></script>
+  <script type="text/javascript" src="../editor.js"></script>
   <script type="text/javascript" src="../../anim/anim.js"></script>
   <script type="text/javascript" src="../../lazr/lazr.js"></script>
-  <script type="text/javascript" src="../../testing/testing.js"></script>
 
   <!-- The test suite -->
-  <script type="text/javascript" src="inline_edit.js"></script>
+  <script type="text/javascript" src="test_inline_edit.js"></script>
 
 </head>
 <body class="yui3-skin-sam">

=== renamed file 'lib/lp/app/javascript/lazr/inlineedit/tests/inline_edit.js' => 'lib/lp/app/javascript/inlineedit/tests/test_inline_edit.js'
--- lib/lp/app/javascript/lazr/inlineedit/tests/inline_edit.js	2011-06-29 14:56:15 +0000
+++ lib/lp/app/javascript/inlineedit/tests/test_inline_edit.js	2011-07-07 06:39:25 +0000
@@ -1,8 +1,14 @@
 /* Copyright (c) 2009, Canonical Ltd. All rights reserved. */
 
-YUI().use('lazr.editor', 'lazr.testing.runner', 'node',
-          'event', 'event-simulate', 'console', 'plugin', function(Y) {
-var SAMPLE_HTML = "                                                                           \
+YUI({
+    base: '../../../../../canonical/launchpad/icing/yui/',
+    filter: 'raw',
+    combine: false,
+    fetchCSS: false
+    }).use('test', 'console', 'node', 'lazr.editor',
+           'event', 'event-simulate', 'plugin', function(Y) {
+
+        var SAMPLE_HTML = "                                                                           \
  <h1>Single-line editing</h1>                                                                 \
   <div id='editable_single_text'>                                                             \
     <span id='single_text' class='yui3-editable_text-text'>Some editable inline text.</span>  \
@@ -1232,19 +1238,30 @@
         Assert.isTrue(editor.get('in_error'), "Editor should be in error");
         // Both the submit and cancel buttons should be visible.
         Assert.areEqual(
-            'inline',
+            'inline-block',
             editor.get('submit_button').getStyle('display'),
             "Submit should be set to display:inline");
         Assert.areEqual(
-            'inline',
+            'inline-block',
             editor.get('cancel_button').getStyle('display'),
             "Cancel should be set to display:inline");
     }
 }));
 
-
-
-Y.lazr.testing.Runner.add(suite);
-Y.lazr.testing.Runner.run();
+// Lock, stock, and two smoking barrels.
+var handle_complete = function(data) {
+    window.status = '::::' + JSON.stringify(data);
+    };
+Y.Test.Runner.on('complete', handle_complete);
+Y.Test.Runner.add(suite);
+
+var yui_console = new Y.Console({
+    newestOnTop: false
+});
+yui_console.render('#log');
+
+Y.on('domready', function() {
+    Y.Test.Runner.run();
+});
 
 });

=== renamed directory 'lib/lp/app/javascript/lazr/lazr/assets' => 'lib/lp/app/javascript/lazr/assets'
=== removed directory 'lib/lp/app/javascript/lazr/lazr'
=== renamed file 'lib/lp/app/javascript/lazr/lazr/lazr.js' => 'lib/lp/app/javascript/lazr/lazr.js'
=== removed directory 'lib/lp/app/javascript/lazr/testing'
=== removed directory 'lib/lp/app/javascript/lazr/testing/assets'
=== removed file 'lib/lp/app/javascript/lazr/testing/assets/testlogger.css'
--- lib/lp/app/javascript/lazr/testing/assets/testlogger.css	2011-06-29 14:56:15 +0000
+++ lib/lp/app/javascript/lazr/testing/assets/testlogger.css	1970-01-01 00:00:00 +0000
@@ -1,24 +0,0 @@
-/* Taken and customized from testlogger.css */
-/*#log .yui3-console-content { width: 44em }*/
-/*#log .yui3-console .yui3-console-bd { height: 30em }*/
-#log .yui3-console .yui3-console-controls { display: none; }
-#log .yui3-console .yui3-console-hd { display: none; }
-#log .yui3-console .yui3-console-ft { position: absolute; top: 0; }
-
-#log .yui3-console-entry-src { display: none; }
-
-#log .yui3-console-entry-pass .yui3-console-entry-cat {
-  background-color: green;
-  font-weight: bold;
-  color: white;
-}
-#log .yui3-console-entry-fail .yui3-console-entry-cat {
-  background-color: red;
-  font-weight: bold;
-  color: white;
-}
-#log .yui3-console-entry-ignore .yui3-console-entry-cat {
-  background-color: #666;
-  font-weight: bold;
-  color: white;
-}

=== removed file 'lib/lp/app/javascript/lazr/testing/config.js'
--- lib/lp/app/javascript/lazr/testing/config.js	2011-06-29 14:56:15 +0000
+++ lib/lp/app/javascript/lazr/testing/config.js	1970-01-01 00:00:00 +0000
@@ -1,6 +0,0 @@
-var YUI_config = {
-    base: '../../yui/',
-    filter: 'debug',
-    combine: false,
-    fetchCSS: false
-};
\ No newline at end of file

=== removed file 'lib/lp/app/javascript/lazr/testing/jsUnitMockTimeout.js'
--- lib/lp/app/javascript/lazr/testing/jsUnitMockTimeout.js	2011-06-29 14:56:15 +0000
+++ lib/lp/app/javascript/lazr/testing/jsUnitMockTimeout.js	1970-01-01 00:00:00 +0000
@@ -1,120 +0,0 @@
-/*
-    Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
-    The contents of this file are subject to the Mozilla Public License Version
-    1.1 (the "License"); you may not use this file except in compliance with
-    the License. You may obtain a copy of the License at
-    http://www.mozilla.org/MPL/
-
-    Software distributed under the License is distributed on an "AS IS" basis,
-    WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-    for the specific language governing rights and limitations under the
-    License.
-
-    The Original Code is Edward Hieatt code.
-
-    The Initial Developer of the Original Code is
-    Edward Hieatt, edward@xxxxxxxxxx.
-    Portions created by the Initial Developer are Copyright (C) 2003
-    the Initial Developer. All Rights Reserved.
-
-    Author Edward Hieatt, edward@xxxxxxxxxx
-
-    Alternatively, the contents of this file may be used under the terms of
-    either the GNU General Public License Version 2 or later (the "GPL"), or
-    the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-    in which case the provisions of the GPL or the LGPL are applicable instead
-    of those above. If you wish to allow use of your version of this file only
-    under the terms of either the GPL or the LGPL, and not to allow others to
-    use your version of this file under the terms of the MPL, indicate your
-    decision by deleting the provisions above and replace them with the notice
-    and other provisions required by the LGPL or the GPL. If you do not delete
-    the provisions above, a recipient may use your version of this file under
-    the terms of any one of the MPL, the GPL or the LGPL.
-*/
-
-// Mock setTimeout, clearTimeout
-// Contributed by Pivotal Computer Systems, www.pivotalsf.com
-//
-// Copied from the JsUnit 2.2alpha1 release, made in Mar 24 2006
-// (http://www.jsunit.net/)
-
-var Clock = {
-    timeoutsMade: 0,
-    scheduledFunctions: {},
-    nowMillis: 0,
-    reset: function() {
-        this.scheduledFunctions = {};
-        this.nowMillis = 0;
-        this.timeoutsMade = 0;
-    },
-    tick: function(millis) {
-        var oldMillis = this.nowMillis;
-        var newMillis = oldMillis + millis;
-        this.runFunctionsWithinRange(oldMillis, newMillis);
-        this.nowMillis = newMillis;
-    },
-    runFunctionsWithinRange: function(oldMillis, nowMillis) {
-        var scheduledFunc;
-        var funcsToRun = [];
-        for (var timeoutKey in this.scheduledFunctions) {
-            scheduledFunc = this.scheduledFunctions[timeoutKey];
-            if (scheduledFunc != undefined &&
-                scheduledFunc.runAtMillis >= oldMillis &&
-                scheduledFunc.runAtMillis <= nowMillis) {
-                funcsToRun.push(scheduledFunc);
-                this.scheduledFunctions[timeoutKey] = undefined;
-            }
-        }
-
-        if (funcsToRun.length > 0) {
-            funcsToRun.sort(function(a, b) {
-                return a.runAtMillis - b.runAtMillis;
-            });
-            for (var i = 0; i < funcsToRun.length; ++i) {
-                try {
-                    this.nowMillis = funcsToRun[i].runAtMillis;
-                    funcsToRun[i].funcToCall();
-                    if (funcsToRun[i].recurring) {
-                        Clock.scheduleFunction(funcsToRun[i].timeoutKey,
-                                funcsToRun[i].funcToCall,
-                                funcsToRun[i].millis,
-                                true);
-                    }
-                } catch(e) {
-                    console.log(e);
-                }
-            }
-            this.runFunctionsWithinRange(oldMillis, nowMillis);
-        }
-    },
-    scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
-        Clock.scheduledFunctions[timeoutKey] = {
-            runAtMillis: Clock.nowMillis + millis,
-            funcToCall: funcToCall,
-            recurring: recurring,
-            timeoutKey: timeoutKey,
-            millis: millis
-        };
-    }
-};
-
-function setTimeout(funcToCall, millis) {
-    Clock.timeoutsMade = Clock.timeoutsMade + 1;
-    Clock.scheduleFunction(Clock.timeoutsMade, funcToCall, millis, false);
-    return Clock.timeoutsMade;
-}
-
-function setInterval(funcToCall, millis) {
-    Clock.timeoutsMade = Clock.timeoutsMade + 1;
-    Clock.scheduleFunction(Clock.timeoutsMade, funcToCall, millis, true);
-    return Clock.timeoutsMade;
-}
-
-function clearTimeout(timeoutKey) {
-    Clock.scheduledFunctions[timeoutKey] = undefined;
-}
-
-function clearInterval(timeoutKey) {
-    Clock.scheduledFunctions[timeoutKey] = undefined;
-}

=== removed file 'lib/lp/app/javascript/lazr/testing/mockio.js'
--- lib/lp/app/javascript/lazr/testing/mockio.js	2011-06-29 14:56:15 +0000
+++ lib/lp/app/javascript/lazr/testing/mockio.js	1970-01-01 00:00:00 +0000
@@ -1,69 +0,0 @@
-/* Copyright (c) 2009, Canonical Ltd. All rights reserved. */
-
-YUI.add('lazr.testing.mockio', function(Y) {
-/**
- * A utility module for use in YUI unit-tests with a helper for mocking Y.io.
- *
- * @module lazr.testing
- */
-var MockIo = function() {
-    this.uri = null;
-    this.cfg = null;
-};
-
-/* Save the Y.io() arguments. */
-MockIo.prototype.io = function(uri, cfg) {
-    this.uri = uri;
-    this.cfg = cfg;
-    return this;  // Usually this isn't used, except for logging.
-};
-
-/* Simulate the Xhr request/response cycle. */
-MockIo.prototype.simulateXhr = function(response, is_failure) {
-    var cfg = this.cfg;
-    var context = cfg.context || this;
-    var args = cfg.arguments;
-    var tId = 'mockTId';
-    if (!response) {
-        response = {};
-    }
-
-    // See the Y.io utility documentation for the signatures.
-    if (cfg.on.start) {
-        cfg.on.start.call(context, tId, args);
-    }
-    if (cfg.on.complete) {
-        cfg.on.complete.call(context, tId, response, args);
-    }
-    if (cfg.on.success && !is_failure) {
-        cfg.on.success.call(context, tId, response, args);
-    }
-    if (cfg.on.failure && is_failure) {
-        cfg.on.failure.call(context, tId, response, args);
-    }
-};
-
-/* Make a successful XHR response object. */
-MockIo.makeXhrSuccessResponse = function(responseText) {
-    var text = responseText || "";
-    return {
-        status: 200,
-        statusText: "OK",
-        responseText: text
-    };
-};
-
-/* Make a failed XHR response object. */
-MockIo.makeXhrFailureResponse = function(responseText) {
-    var text = responseText || "";
-    return {
-        status: 500,
-        statusText: "Internal Server Error",
-        responseText: text
-    };
-};
-
-Y.namespace("lazr.testing");
-Y.lazr.testing.MockIo = MockIo;
-
-}, '0.1', {});

=== removed file 'lib/lp/app/javascript/lazr/testing/testing.js'
--- lib/lp/app/javascript/lazr/testing/testing.js	2011-06-29 14:56:15 +0000
+++ lib/lp/app/javascript/lazr/testing/testing.js	1970-01-01 00:00:00 +0000
@@ -1,131 +0,0 @@
-/* Copyright (c) 2009, Canonical Ltd. All rights reserved. */
-
-YUI.add("lazr.testing.runner", function(Y) {
-
-/**
- * Testing utilities.
- *
- * @module lazr.testing
- * @namespace lazr
- */
-
-Runner = Y.namespace("lazr.testing.Runner");
-
-Runner.add = function(suite) {
-    if ((typeof jstestdriver === "undefined")) {
-        // If we are not running under JsTestDriver, then
-        // register the suite with Y.Test.Runner and run it.
-        Y.Test.Runner.add(suite);
-    } else {
-        // If ``jstestdriver`` is defined, that means we are
-        // running under JsTestDriver, so instead register each
-        // test case from the suite as a separate TestCase() with
-        // JsTestDriver.
-        var tests = [];
-
-        Y.each(suite.items, function(testCase, idx) {
-            var suiteName = suite.name;
-            var testCaseName = testCase.name;
-
-            var clone = {};
-            for (var prop in testCase){
-                // Clone everything that is not a test method.
-                if (prop.indexOf("test") === -1){
-                    clone[prop] = testCase[prop];
-                }
-            }
-
-            // Now for each test method, create a JsTestDriver
-            // TestCase that wraps a single YUI TestSuite, that wraps
-            // a clone of the original TestCase but with only the
-            // single test method that we are interested in.
-            Y.each(testCase, function(property, name) {
-                if (name.indexOf("test") === 0 &&
-                    Y.Lang.isFunction(property)){
-                    tests.push({"suiteName": suiteName,
-                                "caseName": testCaseName,
-                                "case": clone,
-                                "methodName": name,
-                                "method": property});
-                }
-            });
-        });
-
-        Y.each(tests, function(testObject, i) {
-            testObject = tests[i];
-
-            var fakeTestCase = {
-                "setUp": Y.bind(function(testObject){
-                    var testSuite = new Y.Test.Suite(testObject.suiteName);
-                    var testCase = new Y.Test.Case(testObject['case']);
-                    testCase[testObject.methodName] = testObject.method;
-                    testSuite.add(testCase);
-                    Y.Test.Runner.clear();
-                    Y.Test.Runner.add(testSuite);
-                }, this, testObject),
-                "tearDown": function(){
-                    Y.Test.Runner.clear();
-                }
-            };
-
-            fakeTestCase[testObject.methodName] = Y.bind(function (testObject) {
-                var results = [];
-
-                var onComplete = function (methodName, results, e) {
-                    Y.Test.Runner.unsubscribe("testcasecomplete");
-                    results.push(e.results[methodName]);
-                };
-
-                Y.Test.Runner.subscribe(
-                    "testcasecomplete",
-                    Y.bind(onComplete, this, testObject.methodName, results),
-                    Y.Test.Runner);
-
-                Clock.reset();
-                Y.Test.Runner.run();
-                var i = 100;
-                while (i--) {
-                    if (!Y.Test.Runner.isRunning()){
-                        break;
-                    }
-                    Clock.tick(100);
-                }
-
-                var result = results.pop();
-                if (result === undefined) {
-                    fail("Test did not finish after 100 iterations.");
-                } else {
-                    if (result.result == "fail") {
-                        fail(result.message);
-                    }
-                }
-
-            }, this, testObject);
-
-            // JSLint will complain if the constructur is used without `new`
-            // and if the result of `new` is not used. The TestCase class is
-            // defined globally by jstestdriver and automatically registers
-            // itself, so it is not necessary to return this object.
-            var ignored = new TestCase(
-                testObject.caseName + "." + testObject.methodName,
-                fakeTestCase);
-        });
-    }
-};
-
-Runner.run = function(suite) {
-    Y.on("domready", function() {
-        if ((typeof jstestdriver === "undefined")) {
-            // If we are not running under JsTestDriver, then run all
-            // the registered test suites with Y.Test.Runner.
-            var yconsole = new Y.Console({
-                newestOnTop: false,
-                useBrowserConsole: true
-            });
-            yconsole.render("#log");
-            Y.Test.Runner.run();
-        }
-    });
-};
-
-}, "0.1", {"requires": ["oop", "test", "console"]});

=== renamed directory 'lib/lp/app/javascript/lazr/overlay' => 'lib/lp/app/javascript/overlay'
=== renamed file 'lib/lp/app/javascript/lazr/overlay/tests/overlay.html' => 'lib/lp/app/javascript/overlay/tests/test_overlay.html'
--- lib/lp/app/javascript/lazr/overlay/tests/overlay.html	2011-06-29 14:56:15 +0000
+++ lib/lp/app/javascript/overlay/tests/test_overlay.html	2011-07-07 06:39:25 +0000
@@ -1,23 +1,22 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd";>
 <html>
   <head>
   <title>Pretty Overlay</title>
 
   <!-- YUI 3.0 Setup -->
-  <script type="text/javascript" src="../../testing/config.js"></script>
-  <script type="text/javascript" src="../../yui/yui/yui.js"></script>
-  <link rel="stylesheet" href="../../yui/cssreset/reset.css"/>
-  <link rel="stylesheet" href="../../yui/cssfonts/fonts.css"/>
-  <link rel="stylesheet" href="../../yui/cssbase/base.css"/>
-  <link rel="stylesheet" href="../../testing/assets/testlogger.css"/>
+  <!-- YUI 3.0 Setup -->
+  <script type="text/javascript" src="../../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/javascript/test.css" />
 
   <!-- The module under test -->
-  <script type="text/javascript" src="../../overlay/overlay.js"></script>
-  <script type="text/javascript" src="../../testing/testing.js"></script>
+  <script type="text/javascript" src="../overlay.js"></script>
 
   <!-- The test suite -->
-  <script type="text/javascript" src="overlay.js"></script>
+  <script type="text/javascript" src="test_overlay.js"></script>
 
 </head>
 <body class="yui3-skin-sam">

=== renamed file 'lib/lp/app/javascript/lazr/overlay/tests/overlay.js' => 'lib/lp/app/javascript/overlay/tests/test_overlay.js'
--- lib/lp/app/javascript/lazr/overlay/tests/overlay.js	2011-06-29 14:56:15 +0000
+++ lib/lp/app/javascript/overlay/tests/test_overlay.js	2011-07-07 06:39:25 +0000
@@ -1,7 +1,12 @@
 /* Copyright (c) 2009, Canonical Ltd. All rights reserved. */
 
-YUI().use('lazr.overlay', 'lazr.testing.runner', 'node',
-          'event', 'event-simulate', 'widget-stack', 'console', function(Y) {
+YUI({
+    base: '../../../../../canonical/launchpad/icing/yui/',
+    filter: 'raw',
+    combine: false,
+    fetchCSS: false
+    }).use('test', 'console', 'node', 'lazr.overlay',
+           'event', 'event-simulate', 'widget-stack', function(Y) {
 
 // KeyCode for escape
 var ESCAPE = 27;
@@ -211,7 +216,20 @@
 
 }));
 
-Y.lazr.testing.Runner.add(suite);
-Y.lazr.testing.Runner.run();
+// Lock, stock, and two smoking barrels.
+var handle_complete = function(data) {
+    window.status = '::::' + JSON.stringify(data);
+    };
+Y.Test.Runner.on('complete', handle_complete);
+Y.Test.Runner.add(suite);
+
+var yui_console = new Y.Console({
+    newestOnTop: false
+});
+yui_console.render('#log');
+
+Y.on('domready', function() {
+    Y.Test.Runner.run();
+});
 
 });

=== renamed directory 'lib/lp/app/javascript/lazr/picker' => 'lib/lp/app/javascript/picker'
=== modified file 'lib/lp/app/javascript/picker/picker.js'
--- lib/lp/app/javascript/lazr/picker/picker.js	2011-07-05 04:01:35 +0000
+++ lib/lp/app/javascript/picker/picker.js	2011-07-07 06:39:25 +0000
@@ -372,7 +372,9 @@
                 }, alt_link);
             }
             li_title.appendChild('&nbsp;(');
-            li_title.appendChild(document.createTextNode(data.alt_title));
+            var alt_title_node = Y.Node.create('<span></span>')
+                .set('text', data.alt_title);
+            li_title.appendChild(alt_title_node);
             li_title.appendChild(')');
             if (alt_link !== null) {
                 li_title.appendChild(alt_link);

=== renamed file 'lib/lp/app/javascript/picker_patcher.js' => 'lib/lp/app/javascript/picker/picker_patcher.js'
=== renamed file 'lib/lp/app/javascript/tests/test_personpicker.html' => 'lib/lp/app/javascript/picker/tests/test_personpicker.html'
--- lib/lp/app/javascript/tests/test_personpicker.html	2011-07-05 03:55:38 +0000
+++ lib/lp/app/javascript/picker/tests/test_personpicker.html	2011-07-07 06:39:25 +0000
@@ -2,24 +2,28 @@
   <head>
     <title>Launchpad PersonPicker</title>
     <!-- YUI 3.0 Setup -->
-    <script type="text/javascript" src="../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
-    <script type="text/javascript"
-      src="../../../../canonical/launchpad/icing/lazr/build/lazr.js"></script>
-    <link rel="stylesheet"
-      href="../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
-    <link rel="stylesheet"
-      href="../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
-    <link rel="stylesheet"
-      href="../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>
-    <link rel="stylesheet"
-      href="../../../../canonical/launchpad/javascript/test.css" />
-    <script type="text/javascript" src="../../../app/javascript/client.js"></script>
-    <script type="text/javascript" src="../../../app/javascript/lp.js"></script>
-    <script type="text/javascript" src="../lazr/picker/picker.js"></script>
+    <script type="text/javascript" src="../../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
+    <link rel="stylesheet"
+      href="../../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
+    <link rel="stylesheet"
+      href="../../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
+    <link rel="stylesheet"
+      href="../../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>
+    <link rel="stylesheet"
+      href="../../../../../canonical/launchpad/javascript/test.css" />
+
+    <!-- Some required dependencies -->
+    <script type="text/javascript" src="../../client.js"></script>
+    <script type="text/javascript" src="../../lp.js"></script>
+    <script type="text/javascript" src="../../activator/activator.js"></script>
+    <script type="text/javascript" src="../../anim/anim.js"></script>
+    <script type="text/javascript" src="../../lazr/lazr.js"></script>
+    <script type="text/javascript" src="../../overlay/overlay.js"></script>
+    <script type="text/javascript" src="../picker.js"></script>
     <script type="text/javascript" src="../picker_patcher.js"></script>
 
     <!-- The module under test -->
-    <script type="text/javascript" src="../lazr/picker/person_picker.js"></script>
+    <script type="text/javascript" src="../person_picker.js"></script>
 
     <!-- The test suite -->
     <script type="text/javascript" src="test_personpicker.js"></script>

=== renamed file 'lib/lp/app/javascript/tests/test_personpicker.js' => 'lib/lp/app/javascript/picker/tests/test_personpicker.js'
--- lib/lp/app/javascript/tests/test_personpicker.js	2011-07-06 03:20:46 +0000
+++ lib/lp/app/javascript/picker/tests/test_personpicker.js	2011-07-07 06:39:25 +0000
@@ -3,7 +3,7 @@
  */
 
 YUI({
-    base: '../../../../canonical/launchpad/icing/yui/',
+    base: '../../../../../canonical/launchpad/icing/yui/',
     filter: 'raw', combine: false,
     fetchCSS: false
     }).use('test', 'console', 'plugin',

=== renamed file 'lib/lp/app/javascript/lazr/picker/tests/picker.html' => 'lib/lp/app/javascript/picker/tests/test_picker.html'
--- lib/lp/app/javascript/lazr/picker/tests/picker.html	2011-06-29 14:56:15 +0000
+++ lib/lp/app/javascript/picker/tests/test_picker.html	2011-07-07 06:39:25 +0000
@@ -5,22 +5,20 @@
   <title>Picker</title>
 
   <!-- YUI 3.0 Setup -->
-  <script type="text/javascript" src="../../testing/config.js"></script>
-  <script type="text/javascript" src="../../yui/yui/yui.js"></script>
-  <link rel="stylesheet" href="../../yui/cssreset/reset.css"/>
-  <link rel="stylesheet" href="../../yui/cssfonts/fonts.css"/>
-  <link rel="stylesheet" href="../../yui/cssbase/base.css"/>
-  <link rel="stylesheet" href="../../testing/assets/testlogger.css"/>
+  <script type="text/javascript" src="../../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/javascript/test.css" />
 
   <!-- The module under test -->
   <script type="text/javascript" src="../../overlay/overlay.js"></script>
-  <script type="text/javascript" src="../../picker/picker.js"></script>
+  <script type="text/javascript" src="../picker.js"></script>
   <script type="text/javascript" src="../../anim/anim.js"></script>
   <script type="text/javascript" src="../../lazr/lazr.js"></script>
-  <script type="text/javascript" src="../../testing/testing.js"></script>
 
   <!-- The test suite -->
-  <script type="text/javascript" src="picker.js"></script>
+  <script type="text/javascript" src="test_picker.js"></script>
 </head>
 <body class="yui3-skin-sam">
   <div id="log"></div>

=== renamed file 'lib/lp/app/javascript/lazr/picker/tests/picker.js' => 'lib/lp/app/javascript/picker/tests/test_picker.js'
--- lib/lp/app/javascript/lazr/picker/tests/picker.js	2011-07-05 03:17:02 +0000
+++ lib/lp/app/javascript/picker/tests/test_picker.js	2011-07-07 06:39:25 +0000
@@ -1,8 +1,12 @@
 /* Copyright (c) 2009, Canonical Ltd. All rights reserved. */
 
-YUI().use('lazr.picker', 'lazr.testing.runner', 'node',
-          'event', 'event-focus', 'event-simulate', 'console', 'dump',
-          function(Y) {
+YUI({
+    base: '../../../../../canonical/launchpad/icing/yui/',
+    filter: 'raw',
+    combine: false,
+    fetchCSS: false
+    }).use('test', 'console', 'dump', 'node', 'lazr.picker',
+           'event', 'event-simulate', function(Y) {
 
 // Local aliases
 var Assert = Y.Assert,
@@ -160,11 +164,14 @@
                 link_selector + ' link was not clicked');
         }
         check_link(
-            this.picker, '.cool-style:nth-child(1)', 'Joe Schmo',
+            this.picker, 'a.cool-style:nth-child(1)', 'Joe Schmo',
             'http://somewhere.com/');
         check_link(
-            this.picker, '.cool-style:nth-child(2)', 'Joe Again <foo></foo>',
+            this.picker, 'a.cool-style:nth-child(3)', ' Details...',
             'http://somewhereelse.com/');
+        var alt_text_node = this.picker.get('boundingBox')
+            .one('.yui3-picker-result-title span');
+        Assert.areEqual('Joe Again <foo></foo>', alt_text_node.get('text'));
     },
 
     test_title_badges: function () {
@@ -954,7 +961,20 @@
 
 }));
 
-Y.lazr.testing.Runner.add(suite);
-Y.lazr.testing.Runner.run();
+// Lock, stock, and two smoking barrels.
+var handle_complete = function(data) {
+    window.status = '::::' + JSON.stringify(data);
+    };
+Y.Test.Runner.on('complete', handle_complete);
+Y.Test.Runner.add(suite);
+
+var yui_console = new Y.Console({
+    newestOnTop: false
+});
+yui_console.render('#log');
+
+Y.on('domready', function() {
+    Y.Test.Runner.run();
+});
 
 });

=== renamed file 'lib/lp/app/javascript/tests/test_picker.html' => 'lib/lp/app/javascript/picker/tests/test_picker_patcher.html'
--- lib/lp/app/javascript/tests/test_picker.html	2011-07-05 03:55:38 +0000
+++ lib/lp/app/javascript/picker/tests/test_picker_patcher.html	2011-07-07 06:39:25 +0000
@@ -5,27 +5,26 @@
   <title>Launchpad Picker</title>
 
   <!-- YUI 3.0 Setup -->
-  <script type="text/javascript" src="../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
-  <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
-  <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
-  <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>
-  <link rel="stylesheet" href="../../../../canonical/launchpad/javascript/test.css" />
+  <script type="text/javascript" src="../../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>
+  <link rel="stylesheet" href="../../../../../canonical/launchpad/javascript/test.css" />
 
   <!-- Some required dependencies -->
-  <script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/testing/config.js"></script>
-  <script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/activator/activator.js"></script>
-  <script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/overlay/overlay.js"></script>
-  <script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/anim/anim.js"></script>
-  <script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/lazr/lazr.js"></script>
-  <script type="text/javascript" src="../client.js"></script>
+  <script type="text/javascript" src="../../activator/activator.js"></script>
+  <script type="text/javascript" src="../../overlay/overlay.js"></script>
+  <script type="text/javascript" src="../../anim/anim.js"></script>
+  <script type="text/javascript" src="../../lazr/lazr.js"></script>
+  <script type="text/javascript" src="../../client.js"></script>
   <script type="text/javascript" src="../picker_patcher.js"></script>
 
   <!-- The module under test -->
-  <script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/picker/picker.js"></script>
-  <script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/picker/person_picker.js"></script>
+  <script type="text/javascript" src="../picker.js"></script>
+  <script type="text/javascript" src="../person_picker.js"></script>
 
   <!-- The test suite -->
-  <script type="text/javascript" src="test_picker.js"></script>
+  <script type="text/javascript" src="test_picker_patcher.js"></script>
 </head>
 <body class="yui3-skin-sam">
   <div class="yui3-widget yui3-activator yui3-activator-focused">

=== renamed file 'lib/lp/app/javascript/tests/test_picker.js' => 'lib/lp/app/javascript/picker/tests/test_picker_patcher.js'
--- lib/lp/app/javascript/tests/test_picker.js	2011-07-06 03:20:46 +0000
+++ lib/lp/app/javascript/picker/tests/test_picker_patcher.js	2011-07-07 06:39:25 +0000
@@ -1,7 +1,7 @@
 /* Copyright (c) 2011, Canonical Ltd. All rights reserved. */
 
 YUI({
-    base: '../../../../canonical/launchpad/icing/yui/',
+    base: '../../../../../canonical/launchpad/icing/yui/',
     filter: 'raw',
     combine: false,
     fetchCSS: false

=== added directory 'lib/lp/app/javascript/testing'
=== added file 'lib/lp/app/javascript/testing/mockio.js'
--- lib/lp/app/javascript/testing/mockio.js	1970-01-01 00:00:00 +0000
+++ lib/lp/app/javascript/testing/mockio.js	2011-07-07 06:39:25 +0000
@@ -0,0 +1,69 @@
+/* Copyright (c) 2009, Canonical Ltd. All rights reserved. */
+
+YUI.add('lazr.testing.mockio', function(Y) {
+/**
+ * A utility module for use in YUI unit-tests with a helper for mocking Y.io.
+ *
+ * @module lazr.testing
+ */
+var MockIo = function() {
+    this.uri = null;
+    this.cfg = null;
+};
+
+/* Save the Y.io() arguments. */
+MockIo.prototype.io = function(uri, cfg) {
+    this.uri = uri;
+    this.cfg = cfg;
+    return this;  // Usually this isn't used, except for logging.
+};
+
+/* Simulate the Xhr request/response cycle. */
+MockIo.prototype.simulateXhr = function(response, is_failure) {
+    var cfg = this.cfg;
+    var context = cfg.context || this;
+    var args = cfg.arguments;
+    var tId = 'mockTId';
+    if (!response) {
+        response = {};
+    }
+
+    // See the Y.io utility documentation for the signatures.
+    if (cfg.on.start) {
+        cfg.on.start.call(context, tId, args);
+    }
+    if (cfg.on.complete) {
+        cfg.on.complete.call(context, tId, response, args);
+    }
+    if (cfg.on.success && !is_failure) {
+        cfg.on.success.call(context, tId, response, args);
+    }
+    if (cfg.on.failure && is_failure) {
+        cfg.on.failure.call(context, tId, response, args);
+    }
+};
+
+/* Make a successful XHR response object. */
+MockIo.makeXhrSuccessResponse = function(responseText) {
+    var text = responseText || "";
+    return {
+        status: 200,
+        statusText: "OK",
+        responseText: text
+    };
+};
+
+/* Make a failed XHR response object. */
+MockIo.makeXhrFailureResponse = function(responseText) {
+    var text = responseText || "";
+    return {
+        status: 500,
+        statusText: "Internal Server Error",
+        responseText: text
+    };
+};
+
+Y.namespace("lazr.testing");
+Y.lazr.testing.MockIo = MockIo;
+
+}, '0.1', {});

=== modified file 'lib/lp/app/javascript/tests/test_expander.html'
--- lib/lp/app/javascript/tests/test_expander.html	2011-06-30 14:49:16 +0000
+++ lib/lp/app/javascript/tests/test_expander.html	2011-07-07 06:39:25 +0000
@@ -3,8 +3,6 @@
     <title>Expander widget</title>
     <!-- YUI 3.0 Setup -->
     <script type="text/javascript" src="../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
-    <script type="text/javascript"
-      src="../../../../canonical/launchpad/icing/lazr/build/lazr.js"></script>
     <link rel="stylesheet"
       href="../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
     <link rel="stylesheet"
@@ -13,8 +11,8 @@
       href="../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>
     <link rel="stylesheet"
       href="../../../../canonical/launchpad/javascript/test.css" />
-    <script type="text/javascript" src="../../../app/javascript/client.js"></script>
-    <script type="text/javascript" src="../../../app/javascript/lp.js"></script>
+    <script type="text/javascript" src="../client.js"></script>
+    <script type="text/javascript" src="../lp.js"></script>
 
     <!-- The module under test -->
     <script type="text/javascript" src="../expander.js"></script>

=== modified file 'lib/lp/app/javascript/tests/test_hide_comment.html'
--- lib/lp/app/javascript/tests/test_hide_comment.html	2011-06-07 21:15:48 +0000
+++ lib/lp/app/javascript/tests/test_hide_comment.html	2011-07-07 06:39:25 +0000
@@ -3,8 +3,6 @@
     <title>Launchpad Comment Hiding</title>
     <!-- YUI 3.0 Setup -->
     <script type="text/javascript" src="../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
-    <script type="text/javascript"
-      src="../../../../canonical/launchpad/icing/lazr/build/lazr.js"></script>
     <link rel="stylesheet"
       href="../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
     <link rel="stylesheet"

=== modified file 'lib/lp/app/javascript/tests/test_lp_client.html'
--- lib/lp/app/javascript/tests/test_lp_client.html	2011-04-05 11:47:15 +0000
+++ lib/lp/app/javascript/tests/test_lp_client.html	2011-07-07 06:39:25 +0000
@@ -5,7 +5,6 @@
 
   <!-- YUI 3.0 Setup -->
   <script type="text/javascript" src="../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
-  <script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/lazr.js"></script>
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>

=== modified file 'lib/lp/app/javascript/tests/test_lp_collapsibles.html'
--- lib/lp/app/javascript/tests/test_lp_collapsibles.html	2010-11-23 14:18:07 +0000
+++ lib/lp/app/javascript/tests/test_lp_collapsibles.html	2011-07-07 06:39:25 +0000
@@ -5,13 +5,15 @@
 
   <!-- YUI 3.0 Setup -->
   <script type="text/javascript" src="../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
-  <script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/lazr.js"></script>
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>
   <link rel="stylesheet" href="../../../../canonical/launchpad/javascript/test.css" />
 
-  <!-- The module under test -->
+  <!-- Some required dependencies -->
+  <script type="text/javascript" src="../effects/effects.js"></script>
+
+      <!-- The module under test -->
   <script type="text/javascript" src="../lp.js"></script>
 
   <!-- The test suite -->

=== modified file 'lib/lp/app/javascript/tests/test_lp_names.html'
--- lib/lp/app/javascript/tests/test_lp_names.html	2011-06-21 05:37:38 +0000
+++ lib/lp/app/javascript/tests/test_lp_names.html	2011-07-07 06:39:25 +0000
@@ -5,7 +5,6 @@
 
   <!-- YUI 3.0 Setup -->
   <script type="text/javascript" src="../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
-  <script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/lazr.js"></script>
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>

=== modified file 'lib/lp/app/javascript/tests/test_multicheckboxwidget.html'
--- lib/lp/app/javascript/tests/test_multicheckboxwidget.html	2011-04-05 03:15:54 +0000
+++ lib/lp/app/javascript/tests/test_multicheckboxwidget.html	2011-07-07 06:39:25 +0000
@@ -12,9 +12,10 @@
   <link rel="stylesheet" href="../../../../canonical/launchpad/javascript/test.css" />
 
   <!-- Some required dependencies -->
-  <script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/lazr.js"></script>
   <script type="text/javascript" src="../client.js"></script>
-
+  <script type="text/javascript" src="../activator/activator.js"></script>
+  <script type="text/javascript" src="../lazr/lazr.js"></script>
+  <script type="text/javascript" src="../overlay/overlay.js"></script>
   <!-- The module under test -->
   <script type="text/javascript" src="../multicheckbox.js"></script>
 

=== modified file 'lib/lp/app/tests/test_yuitests.py'
--- lib/lp/app/tests/test_yuitests.py	2011-06-09 15:37:18 +0000
+++ lib/lp/app/tests/test_yuitests.py	2011-07-07 06:39:25 +0000
@@ -20,5 +20,5 @@
 
 
 def test_suite():
-    app_testing_path = 'lp/app/javascript/tests'
+    app_testing_path = 'lp/app/javascript'
     return build_yui_unittest_suite(app_testing_path, AppYUIUnitTestCase)

=== modified file 'lib/lp/bugs/javascript/tests/test_bug_notification_level.html'
--- lib/lp/bugs/javascript/tests/test_bug_notification_level.html	2011-04-27 10:19:21 +0000
+++ lib/lp/bugs/javascript/tests/test_bug_notification_level.html	2011-07-07 06:39:25 +0000
@@ -5,8 +5,6 @@
      <!-- YUI 3.0 Setup -->
     <script type="text/javascript"
       src="../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
-    <script type="text/javascript"
-      src="../../../../canonical/launchpad/icing/lazr/build/lazr.js"></script>
     <link rel="stylesheet"
       href="../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
     <link rel="stylesheet"
@@ -18,6 +16,10 @@
 
     <script type="text/javascript"
       src="../../../app/javascript/client.js"></script>
+    <script type="text/javascript"
+      src="../../../app/javascript/anim/anim.js"></script>
+    <script type="text/javascript"
+      src="../../../app/javascript/effects/effects.js"></script>
 
     <!-- The module under test -->
     <script type="text/javascript"

=== modified file 'lib/lp/bugs/javascript/tests/test_bug_subscription_portlet.html'
--- lib/lp/bugs/javascript/tests/test_bug_subscription_portlet.html	2011-06-21 05:37:38 +0000
+++ lib/lp/bugs/javascript/tests/test_bug_subscription_portlet.html	2011-07-07 06:39:25 +0000
@@ -5,8 +5,6 @@
      <!-- YUI 3.0 Setup -->
     <script type="text/javascript"
       src="../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
-    <script type="text/javascript"
-      src="../../../../canonical/launchpad/icing/lazr/build/lazr.js"></script>
     <link rel="stylesheet"
       href="../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
     <link rel="stylesheet"
@@ -20,6 +18,14 @@
       src="../../../app/javascript/client.js"></script>
     <script type="text/javascript"
       src="../../../app/javascript/errors.js"></script>
+    <script type="text/javascript"
+      src="../../../app/javascript/anim/anim.js"></script>
+    <script type="text/javascript"
+      src="../../../app/javascript/effects/effects.js"></script>
+    <script type="text/javascript"
+      src="../../../app/javascript/formoverlay/formoverlay.js"></script>
+    <script type="text/javascript"
+      src="../../../app/javascript/overlay/overlay.js"></script>
 
     <!-- The module under test -->
     <script type="text/javascript"

=== modified file 'lib/lp/bugs/javascript/tests/test_filebug_dupfinder.html'
--- lib/lp/bugs/javascript/tests/test_filebug_dupfinder.html	2011-04-29 01:55:28 +0000
+++ lib/lp/bugs/javascript/tests/test_filebug_dupfinder.html	2011-07-07 06:39:25 +0000
@@ -5,8 +5,6 @@
     <!-- YUI 3.0 Setup -->
     <script type="text/javascript"
             src="../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
-    <script type="text/javascript"
-            src="../../../../canonical/launchpad/icing/lazr/build/lazr.js"></script>
     <link rel="stylesheet"
           href="../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
     <link rel="stylesheet"
@@ -21,6 +19,10 @@
     <script type="text/javascript"
             src="../../../app/javascript/errors.js"></script>
 
+    <!-- Some required dependencies -->
+    <script type="text/javascript" src="../../../app/javascript/effects/effects.js"></script>
+    <script type="text/javascript" src="../../../app/javascript/overlay/overlay.js"></script>
+
     <!-- The module under test -->
     <script type="text/javascript"
             src="../filebug_dupefinder.js"></script>

=== modified file 'lib/lp/bugs/javascript/tests/test_me_too.html'
--- lib/lp/bugs/javascript/tests/test_me_too.html	2011-02-28 00:54:30 +0000
+++ lib/lp/bugs/javascript/tests/test_me_too.html	2011-07-07 06:39:25 +0000
@@ -11,8 +11,6 @@
 
   <!-- Dependency -->
   <script type="text/javascript"
-    src="../../../../canonical/launchpad/icing/lazr/build/lazr.js"></script>
-  <script type="text/javascript"
     src="../../../../canonical/launchpad/icing/yui/attribute/attribute.js">
   </script>
   <script type="text/javascript"
@@ -22,14 +20,13 @@
     src="../../../../canonical/launchpad/icing/yui/oop/oop.js">
   </script>
   <script type="text/javascript"
-    src="../../../../canonical/launchpad/icing/lazr/build/overlay/overlay.js">
+    src="../../../app/javascript/overlay/overlay.js">
   </script>
   <script type="text/javascript"
-    src="../../../../canonical/launchpad/icing/lazr/build/choiceedit/choiceedit.js">
+    src="../../../app/javascript/choiceedit/choiceedit.js">
   </script>
   <script type="text/javascript"
     src="../../../app/javascript/client.js"></script>
-  <script type="text/javascript" src="../subscriber.js"></script>
 
   <!-- The module under test -->
   <script type="text/javascript" src="../bugtask_index.js"></script>

=== modified file 'lib/lp/bugs/javascript/tests/test_subscribers_list.html'
--- lib/lp/bugs/javascript/tests/test_subscribers_list.html	2011-07-05 03:55:38 +0000
+++ lib/lp/bugs/javascript/tests/test_subscribers_list.html	2011-07-07 06:39:25 +0000
@@ -5,8 +5,6 @@
      <!-- YUI 3.0 Setup -->
     <script type="text/javascript"
       src="../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
-    <script type="text/javascript"
-      src="../../../../canonical/launchpad/icing/lazr/build/lazr.js"></script>
     <link rel="stylesheet"
       href="../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
     <link rel="stylesheet"
@@ -23,13 +21,23 @@
     <script type="text/javascript"
       src="../../../app/javascript/lp-names.js"></script>
     <script type="text/javascript"
-      src="../../../app/javascript/picker_patcher.js"></script>
-    <script type="text/javascript"
-      src="../../../app/javascript/lazr/picker/person_picker.js"></script>
-
-    <!-- Pre-requisite -->
-    <script type="text/javascript"
-      src="../subscriber.js"></script>
+      src="../../../app/javascript/anim/anim.js"></script>
+    <script type="text/javascript"
+      src="../../../app/javascript/formoverlay/formoverlay.js"></script>
+    <script type="text/javascript"
+      src="../../../app/javascript/overlay/overlay.js"></script>
+    <script type="text/javascript"
+      src="../../../app/javascript/anim/anim.js"></script>
+    <script type="text/javascript"
+      src="../../../app/javascript/activator/activator.js"></script>
+    <script type="text/javascript"
+      src="../../../app/javascript/lazr/lazr.js"></script>
+    <script type="text/javascript"
+      src="../../../app/javascript/picker/picker_patcher.js"></script>
+    <script type="text/javascript"
+      src="../../../app/javascript/picker/picker.js"></script>
+    <script type="text/javascript"
+      src="../../../app/javascript/picker/person_picker.js"></script>
 
     <!-- The module under test -->
     <script type="text/javascript"

=== modified file 'lib/lp/bugs/javascript/tests/test_subscription.html'
--- lib/lp/bugs/javascript/tests/test_subscription.html	2011-04-15 22:01:06 +0000
+++ lib/lp/bugs/javascript/tests/test_subscription.html	2011-07-07 06:39:25 +0000
@@ -5,8 +5,6 @@
      <!-- YUI 3.0 Setup -->
     <script type="text/javascript"
       src="../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
-    <script type="text/javascript"
-      src="../../../../canonical/launchpad/icing/lazr/build/lazr.js"></script>
     <link rel="stylesheet"
       href="../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
     <link rel="stylesheet"
@@ -20,6 +18,14 @@
       src="../../../app/javascript/client.js"></script>
     <script type="text/javascript"
       src="../../../app/javascript/errors.js"></script>
+    <script type="text/javascript"
+      src="../../../app/javascript/anim/anim.js"></script>
+    <script type="text/javascript"
+      src="../../../app/javascript/effects/effects.js"></script>
+    <script type="text/javascript"
+      src="../../../app/javascript/formoverlay/formoverlay.js"></script>
+    <script type="text/javascript"
+      src="../../../app/javascript/overlay/overlay.js"></script>
 
     <!-- The module under test -->
     <script type="text/javascript"

=== modified file 'lib/lp/bugs/tests/test_yuitests.py'
--- lib/lp/bugs/tests/test_yuitests.py	2011-06-09 15:37:18 +0000
+++ lib/lp/bugs/tests/test_yuitests.py	2011-07-07 06:39:25 +0000
@@ -20,5 +20,5 @@
 
 
 def test_suite():
-    app_testing_path = 'lp/bugs/javascript/tests'
+    app_testing_path = 'lp/bugs/javascript'
     return build_yui_unittest_suite(app_testing_path, BugsYUIUnitTestCase)

=== modified file 'lib/lp/code/browser/branch.py'
--- lib/lp/code/browser/branch.py	2011-06-17 09:56:57 +0000
+++ lib/lp/code/browser/branch.py	2011-07-07 06:39:25 +0000
@@ -108,7 +108,6 @@
     )
 from lp.app.browser.lazrjs import (
     EnumChoiceWidget,
-    vocabulary_to_choice_edit_items,
     )
 from lp.app.errors import NotFoundError
 from lp.app.interfaces.launchpad import ILaunchpadCelebrities
@@ -118,7 +117,6 @@
 from lp.bugs.interfaces.bug import IBugSet
 from lp.bugs.interfaces.bugbranch import IBugBranch
 from lp.bugs.interfaces.bugtask import UNRESOLVED_BUGTASK_STATUSES
-from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJobSet
 from lp.code.browser.branchmergeproposal import (
     latest_proposals_for_each_branch,
     )
@@ -126,7 +124,6 @@
 from lp.code.browser.decorations import DecoratedBranch
 from lp.code.browser.sourcepackagerecipelisting import HasRecipesMenuMixin
 from lp.code.enums import (
-    BranchLifecycleStatus,
     BranchType,
     CodeImportResultStatus,
     CodeImportReviewStatus,
@@ -1039,7 +1036,7 @@
             owner_field = self.schema['owner']
             any_owner_choice = Choice(
                 __name__='owner', title=owner_field.title,
-                description = _("As an administrator you are able to reassign"
+                description=_("As an administrator you are able to reassign"
                                 " this branch to any person or team."),
                 required=True, vocabulary='ValidPersonOrTeam')
             any_owner_field = form.Fields(
@@ -1056,12 +1053,12 @@
                 vocab = UserTeamsParticipationPlusSelfVocabulary()
                 owner = self.context.owner
                 terms = [SimpleTerm(
-                    owner, owner.name, owner.unique_displayname)]
+                    owner, owner.name, owner.displayname)]
                 terms.extend([term for term in vocab])
                 owner_field = self.schema['owner']
                 owner_choice = Choice(
                     __name__='owner', title=owner_field.title,
-                    description = owner_field.description,
+                    description=owner_field.description,
                     required=True, vocabulary=SimpleVocabulary(terms))
                 new_owner_field = form.Fields(
                     owner_choice, render_context=self.render_context)
@@ -1480,7 +1477,8 @@
     def _commitCounts(self):
         """Return a dict of commit counts for rendering."""
         epoch = (
-            datetime.now(tz=pytz.UTC) - timedelta(days=(self.COMMIT_DAYS-1)))
+            datetime.now(
+                tz=pytz.UTC) - timedelta(days=(self.COMMIT_DAYS - 1)))
         # Make a datetime for that date, but midnight.
         epoch = epoch.replace(hour=0, minute=0, second=0, microsecond=0)
         commits = dict(self.context.commitsForDays(epoch))

=== modified file 'lib/lp/code/javascript/tests/test_branchdiff.html'
--- lib/lp/code/javascript/tests/test_branchdiff.html	2011-05-05 17:04:58 +0000
+++ lib/lp/code/javascript/tests/test_branchdiff.html	2011-07-07 06:39:25 +0000
@@ -6,13 +6,15 @@
 
   <!-- YUI 3.0 Setup -->
   <script type="text/javascript" src="../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
-  <script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/lazr.js"></script>
   <script type="text/javascript" src="../../../app/javascript/client.js"></script>
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>
   <link rel="stylesheet" href="../../../../canonical/launchpad/javascript/test.css" />
-  <link rel="stylesheet" href="../../../../canonical/launchpad/icing/lazr/build/lazr-sam.css" />
+  <link rel="stylesheet" href="../../../../canonical/launchpad/icing/build/launchpad-sam.css" />
+
+  <script type="text/javascript"
+    src="../../../app/javascript/overlay/overlay.js"></script>
 
   <!-- The module under test -->
   <script type="text/javascript" src="../branchmergeproposal.diff.js"></script>

=== modified file 'lib/lp/code/javascript/tests/test_productseries-setbranch.html'
--- lib/lp/code/javascript/tests/test_productseries-setbranch.html	2010-11-10 15:33:47 +0000
+++ lib/lp/code/javascript/tests/test_productseries-setbranch.html	2011-07-07 06:39:25 +0000
@@ -6,12 +6,11 @@
 
   <!-- YUI 3.0 Setup -->
   <script type="text/javascript" src="../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
-  <script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/lazr.js"></script>
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>
   <link rel="stylesheet" href="../../../../canonical/launchpad/javascript/test.css" />
-  <script type="text/javascript" src="../../../../canonical/launchpad/javascript/lp/lp.js"></script>
+  <script type="text/javascript" src="../../../app/javascript/lp.js"></script>
 
   <!-- The module under test -->
   <script type="text/javascript" src="../productseries-setbranch.js"></script>

=== modified file 'lib/lp/code/tests/test_yuitests.py'
--- lib/lp/code/tests/test_yuitests.py	2011-06-09 15:37:18 +0000
+++ lib/lp/code/tests/test_yuitests.py	2011-07-07 06:39:25 +0000
@@ -20,5 +20,5 @@
 
 
 def test_suite():
-    app_testing_path = 'lp/code/javascript/tests'
+    app_testing_path = 'lp/code/javascript'
     return build_yui_unittest_suite(app_testing_path, CodeYUIUnitTestCase)

=== modified file 'lib/lp/registry/javascript/tests/test_distroseries.html'
--- lib/lp/registry/javascript/tests/test_distroseries.html	2011-03-18 12:24:01 +0000
+++ lib/lp/registry/javascript/tests/test_distroseries.html	2011-07-07 06:39:25 +0000
@@ -7,8 +7,6 @@
     <!-- YUI 3.0 Setup -->
     <script type="text/javascript"
             src="../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
-    <script type="text/javascript"
-            src="../../../../canonical/launchpad/icing/lazr/build/lazr.js"></script>
     <link rel="stylesheet"
           href="../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
     <link rel="stylesheet"
@@ -19,6 +17,13 @@
           href="../../../../canonical/launchpad/javascript/test.css" />
     <!-- Required modules -->
     <script type="text/javascript" src="../../../app/javascript/client.js"></script>
+    <script type="text/javascript" src="../../../app/javascript/activator/activator.js"></script>
+    <script type="text/javascript" src="../../../app/javascript/anim/anim.js"></script>
+    <script type="text/javascript" src="../../../app/javascript/lazr/lazr.js"></script>
+    <script type="text/javascript" src="../../../app/javascript/overlay/overlay.js"></script>
+    <script type="text/javascript" src="../../../app/javascript/picker/picker.js"></script>
+    <script type="text/javascript" src="../../../app/javascript/picker/person_picker.js"></script>
+    <script type="text/javascript" src="../../../app/javascript/picker/picker_patcher.js"></script>
     <!-- The module under test -->
     <script type="text/javascript" src="../distroseries.js"></script>
     <!-- The test suite -->

=== modified file 'lib/lp/registry/javascript/tests/test_distroseriesdifferences_details.html'
--- lib/lp/registry/javascript/tests/test_distroseriesdifferences_details.html	2011-05-12 12:09:17 +0000
+++ lib/lp/registry/javascript/tests/test_distroseriesdifferences_details.html	2011-07-07 06:39:25 +0000
@@ -5,7 +5,6 @@
 
   <!-- Required js modules -->
   <script type="text/javascript" src="../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
-  <script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/lazr.js"></script>
   <script type="text/javascript" src="../../../app/javascript/client.js"></script>
   <script type="text/javascript" src="../../../soyuz/javascript/base.js"></script>
   <script type="text/javascript" src="../../../soyuz/javascript/lp_dynamic_dom_updater.js"></script>
@@ -14,7 +13,7 @@
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>
   <link rel="stylesheet" href="../../../../canonical/launchpad/javascript/test.css" />
-  <link rel="stylesheet" href="../../../../canonical/launchpad/icing/style-3-0.css.in" />
+  <link rel="stylesheet" href="../../../../canonical/launchpad/icing/style-3-0.css" />
 
   <!-- The module under test -->
   <script type="text/javascript" src="../distroseriesdifferences_details.js"></script>

=== modified file 'lib/lp/registry/javascript/tests/test_milestone_table.html'
--- lib/lp/registry/javascript/tests/test_milestone_table.html	2010-11-23 14:18:07 +0000
+++ lib/lp/registry/javascript/tests/test_milestone_table.html	2011-07-07 06:39:25 +0000
@@ -5,12 +5,14 @@
 
   <!-- YUI 3.0 Setup -->
   <script type="text/javascript" src="../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
-  <script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/lazr.js"></script>
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>
   <link rel="stylesheet" href="../../../../canonical/launchpad/javascript/test.css" />
 
+  <script type="text/javascript"
+    src="../../../app/javascript/anim/anim.js"></script>
+
   <!-- The module under test -->
   <script type="text/javascript" src="../milestonetable.js"></script>
 

=== modified file 'lib/lp/registry/javascript/tests/test_structural_subscription.html'
--- lib/lp/registry/javascript/tests/test_structural_subscription.html	2011-06-07 21:15:48 +0000
+++ lib/lp/registry/javascript/tests/test_structural_subscription.html	2011-07-07 06:39:25 +0000
@@ -8,26 +8,17 @@
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssfonts/fonts.css"/>
   <link rel="stylesheet" href="../../../../canonical/launchpad/icing/yui/cssbase/base.css"/>
-  <link rel="stylesheet"
-      href="../../../../canonical/launchpad/icing/lazr/build/testing/assets/testlogger.css"/>
   <link rel="stylesheet" href="../../../../canonical/launchpad/javascript/test.css" />
 
   <!-- Dependency -->
   <script type="text/javascript"
-    src="../../../../canonical/launchpad/icing/lazr/build/lazr.js"></script>
-  <script type="text/javascript"
-    src="../../../../canonical/launchpad/icing/lazr/build/testing/testing.js"></script>
-  <script type="text/javascript"
-    src="../../../../canonical/launchpad/icing/lazr/build/testing/mockio.js"></script>
-  <script type="text/javascript"
-    src="../../../../canonical/launchpad/icing/lazr/build/overlay/overlay.js">
-  </script>
-  <script type="text/javascript"
-    src="../../../../canonical/launchpad/icing/lazr/build/formoverlay/formoverlay.js">
-  </script>
-  <script type="text/javascript"
-    src="../../../../canonical/launchpad/icing/lazr/build/choiceedit/choiceedit.js">
-  </script>
+    src="../../../app/javascript/anim/anim.js"></script>
+  <script type="text/javascript"
+    src="../../../app/javascript/effects/effects.js"></script>
+  <script type="text/javascript"
+    src="../../../app/javascript/formoverlay/formoverlay.js"></script>
+  <script type="text/javascript"
+    src="../../../app/javascript/overlay/overlay.js"></script>
   <script type="text/javascript"
     src="../../../app/javascript/client.js"></script>
   <script type="text/javascript"

=== modified file 'lib/lp/registry/tests/test_yuitests.py'
--- lib/lp/registry/tests/test_yuitests.py	2011-06-09 15:37:18 +0000
+++ lib/lp/registry/tests/test_yuitests.py	2011-07-07 06:39:25 +0000
@@ -20,5 +20,5 @@
 
 
 def test_suite():
-    app_testing_path = 'lp/registry/javascript/tests'
+    app_testing_path = 'lp/registry/javascript'
     return build_yui_unittest_suite(app_testing_path, RegistryYUIUnitTestCase)

=== modified file 'lib/lp/registry/vocabularies.py'
--- lib/lp/registry/vocabularies.py	2011-06-29 15:02:28 +0000
+++ lib/lp/registry/vocabularies.py	2011-07-07 06:39:25 +0000
@@ -168,9 +168,6 @@
 from lp.registry.interfaces.projectgroup import IProjectGroup
 from lp.registry.interfaces.sourcepackage import ISourcePackage
 from lp.registry.model.distribution import Distribution
-from lp.registry.model.distributionsourcepackage import (
-    DistributionSourcePackage,
-    )
 from lp.registry.model.distroseries import DistroSeries
 from lp.registry.model.distroseriesparent import DistroSeriesParent
 from lp.registry.model.featuredproject import FeaturedProject
@@ -200,7 +197,6 @@
 from lp.soyuz.model.binarypackagerelease import BinaryPackageRelease
 from lp.soyuz.model.distroarchseries import DistroArchSeries
 from lp.soyuz.model.publishing import (
-    BinaryPackagePublishingHistory,
     SourcePackagePublishingHistory,
     )
 from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease
@@ -375,10 +371,6 @@
     _table = Person
     _orderBy = 'displayname'
 
-    def toTerm(self, obj):
-        """See `IVocabulary`."""
-        return SimpleTerm(obj, obj.name, obj.unique_displayname)
-
     def __iter__(self):
         kw = {}
         if self._orderBy:
@@ -1962,7 +1954,7 @@
         # package names are always lowercase.
         return super(SourcePackageNameVocabulary, self).getTermByToken(
             token.lower())
- 
+
 
 class DistributionSourcePackageVocabulary:
 

=== modified file 'lib/lp/scripts/utilities/js/jsbuild.py'
--- lib/lp/scripts/utilities/js/jsbuild.py	2011-06-30 11:10:08 +0000
+++ lib/lp/scripts/utilities/js/jsbuild.py	2011-07-07 06:39:25 +0000
@@ -1,8 +1,10 @@
 """build.py - Minifies and creates the JS build directory."""
 
 __metaclass__ = type
-__all__ = []
-
+__all__ = [
+    'CSSComboFile',
+    'JSComboFile',
+    ]
 
 import optparse
 import os
@@ -15,14 +17,13 @@
 
 HERE = os.path.dirname(__file__)
 BUILD_DIR = os.path.normpath(os.path.join(HERE, '..', '..', '..', 'build'))
-DEFAULT_SRC_DIR = os.path.normpath(os.path.join(HERE, '..', '..', '..', 'app', 'javascript', 'lazr'))
+DEFAULT_SRC_DIR = os.path.normpath(os.path.join(
+    HERE, '..', '..', '..', 'app', 'javascript'))
 
 ESCAPE_STAR_PROPERTY_RE = re.compile(r'\*([a-zA-Z0-9_-]+):')
 UNESCAPE_STAR_PROPERTY_RE = re.compile(r'([a-zA-Z0-9_-]+)_ie_star_hack:')
 URL_RE = re.compile("url\([ \"\']*([^ \"\']+)[ \"\']*\)")
 
-from jsmin import JavascriptMinify
-
 
 def relative_path(from_file, to_file):
     """Return the relative path between from_file and to_file."""
@@ -77,7 +78,8 @@
                 content = fh.read()
                 fh.close()
                 try:
-                    target_fh.write(self.filter_file_content(content, src_file))
+                    target_fh.write(
+                        self.filter_file_content(content, src_file))
                 except Exception:
                     os.remove(self.target_file)
                     raise
@@ -147,6 +149,7 @@
             src_dir = os.path.dirname(path)
             relative_parts = relative_path(self.target_file, src_dir).split(
                 os.path.sep)
+
             def fix_relative_url(match):
                 url = match.group(1)
                 # Don't modify absolute URLs or 'data:' urls.
@@ -185,8 +188,8 @@
 
 class Builder:
 
-    def __init__(self, name='lazr', build_dir=BUILD_DIR, src_dir=DEFAULT_SRC_DIR,
-                 extra_files=None, exclude_regex='', file_type='raw'):
+    def __init__(self, name='launchpad', build_dir=BUILD_DIR,
+                 src_dir=DEFAULT_SRC_DIR, extra_files=None):
         """Create a new Builder.
 
         :param name: The name of the package we are building. This will
@@ -195,13 +198,6 @@
         :param src_dir: The directory containing the source files.
         :param extra_files: List of files that should be bundled in the
             standalone file.
-        :param exclude_regex: A regex that will exclude file paths from the
-            final rollup.  -min and -debug versions will still be built.
-        :param file_type: A string specifying which type of files to include
-            in the final rollup.  Default is to use the raw, unmodified JS
-            file.  Possible values are 'raw', 'min', and 'debug'.  File types
-            are identified by their basename suffix: foo.js, foo-min.js,
-            foo-debug.js, etc.
         """
         self.name = name
         self.build_dir = build_dir
@@ -218,11 +214,6 @@
         else:
             self.extra_files = extra_files
 
-        self.exclusion_regex = exclude_regex
-        self.file_type = file_type
-
-        self.log("Using filter: " + self.file_type)
-
     def log(self, msg):
         sys.stdout.write(msg + '\n')
 
@@ -231,13 +222,6 @@
         sys.stderr.write(msg + '\n')
         sys.exit(1)
 
-    def file_is_excluded(self, filepath):
-        """Is the given file path excluded from the rollup process?"""
-        if not self.exclusion_regex:
-            # Include everything.
-            return False
-        return re.search(self.exclusion_regex, filepath)
-
     def ensure_build_directory(self, path):
         """Make sure that the named relative path is a directory."""
         target_dir = os.path.join(self.build_dir, path)
@@ -260,34 +244,6 @@
             self.log('Linking %s -> %s' % (src, dst))
             os.symlink(src, dst)
 
-    def link_and_minify(self, component, js_file):
-        """Create raw, debug and min version of js_file."""
-        component_dir = os.path.join(self.build_dir, component)
-        basename = os.path.splitext(os.path.basename(js_file))[0]
-
-        raw_file = os.path.join(component_dir, basename + '.js')
-        rel_js_file = relative_path(raw_file, js_file)
-        self.ensure_link(rel_js_file, raw_file)
-
-        debug_file = os.path.join(component_dir, basename + '-debug.js')
-        self.ensure_link(rel_js_file, debug_file)
-
-        min_file = os.path.join(component_dir, basename + '-min.js')
-        if (not os.path.exists(min_file)
-            or os.stat(min_file).st_mtime < os.stat(js_file).st_mtime):
-            self.log("Minifying %s into %s." % (js_file, min_file))
-            js_in = open(js_file, 'r')
-            min_out = open(min_file, 'w')
-            minifier = JavascriptMinify()
-            minifier.minify(js_in, min_out)
-            js_in.close()
-            min_out.close()
-
-        self.built_files.append(
-            {'raw': raw_file,
-             'debug': debug_file,
-             'min': min_file})
-
     def build_assets(self, component_name):
         """Build a component's "assets" directory."""
         join = os.path.join
@@ -369,25 +325,6 @@
                     target_skin_file))
                 combined_css.update()
 
-    def update_combined_js_file(self):
-        # Compile all the files in one JS file.  Apply the filter to see
-        # which file extensions we should include.
-        build_file = os.path.join(self.build_dir, "%s.js" % self.name)
-
-        included_files = []
-        extra_files = [f for f in self.extra_files if f.endswith('.js')]
-        built_files = [f[self.file_type] for f in self.built_files]
-
-        included_files.extend(extra_files)
-        included_files.extend(built_files)
-        files_to_combine = [f for f in included_files
-                            if not self.file_is_excluded(f)]
-
-        combined_js = JSComboFile(files_to_combine, build_file)
-        if combined_js.needs_update():
-            self.log('Updating %s...' % build_file)
-            combined_js.update()
-
     def update_combined_css_skins(self):
         """Create one combined CSS file per skin."""
         extra_css_files = [f for f in self.extra_files if f.endswith('.css')]
@@ -401,27 +338,12 @@
                 self.log('Updating %s...' % skin_build_file)
                 combined_css.update()
 
-    def find_components(self):
-        """Find all of the project sub-component names and directories."""
+    def do_build(self):
         for name in os.listdir(self.src_dir):
             path = os.path.join(self.src_dir, name)
             if not os.path.isdir(path):
                 continue
-            yield name, path
-
-    def do_build(self):
-        for name, cpath in self.find_components():
-            files_to_link = glob(os.path.join(cpath, '*.js'))
-            if len(files_to_link) == 0:
-                continue
-            self.ensure_build_directory(name)
-
-            for js_file in files_to_link:
-                self.link_and_minify(name, js_file)
-
             self.build_assets(name)
-
-        self.update_combined_js_file()
         self.update_combined_css_skins()
 
 
@@ -433,35 +355,24 @@
             "Create a build directory of CSS/JS files. "
             ))
     parser.add_option(
-        '-n', '--name', dest='name', default='lazr',
+        '-n', '--name', dest='name', default='launchpad',
         help=('The basename of the generated compilation file. Defaults to '
-            '"lazr".'))
+            '"launchpad".'))
     parser.add_option(
         '-b', '--builddir', dest='build_dir', default=BUILD_DIR,
         help=('The directory that should contain built files.'))
     parser.add_option(
         '-s', '--srcdir', dest='src_dir', default=DEFAULT_SRC_DIR,
         help=('The directory containing the src files.'))
-    parser.add_option(
-        '-x', '--exclude', dest='exclude', default='',
-        metavar='REGEX',
-        help=('Exclude any files that match the given regular expression.'))
-    parser.add_option(
-        '-f', '--filetype', dest='file_type', default='min',
-        help=('Only bundle files in the source directory that match the '
-              'specified file-type filter. Possible values are '
-              '[min, raw, debug]. [default: %default]'))
     return parser.parse_args()
 
 
 def main():
-    options, extra= get_options()
+    options, extra = get_options()
 
     Builder(
        name=options.name,
        build_dir=options.build_dir,
        src_dir=options.src_dir,
        extra_files=extra,
-       exclude_regex=options.exclude,
-       file_type=options.file_type,
        ).do_build()

=== added directory 'lib/lp/scripts/utilities/js/tests'
=== added file 'lib/lp/scripts/utilities/js/tests/__init__.py'
=== added file 'lib/lp/scripts/utilities/js/tests/test_combo.py'
--- lib/lp/scripts/utilities/js/tests/test_combo.py	1970-01-01 00:00:00 +0000
+++ lib/lp/scripts/utilities/js/tests/test_combo.py	2011-07-07 06:39:25 +0000
@@ -0,0 +1,561 @@
+import os
+import shutil
+import tempfile
+
+from paste.fixture import TestApp
+
+from lp.scripts.utilities.js.combo import parse_url, combine_files, combo_app
+from lp.testing import TestCase
+
+
+class ComboTestBase(TestCase):
+
+    def setUp(self):
+        self.__cleanup_paths = []
+        self.addCleanup(self.__cleanup)
+        super(ComboTestBase, self).setUp()
+
+    def __cleanup(self):
+        for path in self.__cleanup_paths:
+            if os.path.isfile(path):
+                os.unlink(path)
+            elif os.path.isdir(path):
+                shutil.rmtree(path)
+
+    def makeFile(self, content=None, suffix="", prefix="tmp", basename=None,
+                 dirname=None, path=None):
+        """Create a temporary file and return the path to it.
+
+        @param content: Initial content for the file.
+        @param suffix: Suffix to be given to the file's basename.
+        @param prefix: Prefix to be given to the file's basename.
+        @param basename: Full basename for the file.
+        @param dirname: Put file inside this directory.
+
+        The file is removed after the test runs.
+        """
+        if path is not None:
+            self.__cleanup_paths.append(path)
+        elif basename is not None:
+            if dirname is None:
+                dirname = tempfile.mkdtemp()
+                self.__cleanup_paths.append(dirname)
+            path = os.path.join(dirname, basename)
+        else:
+            fd, path = tempfile.mkstemp(suffix, prefix, dirname)
+            self.__cleanup_paths.append(path)
+            os.close(fd)
+            if content is None:
+                os.unlink(path)
+        if content is not None:
+            file = open(path, "w")
+            file.write(content)
+            file.close()
+        return path
+
+    def makeDir(self, suffix="", prefix="tmp", dirname=None, path=None):
+        """Create a temporary directory and return the path to it.
+
+        @param suffix: Suffix to be given to the file's basename.
+        @param prefix: Prefix to be given to the file's basename.
+        @param dirname: Put directory inside this parent directory.
+
+        The directory is removed after the test runs.
+        """
+        if path is not None:
+            os.makedirs(path)
+        else:
+            path = tempfile.mkdtemp(suffix, prefix, dirname)
+        self.__cleanup_paths.append(path)
+        return path
+
+    def makeSampleFile(self, root, fname, content):
+        full = os.path.join(root, fname)
+        parent = os.path.dirname(full)
+        if not os.path.exists(parent):
+            os.makedirs(parent)
+        return self.makeFile(content=content, path=full)
+
+
+class TestCombo(ComboTestBase):
+
+    def test_parse_url_keeps_order(self):
+        """Parsing a combo loader URL returns an ordered list of filenames."""
+        self.assertEquals(
+            parse_url(("http://yui.yahooapis.com/combo?";
+                       "3.0.0/build/yui/yui-min.js&"
+                       "3.0.0/build/oop/oop-min.js&"
+                       "3.0.0/build/event-custom/event-custom-min.js&")),
+            ("3.0.0/build/yui/yui-min.js",
+             "3.0.0/build/oop/oop-min.js",
+             "3.0.0/build/event-custom/event-custom-min.js"))
+
+    def test_combine_files_includes_filename(self):
+        """Combining files should include their relative filename at the top."""
+        test_dir = self.makeDir()
+
+        files = [
+            self.makeSampleFile(
+                test_dir,
+                os.path.join("yui", "yui-min.js"),
+                "** yui-min **"),
+            self.makeSampleFile(
+                test_dir,
+                os.path.join("oop", "oop-min.js"),
+                "** oop-min **"),
+            self.makeSampleFile(
+                test_dir,
+                os.path.join("event-custom", "event-custom-min.js"),
+                "** event-custom-min **"),
+            ]
+
+        expected = "\n".join(("// yui/yui-min.js",
+                              "** yui-min **",
+                              "// oop/oop-min.js",
+                              "** oop-min **",
+                              "// event-custom/event-custom-min.js",
+                              "** event-custom-min **"))
+        self.assertEquals(
+            "".join(combine_files(["yui/yui-min.js",
+                                   "oop/oop-min.js",
+                                   "event-custom/event-custom-min.js"],
+                                  root=test_dir)).strip(),
+            expected)
+
+    def test_combine_css_minifies_and_makes_relative(self):
+        """
+        Combining CSS files minifies and makes URLs in CSS
+        declarations relative to the target path.
+        """
+        test_dir = self.makeDir()
+
+        files = [
+            self.makeSampleFile(
+                test_dir,
+                os.path.join("widget", "assets", "skins", "sam", "widget.css"),
+                """\
+                /* widget skin */
+                .yui-widget {
+                   background: url("img/bg.png");
+                }
+                """),
+            self.makeSampleFile(
+                test_dir,
+                os.path.join("editor", "assets", "skins", "sam", "editor.css"),
+                """\
+                /* editor skin */
+                .yui-editor {
+                   background: url("img/bg.png");
+                }
+                """),
+            ]
+
+        expected = "\n".join(
+            ("/* widget/assets/skins/sam/widget.css */",
+             ".yui-widget{background:url(widget/assets/skins/sam/img/bg.png)}",
+             "/* editor/assets/skins/sam/editor.css */",
+             ".yui-editor{background:url(editor/assets/skins/sam/img/bg.png)}",
+             ))
+        self.assertEquals(
+            "".join(combine_files(["widget/assets/skins/sam/widget.css",
+                                   "editor/assets/skins/sam/editor.css"],
+                                  root=test_dir)).strip(),
+            expected)
+
+    def test_combine_css_leaves_absolute_urls_untouched(self):
+        """
+        Combining CSS files does not touch absolute URLs in
+        declarations.
+        """
+        test_dir = self.makeDir()
+
+        files = [
+            self.makeSampleFile(
+                test_dir,
+                os.path.join("widget", "assets", "skins", "sam", "widget.css"),
+                """\
+                /* widget skin */
+                .yui-widget {
+                   background: url("/static/img/bg.png");
+                }
+                """),
+            self.makeSampleFile(
+                test_dir,
+                os.path.join("editor", "assets", "skins", "sam", "editor.css"),
+                """\
+                /* editor skin */
+                .yui-editor {
+                   background: url("http://foo/static/img/bg.png";);
+                }
+                """),
+            ]
+
+        expected = "\n".join(
+            ("/* widget/assets/skins/sam/widget.css */",
+             ".yui-widget{background:url(/static/img/bg.png)}",
+             "/* editor/assets/skins/sam/editor.css */",
+             ".yui-editor{background:url(http://foo/static/img/bg.png)}",
+             ))
+        self.assertEquals(
+            "".join(combine_files(["widget/assets/skins/sam/widget.css",
+                                   "editor/assets/skins/sam/editor.css"],
+                                  root=test_dir)).strip(),
+            expected)
+
+    def test_combine_css_leaves_data_uris_untouched(self):
+        """
+        Combining CSS files does not touch data uris in
+        declarations.
+        """
+        test_dir = self.makeDir()
+
+        files = [
+            self.makeSampleFile(
+                test_dir,
+                os.path.join("widget", "assets", "skins", "sam", "widget.css"),
+                """\
+                /* widget skin */
+                .yui-widget {
+                background: url("data:image/gif;base64,base64-data");
+                }
+                """),
+            self.makeSampleFile(
+                test_dir,
+                os.path.join("editor", "assets", "skins", "sam", "editor.css"),
+                """\
+                /* editor skin */
+                .yui-editor {
+                   background: url(data:image/gif;base64,base64-data);
+                }
+                """),
+            ]
+
+        expected = "\n".join(
+            ('/* widget/assets/skins/sam/widget.css */',
+             '.yui-widget{background:url("data:image/gif;base64,base64-data")}',
+             '/* editor/assets/skins/sam/editor.css */',
+             '.yui-editor{background:url("data:image/gif;base64,base64-data")}',
+             ))
+        self.assertEquals(
+            "".join(combine_files(["widget/assets/skins/sam/widget.css",
+                                   "editor/assets/skins/sam/editor.css"],
+                                  root=test_dir)).strip(),
+            expected)
+
+    def test_combine_css_disable_minify(self):
+        """
+        It is possible to disable CSS minification altogether, while
+        keeping the URL rewriting behavior.
+        """
+        test_dir = self.makeDir()
+
+        files = [
+            self.makeSampleFile(
+                test_dir,
+                os.path.join("widget", "assets", "skins", "sam", "widget.css"),
+                "\n".join(
+                    ('/* widget skin */',
+                     '.yui-widget {',
+                     '   background: url("img/bg.png");',
+                     '}'))
+                ),
+            self.makeSampleFile(
+                test_dir,
+                os.path.join("editor", "assets", "skins", "sam", "editor.css"),
+                "\n".join(('/* editor skin */',
+                           '.yui-editor {',
+                           '   background: url("img/bg.png");',
+                           '}'))
+                ),
+            ]
+
+        expected = "\n".join(
+            ("/* widget/assets/skins/sam/widget.css */",
+             "/* widget skin */",
+             ".yui-widget {",
+             "   background: url(widget/assets/skins/sam/img/bg.png);",
+             "}",
+             "/* editor/assets/skins/sam/editor.css */",
+             "/* editor skin */",
+             ".yui-editor {",
+             "   background: url(editor/assets/skins/sam/img/bg.png);",
+             "}",
+             ))
+        self.assertEquals(
+            "".join(combine_files(["widget/assets/skins/sam/widget.css",
+                                   "editor/assets/skins/sam/editor.css"],
+                                  root=test_dir, minify_css=False)).strip(),
+            expected)
+
+    def test_combine_css_disable_rewrite_url(self):
+        """
+        It is possible to disable the rewriting of urls in the CSS
+        file.
+        """
+        test_dir = self.makeDir()
+
+        files = [
+            self.makeSampleFile(
+                test_dir,
+                os.path.join("widget", "assets", "skins", "sam", "widget.css"),
+                """\
+                /* widget skin */
+                .yui-widget {
+                   background: url("img/bg.png");
+                }
+                """),
+            self.makeSampleFile(
+                test_dir,
+                os.path.join("editor", "assets", "skins", "sam", "editor.css"),
+                """\
+                /* editor skin */
+                .yui-editor {
+                   background: url("img/bg.png");
+                }
+                """),
+            ]
+
+        expected = "\n".join(
+            ("/* widget/assets/skins/sam/widget.css */",
+             ".yui-widget{background:url(img/bg.png)}",
+             "/* editor/assets/skins/sam/editor.css */",
+             ".yui-editor{background:url(img/bg.png)}",
+             ))
+        self.assertEquals(
+            "".join(combine_files(["widget/assets/skins/sam/widget.css",
+                                   "editor/assets/skins/sam/editor.css"],
+                                  root=test_dir, rewrite_urls=False)).strip(),
+            expected)
+
+    def test_combine_css_disable_rewrite_url_and_minify(self):
+        """
+        It is possible to disable both the rewriting of urls in the
+        CSS file and minification, in which case the files are
+        returned unchanged.
+        """
+        test_dir = self.makeDir()
+
+        files = [
+            self.makeSampleFile(
+                test_dir,
+                os.path.join("widget", "assets", "skins", "sam", "widget.css"),
+                "\n".join(
+                    ('/* widget skin */',
+                     '.yui-widget {',
+                     '   background: url("img/bg.png");',
+                     '}'))
+                ),
+            self.makeSampleFile(
+                test_dir,
+                os.path.join("editor", "assets", "skins", "sam", "editor.css"),
+                "\n".join(('/* editor skin */',
+                           '.yui-editor {',
+                           '   background: url("img/bg.png");',
+                           '}'))
+                ),
+            ]
+
+        expected = "\n".join(
+            ('/* widget/assets/skins/sam/widget.css */',
+             '/* widget skin */',
+             '.yui-widget {',
+             '   background: url("img/bg.png");',
+             '}',
+             '/* editor/assets/skins/sam/editor.css */',
+             '/* editor skin */',
+             '.yui-editor {',
+             '   background: url("img/bg.png");',
+             '}',
+             ))
+        self.assertEquals(
+            "".join(combine_files(["widget/assets/skins/sam/widget.css",
+                                   "editor/assets/skins/sam/editor.css"],
+                                  root=test_dir,
+                                  minify_css=False,
+                                  rewrite_urls=False)).strip(),
+            expected)
+
+    def test_combine_css_adds_custom_prefix(self):
+        """
+        Combining CSS files minifies and makes URLs in CSS
+        declarations relative to the target path. It's also possible
+        to specify an additional prefix for the rewritten URLs.
+        """
+        test_dir = self.makeDir()
+
+        files = [
+            self.makeSampleFile(
+                test_dir,
+                os.path.join("widget", "assets", "skins", "sam", "widget.css"),
+                """\
+                /* widget skin */
+                .yui-widget {
+                   background: url("img/bg.png");
+                }
+                """),
+            self.makeSampleFile(
+                test_dir,
+                os.path.join("editor", "assets", "skins", "sam", "editor.css"),
+                """\
+                /* editor skin */
+                .yui-editor {
+                   background: url("img/bg.png");
+                }
+                """),
+            ]
+
+        expected = "\n".join(
+            ("/* widget/assets/skins/sam/widget.css */",
+             ".yui-widget{background:url(" +
+             "/static/widget/assets/skins/sam/img/bg.png)}",
+             "/* editor/assets/skins/sam/editor.css */",
+             ".yui-editor{background:url(" +
+             "/static/editor/assets/skins/sam/img/bg.png)}",
+             ))
+        self.assertEquals(
+            "".join(combine_files(["widget/assets/skins/sam/widget.css",
+                                   "editor/assets/skins/sam/editor.css"],
+                                  root=test_dir,
+                                  resource_prefix="/static/")).strip(),
+            expected)
+
+    def test_missing_file_is_ignored(self):
+        """If a missing file is requested we should still combine the others."""
+        test_dir = self.makeDir()
+
+        files = [
+            self.makeSampleFile(
+                test_dir,
+                os.path.join("yui", "yui-min.js"),
+                "** yui-min **"),
+            self.makeSampleFile(
+                test_dir,
+                os.path.join("event-custom", "event-custom-min.js"),
+                "** event-custom-min **"),
+            ]
+
+        expected = "\n".join(("// yui/yui-min.js",
+                              "** yui-min **",
+                              "// oop/oop-min.js",
+                              "// [missing]",
+                              "// event-custom/event-custom-min.js",
+                              "** event-custom-min **"))
+        self.assertEquals(
+            "".join(combine_files(["yui/yui-min.js",
+                                   "oop/oop-min.js",
+                                   "event-custom/event-custom-min.js"],
+                                  root=test_dir)).strip(),
+            expected)
+
+    def test_no_parent_hack(self):
+        """If someone tries to hack going up the root, he'll get a miss."""
+        test_dir = self.makeDir()
+        files = [
+            self.makeSampleFile(
+                test_dir,
+                os.path.join("oop", "oop-min.js"),
+                "** oop-min **"),
+            ]
+
+        root = os.path.join(test_dir, "root", "lazr")
+        os.makedirs(root)
+
+        hack = "../../oop/oop-min.js"
+        self.assertTrue(os.path.exists(os.path.join(root, hack)))
+
+        expected = "\n".join(("// ../../oop/oop-min.js",
+                              "// [missing]"))
+        self.assertEquals(
+            "".join(combine_files([hack], root=root)).strip(),
+            expected)
+
+    def test_rewrite_url_normalizes_parent_references(self):
+        """URL references in CSS files get normalized for parent dirs."""
+        test_dir = self.makeDir()
+        files = [
+            self.makeSampleFile(
+                test_dir,
+                os.path.join("yui", "base", "base.css"),
+                ".foo{background-image:url(../../img.png)}"),
+            ]
+
+        expected = "\n".join(("/* yui/base/base.css */",
+                              ".foo{background-image:url(img.png)}"))
+        self.assertEquals(
+            "".join(combine_files(files, root=test_dir)).strip(),
+            expected)
+
+
+    def test_no_absolute_path_hack(self):
+        """If someone tries to fetch an absolute file, he'll get nothing."""
+        test_dir = self.makeDir()
+
+        hack = "/etc/passwd"
+        self.assertTrue(os.path.exists("/etc/passwd"))
+
+        expected = ""
+        self.assertEquals(
+            "".join(combine_files([hack], root=test_dir)).strip(),
+            expected)
+
+
+class TestWSGICombo(ComboTestBase):
+
+    def setUp(self):
+        super(TestWSGICombo, self).setUp()
+        self.root = self.makeDir()
+        self.app = TestApp(combo_app(self.root))
+
+    def test_combo_app_sets_content_type_for_js(self):
+        """The WSGI App should set a proper Content-Type for Javascript."""
+        files = [
+            self.makeSampleFile(
+                self.root,
+                os.path.join("yui", "yui-min.js"),
+                "** yui-min **"),
+            self.makeSampleFile(
+                self.root,
+                os.path.join("oop", "oop-min.js"),
+                "** oop-min **"),
+            self.makeSampleFile(
+                self.root,
+                os.path.join("event-custom", "event-custom-min.js"),
+                "** event-custom-min **"),
+            ]
+
+        expected = "\n".join(("// yui/yui-min.js",
+                              "** yui-min **",
+                              "// oop/oop-min.js",
+                              "** oop-min **",
+                              "// event-custom/event-custom-min.js",
+                              "** event-custom-min **"))
+
+        res = self.app.get("/?" + "&".join(
+            ["yui/yui-min.js",
+             "oop/oop-min.js",
+             "event-custom/event-custom-min.js"]), status=200)
+        self.assertEquals(res.headers, [("Content-Type", "text/javascript")])
+        self.assertEquals(res.body.strip(), expected)
+
+    def test_combo_app_sets_content_type_for_css(self):
+        """The WSGI App should set a proper Content-Type for CSS."""
+        files = [
+            self.makeSampleFile(
+                self.root,
+                os.path.join("widget", "skin", "sam", "widget.css"),
+                "/* widget-skin-sam */"),
+            ]
+
+        expected = "/* widget/skin/sam/widget.css */"
+
+        res = self.app.get("/?" + "&".join(
+            ["widget/skin/sam/widget.css"]), status=200)
+        self.assertEquals(res.headers, [("Content-Type", "text/css")])
+        self.assertEquals(res.body.strip(), expected)
+
+    def test_no_filename_gives_404(self):
+        """If no filename is included, a 404 should be returned."""
+        res = self.app.get("/", status=404)
+        self.assertEquals(res.headers, [("Content-Type", "text/plain")])
+        self.assertEquals(res.body, "Not Found")
+

=== modified file 'lib/lp/soyuz/tests/test_yuitests.py'
--- lib/lp/soyuz/tests/test_yuitests.py	2011-06-09 15:37:18 +0000
+++ lib/lp/soyuz/tests/test_yuitests.py	2011-07-07 06:39:25 +0000
@@ -20,5 +20,5 @@
 
 
 def test_suite():
-    app_testing_path = 'lp/soyuz/javascript/tests'
+    app_testing_path = 'lp/soyuz/javascript'
     return build_yui_unittest_suite(app_testing_path, SoyuzYUIUnitTestCase)

=== modified file 'lib/lp/testing/__init__.py'
--- lib/lp/testing/__init__.py	2011-06-27 23:06:19 +0000
+++ lib/lp/testing/__init__.py	2011-07-07 06:39:25 +0000
@@ -920,16 +920,25 @@
 def build_yui_unittest_suite(app_testing_path, yui_test_class):
     suite = unittest.TestSuite()
     testing_path = os.path.join(config.root, 'lib', app_testing_path)
-    unit_test_names = [
-        file_name for file_name in os.listdir(testing_path)
-        if file_name.startswith('test_') and file_name.endswith('.html')]
-    for unit_test_name in unit_test_names:
-        test_path = os.path.join(app_testing_path, unit_test_name)
+    unit_test_names = _harvest_yui_test_files(testing_path)
+    for unit_test_path in unit_test_names:
         test_case = yui_test_class()
-        test_case.initialize(test_path)
+        test_case.initialize(unit_test_path)
         suite.addTest(test_case)
     return suite
 
+def _harvest_yui_test_files(file_path):
+    file_names = []
+    dirs = []
+    for file_name in os.listdir(file_path):
+        full_name = os.path.join(file_path, file_name)
+        if file_name.startswith('test_') and file_name.endswith('.html'):
+            file_names.append(full_name)
+        elif os.path.isdir(full_name):
+            dirs.append(full_name)
+    for dir_name in dirs:
+        file_names.extend(_harvest_yui_test_files(dir_name))
+    return file_names
 
 class ZopeTestInSubProcess:
     """Run tests in a sub-process, respecting Zope idiosyncrasies.

=== modified file 'lib/lp/translations/javascript/tests/test_sourcepackage_sharing_details.html'
--- lib/lp/translations/javascript/tests/test_sourcepackage_sharing_details.html	2011-04-14 19:33:40 +0000
+++ lib/lp/translations/javascript/tests/test_sourcepackage_sharing_details.html	2011-07-07 06:39:25 +0000
@@ -3,8 +3,6 @@
     <title>Launchpad translationsharingconfig</title>
     <!-- YUI 3.0 Setup -->
     <script type="text/javascript" src="../../../../canonical/launchpad/icing/yui/yui/yui.js"></script>
-    <script type="text/javascript"
-      src="../../../../canonical/launchpad/icing/lazr/build/lazr.js"></script>
     <link rel="stylesheet"
       href="../../../../canonical/launchpad/icing/yui/cssreset/reset.css"/>
     <link rel="stylesheet"

=== modified file 'lib/lp/translations/tests/test_yuitests.py'
--- lib/lp/translations/tests/test_yuitests.py	2011-06-09 15:37:18 +0000
+++ lib/lp/translations/tests/test_yuitests.py	2011-07-07 06:39:25 +0000
@@ -20,7 +20,7 @@
 
 
 def test_suite():
-    app_testing_path = 'lp/translations/javascript/tests'
+    app_testing_path = 'lp/translations/javascript'
     return build_yui_unittest_suite(
             app_testing_path,
             TranslationsYUIUnitTestCase)