← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~wgrant/launchpad/no-icing-contrib into lp:launchpad

 

William Grant has proposed merging lp:~wgrant/launchpad/no-icing-contrib into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~wgrant/launchpad/no-icing-contrib/+merge/85061

/+icing-contrib contains json2 and JSONScriptRequest, both of which were only used for the long-removed Google Maps widgets. It's so ancient that there's even a needs_json request attribute to turn on JS inclusion in the template.

This branch removes +icing-contrib and related cruft.
-- 
https://code.launchpad.net/~wgrant/launchpad/no-icing-contrib/+merge/85061
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/no-icing-contrib into lp:launchpad.
=== removed directory 'lib/canonical/launchpad/icing-contrib'
=== removed file 'lib/canonical/launchpad/icing-contrib/JSONScriptRequest.js'
--- lib/canonical/launchpad/icing-contrib/JSONScriptRequest.js	2008-06-18 18:20:11 +0000
+++ lib/canonical/launchpad/icing-contrib/JSONScriptRequest.js	1970-01-01 00:00:00 +0000
@@ -1,707 +0,0 @@
-/* This comes from http://openjsan.org/doc/y/yo/yoshida/JSONScriptRequest/
-
-{
-    "resources": {
-        "license": "http://opensource.org/licenses/mit-license.php";
-    },
-    "generated_by": "Module::Build version 0.2806",
-    "meta-spec": {
-        "version": 1.2,
-        "url": "http://module-build.sourceforge.net/META-spec-v1.2.html";
-    },
-    "version": 0.03,
-    "name": "JSONScriptRequest",
-    "author": [
-        "Hironori Yoshida <yoshida@xxxxxxxx>"
-    ],
-    "license": "mit",
-    "build_requires": {
-        "Test.Simple": 0.2
-    },
-    "keywords": [
-        "json",
-        "script",
-        "request",
-        "ajax",
-        "XMLHttpRequest"
-    ],
-    "provides": {
-        "JSONScriptRequest": {
-            "version": 0.03,
-            "file": "lib/JSONScriptRequest.js"
-        }
-    },
-    "abstract": "Call the JSONP API like XMLHttpRequest"
-}
- */
-
-// This specification does not include the following features that may or may not be implemented by user agents:
-//
-//     * load event and onload attribute;
-//     * error event and onerror attribute;
-//     * progress event and onprogress attribute;
-//     * abort event and onabort attribute;
-//     * Timers have been suggested, perhaps an ontimeout attribute;
-//     * Property to disable following redirects;
-//     * responseXML for text/html documents;
-//     * Cross-site XMLHttpRequest.
-//
-// HTTP requests sent from multiple different XMLHttpRequest objects in succession should be pipelined into shared HTTP connections.
-//
-// readystatechange
-// The readystatechange event must be dispatched when readyState changes value.
-// It must not bubble, must not be cancelable and must implement the Event interface [DOM3Events].
-// The event has no namespace (Event.namespaceURI is null).
-
-function JSONScriptRequest(args) {
-    this._initialize_all();
-
-    if (typeof args != 'undefined') {
-        if (typeof args['callback_param'] != 'undefined') {
-            this._callback_param = args['callback_param'];
-        }
-    }
-};
-
-JSONScriptRequest.VERSION = 0.03;
-
-JSONScriptRequest._extends = function(base, thisConstructor, thisPrototype) {
-    if (typeof thisPrototype == 'undefined' || thisPrototype == null) {
-        thisPrototype = {};
-    }
-
-    // modify base class
-    if (base.prototype.constructor == Object.prototype.constructor) {
-        base.prototype.constructor = base;
-    }
-
-    // create prototype
-    var Prototype = function() {};
-    Prototype.prototype = base.prototype;
-
-    // create class
-    thisConstructor.prototype = new Prototype();
-
-    for (var property in thisPrototype) {
-        thisConstructor.prototype[property] = thisPrototype[property];
-    }
-    var dontEnums = ['constructor',
-                     'hasOwnProperty',
-                     'isPrototypeOf',
-                     'toLocaleString',
-                     'toString',
-                     'valueOf'];
-    for (var i = 0; i < dontEnums.length; i++) {
-        var property = dontEnums[i];
-        if (thisPrototype.hasOwnProperty(property)) {
-            thisConstructor.prototype[property] = thisPrototype[property];
-        }
-    }
-    thisConstructor.prototype.constructor = thisConstructor;
-    thisConstructor.prototype.base = base;
-
-    return thisConstructor;
-};
-
-JSONScriptRequest._Exception = JSONScriptRequest._extends
-(Object,
- function(name, message) {
-     this.name = name;
-     this.message = message;
- },
- {
-     toString: function() {
-         return this.name + ': ' + this.message + ' [JSONScriptRequest]';
-     }
- });
-
-JSONScriptRequest.SYNTAX_ERR = JSONScriptRequest._extends
-(JSONScriptRequest._Exception,
- function(message) {
-     this.base('SYNTAX_ERR', message);
- });
-
-JSONScriptRequest.SECURITY_ERR = JSONScriptRequest._extends
-(JSONScriptRequest._Exception,
- function(message) {
-     this.base('SECURITY_ERR', message);
- });
-
-JSONScriptRequest.INVALID_STATE_ERR = JSONScriptRequest._extends
-(JSONScriptRequest._Exception,
- function(message) {
-     this.base('INVALID_STATE_ERR', message);
- });
-
-
-JSONScriptRequest._RE = {
-        'method': /^(?:OPTIONS|GET|HEAD|POST|PUT|DELETE|TRACE|CONNECT|[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7A\x7C\x7E]+)$/,
-        'field-name': /^[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7A\x7C\x7E]+$/,
-        'http_URL-custom': /^.+$/,
-        'userinfo': /^([A-Za-z0-9\-\._~]|%[0-9A-F][0-9A-F]|[!$&\x27\(\)\*\+,;=]|:)*$/,
-        'username-value': /^\x22(?:[\x20\x21\x23-\x7E\x80-\xFF]|(?:\x0D\x0A)?[\x20\x09]+|\\[\x00-\x7F])*\x22$/,
-        'username-value-custom': /^(?:[\x20\x21\x23-\x7E\x80-\xFF]|(?:\x0D\x0A)?[\x20\x09]+|\\[\x00-\x7F])*$/,
-        'field-value': /^(?:(?:(?:[\x20\x21\x23-\x7E\x80-\xFF]|(?:\x0D\x0A)?[\x20\x09]+)*|(?:[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7A\x7C\x7E]+|[\x22\x28\x29\x2C\x2F\x3A-\x40\x5B-\x5D\x7B\x7D]| (?:\x22(?:[\x20\x21\x23-\x7E\x80-\xFF]|(?:\x0D\x0A)?[\x20\x09]+|\\[\x00-\x7F])*\x22))*)|(?:\x0D\x0A)?[\x20\x09]+)*$/
-};
-
-JSONScriptRequest._toSourceHelper = function(target) {
-    if (typeof target == 'undefined') {
-        return 'undefined';
-    } else if (target == null) {
-        return 'null';
-    } else if (target.constructor == String) {
-        return '"' + target + '"';
-    } else if (target.constructor == Number) {
-        return target;
-    } else if (target.constructor == Array) {
-        var r = [];
-        for(var i = 0, n = target.length; i < n; i++) {
-            r.push(JSONScriptRequest._toSourceHelper(target[i]));
-        }
-        return '[' + r.join(', ') + ']';
-    } else if (target.constructor == Object) {
-        var r = [];
-        for(var i in target) {
-            r.push(i + ':' + JSONScriptRequest._toSourceHelper(target[i]));
-        }
-        return '{' + r.join(', ') + '}';
-    }
-};
-
-JSONScriptRequest._toSource = function(target) {
-    if (target && target.constructor == Object) {
-        return '(' + JSONScriptRequest._toSourceHelper(target) + ')';
-    } else {
-        return JSONScriptRequest._toSourceHelper(target);
-    }
-};
-
-JSONScriptRequest._dispatchers = [];
-
-JSONScriptRequest.prototype = {
-
-    // TODO: Objects implementing the XMLHttpRequest interface must also implement the EventTarget interface [DOM3Events].
-    //       http://www.w3.org/TR/DOM-Level-3-Events/events.html#Events-EventTarget
-    addEventListener: function() {
-        throw new JSONScriptRequest.SYNTAX_ERR('addEventListener is not implemented');
-        return;
-    },
-
-    removeEventListener: function() {
-        throw new JSONScriptRequest.SYNTAX_ERR('removeEventListener is not implemented');
-        return;
-    },
-
-    dispatchEvent: function() {
-        throw new JSONScriptRequest.SYNTAX_ERR('dispatchEvent is not implemented');
-        return false;
-    },
-
-    addEventListenerNS: function() {
-        throw new JSONScriptRequest.SYNTAX_ERR('addEventListenerNS is not implemented');
-        return;
-    },
-
-    removeEventListenerNS: function() {
-        throw new JSONScriptRequest.SYNTAX_ERR('removeEventListenerNS is not implemented');
-        return;
-    },
-
-    open: function(method, url, async, user, password) {
-        // If open() is invoked when readyState is 4 (Loaded) all members of the object must be set to their initial values.
-        if (this.readyState == 4) {
-            this._initialize_all();
-        }
-
-        // If the method argument doesn't match the method production defined in section 5.1.1 of [RFC2616] a SYNTAX_ERR  must be raised by the user agent.
-        if (   typeof method == 'undefined'
-            || method == null
-            || !method.match(JSONScriptRequest._RE['method'])
-            )
-        {
-            throw new JSONScriptRequest.SYNTAX_ERR('method: ' + method);
-        }
-
-        var METHOD = method.toUpperCase();
-        // TODO: If the user agent doesn't support the given method for security reasons a SECURITY_ERR should be raised.
-        ;
-
-        // User agents must at least support the following list of methods (see [RFC2616], [RFC2518], [RFC3253], [RFC3648] and [RFC3744])
-        if (METHOD != 'GET' && (   METHOD == 'POST'
-                                || METHOD == 'HEAD'
-                                || METHOD == 'PUT'
-                                || METHOD == 'DELETE'
-                                || METHOD == 'PROPFIND'
-                                || METHOD == 'PROPPATCH'
-                                || METHOD == 'MKCOL'
-                                || METHOD == 'COPY'
-                                || METHOD == 'MOVE'
-                                || METHOD == 'LOCK'
-                                || METHOD == 'UNLOCK'
-                                || METHOD == 'VERSION-CONTROL'
-                                || METHOD == 'REPORT'
-                                || METHOD == 'CHECKOUT'
-                                || METHOD == 'CHECKIN'
-                                || METHOD == 'UNCHECKOUT'
-                                || METHOD == 'MKWORKSPACE'
-                                || METHOD == 'UPDATE'
-                                || METHOD == 'LABEL'
-                                || METHOD == 'MERGE'
-                                || METHOD == 'BASELINE-CONTROL'
-                                || METHOD == 'MKACTIVITY'
-                                || METHOD == 'ORDERPATCH'
-                                || METHOD == 'ACL'
-                                )
-            )
-        {
-            throw new JSONScriptRequest.SYNTAX_ERR(method + ' is not supported');
-        }
-
-        // User agents should support any method argument that matches the method production.
-        if (METHOD != 'GET'/* JSONScriptRequest can only GET request*/) {
-            throw new JSONScriptRequest.SYNTAX_ERR(method + ' is not supported');
-        }
-
-        // When method case-insensitively matches GET, POST, HEAD, PUT or DELETE the user agent must use the uppercase equivalent instead.
-        if (   METHOD == 'GET'
-            || METHOD == 'POST'
-            || METHOD == 'HEAD'
-            || METHOD == 'PUT'
-            || METHOD == 'DELETE'
-            )
-        {
-            method = METHOD;
-        }
-
-        // TODO: If the url parameter doesn't match the syntax defined in section 3.2.2 of [RFC2616] a SYNTAX_ERR must be raised.
-        if (   typeof url == 'undefined'
-            || url == null
-            || !url.match(JSONScriptRequest._RE['http_URL-custom'])
-            )
-        {
-            throw new JSONScriptRequest.SYNTAX_ERR('url: ' + url);
-        }
-
-        // When a non same-origin url argument is given user agents should throw a SECURITY_ERR exception.
-        // Note: A future version or extension of this specification will define a way of doing cross-site requests.
-        if (0 /* JSONScriptRequest can deal with cross-site request */) {
-            throw new JSONScriptRequest.SECURITY_ERR('url: ' + url + ' is cross-site');
-        }
-
-        // TODO: User agents should not support the "user:password" format in the userinfo production defined in section 3.2.1 of [RFC3986] and must throw a SYNTAX_ERR when doing so (not supporting it).
-        if (url.match(new RegExp('^[^:]+://([^@]*)@[^/]+'))) {
-            throw new JSONScriptRequest.SYNTAX_ERR(RegExp.$1 + ' is not supported');
-            var userinfo = RegExp.$1;
-            if (!userinfo.match(JSONScriptRequest._RE['userinfo'])) {
-                throw new JSONScriptRequest.SYNTAX_ERR('userinfo: ' + userinfo);
-            }
-            userinfo = (userinfo.indexOf(':') != -1) ? userinfo.split(/:/) : [userinfo];
-            if (2 < userinfo.length) {
-                throw new JSONScriptRequest.SYNTAX_ERR('userinfo: ' + userinfo);
-            }
-            // When they do support it, or in case of people using the format "user", user agents must use them if the user and password arguments are omitted. If the arguments are not omitted, they take precedence, even if they are null.
-            if (typeof user == 'undefined') {
-                user = userinfo[0];
-            }
-            if (typeof password == 'undefined') {
-                password = userinfo[1];
-            }
-        }
-
-        // If the user argument doesn't match the username-value production defined in section 3.2.2 of [RFC2617] user agents must throw a SYNTAX_ERR exception.
-        if (   user != null
-            && typeof user != 'undefined'
-            && !user.match(JSONScriptRequest._RE['username-value-custom'])
-            )
-        {
-            throw new JSONScriptRequest.SYNTAX_ERR('user: ' + user);
-        }
-
-        // must initialize the object by remembering
-        this._method   = method;
-        this._url      = url;
-        this._async    = typeof async    == 'undefined' ? true : async;    // defaulting to true if omitted
-        this._user     = typeof user     == 'undefined' ? null : user;     // defaulting to null if omitted
-        this._password = typeof password == 'undefined' ? null : password; // defaulting to null if omitted
-
-        // resetting the responseText, responseXML, status, and statusText attributes to their initial values
-        this.responseText = null;
-        this.responseXML = null;
-        this.status = 0;
-        this.statusText = '';
-
-        // resetting the list of request headers
-        this._requestHeaders = {};
-
-        // setting the readyState attribute to 1 (Open)
-        this._readystatechange(1);
-
-        return;
-    },
-
-    setRequestHeader: function(header, value) {
-        // If the readyState  attribute has a value other than 1 (Open), an INVALID_STATE_ERR exception must be raised;
-        if (this.readyState != 1) {
-            throw new JSONScriptRequest.INVALID_STATE_ERR('readyState: ' + this.readyState + ' is other than 1');
-        }
-        // If the header argument doesn't match the field-name production as defined by section 4.2 of [RFC2616] a SYNTAX_ERR must be raised;
-        if (   typeof header == 'undefined'
-            || header == null
-            || !header.match(JSONScriptRequest._RE['field-name'])
-            )
-        {
-            throw new JSONScriptRequest.SYNTAX_ERR('header: ' + header);
-        }
-        // If the value argument doesn't match the field-value production as defined by section 4.2 of [RFC2616] a SYNTAX_ERR must be raised;
-        if (!value.match(JSONScriptRequest._RE['field-value'])) {
-            throw new JSONScriptRequest.SYNTAX_ERR('value: ' + value);
-        }
-
-        // For security reasons nothing should be done if the header argument matches Accept-Charset, Accept-Encoding, Content-Length, Expect, Date, Host, Keep-Alive, Referer, TE, Trailer, Transfer-Encoding or Upgrade case-insensitively.
-        if (header.match(new RegExp('Accept-Charset|Accept-Encoding|Content-Length|Expect|Date|Host|Keep-Alive|Referer|TE|Trailer|Transfer-Encoding|Upgrade', 'i'))) {
-            return;
-        }
-
-        // Implementations must replace any existing value if the nominated request header field value is one of: Authorization, Content-Base, Content-Location, Content-MD5, Content-Range, Content-Type, Content-Version, Delta-Base, Depth, Destination, ETag, Expect, From, If-Modified-Since, If-Range, If-Unmodified-Since, Max-Forwards, MIME-Version, Overwrite, Proxy-Authorization, SOAPAction or Timeout.
-        if (header.match(new RegExp('Authorization|Content-Base|Content-Location|Content-MD5|Content-Range|Content-Type|Content-Version|Delta-Base|Depth|Destination|ETag|Expect|From|If-Modified-Since|If-Range|If-Unmodified-Since|Max-Forwards|MIME-Version|Overwrite|Proxy-Authorization|SOAPAction|Timeout', 'i')))
-        {
-            this._requestHeaders[header] = value;
-        }
-        else {
-            // Otherwise, if the nominated request header field already has a value, the new value must be combined with the existing value (section 4.2, [RFC2616]).
-            if (header in this._requestHeaders) {
-                if (typeof this._requestHeaders[header] == 'string') {
-                    var existing = this._requestHeaders[header];
-                    this._requestHeaders[header] = [];
-                    this._requestHeaders[header].push(existing);
-                    this._requestHeaders[header].push(value);
-                } else {
-                    this._requestHeaders[header].push(value);
-                }
-            } else {
-                this._requestHeaders[header] = value;
-            }
-        }
-
-        return;
-    },
-
-    send: function(data) {
-        // If the readyState attribute has a value other than 1 (Open), an INVALID_STATE_ERR  exception must be raised.
-        if (this.readyState != 1) {
-            throw new JSONScriptRequest.INVALID_STATE_ERR('readyState: ' + this.readyState + ' is other than 1');
-        }
-
-        // url, if relative, must be resolved using window.document.baseURI of the window whose constructor is used.
-        var url = this._url;
-        if (url.indexOf('http://') == -1) {
-            if (   typeof window.document.baseURI != 'undefined'
-                && window.document.baseURI.match(new RegExp('(.*/)[^/]*$'))
-                )
-            {
-                url = RegExp.$1 + url;
-            } else {
-                // do nothing because it seems like localdomain
-            }
-        }
-
-        // dispatcher
-        this._create_dispatcher();
-        url += (url.indexOf('?') == -1 ? '?' : '&')
-            + this._callback_param + '=' + encodeURIComponent('JSONScriptRequest._dispatchers[' + this._id + ']');
-
-        // TODO: If the async flag is set to false, then the method must not return until the request has completed.
-        //       Otherwise, it must return immediately. (See: open().)
-        ;
-
-        // Invoking send() without the data argument must give the same result as if it was invoked with null as argument.
-        if (typeof data == 'undefined') {
-            data = null;
-        }
-
-        if (data != null) {
-            if (typeof data == 'string') {
-                // If data is a DOMString, it must be encoded as UTF-8 for transmission.
-            }
-            else if (   typeof data == 'object'
-                     && 'nodeType' in data
-                     && data.nodeType == 9/*NODE_DOCUMENT*/) {
-                // TODO: If the data is a Document, it must be serialized using the encoding given by data.xmlEncoding, if specified and supported, or UTF-8 otherwise [DOM3Core].
-                if ('xmlEncoding' in data) {
-                    // TODO: serialize and encode as data.xmlEncoding
-                }
-                else {
-                    // TODO: serialize and encode as UTF-8
-                }
-                // TODO: If the argument to send() is a Document and no Content-Type header has been set user agents must set it to application/xml for XML documents and to the most appropriate media type for other documents (using intrinsic knowledge about the document).
-            } else {
-                // If data is not a DOMString or a Document the host language its stringification mechanisms must be used on the argument that was passed and the result must be treated as if data is a DOMString.
-                data = data.toString();
-            }
-            url += '&' + data;
-        }
-
-        // TODO: If the user agent allows the specification of a proxy it should modify the request appropriately;
-        //       i.e., connect to the proxy host instead of the origin server, modify the Request-Line and send Proxy-Authorization headers as specified.
-
-        // TODO: If the user agent supports HTTP Authentication ([RFC2617]) it should  consider requests originating from this object to be part of the protection space that includes the accessed URIs and send Authorization headers and handle 401 Unauthorised requests appropriately.
-        //       if authentication fails, user agents should prompt the users for credentials.
-
-        // TODO: If the user agent supports HTTP State Mangement  ([RFC2109], [RFC2965]) it should  persist, discard and send cookies (as received in the Set-Cookie and Set-Cookie2 response headers, and sent in the Cookie header) as applicable.
-
-        // TODO: If the user agent implements server-driven content-negotiation ([RFC2616]) it should set Accept-Language, Accept-Encoding and Accept-Charset headers as appropriate; it must not automatically set the Accept header.
-        //       Responses to such requests must have content-codings automatically removed.
-
-        // user, password
-        if ( this._user != null || this._password != null) {
-            // This will not work.
-            var userinfo = ( this._user != null ? this._user : '' ) + ':' + ( this._password != null ? this._password : '' );
-
-            url.replace(new RegExp('(https?://)(.+)', 'i'), RegExp.$1 + userinfo + '@' + RegExp.$2);
-        }
-
-        var script = document.createElement('script');
-        script.src = url;
-        script.type = 'text/javascript';
-        script.charset = 'UTF-8';
-
-        // Once the request has been successfully acknowledged readyState must be set to 2 (Sent).
-        this._readystatechange(2);
-
-        document.documentElement.appendChild(script);
-
-        return;
-    },
-
-    abort: function() {
-        // When invoked, this method must cancel any network activity for which the object is responsible and set all the members of the object to their initial values.
-        var id = this._id;
-        this._initialize_all();
-
-        // register self destruction
-        if (id != null) {
-            JSONScriptRequest._dispatchers[id] = function(json) {
-                delete JSONScriptRequest._dispatchers[id];
-            };
-        }
-        return;
-    },
-
-    getAllResponseHeaders: function() {
-        // If the readyState attribute has a value other than 3 (Receiving) or 4 (Loaded), user agents must raise an INVALID_STATE_ERR exception.
-        if (this.readyState != 3 && this.readyState != 4) {
-            throw new JSONScriptRequest.INVALID_STATE_ERR('readyState: ' + this.readyState + ' is other than 3 or 4');
-        }
-        // Otherwise, it must return all the HTTP headers, as a single string, with each header line separated by a CR (U+000D) LF (U+000A) pair.
-        // The status line must not be included.
-        var allResponseHeaders = '';
-        for (var header in this._responseHeaders) {
-            allResponseHeaders += header + ': ' + this._responseHeaders[header].toString() + '\x0D\x0A';
-        }
-        return allResponseHeaders;
-    },
-
-    getResponseHeader: function(header) {
-        // If the header argument doesn't match the field-name production a SYNTAX_ERR must be raised.
-        if (!header.match(JSONScriptRequest._RE['field-name'])) {
-            throw new JSONScriptRequest.SYNTAX_ERR('header: ' + header);
-        }
-        // If the readyState attribute has a value other than 3 (Receiving) or 4 (Loaded), the user agent must raise an INVALID_STATE_ERR exception.
-        if (this.readyState != 3 && this.readyState != 4) {
-            throw new JSONScriptRequest.INVALID_STATE_ERR('readyState: ' + this.readyState + ' is other than 3 or 4');
-        }
-
-        // Header names must be compared case-insensitively to the method its argument (header).
-        header = header.toUpperCase();
-
-        var values = [];
-        for (var i in this._responseHeaders) {
-            // Header names must be compared case-insensitively to the method its argument (header).
-            if (i.toUpperCase() == header) {
-                values.push(this._responseHeaders[i]);
-            }
-        }
-
-        if (values.length == 0) {
-            // If no headers of that name were received, then it must return null.
-            return null
-        } else {
-            // it must represent the value of the given HTTP header (header) in the data received so far for the last request sent, as a single string.
-            // If more than one header of the given name was received, then the values must be concatenated, separated from each other by an U+002C COMMA followed by an U+0020 SPACE.
-            return values.join(', ');
-        }
-    },
-
-    _initialize: function() {
-        // onreadystatechange  of type EventListener
-        // -----------------------------------------
-        // An attribute that takes an EventListener as value that must be invoked when readystatechange is dispatched on the object implementing the XMLHttpRequest interface.
-        // Its initial value must be null.
-        this.onreadystatechange = null;
-        // readyState of type unsigned short, readonly
-        // -------------------------------------------
-        // The state of the object. The attribute must be one of the following values:
-        // 0 Uninitialized: The initial value.
-        // 1 Open: The open() method has been successfully called.
-        // 2 Sent: The user agent successfully acknowledged the request.
-        // 3 Receiving: Immediately before receiving the message body (if any). All HTTP headers have been received.
-        // 4 Loaded: The data transfer has been completed.
-        this.readyState = 0;
-        // responseText of type DOMString, readonly
-        // ----------------------------------------
-        // TODO: Otherwise, it must be the fragment of the entity body received so far (when readyState is 3 (Receiving)) or the complete entity body (when readyState is 4 (Loaded)), interpreted as a stream of characters.
-        // TODO: If the response includes a Content-Type understood by the user agent the characters are encoded following the relevant media type specification, with the exception that the rule in the final paragraph of section 3.7.1 of [RFC2616], and the rules in section 4.1.2 of [RFC2046] must be treated as if they specified the default character encoding as being UTF-8.
-        // TODO: Invalid bytes must be converted to U+FFFD REPLACEMENT CHARACTER. If the user agent can't derive a character stream in accord with the media type specification, reponseText must be null.
-        // Its initial value must be the null.
-        this.responseText = null;
-        // (XML -> JSON)
-        // responseXML of type Document, readonly
-        // --------------------------------------
-        // TODO: Otherwise, if the Content-Type header contains a media type (ignoring any parameters) that is either text/xml, application/xml, or ends in +xml, it must be an object that implements the Document interface representing the parsed document.
-        // TODO: If Content-Type did not contain such a media type, or if the document could not be parsed (due to an XML well-formedness error or unsupported character encoding, for instance), it must be null.
-        // Its initial value must be null.
-        this.responseJSON = null;
-        // status of type unsigned short, readonly
-        // ---------------------------------------
-        // TODO: If the status attribute is not available an INVALID_STATE_ERR exception must be raised.
-        // When available, it must represent the HTTP status code (typically 200 for a successful connection).
-        // Its initial value must be 0.
-        this.status = 0;
-        // statusText of type DOMString, readonly
-        // --------------------------------------
-        // TODO: If the statusText attribute is not available an INVALID_STATE_ERR exception must be raised.
-        // When available, it must represent the HTTP status text sent by the server (appears after the status code).
-        // Its initial value must be the empty string.
-        this.statusText = '';
-
-        this._readystatechange(0);
-    },
-
-    _initialize_dispatcher: function() {
-        if (this._id != null) {
-            delete JSONScriptRequest._dispatchers[this._id];
-            this._id = null;
-        }
-    },
-
-    _initialize_all: function() {
-        this._initialize();
-
-        this._initialize_dispatcher();
-        this._callback_param = 'callback';
-
-        this._method   = null;
-        this._url      = null;
-        this._async    = true;
-        this._user     = null;
-        this._password = null;
-        this._requestHeaders = {};
-        this._responseHeaders = {};
-    },
-
-    _readystatechange: function(readyState) {
-        if (this.readyState == readyState) {
-            // It is not changed but continue to follow to
-            // ActiveXObject of IE and XMLHttpRequest of Firefox.
-        }
-        this.readyState = readyState;
-
-        // If the readyState attribute has a value other than 4 (Loaded), user agents must raise an INVALID_STATE_ERR exception.
-        if (   this.readyState != 4
-            && this.responseJSON != null)
-        {
-            // [LIMIT: the exception occurs at _readystatechange]
-            throw new JSONScriptRequest.INVALID_STATE_ERR('readyState: ' + this.readyState + ' is other than 4, but' +
-                                                          'responseJSON: ' + this.responseJSON + ' has a value');
-        }
-
-        // If the readyState attribute has a value other than 3 (Receiving) or 4 (Loaded), the user agent must raise an INVALID_STATE_ERR exception.
-        if (   this.readyState != 3
-            && this.readyState != 4
-            && this.responseText != null)
-        {
-            // [LIMIT: the exception occurs at _readystatechange]
-            throw new JSONScriptRequest.INVALID_STATE_ERR('readyState: ' + this.readyState + ' is other than 3 or 4, but' +
-                                                          'responseText: ' + this.responseText + ' has a value');
-        }
-
-        // It must be available when readyState is 3 (Receiving) or 4 (Loaded).
-        if (   (this.readyState == 3 || this.readyState == 4)
-            && (this.status == 0 || this.statusText == '')
-            )
-        {
-            throw new JSONScriptRequest.INVALID_STATE_ERR('status and statusText must be available when readyState is 3 or 4');
-        }
-
-        if (this.onreadystatechange) {
-            this.onreadystatechange();
-        }
-        return;
-    },
-
-    _create_dispatcher: function() {
-        this._initialize_dispatcher();
-        for (this._id = 0; this._id < JSONScriptRequest._dispatchers.length; this._id++) {
-            if (!this.id in JSONScriptRequest._dispatchers) {
-                break;
-            }
-        }
-
-        var owner = this;
-        JSONScriptRequest._dispatchers[this._id] = (function() {
-            return function(json) {
-                owner._initialize_dispatcher();
-                owner._dispatcher(json);
-            };
-        })();
-
-        return;
-    },
-
-    _dispatcher: function(json) {
-        // TODO: If the response is an HTTP redirect (status code 301, 302, 303 or 307), then it must be transparently followed (unless it violates security, infinite loop precautions or the scheme isn't supported).
-        //       Note that HTTP ([RFC2616]) places requirements on user agents regarding the preservation of the request method during redirects, and also requires users to be notified of certain kinds of automatic redirections.
-
-        // TODO: If something goes wrong (infinite loop, network errors) the readyState attribute must be set to 4 (Loaded) and all other members of the object must be set to their initial value.
-        //       Note: In future versions of this specification user agents will be required to dispatch an error event if the above occurs.
-
-        // TODO: If the user agent implements a HTTP cache ([RFC2616]) it should  respect Cache-Control request headers set by the author (e.g., Cache-Control: no-cache bypasses the cache).
-        //       It must not  send Cache-Control or Pragma request headers automatically unless the user explicitly requests such behaviour (e.g., by (force-)reloading the page).
-        //       304 Not Modified responses that are a result of a user agent generated conditional request must be presented as 200 OK responses with the appropriate content.
-        //       Such user agents must allow authors to override automatic cache validation by setting request headers (e.g., If-None-Match, If-Modified-Since), in which case 304 Not Modified responses must be passed through.
-
-        // TODO: If the user agent supports Expect/Continue for request bodies ([RFC2616]) it should insert Expect headers and handle 100 Continue responses appropriately.
-
-        // Immediately before receiving the message body (if any), the readyState attribute must be set to to 3 (Receiving).
-        if (typeof json == 'undefined' || json == null) {
-            // TODO: This behavior is really ok?
-            this.status = 400;
-            this.statusText = 'Bad Request';
-        } else {
-            this.status = 200;
-            this.statusText = 'OK';
-        }
-        this.responseText = '';
-        this._readystatechange(3);
-
-        // In case of a HEAD request readyState must be set to 4 (Loaded) immediately after having gone to 3 (Receiving).
-        if (this._method == 'HEAD') {
-            this._readystatechange(4);
-        } else {
-            this.responseText = JSONScriptRequest._toSource(json).replace(/^\(/, '').replace(/\)$/, '');
-
-            this._readystatechange(3);
-
-            this.responseJSON = json;
-            // When the request has completed loading, the readyState attribute must be set to 4 (Loaded).
-            this._readystatechange(4);
-        }
-
-        return;
-    }
-};
-
-/*
-
-*/
-

=== removed file 'lib/canonical/launchpad/icing-contrib/json2.js'
--- lib/canonical/launchpad/icing-contrib/json2.js	2008-06-16 18:58:27 +0000
+++ lib/canonical/launchpad/icing-contrib/json2.js	1970-01-01 00:00:00 +0000
@@ -1,473 +0,0 @@
-/*
-    http://www.JSON.org/json2.js
-    2008-06-15
-
-    Public Domain.
-
-    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
-
-    See http://www.JSON.org/js.html
-
-    This file creates a global JSON object containing two methods: stringify
-    and parse.
-
-
-        JSON.stringify(value, replacer, space)
-            value       any JavaScript value, usually an object or array.
-
-            replacer    an optional parameter that determines how object
-                        values are stringified for objects without a toJSON
-                        method. It can be a function or an array.
-
-            space       an optional parameter that specifies the indentation
-                        of nested structures. If it is omitted, the text will
-                        be packed without extra whitespace. If it is a number,
-                        it will specify the number of spaces to indent at each
-                        level. If it is a string (such as '\t' or '&nbsp;'),
-                        it contains the characters used to indent at each level.
-
-            This method produces a JSON text from a JavaScript value.
-
-            When an object value is found, if the object contains a toJSON
-            method, its toJSON method will be called and the result will be
-            stringified. A toJSON method does not serialize: it returns the
-            value represented by the name/value pair that should be serialized,
-            or undefined if nothing should be serialized. The toJSON method
-            will be passed the key associated with the value, and this will be
-            bound to the object holding the key.
-
-            For example, this would serialize Dates as ISO strings.
-
-                Date.prototype.toJSON = function (key) {
-                    function f(n) {
-                        // Format integers to have at least two digits.
-                        return n < 10 ? '0' + n : n;
-                    }
-
-                    return this.getUTCFullYear()   + '-' +
-                         f(this.getUTCMonth() + 1) + '-' +
-                         f(this.getUTCDate())      + 'T' +
-                         f(this.getUTCHours())     + ':' +
-                         f(this.getUTCMinutes())   + ':' +
-                         f(this.getUTCSeconds())   + 'Z';
-                };
-
-            You can provide an optional replacer method. It will be passed the
-            key and value of each member, with this bound to the containing
-            object. The value that is returned from your method will be
-            serialized. If your method returns undefined, then the member will
-            be excluded from the serialization.
-
-            If the replacer parameter is an array, then it will be used to
-            select the members to be serialized. It filters the results such
-            that only members with keys listed in the replacer array are
-            stringified.
-
-            Values that do not have JSON representations, such as undefined or
-            functions, will not be serialized. Such values in objects will be
-            dropped; in arrays they will be replaced with null. You can use
-            a replacer function to replace those with JSON values.
-            JSON.stringify(undefined) returns undefined.
-
-            The optional space parameter produces a stringification of the
-            value that is filled with line breaks and indentation to make it
-            easier to read.
-
-            If the space parameter is a non-empty string, then that string will
-            be used for indentation. If the space parameter is a number, then
-            then indentation will be that many spaces.
-
-            Example:
-
-            text = JSON.stringify(['e', {pluribus: 'unum'}]);
-            // text is '["e",{"pluribus":"unum"}]'
-
-
-            text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
-            // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
-
-            text = JSON.stringify([new Date()], function (key, value) {
-                return this[key] instanceof Date ?
-                    'Date(' + this[key] + ')' : value;
-            });
-            // text is '["Date(---current time---)"]'
-
-
-        JSON.parse(text, reviver)
-            This method parses a JSON text to produce an object or array.
-            It can throw a SyntaxError exception.
-
-            The optional reviver parameter is a function that can filter and
-            transform the results. It receives each of the keys and values,
-            and its return value is used instead of the original value.
-            If it returns what it received, then the structure is not modified.
-            If it returns undefined then the member is deleted.
-
-            Example:
-
-            // Parse the text. Values that look like ISO date strings will
-            // be converted to Date objects.
-
-            myData = JSON.parse(text, function (key, value) {
-                var a;
-                if (typeof value === 'string') {
-                    a =
-/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
-                    if (a) {
-                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
-                            +a[5], +a[6]));
-                    }
-                }
-                return value;
-            });
-
-            myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
-                var d;
-                if (typeof value === 'string' &&
-                        value.slice(0, 5) === 'Date(' &&
-                        value.slice(-1) === ')') {
-                    d = new Date(value.slice(5, -1));
-                    if (d) {
-                        return d;
-                    }
-                }
-                return value;
-            });
-
-
-    This is a reference implementation. You are free to copy, modify, or
-    redistribute.
-
-    This code should be minified before deployment.
-    See http://javascript.crockford.com/jsmin.html
-
-    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD THIRD PARTY
-    CODE INTO YOUR PAGES.
-*/
-
-/*jslint evil: true */
-
-/*global JSON */
-
-/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", call,
-    charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, getUTCMinutes,
-    getUTCMonth, getUTCSeconds, hasOwnProperty, join, lastIndex, length,
-    parse, propertyIsEnumerable, prototype, push, replace, slice, stringify,
-    test, toJSON, toString
-*/
-
-if (!this.JSON) {
-
-// Create a JSON object only if one does not already exist. We create the
-// object in a closure to avoid global variables.
-
-    JSON = function () {
-
-        function f(n) {
-            // Format integers to have at least two digits.
-            return n < 10 ? '0' + n : n;
-        }
-
-        Date.prototype.toJSON = function (key) {
-
-            return this.getUTCFullYear()   + '-' +
-                 f(this.getUTCMonth() + 1) + '-' +
-                 f(this.getUTCDate())      + 'T' +
-                 f(this.getUTCHours())     + ':' +
-                 f(this.getUTCMinutes())   + ':' +
-                 f(this.getUTCSeconds())   + 'Z';
-        };
-
-        var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
-            escapeable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
-            gap,
-            indent,
-            meta = {    // table of character substitutions
-                '\b': '\\b',
-                '\t': '\\t',
-                '\n': '\\n',
-                '\f': '\\f',
-                '\r': '\\r',
-                '"' : '\\"',
-                '\\': '\\\\'
-            },
-            rep;
-
-
-        function quote(string) {
-
-// If the string contains no control characters, no quote characters, and no
-// backslash characters, then we can safely slap some quotes around it.
-// Otherwise we must also replace the offending characters with safe escape
-// sequences.
-
-            escapeable.lastIndex = 0;
-            return escapeable.test(string) ?
-                '"' + string.replace(escapeable, function (a) {
-                    var c = meta[a];
-                    if (typeof c === 'string') {
-                        return c;
-                    }
-                    return '\\u' + ('0000' +
-                            (+(a.charCodeAt(0))).toString(16)).slice(-4);
-                }) + '"' :
-                '"' + string + '"';
-        }
-
-
-        function str(key, holder) {
-
-// Produce a string from holder[key].
-
-            var i,          // The loop counter.
-                k,          // The member key.
-                v,          // The member value.
-                length,
-                mind = gap,
-                partial,
-                value = holder[key];
-
-// If the value has a toJSON method, call it to obtain a replacement value.
-
-            if (value && typeof value === 'object' &&
-                    typeof value.toJSON === 'function') {
-                value = value.toJSON(key);
-            }
-
-// If we were called with a replacer function, then call the replacer to
-// obtain a replacement value.
-
-            if (typeof rep === 'function') {
-                value = rep.call(holder, key, value);
-            }
-
-// What happens next depends on the value's type.
-
-            switch (typeof value) {
-            case 'string':
-                return quote(value);
-
-            case 'number':
-
-// JSON numbers must be finite. Encode non-finite numbers as null.
-
-                return isFinite(value) ? String(value) : 'null';
-
-            case 'boolean':
-            case 'null':
-
-// If the value is a boolean or null, convert it to a string. Note:
-// typeof null does not produce 'null'. The case is included here in
-// the remote chance that this gets fixed someday.
-
-                return String(value);
-
-// If the type is 'object', we might be dealing with an object or an array or
-// null.
-
-            case 'object':
-
-// Due to a specification blunder in ECMAScript, typeof null is 'object',
-// so watch out for that case.
-
-                if (!value) {
-                    return 'null';
-                }
-
-// Make an array to hold the partial results of stringifying this object value.
-
-                gap += indent;
-                partial = [];
-
-// If the object has a dontEnum length property, we'll treat it as an array.
-
-                if (typeof value.length === 'number' &&
-                        !(value.propertyIsEnumerable('length'))) {
-
-// The object is an array. Stringify every element. Use null as a placeholder
-// for non-JSON values.
-
-                    length = value.length;
-                    for (i = 0; i < length; i += 1) {
-                        partial[i] = str(i, value) || 'null';
-                    }
-
-// Join all of the elements together, separated with commas, and wrap them in
-// brackets.
-
-                    v = partial.length === 0 ? '[]' :
-                        gap ? '[\n' + gap +
-                                partial.join(',\n' + gap) + '\n' +
-                                    mind + ']' :
-                              '[' + partial.join(',') + ']';
-                    gap = mind;
-                    return v;
-                }
-
-// If the replacer is an array, use it to select the members to be stringified.
-
-                if (rep && typeof rep === 'object') {
-                    length = rep.length;
-                    for (i = 0; i < length; i += 1) {
-                        k = rep[i];
-                        if (typeof k === 'string') {
-                            v = str(k, value, rep);
-                            if (v) {
-                                partial.push(quote(k) + (gap ? ': ' : ':') + v);
-                            }
-                        }
-                    }
-                } else {
-
-// Otherwise, iterate through all of the keys in the object.
-
-                    for (k in value) {
-                        if (Object.hasOwnProperty.call(value, k)) {
-                            v = str(k, value, rep);
-                            if (v) {
-                                partial.push(quote(k) + (gap ? ': ' : ':') + v);
-                            }
-                        }
-                    }
-                }
-
-// Join all of the member texts together, separated with commas,
-// and wrap them in braces.
-
-                v = partial.length === 0 ? '{}' :
-                    gap ? '{\n' + gap +
-                            partial.join(',\n' + gap) + '\n' +
-                            mind + '}' :
-                          '{' + partial.join(',') + '}';
-                gap = mind;
-                return v;
-            }
-        }
-
-
-// Return the JSON object containing the stringify, parse, and quote methods.
-
-        return {
-            stringify: function (value, replacer, space) {
-
-// The stringify method takes a value and an optional replacer, and an optional
-// space parameter, and returns a JSON text. The replacer can be a function
-// that can replace values, or an array of strings that will select the keys.
-// A default replacer method can be provided. Use of the space parameter can
-// produce text that is more easily readable.
-
-                var i;
-                gap = '';
-                indent = '';
-
-// If the space parameter is a number, make an indent string containing that
-// many spaces.
-
-                if (typeof space === 'number') {
-                    for (i = 0; i < space; i += 1) {
-                        indent += ' ';
-                    }
-
-// If the space parameter is a string, it will be used as the indent string.
-
-                } else if (typeof space === 'string') {
-                    indent = space;
-                }
-
-// If there is a replacer, it must be a function or an array.
-// Otherwise, throw an error.
-
-                rep = replacer;
-                if (replacer && typeof replacer !== 'function' &&
-                        (typeof replacer !== 'object' ||
-                         typeof replacer.length !== 'number')) {
-                    throw new Error('JSON.stringify');
-                }
-
-// Make a fake root object containing our value under the key of ''.
-// Return the result of stringifying the value.
-
-                return str('', {'': value});
-            },
-
-
-            parse: function (text, reviver) {
-
-// The parse method takes a text and an optional reviver function, and returns
-// a JavaScript value if the text is a valid JSON text.
-
-                var j;
-
-                function walk(holder, key) {
-
-// The walk method is used to recursively walk the resulting structure so
-// that modifications can be made.
-
-                    var k, v, value = holder[key];
-                    if (value && typeof value === 'object') {
-                        for (k in value) {
-                            if (Object.hasOwnProperty.call(value, k)) {
-                                v = walk(value, k);
-                                if (v !== undefined) {
-                                    value[k] = v;
-                                } else {
-                                    delete value[k];
-                                }
-                            }
-                        }
-                    }
-                    return reviver.call(holder, key, value);
-                }
-
-
-// Parsing happens in four stages. In the first stage, we replace certain
-// Unicode characters with escape sequences. JavaScript handles many characters
-// incorrectly, either silently deleting them, or treating them as line endings.
-
-                cx.lastIndex = 0;
-                if (cx.test(text)) {
-                    text = text.replace(cx, function (a) {
-                        return '\\u' + ('0000' +
-                                (+(a.charCodeAt(0))).toString(16)).slice(-4);
-                    });
-                }
-
-// In the second stage, we run the text against
-// regular expressions that look for non-JSON patterns. We are especially
-// concerned with '()' and 'new' because they can cause invocation, and '='
-// because it can cause mutation. But just to be safe, we want to reject all
-// unexpected forms.
-
-// We split the second stage into 4 regexp operations in order to work around
-// crippling inefficiencies in IE's and Safari's regexp engines. First we
-// replace all backslash pairs with '@' (a non-JSON character). Second, we
-// replace all simple value tokens with ']' characters. Third, we delete all
-// open brackets that follow a colon or comma or that begin the text. Finally,
-// we look to see that the remaining characters are only whitespace or ']' or
-// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
-
-                if (/^[\],:{}\s]*$/.test(text.replace(/\\["\\\/bfnrtu]/g, '@').
-replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
-replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
-
-// In the third stage we use the eval function to compile the text into a
-// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
-// in JavaScript: it can begin a block or an object literal. We wrap the text
-// in parens to eliminate the ambiguity.
-
-                    j = eval('(' + text + ')');
-
-// In the optional fourth stage, we recursively walk the new structure, passing
-// each name/value pair to a reviver function for possible transformation.
-
-                    return typeof reviver === 'function' ?
-                        walk({'': j}, '') : j;
-                }
-
-// If the text is not JSON parseable, then a SyntaxError is thrown.
-
-                throw new SyntaxError('JSON.parse');
-            }
-        };
-    }();
-}

=== modified file 'lib/canonical/launchpad/pagetests/basics/notfound-traversals.txt'
--- lib/canonical/launchpad/pagetests/basics/notfound-traversals.txt	2011-12-07 05:39:39 +0000
+++ lib/canonical/launchpad/pagetests/basics/notfound-traversals.txt	2011-12-09 05:23:25 +0000
@@ -433,18 +433,10 @@
 >>> check_redirect("/products/ubuntu-product", status=301)
 >>> check_redirect("/people/stub", status=301)
 
-
 Check redirects of Unicode URLs works
 
 >>> check_not_found("/ubuntu/foo%C3%A9")
 
-
-Icing resources.
-
->>> from lp.app.versioninfo import revno
->>> check("/+icing-contrib/rev%s/JSONScriptRequest.js" % revno)
->>> check("/+icing-contrib/rev%s/json2.js" % revno)
-
 Image resources are available from all the virtual hosts.
 
 >>> check('/@@/add', host='launchpad.dev')

=== modified file 'lib/canonical/launchpad/webapp/servers.py'
--- lib/canonical/launchpad/webapp/servers.py	2011-12-08 05:13:31 +0000
+++ lib/canonical/launchpad/webapp/servers.py	2011-12-09 05:23:25 +0000
@@ -565,7 +565,6 @@
         self._wsgi_keys = set()
         self.needs_datepicker_iframe = False
         self.needs_datetimepicker_iframe = False
-        self.needs_json = False
         super(BasicLaunchpadRequest, self).__init__(
             body_instream, environ, response)
 
@@ -860,11 +859,6 @@
     >>> request.needs_datepicker_iframe
     False
 
-    And for JSON:
-
-    >>> request.needs_json
-    False
-
     """
     implements(
         INotificationRequest, IBasicLaunchpadRequest, IParticipation,
@@ -882,7 +876,6 @@
         self.traversed_objects = []
         self.needs_datepicker_iframe = False
         self.needs_datetimepicker_iframe = False
-        self.needs_json = False
         # Use an existing feature controller if one exists, otherwise use the
         # null controller.
         self.features = get_relevant_feature_controller()

=== modified file 'lib/lp/app/browser/configure.zcml'
--- lib/lp/app/browser/configure.zcml	2011-12-04 04:21:34 +0000
+++ lib/lp/app/browser/configure.zcml	2011-12-09 05:23:25 +0000
@@ -133,14 +133,6 @@
       permission="zope.Public"
       />
 
-    <browser:page
-      for="canonical.launchpad.webapp.interfaces.ILaunchpadApplication"
-      name="+icing-contrib"
-      class="lp.app.browser.launchpad.IcingContribFolder"
-      attribute="__call__"
-      permission="zope.Public"
-      />
-
     <!-- A page to list all the icons in LP -->
     <browser:page
         for="canonical.launchpad.webapp.interfaces.ILaunchpadApplication"

=== modified file 'lib/lp/app/browser/launchpad.py'
--- lib/lp/app/browser/launchpad.py	2011-12-04 04:21:34 +0000
+++ lib/lp/app/browser/launchpad.py	2011-12-09 05:23:25 +0000
@@ -8,7 +8,6 @@
     'AppFrontPageSearchView',
     'DoesNotExistView',
     'Hierarchy',
-    'IcingContribFolder',
     'IcingFolder',
     'iter_view_registrations',
     'LaunchpadImageFolder',
@@ -852,15 +851,6 @@
         config.root, 'lib/canonical/launchpad/images/')
 
 
-class IcingContribFolder(ExportedFolder):
-    """Export the contrib icing."""
-
-    export_subdirectories = True
-
-    folder = os.path.join(
-        config.root, 'lib/canonical/launchpad/icing-contrib/')
-
-
 class LaunchpadTourFolder(ExportedFolder):
     """Export a launchpad tour folder.
 

=== modified file 'lib/lp/app/templates/base-layout-macros.pt'
--- lib/lp/app/templates/base-layout-macros.pt	2011-11-30 01:18:42 +0000
+++ lib/lp/app/templates/base-layout-macros.pt	2011-12-09 05:23:25 +0000
@@ -91,18 +91,11 @@
 <metal:page-javascript define-macro="page-javascript"
   tal:define="
       revno modules/lp.app.versioninfo/revno | string:unknown;
-      icingroot_contrib string:/+icing-contrib/rev${revno};
       devmode modules/canonical.config/config/devmode;
       map_query string:&amp;file=api&amp;v=2&amp;key=${modules/canonical.config/config/google/maps_api_key};">
   <tal:comment replace="nothing">
     Load and initialize the common script used by all pages.
   </tal:comment>
-  <tal:needs_json tal:condition="request/needs_json">
-    <script type="text/javascript"
-            tal:attributes="src string:${icingroot_contrib}/json2.js"></script>
-    <script type="text/javascript"
-            tal:attributes="src string:${icingroot_contrib}/JSONScriptRequest.js"></script>
-  </tal:needs_json>
 
   <metal:load-lavascript use-macro="context/@@+base-layout-macros/load-javascript" />
 

=== modified file 'lib/lp/app/templates/base-layout.pt'
--- lib/lp/app/templates/base-layout.pt	2011-11-30 01:18:42 +0000
+++ lib/lp/app/templates/base-layout.pt	2011-12-09 05:23:25 +0000
@@ -10,7 +10,6 @@
     is_lpnet modules/canonical.config/config/launchpad/is_lpnet;
     site_message modules/canonical.config/config/launchpad/site_message;
     icingroot string:${rooturl}+icing/rev${revno};
-    icingroot_contrib string:${rooturl}+icing-contrib/rev${revno};
     features request/features;
     feature_scopes request/features/scopes;
     CONTEXTS python:{'template':template, 'context': context, 'view':view};

=== modified file 'lib/lp/app/widgets/doc/location-widget.txt'
--- lib/lp/app/widgets/doc/location-widget.txt	2011-02-01 21:46:58 +0000
+++ lib/lp/app/widgets/doc/location-widget.txt	2011-12-09 05:23:25 +0000
@@ -9,20 +9,10 @@
     >>> salgado = getUtility(IPersonSet).getByName('salgado')
     >>> field = LocationField(__name__='location', title=u'Location')
 
-JavaScript and JSON are used by the location widget.  By setting the
-needs_json attributes of the request, the main template
-will include the necessary code to enable these features.
-
     >>> bound_field = field.bind(salgado)
     >>> request = LaunchpadTestRequest(
     ...     # Let's pretend requests are coming from Brazil.
     ...     environ={'REMOTE_ADDR': '201.13.165.145'})
-    >>> request.needs_json
-    False
-
-    >>> widget = LocationWidget(bound_field, request)
-    >>> request.needs_json
-    True
 
 When rendering salgado's location widget to himself, we'll center the
 map around the location where he seems to be, based on the IP address of

=== modified file 'lib/lp/app/widgets/location.py'
--- lib/lp/app/widgets/location.py	2011-09-13 05:23:16 +0000
+++ lib/lp/app/widgets/location.py	2011-12-09 05:23:25 +0000
@@ -62,10 +62,6 @@
     __call__ = ViewPageTemplateFile("templates/location.pt")
 
     def __init__(self, context, request):
-        # This widget makes use of javascript for googlemaps and
-        # json-handling, so we flag that in the request so that our
-        # base-layout includes the necessary javascript files.
-        request.needs_json = True
         super(LocationWidget, self).__init__(context, request)
         fields = form.Fields(
             Float(__name__='latitude', title=_('Latitude'), required=False),