← Back to team overview

harvest-dev team mailing list archive

[Merge] lp:~dylanmccall/harvest/gsoc-client-stuff into lp:harvest

 

Dylan McCall has proposed merging lp:~dylanmccall/harvest/gsoc-client-stuff into lp:harvest.

Requested reviews:
  harvest-dev (harvest-dev)


Begins implementing a new client portion for Harvest with a bunch of back-end changes to accommodate it.

Filter rendering functions now behave a bit better, generating more useful HTML with fewer FIXMEs and TODOs.

New look based on the shiny new Ubuntu branding :)

Separate view functions to get output for specific chunks of the page.

I'm pulling in JQuery, using its ajax and animation functions to request new content from the server and place it in the page asynchronously. This happens both for selecting filters (their results appear to the right after a moment), and for expanding packages in the results.
Gracefully falls back to function with plain HTML, but of course works nicest with Javascript (by a considerable margin, if you ask me — but then, I spent two weeks on it).


Lots of old stuff cleared out for sanity, which is either suited fine by filters or needs to be reimplemented on the new design. These spring to mind in particular:
 * The landing page.
 * Editing opportunities. (Needs ajax with a static HTML fallback).
 * Browsing by opportunity list, with opp list name as header in the results. Now the results always show package names with opportunities below them. I think that is enough given the filtering, but it could be made more flexible if it's needed.
 * Linking directly to specific packages (in a pleasant way).


Sorry, another ginormous merge. Hoping I can manage more manageable branches from here on out! The different bits should be able to talk to each other now.
-- 
https://code.launchpad.net/~dylanmccall/harvest/gsoc-client-stuff/+merge/29838
Your team harvest-dev is requested to review the proposed merge of lp:~dylanmccall/harvest/gsoc-client-stuff into lp:harvest.
=== added file 'doc/DOM for filters.txt'
--- doc/DOM for filters.txt	1970-01-01 00:00:00 +0000
+++ doc/DOM for filters.txt	2010-07-14 06:16:47 +0000
@@ -0,0 +1,82 @@
+It is critical that we describe filters using a consistent format. Every morsel of data provided in HTML is used by Javascript and CSS for context-specific behaviours and styles.
+
+We need to support static HTML output with or without CSS, and with or without Javascript. So, don't expect it to be entirely elegant, but it works!
+
+For brevity, this document uses standard CSS selectors to refer to elements. For example, #elemid refers to an element's ID attribute and .elemclass refers to a class attribute.
+
+
+
+
+----- General overview -----
+
+Here I will define the expected DOM hierarchy to be described in HTML and what it all means.
+
+#container - Contains everything. This is important for CSS, to align the footer correctly.
+	#header - The top part of the page, consistent and visible on most pages.
+		span#pagetitle - The title, which is drawn as the leftmost part of the header with a special font.
+			img#sitelogo - Logo for the web site.
+			h1#sitename - The actual name of the site.
+			span#releasename - The name of the current release. Eg: Beta, Revision 201. Should be blank if it is a stable release. Printed as a subscript beside sitename.
+		span#userdata - Tools specific to logging in, or the logged in user.
+
+
+
+	#content - The portion of the page that changes specific to what is being looked at.
+		#filters - Contains the list of filters. Shows their current state and allows the user to interact with them, enabling / disabling filters and setting their values. Filters are explained in more detail later.
+		
+		#results-pane - Container that holds results and surrounding widgets.
+			#results - Holds the list of packages that results from the selected filters.
+	
+	#footer
+		#footnav - More technical links go in here...
+		#smallprint - The fine print. Contents are shrunken and ellipsized (where supported) to be really unobtrusive. When moused over, they are shown in more detail.
+			#copyright - Copyright notice.
+			#techdetails - Stuff geeks and Harvest hackers may want to know, like page generation time and SQL queries count.
+
+
+
+
+-----Filters-----
+
+A list of filters goes inside the element #filters. (These are probably FilterGroups, which contain more filters). A filter is described as follows:
+<span class="filter editfilter pkgnamefilter" data-filter-fullname="filter-pkg:name">
+The class is set to the actual Python class hierarchy of the Filter object in Django, with all Filter subclasses that influence its behaviour. The data-filter-fullname field is the full name of the Filter object in Django, as used in the querystring.
+
+
+The immediate contents of each Filter object should be consistent:
+
+.filter
+	.filter-label - The filter's label. This is its name, usually spanning a single line.
+		a.item-toggle - May not be present, but in most cases it is. See .filter.filtergroup .filter-value ul below for more information. Usually .item-toggle for a filter spans its entire .filter-label element.
+	.filter-value - (Optional) Contains a list, a text field or some other element corresponding to the value assigned to this filter, depending on its class.
+
+
+Now I will describe the different .filter-value elements that are expected.
+
+.filtergroup , .choicefilter
+	.filter-value ul - List items are all possible choices for the filter.
+		li - Needs the data-choice-id attribute, which specifies the exact ID of this choice relative to the current Filter. Add the data-selected attribute if this element is selected.
+			.checkbox - Must always be present. Contents indicate whether the element is selected. If it is currently selected, it must be populated with a check mark character (✓, U+2713, or &#10003;).
+
+.choicefilter
+	ul > li > a.item-toggle - Expected to enable or disable the item. The href field should be a querystring that does this with static pages from Django, and Javascript will override that default behaviour.
+
+.filtergroup
+	ul > li .filter > .filter-label > .item-toggle - Just like a.item-toggle with .choicefilter; just unfortunately placed for technical reasons.
+
+.editfilter
+	.filter-value input - An HTML input field. Should not be attached to a form. For now, we are relying on Javascript to hande its value.
+	(##TODO##: require type="hidden" if Javascript dependency remains).
+
+
+
+
+-----Standard Attributes-----
+
+For .filter:
+	data-filter-fullname: Should be the full name of the filter, as it is in the querystring and in the FilterSystem in Django. (Eg: id="filter-pkg:set").
+	data-filter-value: The filter's value in serialized form. This attribute does not need to be filled initially, but our Javascript will fill it in as new values are generated.
+
+For .filtergroup > ul > li and .choicefilter > ul > li:
+	data-item-name: The id of this item relative to the parent filter; not its full name. (Eg: data-item-name="netbook" for the choice with id_str="netbook").
+	data-selected: Add if the choice is currently selected.
\ No newline at end of file

=== modified file 'harvest/common/context_processors.py'
--- harvest/common/context_processors.py	2010-06-01 16:16:19 +0000
+++ harvest/common/context_processors.py	2010-07-14 06:16:47 +0000
@@ -11,6 +11,17 @@
 
     return {'harvest_version': version}
 
+def harvest_version_name(request):
+    """
+    add short harvest version name to template context processor
+    """
+    try:
+        version_name = settings.VERSION_NAME_STRING
+    except AttributeError:
+        version_name = ""
+
+    return {'harvest_version_name': version_name}
+
 def login_redirect(request):
     return {'login_next': request.get_full_path()}
 

=== added directory 'harvest/common/middleware'
=== added file 'harvest/common/middleware/__init__.py'
=== added file 'harvest/common/middleware/timer.py'
--- harvest/common/middleware/timer.py	1970-01-01 00:00:00 +0000
+++ harvest/common/middleware/timer.py	2010-07-14 06:16:47 +0000
@@ -0,0 +1,15 @@
+from time import time
+
+class TimerMiddleware(object):
+    def process_request(self, request):
+        request._tm_start_time = time()
+    
+    def process_response(self, request, response):
+        if not hasattr(request, "_tm_start_time"):
+            return
+        
+        total_time = time() - request._tm_start_time
+        
+        response['X-Django-Request-Time'] = '%fs' % total_time
+        
+        return response

=== added file 'harvest/common/ordereddict.py'
--- harvest/common/ordereddict.py	1970-01-01 00:00:00 +0000
+++ harvest/common/ordereddict.py	2010-07-14 06:16:47 +0000
@@ -0,0 +1,127 @@
+# Copyright (c) 2009 Raymond Hettinger
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+#     The above copyright notice and this permission notice shall be
+#     included in all copies or substantial portions of the Software.
+#
+#     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+#     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+#     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+#     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+#     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+#     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+#     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+#     OTHER DEALINGS IN THE SOFTWARE.
+
+from UserDict import DictMixin
+
+class OrderedDict(dict, DictMixin):
+
+    def __init__(self, *args, **kwds):
+        if len(args) > 1:
+            raise TypeError('expected at most 1 arguments, got %d' % len(args))
+        try:
+            self.__end
+        except AttributeError:
+            self.clear()
+        self.update(*args, **kwds)
+
+    def clear(self):
+        self.__end = end = []
+        end += [None, end, end]         # sentinel node for doubly linked list
+        self.__map = {}                 # key --> [key, prev, next]
+        dict.clear(self)
+
+    def __setitem__(self, key, value):
+        if key not in self:
+            end = self.__end
+            curr = end[1]
+            curr[2] = end[1] = self.__map[key] = [key, curr, end]
+        dict.__setitem__(self, key, value)
+
+    def __delitem__(self, key):
+        dict.__delitem__(self, key)
+        key, prev, next = self.__map.pop(key)
+        prev[2] = next
+        next[1] = prev
+
+    def __iter__(self):
+        end = self.__end
+        curr = end[2]
+        while curr is not end:
+            yield curr[0]
+            curr = curr[2]
+
+    def __reversed__(self):
+        end = self.__end
+        curr = end[1]
+        while curr is not end:
+            yield curr[0]
+            curr = curr[1]
+
+    def popitem(self, last=True):
+        if not self:
+            raise KeyError('dictionary is empty')
+        if last:
+            key = reversed(self).next()
+        else:
+            key = iter(self).next()
+        value = self.pop(key)
+        return key, value
+
+    def __reduce__(self):
+        items = [[k, self[k]] for k in self]
+        tmp = self.__map, self.__end
+        del self.__map, self.__end
+        inst_dict = vars(self).copy()
+        self.__map, self.__end = tmp
+        if inst_dict:
+            return (self.__class__, (items,), inst_dict)
+        return self.__class__, (items,)
+
+    def keys(self):
+        return list(self)
+
+    setdefault = DictMixin.setdefault
+    update = DictMixin.update
+    pop = DictMixin.pop
+    values = DictMixin.values
+    items = DictMixin.items
+    iterkeys = DictMixin.iterkeys
+    itervalues = DictMixin.itervalues
+    iteritems = DictMixin.iteritems
+
+    def __repr__(self):
+        if not self:
+            return '%s()' % (self.__class__.__name__,)
+        return '%s(%r)' % (self.__class__.__name__, self.items())
+
+    def copy(self):
+        return self.__class__(self)
+
+    @classmethod
+    def fromkeys(cls, iterable, value=None):
+        d = cls()
+        for key in iterable:
+            d[key] = value
+        return d
+
+    def __eq__(self, other):
+        if isinstance(other, OrderedDict):
+            if len(self) != len(other):
+                return False
+            for p, q in  zip(self.items(), other.items()):
+                if p != q:
+                    return False
+            return True
+        return dict.__eq__(self, other)
+
+    def __ne__(self, other):
+        return not self == other

=== modified file 'harvest/common/utils.py'
--- harvest/common/utils.py	2010-06-01 16:16:19 +0000
+++ harvest/common/utils.py	2010-07-14 06:16:47 +0000
@@ -23,3 +23,24 @@
 
     return "version %s (rev %s)" % (version, bzr_revno)
 
+
+def get_harvest_version_name(version_file, debug):
+    """
+    return a short string describing the version of harvest
+    """
+    
+    version_str = ""
+    
+    if debug:
+        try:
+            from bzrlib.branch import Branch
+            branch = Branch.open_containing('.')[0]
+            version_str = "Revision %s" % branch.revno()
+        except:
+            pass
+    elif os.path.exists(version_file):
+        f = email.message_from_file(open(version_file))
+        if "versionname" in f:
+            version_str = f["versionname"]
+    
+    return version_str
\ No newline at end of file

=== modified file 'harvest/filters/containers.py'
--- harvest/filters/containers.py	2010-06-24 06:53:17 +0000
+++ harvest/filters/containers.py	2010-07-14 06:16:47 +0000
@@ -1,4 +1,5 @@
 from harvest.common.url_tools import current_url_with_parameters
+from harvest.common.ordereddict import OrderedDict #while we wait for Python 2.7 :)
 
 class FilterContainer(object): #abstract
     """
@@ -9,17 +10,17 @@
     to exist for the entire life of the container.
     """
     
-    def __init__(self, filters_set): 
-        self.filters_dict = dict() #refers to Filter objects by their unique IDs
-        self.add_filters(filters_set)
+    def __init__(self, filters_list): 
+        self.filters_dict = OrderedDict() #refers to Filter objects by their unique IDs
+        self.add_filters(filters_list)
     
-    def add_filters(self, filters_set): #final
+    def add_filters(self, filters_list): #final
         """
-        Adds a set of filters to be children of this one and informs
+        Adds a list of filters to be children of this one and informs
         each child that it belongs to this container.
-        @param filter_set: a set of Filter objects
+        @param filter_list: a list of Filter objects
         """
-        for child in set(filters_set):
+        for child in list(filters_list):
             self.filters_dict[child.get_id()] = child
             child.set_container(self)
     
@@ -56,8 +57,8 @@
     update_from_http should be called with the current HttpRequest.
     """
     
-    def __init__(self, filters_set, default_parameters = dict()):
-        FilterContainer.__init__(self, filters_set)
+    def __init__(self, filters_list, default_parameters = dict()):
+        FilterContainer.__init__(self, filters_list)
         self.request = None #current http request
         self.default_parameters = default_parameters
     

=== modified file 'harvest/filters/filters.py'
--- harvest/filters/filters.py	2010-06-27 21:05:08 +0000
+++ harvest/filters/filters.py	2010-07-14 06:16:47 +0000
@@ -1,5 +1,5 @@
-#FIXME: Make ChoiceFilter a bit nicer so we don't need to call super() and all that bother from harvest.opportunities.filters.
-#TODO: adjust Filter.render() methods for custom template tags, with django.template.Template
+#FIXME: The order that items are rendered in ChoiceFilter and FilterGroup needs to be as specified in the constructor. Currently, we are not in control of the order.
+#TODO: adjust Filter.render() methods for custom template tags and use django.template.Template
 
 from containers import FilterContainer, FilterSystem
 from django.utils.safestring import mark_safe
@@ -27,11 +27,24 @@
     describing it for a user interface.
     """
     
-    #TODO: figure out get_system and get_full_name when set_container is called and store the value
+    #TODO: generate this automatically
+    html_class = 'filter'
+    """
+    The class that this object should have in its html representation.
+    A subclass should override this property to list all Filter classes
+    it inherits from, separated by spaces and in lower case.
+    """
     
-    def __init__(self, id_str): #final
+    def __init__(self, id_str, **kwargs): #final
         self.id_str = id_str #local name
         self.container = None #immediate container (FilterContainer)
+        
+        self.system = None #cache for self.get_system
+        self.full_name = None #cache for self.get_full_name
+        
+        self.name = self.id_str
+        if 'name' in kwargs:
+            self.name = kwargs['name']
     
     def get_id(self): #final
         """
@@ -56,27 +69,36 @@
     
     def get_system(self): #final
         """
-        @return: the FilterSystem that this filter ultimately belongs to
+        Returns the FilterSystem that this filter ultimately belongs to.
+        All objects in the system need to be created by the time this
+        method is called.
+        @return: the root FilterSystem
         """
-        container = self.get_container()
-        system = None
-        if isinstance(container, Filter): 
-            system = container.get_system()
-        elif isinstance(container, FilterSystem):
-            system = container
-        return system
+        if self.system == None:
+            container = self.get_container()
+            system = None
+            if isinstance(container, Filter): 
+                system = container.get_system()
+            elif isinstance(container, FilterSystem):
+                system = container
+            self.system = system
+        return self.system
     
     def get_full_name(self): #final
         """
         Returns the filter's full name, which should make sense from anywhere
         in the application. This name is in the format parent:child:child.
+        All objects in the system need to be created by the time this
+        method is called.
         @return: the filter's full name, which is a string
         """
-        full_name = self.get_id()
-        container = self.get_container()
-        if isinstance(container, Filter):
-            full_name = "%s:%s" % (container.get_full_name(), full_name)
-        return full_name
+        if self.full_name == None:
+            full_name = self.get_id()
+            container = self.get_container()
+            if isinstance(container, Filter):
+                full_name = "%s:%s" % (container.get_full_name(), full_name)
+            self.full_name = full_name
+        return self.full_name
     
     def set_value(self, value): #abstract
         """
@@ -92,15 +114,6 @@
         """
         raise NotImplementedError(self.get_value)
     
-    def serialize_value(self, value): #abstract
-        """
-        The inverse of set_value. Returns the given value as a string that could
-        be added to an HTTP query string.
-        @param value: the value to serialize, in a format native to this Filter (see get_value)
-        @return: a unicode string formatted for set_value
-        """
-        raise NotImplementedError(self.serialize_value)
-    
     def serialize(self, value = None): #final
         """
         Creates a dictionary of parameters to describe this object, either
@@ -114,17 +127,14 @@
         value_str = self.serialize_value(value)
         return {key : value_str}
     
-    def get_container_toggle_parameters(self): #final
-        """
-        Helper method to get the parameter for toggling this filter's state in
-        its container, if there is one.
-        @return: a dictionary of key:value pairs to generate new GET parameters
-        """
-        container = self.get_container()
-        params = dict()
-        if isinstance(container, FilterGroup):
-            params = container.serialize(container.get_value_with_selection(self.get_id()))
-        return params
+    def serialize_value(self, value): #abstract
+        """
+        The inverse of set_value. Returns the given value as a string that could
+        be added to an HTTP query string.
+        @param value: the value to serialize, in a format native to this Filter (see get_value)
+        @return: a unicode string formatted for set_value
+        """
+        raise NotImplementedError(self.serialize_value)
     
     def process_queryset(self, queryset): #abstract
         """
@@ -135,29 +145,62 @@
         """
         raise NotImplementedError(self.process_queryset)
     
-    def render(self): #final
+    def render(self, **kwargs): #final
         """
         @return: the default rendering of the filter itself in given context
         """
         return self.render_html()
     
-    def render_html(self):
+    def render_html(self, **kwargs): #final
+        """
+        @return: the entire filter, rendered as html
+        """
+        inner_html = self.render_html_inner(**kwargs)
+        
+        #safe because we are in full control of this content
+        return mark_safe(
+            u'<span class="%s" data-filter-fullname="%s">\n%s\n</span>' % \
+            (self.html_class,
+             self.get_full_name(),
+             inner_html ))
+    
+    def render_html_inner(self, **kwargs):
         """
         Extend this to return the html output for the filter itself.
-        The output should be very simple and semantically meaningful,
-        with no specific concern about formatting. It will be
-        placed within other  tags that describe its context, and it is
-        up to the template to describe style.
-        @return: a unicode string containing html representing this filter
-        """
-        system = self.get_system()
-        toggle_params = self.get_container_toggle_parameters()
-        href = system.get_url_with_parameters(toggle_params)
-        
-        return mark_safe(u'<a href="%s">(%s)</a>'
-            % (href, self.get_id()))
-
-
+        (The inside part, without the <span class=filter> boilerplate).
+        The output should be simple and semantically meaningful, with no
+        specific concern about formatting. It will be placed within other
+        tags that describe its context.
+        @return: the filter's contents, rendered as html
+        """
+        label = self.render_html_label(**kwargs)
+        if label: label = '<span class="filter-label">%s</span>' % label
+        else: label = ''
+        
+        value = self.render_html_value(**kwargs)
+        if value: value = '<span class="filter-value">%s</span>' % value
+        else: value = ''
+        
+        return '%s\n%s' % (label, value)
+    
+    def render_html_label(self, **kwargs):
+        """
+        @return: the filter's label, rendered as html
+        """
+        link_url = None
+        if 'toggle_href' in kwargs: link_url = kwargs['toggle_href']
+        
+        label = self.name
+        if link_url:
+            label = '<a class="item-toggle" href="%s">%s</a>' % (link_url, label)
+        
+        return label
+    
+    def render_html_value(self, **kwargs):
+        """
+        @return: the filter's value, rendered as html
+        """
+        return None
 
 
 class EditFilter(Filter): #abstract, extend in application
@@ -167,8 +210,10 @@
     Serialized as stored ("value")
     """
     
-    def __init__(self, id_str):
-        Filter.__init__(self, id_str)
+    html_class = 'filter editfilter'
+    
+    def __init__(self, id_str, **kwargs):
+        Filter.__init__(self, id_str, **kwargs)
         self.input_str = ""
     
     def set_value(self, value): #overrides Filter
@@ -180,13 +225,11 @@
     def serialize_value(self, value): #overrides Filter
         return value
     
-    def render_html(self):
-        system = self.get_system()
-        toggle_params = self.get_container_toggle_parameters()
-        href = system.get_url_with_parameters(toggle_params)
-        
-        return mark_safe(u'<a href="%s">%s: %s</a>'
-            % (href, self.get_id(), self.get_value()))
+    def render_html_value(self, **kwargs):
+        field_value = self.get_value()
+        if field_value:
+            field_value = 'value="%s"' % field_value 
+        return '<input type="text" placeholder="(type here)" spellcheck="false" %s />' % field_value
 
 
 class SetFilter(Filter): #abstract, extend in application
@@ -196,8 +239,10 @@
     Serialized as a comma-separated list ("dog,cat,horse,mouse")
     """
     
-    def __init__(self, id_str):
-        Filter.__init__(self, id_str)
+    html_class = 'filter setfilter'
+    
+    def __init__(self, id_str, **kwargs):
+        Filter.__init__(self, id_str, **kwargs)
         self.selected_set = set()
     
     def set_value(self, value): #overrides Filter
@@ -228,7 +273,7 @@
     
     def id_allowed(self, item_id):
         return True
-        
+
 
 class ChoiceFilter(SetFilter): #abstract, extend in application
     """
@@ -240,79 +285,75 @@
     Serialized as a comma-separated list, like SetFilter.
     """
     
-    def __init__(self, id_str, choices_dict):
-        SetFilter.__init__(self, id_str)
-        self.choices_dict = choices_dict
+    html_class = 'filter setfilter choicefilter'
+    
+    def __init__(self, id_str, choices_dict = None, **kwargs):
+        SetFilter.__init__(self, id_str, **kwargs)
+        if choices_dict:
+            self.choices_dict = choices_dict
+        else:
+            self.choices_dict = self.default_choices_dict()
+    
+    def default_choices_dict(self):
+        """
+        @return the default dictionary of choices if none is given to __init__
+        """
+        return None
     
     def id_allowed(self, item_id): #overrides SetFilter
         return item_id in self.choices_dict
     
-    def get_selected_items(self):
+    def get_selected_choices(self):
         return [self.choices_dict[s] for s in self.selected_set]
-        
-    def render_html(self): #overrides Filter
-        choices = ""
-        
-        for c in self.choices_dict:
-            c_render = self._render_html_choice(c)
-            if self.id_selected(c):
-                c_render = "<b>%s</b>" % c_render
-            choices += "<li>%s</li>" % c_render
-        
-        system = self.get_system()
-        toggle_params = self.get_container_toggle_parameters() 
-        self_href = system.get_url_with_parameters(toggle_params)
-        
-        return mark_safe(u'<a href="%s">%s</a>:<ul>%s</ul>' % (self_href, self.get_id(), choices))
-    
-    def _render_html_choice(self, item_id):
-        system = self.get_system()
+    
+    def render_html_value(self, **kwargs):
+        choices = ''
+        
+        for c_id in self.choices_dict:
+            c_render = self.render_html_value_choice(c_id)
+            li_params = 'data-item-id="%s"' % c_id
+            checkbox_inner = ''
+            if self.id_selected(c_id):
+                li_params = '%s data-selected' % li_params
+                checkbox_inner = '&#10003;' #a check mark
+            checkbox = '<span class="checkbox">%s</span>' % checkbox_inner
+            choices += '\n<li %s>\n%s\n%s\n</li>\n' % (li_params, checkbox, c_render)
+        
+        return '<ul>\n%s\n</ul>' % choices
+    
+    def render_html_value_choice(self, item_id):
         toggle_params = self.serialize(self.get_value_with_selection(item_id))
-        item_href = system.get_url_with_parameters(toggle_params)
+        item_href = self.get_system().get_url_with_parameters(toggle_params)
         
-        return mark_safe(u'<a href="%s">%s</a>' % (item_href, item_id))
-
-
-
-
-class FilterGroup(FilterContainer, SetFilter): #final
+        return mark_safe(u'<a class="item-toggle" href="%s">%s</a>' % (item_href, item_id))
+
+
+class FilterGroup(FilterContainer, ChoiceFilter): #final
     """
     A collection of other Filters, which are selected (enabled) according to the
-    rules of SetFilter.
-    
-    The do_queryset method mixes the output from all selected Filters, so only
-    the one for this FilterGroup needs to be (or should be) called.
-    
-    Serialized as a comma-separated list, like SetFilter.
+    rules of ChoiceFilter.
+    
+    The do_queryset method combines the output from all selected Filters.
+    
+    Serialized as a comma-separated list, like ChoiceFilter.
     """
     
-    def __init__(self, id_str, filters_set):
+    html_class = 'filter setfilter choicefilter filtergroup'
+    
+    def __init__(self, id_str, filters_set, **kwargs):
         FilterContainer.__init__(self, filters_set)
-        SetFilter.__init__(self, id_str) 
-    
-    def id_allowed(self, item_id): #overrides SetFilter
-        return item_id in self.filters_dict
-    
-    def get_selected_filters(self, filter_id):
-        return [self.filters_dict[s] for s in self.selected_set]
+        #self.filters_dict comes from FilterContainer's initializer
+        ChoiceFilter.__init__(self, id_str, self.filters_dict, **kwargs)
     
     def process_queryset(self, queryset): #overrides Filter
-        for f in self.selected_set:
-            queryset = self.filters_dict[f].process_queryset(queryset) #returns something like QuerySet.filter(blah)
+        for f in self.get_selected_choices():
+            queryset = f.process_queryset(queryset) #returns something like QuerySet.filter(blah)
         return queryset
     
-    def render_html(self): #overrides Filter
-        filters = ""
-        
-        for f in self.filters_dict:
-            f_render = self._render_html_filter(f)
-            if self.id_selected(f):
-                f_render = "<em>%s</em>" % f_render
-            filters += "<li>%s</li>" % f_render
-        
-        return mark_safe(u'%s:<ul>%s</ul>' % (self.get_id(), filters))
-    
-    def _render_html_filter(self, filter_id):
+    def render_html_value_choice(self, filter_id):
+        toggle_params = self.serialize(self.get_value_with_selection(filter_id))
+        toggle_href = self.get_system().get_url_with_parameters(toggle_params)
+        
         f = self.filters_dict[filter_id]
-        return f.render_html()
+        return f.render_html(toggle_href = toggle_href)
 

=== added file 'harvest/media/css/footer-pattern.png'
Binary files harvest/media/css/footer-pattern.png	1970-01-01 00:00:00 +0000 and harvest/media/css/footer-pattern.png	2010-07-14 06:16:47 +0000 differ
=== added file 'harvest/media/css/reset.css'
--- harvest/media/css/reset.css	1970-01-01 00:00:00 +0000
+++ harvest/media/css/reset.css	2010-07-14 06:16:47 +0000
@@ -0,0 +1,46 @@
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, font, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td {
+	margin: 0;
+	padding: 0;
+	border: 0;
+	outline: 0;
+	font-weight: inherit;
+	font-style: inherit;
+	font-size: 100%;
+	font-family: inherit;
+	vertical-align: baseline;
+}
+/* remember to define focus styles! */
+:focus {
+	outline: 0;
+}
+body {
+	line-height: 1;
+	color: black;
+	background: white;
+}
+ol, ul {
+	list-style: none;
+}
+/* tables still need 'cellspacing="0"' in the markup */
+table {
+	border-collapse: separate;
+	border-spacing: 0;
+}
+caption, th, td {
+	text-align: left;
+	font-weight: normal;
+}
+blockquote:before, blockquote:after,
+q:before, q:after {
+	content: "";
+}
+blockquote, q {
+	quotes: "" "";
+}

=== modified file 'harvest/media/css/style.css'
--- harvest/media/css/style.css	2010-03-02 16:06:21 +0000
+++ harvest/media/css/style.css	2010-07-14 06:16:47 +0000
@@ -1,191 +1,390 @@
 body {
-    background-image: url(../img/bgrepeat.jpg);
-    background-color: #D3CAAA;
-    background-repeat: repeat-x;
-    padding: 0;
-    margin: 0;
-}
+	background-color:rgb(255,255,255);
+	color:rgb(51,51,51);
+	
+	font-family:'Bitstream Vera Sans', 'DejaVu Sans', sans-serif;
+	font-size:14px;
+	line-height:1.2em;
+}
+
+h1,h2,h3,h4,h5,h6 {
+	color:rgb(0,0,0);
+	font-family:'Molengo', 'Bitstream Vera Sans', 'DejaVu Sans', sans-serif;
+}
+
+.bottom {
+	display:block;
+	clear:both;
+}
+
+strong {
+	color:rgb(0,0,0);
+	font-weight:bold;
+}
+small, .small {
+	color:rgb(80,80,80);
+	font-size:smaller;
+}
+em {
+	font-style:italic;
+}
+
+*:focus {
+	outline:rgb(244,116,33) dashed 1px;
+}
+
+a {
+	color:rgb(110,64,84);
+	text-decoration:inherit;
+}
+a:hover,
+a:focus {
+	/*color:rgb(162,129,143);*/
+	text-decoration:underline;
+}
+
+#header a,
+#footer a {
+	color:rgb(0,0,0);
+}
+
+input.placeheld {
+	/* only used in browsers that don't already do placeholder text */
+	color:rgb(180,180,180);
+}
+
+
 
 #container {
-    margin: 0 auto;
-    padding: 0 0 0 14px;
-    position: relative;
-    background-color: #fff;
-    background-image: url(../img/page-border-left-repeat.jpg);
-    background-repeat: repeat-y;
-    background-position: left;
-    width: 94%;
-    /*max-width: 950px;*/
-    min-width: 760px;
-}
+	display:block;
+	position:absolute;
+	width:100%;
+	min-width:600px;
+	min-height:100%;
+}
+
+
+
+#header {
+	display:block;
+	width:100%;
+	min-height:80px;
+	
+	padding-top:12px;
+	padding-bottom:12px;
+}
+#header #pagetitle {
+	display:inline;
+	position:static;
+	margin-left:80px;
+	margin-right:40px;
+	
+	text-transform:lowercase;
+	color:rgb(0,0,0);
+	font-family:'Molengo', 'Bitstream Vera Sans', 'DejaVu Sans', sans-serif;
+}
+#header #pagetitle #sitelogo {
+	width:auto; /* line up with #sitename font-size */
+	height:36px;
+}
+#header #pagetitle #sitename {
+	display:inline;
+	position:static;
+	
+	font-size:36px;
+}
+#header #pagetitle #releasename {
+	display:inline;
+	position:static;
+	
+	font-size:14px;
+	vertical-align:sub;
+}
+#header #userdata {
+	float:right;
+	margin-top:12px;
+	margin-left:40px;
+	margin-right:80px;
+	
+	text-align:right;
+}
+#header #userdata .username {
+}
+#header #userdata .loginbutton {
+}
+
 
 #content {
-    margin: 0;
-    padding: 0 13px 0 0;
-    min-height: 538px;
-    position: relative;
-    background-color: #fff;
-    background-image: url(../img/page-border-right-repeat.jpg);
-    background-repeat: repeat-y;
-    background-position: right;
-}
-
-#content a {
-    text-decoration: none;
-}
-
-#topNav {
-    width: 100%;
-    position: relative;
-    height: 70px;
-
-    background-image: url(../img/top.jpg);
-    background-repeat: repeat-x;
-    background-position: top;
-    padding-top: 10px;
-    z-index: 1;
-}
-
-#topNav a {
-    color: #656565;
-    text-decoration: none;
-    font-size: 80%;
-    border-bottom: 1px dotted #fff;
-}
-
-#topNav #whoami {
-    display: block;
-    margin: 0;
-    padding: 0 0px .5em 0px;
-    position: absolute;
-    top: 20px;
-    right: 0px;
-}
-
-#topNav #ubuntulogo {
-    margin: 0;
-    padding: 0;
-    border-style: none;
-
-    position: absolute;
-    top: 22px;
-    left: 0;
-}
-#bg-left {
-        position: absolute;
-        top: 0;
-        left: 0;
-        width: 14px;
-        height: 538px;
-        background-image: url(../img/page-border-left.jpg);
-        background-repeat: no-repeat;
-        background-position: top left;
-        z-index: 6;
-}
-#bg-right {
-        position: absolute;
-        top: 0;
-        right: 0;
-        width: 13px;
-        height: 538px;
-        background-image: url(../img/page-border-right.jpg);
-        background-repeat: no-repeat;
-        background-position: top right;
-        z-index: 6;
-}
-#bottom-left {
-        width: 14px;
-        height: 34px;
-        background-image: url(../img/footerbg-left.jpg);
-        position: absolute;
-        bottom: 0;
-        left: 0;
-        z-index: 7;
-}
-#bottom-right {
-        width: 13px;
-        height: 34px;
-        background-image: url(../img/footerbg-right.jpg);
-        position: absolute;
-        bottom: 0;
-        right: 0;
-        z-index: 7;
-}
-/* bodyouter provides the borders for the left navigation */
-/* see http://webhost.bridgew.edu/etribou/layouts/skidoo_too/ */
-#body {
-        position: relative;
-        overflow: hidden;
-        margin: 0 0;
-        padding-left: 0 50px;
-        min-height: 538px;
-}
-* html #body {
-        height: 1%;
-}
-#leftsidebar {
-        width: 205px;
-        float: right;
-        margin-left: -205px;
-}
+	clear:both;
+	padding-bottom:140px;
+}
+
+
+
+#filters {
+	display:block;
+	position:relative;
+	float:left;
+	min-width:160px;
+	
+	padding:0px 20px 20px 20px;
+	font-size:12px;
+	line-height:1.4em;
+	color:rgb(51,51,51);
+}
+#filters a {
+	/* these are self-explanatory; they should disappear */
+	display:inline-block;
+	height:100%;
+	
+	color:inherit;
+	text-decoration:inherit;
+	font-style:inherit;
+}
+
+#filters ul {
+	display:block;
+	margin-left:20px;
+	width:100%;
+}
+#filters ul li {
+	display:block;
+	width:100%;
+}
+
+
+#filters .checkbox {
+	/* checkbox element should always be the same size */
+	display:inline-block;
+	width:12px;
+	color:inherit;
+}
+
+#filters .setfilter > .filter-value > ul > li:not([data-selected]) > .filter > .filter-value {
+	/* parent filter is turned off */
+	color:rgb(140,140,140);
+}
+
+#filters .setfilter > .filter-value > ul > li.prelight-off > .checkbox {
+	/* prelight for an item about to be deselected */
+	color:rgb(140,140,140);
+	text-decoration:line-through;
+}
+#filters .setfilter > .filter-value > ul > li.prelight-on > .checkbox {
+	/* prelight for an item about to be selected */
+	color:inherit;
+}
+
+#filters .setfilter > .filter-value > ul > li.prelight-off > .filter > .filter-value {
+	/* parent filter is about to be turned off */
+	color:rgb(140,140,140);
+}
+#filters .setfilter > .filter-value > ul > li.prelight-on > .filter > .filter-value {
+	/* parent filter is about to be turned on */
+	color:inherit;
+}
+
+
+
+#filters > .filtergroup {
+	/* a top-level filter group */
+	display:block;
+	margin-bottom:4em;
+}
+#filters > .filtergroup > .filter-label {
+	display:block;
+	margin-bottom:.5em;
+	color:rgb(0,0,0);
+	font-size:14px;
+	font-weight:bold;
+}
+#filters > .filtergroup > .filter-value > ul {
+	margin-left:0px;
+}
+#filters > .filtergroup > .filter-value > ul > li {
+	padding-bottom:5px;
+}
+
+#filters .editfilter input {
+	width:8em;
+	border:none;
+	padding:0px 2px 0px 2px;
+	border-bottom:1px solid rgb(180,180,180);
+	
+	background-color:inherit;
+	color:inherit;
+	font:inherit;
+}
+#filters .editfilter input.placeheld {
+	color:rgb(180,180,180);
+}
+
+
+
+#results-pane {
+	display:block;
+	min-width:250px;
+	max-width:1000px;
+	padding:20px 20px 0px 20px;
+	overflow:auto;
+	line-height:1.6em;
+}
+
+#results-pane > #results-status {
+	position:relative;
+	display:none;
+	text-align:center;
+}
+#results-pane > #results-status > div {
+	display:inline-block;
+	width:300px;
+	height:30px;
+}
+
+#results > ul {
+	margin-left:20px;
+	margin-bottom:10px;
+}
+
+#results .sourcepackage {
+	display:block;
+	margin-top:5px;
+	margin-bottom:5px;
+	border:1px solid rgb(250,250,250);
+	-moz-border-radius:3px 3px 0px 0px;
+	border-radius:3px 3px 0px 0px;
+}
+
+#results .sourcepackage > .sourcepackage-header {
+	display:block;
+	padding:8px 20px 8px 20px;
+	-moz-border-radius:3px 3px 0px 0px;
+	border-radius:3px 3px 0px 0px; /* to line up with .sourcepackage's border */
+}
+#results .sourcepackage > a.sourcepackage-header {
+	color:inherit;
+	text-decoration:none;
+}
+#results .sourcepackage > .sourcepackage-header > .sourcepackage-name {
+	margin-right:10px;
+	color:rgb(0,0,0);
+	font-size:16px;
+}
+#results .sourcepackage > .sourcepackage-header > .sourcepackage-summary {
+	float:right;
+	text-align:right;
+	font-size:10px;
+}
+#results .sourcepackage > .sourcepackage-details {
+	display:block;
+	padding:0px 10px 5px 50px;
+}
+
+/* prelights */
+#results .sourcepackage > a.sourcepackage-header:hover,
+#results .sourcepackage > a.sourcepackage-header:focus {
+	/* use the opportunity count or experience measure here */
+	background-color:rgb(240,255,243);
+}
+#results .sourcepackage > a.sourcepackage-header:hover .sourcepackage-name,
+#results .sourcepackage > a.sourcepackage-header:focus .sourcepackage-name {
+	text-decoration:underline;
+}
+
+#results .sourcepackage > .sourcepackage-header > .status {
+	display:none; /* harvest.js will override this where necessary */
+}
+#results .sourcepackage > .sourcepackage-header > .status img {
+	width:16px;
+	height:16px;
+}
+
+/* expanded / collapsed state */
+#results .sourcepackage.expanded {
+	margin-bottom:10px;
+	border-color:rgb(200,200,200);
+	-moz-border-radius:3px;
+	border-radius:3px; /* round border on bottom as well */
+}
+#results .sourcepackage.collapsed > .sourcepackage-details {
+	display:none;
+}
+
+
 
 #footer {
-        background-image: url(../img/footerbg.jpg); 
-        background-repeat: repeat-x;
-        background-position: bottom;
-        padding: 0 0 0 0;
-}
-#footer .wrapper {
-        padding: 0 15px 5px 15px;
-        color: #656565;
-        font-size: 70%;
-        position: relative;
-}
-#footer .wrapper a {
-        color: #656565;
-        text-decoration: none;
-}
-#footer .wrapper p {
-        width: 70%;
-        font-size: 90%;
-}
-
-.pagination .current-page {
-    margin: 0px 2px;
-    font-weight: bold;
-}
-
-.pagination .pages {
-    margin: 0px 10px;
-}
-
-div.package_name { padding: 3px; }
-div.package_name span.name { font-weight: bold; }
-div.package_name span.count { font-size: 75%; }
-div.package_name:hover { background: #eee; }
-div.package_details { padding: 5px; display: none; }
-div.package_details:hover {}
-
-div.thresholdGREEN { background-color: #cfc; }
-div.thresholdYELLOW { background-color: #ffc; }
-div.thresholdRED { background-color: #fcc; }
-
-span.featureYES { font-weight: bold; }
-span.featureNO { font-size: 100%; }
-
-span.experience1 { float: right; content:url(../img/easy.png); }
-span.experience2 { float: right; content:url(../img/medium.png); }
-span.experience3 { float: right; content:url(../img/hard.png); }
-
-ul.toplevellist {
-    list-style-type: none;
-    border-bottom: 1px solid #999;
-    padding-left: 0px;
-    margin-left: 15px;
-}
-
-ul.toplevellist li div {
-    border-top: 1px solid #999;
-    border-left: 1px solid #999;
-    border-right: 1px solid #999;
-}
+	display:block;
+	position:absolute;
+	left:0px;
+	right:0px;
+	bottom:0px;
+	min-height:100px;
+	
+	overflow:visible;
+	background-image:url('footer-pattern.png');
+	background-position:left bottom;
+	background-repeat:repeat-x;
+	
+	padding-left:32px;
+	padding-right:32px;
+}
+#footnav {
+	display:block;
+	height:20px;
+	
+	padding:2px;
+	white-space:nowrap;
+	background-color:rgb(255,255,255);
+	font-size:16px;
+}
+#footnav a {
+	margin-left:1em;
+	margin-right:1em;
+}
+#footnav a:last-child {
+}
+#footnav .title {
+	margin-left:0em;
+	margin-right:4em;
+	text-decoration:none;
+}
+
+#smallprint {
+	margin-top:40px;
+	bottom:3px;
+	left:8px;
+	right:8px;
+	
+	color:rgb(120,120,120);
+	font-size:10px;
+	line-height:1.2em;
+}
+#smallprint #techdetails,
+#smallprint #copyright {
+	max-width:200px;
+	
+	padding:5px;
+	overflow:hidden;
+	white-space:nowrap;
+	text-overflow:ellipsis;
+	background-color:rgb(255,255,255);
+}
+#smallprint:hover #techdetails,
+#smallprint:hover #copyright,
+#smallprint:focus #techdetails,
+#smallprint:focus #copyright {
+	max-width:none;
+	overflow:visible;
+}
+#smallprint #copyright {
+	float:left;
+	
+	text-align:left;
+}
+#smallprint #techdetails {
+	float:right;
+	
+	text-align:right;
+	text-transform:lowercase;
+}
+\
\ No newline at end of file

=== removed file 'harvest/media/img/bgrepeat.jpg'
Binary files harvest/media/img/bgrepeat.jpg	2009-07-08 11:31:32 +0000 and harvest/media/img/bgrepeat.jpg	1970-01-01 00:00:00 +0000 differ
=== removed file 'harvest/media/img/footerbg-left.jpg'
Binary files harvest/media/img/footerbg-left.jpg	2009-08-26 14:19:44 +0000 and harvest/media/img/footerbg-left.jpg	1970-01-01 00:00:00 +0000 differ
=== removed file 'harvest/media/img/footerbg-right.jpg'
Binary files harvest/media/img/footerbg-right.jpg	2009-08-26 14:19:44 +0000 and harvest/media/img/footerbg-right.jpg	1970-01-01 00:00:00 +0000 differ
=== removed file 'harvest/media/img/footerbg.jpg'
Binary files harvest/media/img/footerbg.jpg	2009-08-26 14:19:44 +0000 and harvest/media/img/footerbg.jpg	1970-01-01 00:00:00 +0000 differ
=== added file 'harvest/media/img/logo_humanity-search-icon.png'
Binary files harvest/media/img/logo_humanity-search-icon.png	1970-01-01 00:00:00 +0000 and harvest/media/img/logo_humanity-search-icon.png	2010-07-14 06:16:47 +0000 differ
=== removed file 'harvest/media/img/page-border-left-repeat.jpg'
Binary files harvest/media/img/page-border-left-repeat.jpg	2009-07-08 11:31:32 +0000 and harvest/media/img/page-border-left-repeat.jpg	1970-01-01 00:00:00 +0000 differ
=== removed file 'harvest/media/img/page-border-left.jpg'
Binary files harvest/media/img/page-border-left.jpg	2009-07-08 11:31:32 +0000 and harvest/media/img/page-border-left.jpg	1970-01-01 00:00:00 +0000 differ
=== removed file 'harvest/media/img/page-border-right-repeat.jpg'
Binary files harvest/media/img/page-border-right-repeat.jpg	2009-07-08 11:31:32 +0000 and harvest/media/img/page-border-right-repeat.jpg	1970-01-01 00:00:00 +0000 differ
=== removed file 'harvest/media/img/page-border-right.jpg'
Binary files harvest/media/img/page-border-right.jpg	2009-07-08 11:31:32 +0000 and harvest/media/img/page-border-right.jpg	1970-01-01 00:00:00 +0000 differ
=== added file 'harvest/media/img/pkg-status-loading.gif'
Binary files harvest/media/img/pkg-status-loading.gif	1970-01-01 00:00:00 +0000 and harvest/media/img/pkg-status-loading.gif	2010-07-14 06:16:47 +0000 differ
=== added file 'harvest/media/img/results-status-loading.gif'
Binary files harvest/media/img/results-status-loading.gif	1970-01-01 00:00:00 +0000 and harvest/media/img/results-status-loading.gif	2010-07-14 06:16:47 +0000 differ
=== added file 'harvest/media/img/results-status-waiting.gif'
Binary files harvest/media/img/results-status-waiting.gif	1970-01-01 00:00:00 +0000 and harvest/media/img/results-status-waiting.gif	2010-07-14 06:16:47 +0000 differ
=== removed file 'harvest/media/img/top.jpg'
Binary files harvest/media/img/top.jpg	2009-08-26 14:19:44 +0000 and harvest/media/img/top.jpg	1970-01-01 00:00:00 +0000 differ
=== removed file 'harvest/media/img/ubuntulogo.png'
Binary files harvest/media/img/ubuntulogo.png	2009-07-08 11:31:32 +0000 and harvest/media/img/ubuntulogo.png	1970-01-01 00:00:00 +0000 differ
=== added file 'harvest/media/js/harvest.js'
--- harvest/media/js/harvest.js	1970-01-01 00:00:00 +0000
+++ harvest/media/js/harvest.js	2010-07-14 06:16:47 +0000
@@ -0,0 +1,620 @@
+/* depends on:
+	jquery core 1.4.2 or later <http://jquery.com>
+	jquery scrollstay plugin
+	jquery placeheld plugin <http://plugins.jquery.com/project/placeheld>
+*/
+
+
+// Array Remove - By John Resig (MIT Licensed)
+Array.prototype.remove = function(from, to) {
+  var rest = this.slice((to || from) + 1 || this.length);
+  this.length = from < 0 ? this.length + from : from;
+  return this.push.apply(this, rest);
+};
+
+
+var harvest_results;
+var harvest_filters_list;
+
+var MEDIA_PATH = '/media/' /* we should get this from Django somehow */
+
+
+function Filter (dom_node) {
+	/* Attaches to a .filter object in the document. Handles events
+	   specific to each type of filter and provides some extra data
+	   and utilities. */
+	
+	var filter = this; /* so we can access this from event handlers */
+	
+	$(dom_node).data('filter',this); /* so we can get here from the JQuery object */
+	
+	this.full_name = $(dom_node).attr('data-filter-fullname');
+	this.parent_filter_node = $(dom_node).parent().closest('.filter');
+	this.container = $(dom_node).closest('li'); /* the list item in the parent that this belongs to */
+	this.value_node = $(dom_node).children('.filter-value');
+	
+	
+	this.is_class = function (class_name) {
+		return $(dom_node).hasClass(class_name);
+	}
+	
+	
+	this.get_value_serialized = function () {
+		/* Returns the value of this filter, serialized in the same
+		   format we would use in Harvest's Django end.
+		   Does nothing by default. Implement this in each
+		   "class"-specific initializer below. */
+		
+		return null;
+	}
+	
+	this.value_changed = function () {
+		/* Should be called when the filter's value has changed.
+		   This posts the new value to the global Results object */
+		
+		value = this.get_value_serialized();
+		if ( value != null ) {
+			harvest_results.post_query(this.full_name, value);
+		}
+	}
+	
+	
+	/********/
+	/* Ugly hacks for talking to the parent node */
+	
+	this.get_parent_filtergroup = function () {
+		/* Returns the FilterGroup that is a parent of this filter.
+		   Returns null if the parent doesn't exist or isn't a FilterGroup. */
+		parent = null;
+		if ( this.parent_filter_node ) {
+			parent_test = this.parent_filter_node.data('filter');
+			if ( parent_test && parent_test.is_class('filtergroup') ) parent = parent_test;
+		} 
+		return parent;
+	}
+	
+	
+	this.force_enable_prelight_add = function () {
+		/* Tells the parent (if there is one) to create a prelight for
+		   enabling this item.
+		   We assume the parent is a FilterGroup, which is probably right. */
+		parent_filter = this.get_parent_filtergroup();
+		if ( parent_filter && ! parent_filter.item_is_selected(this.container) ) {
+			/* only do this if we weren't already selected */
+			parent_filter.toggle_item_prelight_add(this.container);
+		}
+	}
+	
+	this.force_enable_prelight_clear = function () {
+		/* Tells the parent (if there is one) to remove the prelight for
+		   enabling this item.
+		   We assume the parent is a FilterGroup. */
+		parent_filter = this.get_parent_filtergroup()
+		
+		if ( parent_filter ) parent_filter.toggle_item_prelight_clear(this.container);
+	}
+	
+	
+	this.force_enable = function () {
+		/* Tells the parent (if there is one) to enable this item,
+		   because it said so!
+		   We assume the parent is a FilterGroup. */
+		parent_filter = this.get_parent_filtergroup();
+		if ( parent_filter && ! parent_filter.item_is_selected(this.container) ) {
+			parent_filter.enable_item(this.container);
+		}
+	}
+	
+	
+	/* Callback functions */
+	this.enabled = function() {} /* called when this filter is enabled */
+	this.disabled = function() {} /* called when this filter is disabled */
+	
+	
+	/********/
+	/* "Class"-specific initialization stuff. Setting up functions and
+	   handlers in filter.value_node */
+	
+	if ( this.is_class('choicefilter') ) {
+		var list_items = this.value_node.children('ul').children('li');
+		
+		
+		/* Callback functions */
+		this.item_enabled = function(item) {} /* called after enabling an item */
+		this.item_disabled = function(item) {} /* called after disabling an item */
+		
+		
+		this.get_value_serialized = function () {
+			var item_ids = Array();
+			/* we add the data-item-id attribute of all selected items */
+			list_items.each(function () {
+				if ($(this).attr('data-selected') != null) {
+					item_ids.push($(this).attr('data-item-id'));
+				}
+			} );
+			return item_ids.join(',');
+		}
+		
+		
+		this.item_is_selected = function (item) {
+			return ( item.attr('data-selected') != null );
+		}
+		
+		this.toggle_item_prelight_add = function (item) {
+			if ( this.item_is_selected(item) ) {
+				item.addClass('prelight-off');
+			} else {
+				item.addClass('prelight-on');
+				item.children('.checkbox').html('&#10003;'); /* decoration :) */
+				this.force_enable_prelight_add();
+			}
+		}
+		
+		this.toggle_item_prelight_clear = function (item) {
+			/* remove the decoration in the checkbox if we added it */
+			if ( ! this.item_is_selected(item) ) {
+				item.children('.checkbox').html('');
+			}
+			
+			item.removeClass('prelight-on');
+			item.removeClass('prelight-off');
+			this.force_enable_prelight_clear();
+		}
+		
+		
+		this.enable_item = function (item) {
+			item.attr('data-selected','');
+			item.children('.checkbox').html('&#10003;');
+			
+			this.force_enable();
+			this.value_changed();
+			
+			this.item_enabled(item);
+		}
+		
+		this.disable_item = function (item) {
+			item.removeAttr('data-selected');
+			item.children('.checkbox').html('');
+			
+			this.value_changed();
+			
+			this.item_disabled(item);
+		}
+		
+		this.toggle_item = function (item) {
+			if ( this.item_is_selected(item) ) {
+				this.disable_item(item);
+			} else {
+				this.enable_item(item);
+			}
+		}
+		
+		
+		this.get_item_toggle_node = function (item) {
+			/* returns the node(s) used to toggle the given item in this filter */
+			return item.children('a.item-toggle');
+		}
+		
+		
+		/* "Subclass" setup goes here because we need to do overrides before any movement happens */
+		if ( this.is_class('filtergroup') ) {
+			this.item_enabled = function (item) {
+				/* Tell child it has been enabled. It might do something cool! */
+				child_filter = item.children('.filter').data('filter');
+				child_filter.enabled();
+			}
+			
+			this.item_disabled = function (item) {
+				/* Tell child it has been disabled. */
+				child_filter = item.children('.filter').data('filter');
+				child_filter.disabled();
+			}
+		
+			this.get_item_toggle_node = function (item) {
+				return item.children('.filter').children('.filter-label').children('a.item-toggle');
+			}
+		}
+		
+		
+		/* setup the event handlers we described on all the items */
+		list_items.each(function () {
+			var item = $(this);
+			toggle_node = filter.get_item_toggle_node(item);
+			toggle_node.bind('mouseenter focusin', function () { filter.toggle_item_prelight_add(item); } );
+			toggle_node.bind('mouseleave focusout', function () { filter.toggle_item_prelight_clear(item); } );
+			
+			toggle_node.bind('click', function () {
+				filter.toggle_item(item);
+				filter.toggle_item_prelight_clear(item);
+				
+				return false; /* stops link from being followed */
+			} );
+		});
+	}
+	
+	
+	if ( this.is_class('editfilter') ) {
+		var edit_field = this.value_node.children('input');
+		
+		
+		this.edit_field_changed = function() {
+			this.force_enable();
+			this.value_changed();
+		}
+		
+		this.get_value_serialized = function () {
+			return escape(edit_field.val());
+		}
+		
+		this.enabled = function () {
+			edit_field.focus();
+		}
+		
+		/* TODO: add a clear button to this element, like Webkit does for input type="search" */ 
+		/* we could handle 'change' instead of 'input' to only check value when typing has stopped */
+		edit_field.bind('input', function () { filter.edit_field_changed(); } );
+	}
+	
+	
+	/* send initial state to Results object so it can behave neatly */
+	value = this.get_value_serialized();
+	if ( value != null ) {
+		harvest_results.update_current_query(this.full_name, value);
+	}
+}
+
+
+function Package (dom_node, details_url, opps_query) {
+	/* Created for each package inside the #results element */
+	
+	/* gtksourceview gives an error box around "package", so we'll have to forego the convention */
+	var pkg = this;
+	
+	this.id = $(dom_node).attr('data-results-packageid');
+	this.details = $(dom_node).children('.sourcepackage-details');
+	
+	this.loading_xhr = null;
+	this.is_expanded = false;
+	
+	/* Callback functions */
+	this.expanded = function() {} /* called when the package is expanded */
+	this.collapsed = function() {} /* called when the package is collapsed */
+	
+	
+	this.show_status = function (status) {
+		var indicator = dom_node.children('.sourcepackage-header').children('.status');
+		if ( status ) {
+			indicator.stop(true, true);
+			var status_img = MEDIA_PATH + 'img/pkg-status-'+status+'.gif';
+			indicator.html('<img src="'+status_img+'" />');
+			if ( this.visible_status == null ) {
+				indicator.fadeIn(1500);
+			}
+		} else {
+			/* stop the previous animation as it was; we don't expect it to finish usually */
+			indicator.stop(true, false);
+			indicator.fadeOut(150, function () {
+				indicator.html('');
+			});
+		}
+		
+		this.visible_status = status;
+	}
+	
+	this.hide_status = function (status) {
+		if ( this.visible_status == status ) this.show_status(null);
+	}
+	
+	
+	this.expand = function () {
+		if ( this.is_expanded ) return;
+		
+		var show = function () {
+			/* from #"results .sourcepackage.expanded" rule in /media/css/style.css */
+			fadeto = 'rgb(200,200,200);';
+			dom_node.animate({borderTopColor:    fadeto,
+							borderRightColor:  fadeto,
+							borderBottomColor: fadeto,
+							borderLeftColor:   fadeto}, 150);
+			pkg.details.animate({height: 'show', opacity: 'show'}, 150);
+			dom_node.removeClass('collapsed');
+			dom_node.addClass('expanded');
+		}
+	
+		/* run the callback saying this package will be expanded */
+		this.is_expanded = true;
+		this.expanded();
+	
+		/* first, get package details from the server if they aren't already here */
+		/* this poorly assumes that this.details contains no text at all if we haven't hit the server */
+		if ( $.trim(this.details.html()) == '' ) {
+			this.show_status('loading');
+			
+			this.loading_xhr = $.ajax({
+				type: "GET",
+				url: details_url + this.id,
+				data: opps_query,
+				dataType: 'html',
+				complete: function (xhr, status) {
+						pkg.hide_status('loading');
+						pkg.loading_xhr = null;
+					},
+				success: function (data, status, xhr) {
+						/* check that xhr.status is set. If it isn't, xhr.abort was called */
+						if (xhr.status) {
+							pkg.details.html(data);
+							show();
+						}
+					},
+				}); 
+		} else {
+			show();
+		}
+	}
+	
+	this.stop_loading = function () {
+		/* stops loading package details */
+		if ( this.loading_xhr != null ) this.loading_xhr.abort();
+	}
+	
+	this.collapse = function () {
+		this.stop_loading();
+		if ( ! this.is_expanded ) return;
+		
+		/* run the callback saying this package will be collapsed */
+		this.is_expanded = false;
+		this.collapsed();
+	
+		fadeto = 'rgb(250,250,250);';
+		dom_node.animate({borderTopColor:    fadeto,
+						borderRightColor:  fadeto,
+						borderBottomColor: fadeto,
+						borderLeftColor:   fadeto}, 150);
+		pkg.details.animate({height: 'hide', opacity: 'hide'}, 150);
+		dom_node.removeClass('expanded');
+		dom_node.addClass('collapsed');
+	}
+	
+	
+	
+	/********/
+	/* Object initialization */
+	
+	dom_node.children('a.sourcepackage-header').bind('click', function () {
+		if ( pkg.is_expanded || pkg.loading_xhr != null ) {
+			pkg.collapse();
+		} else {
+			pkg.expand();
+		}
+	
+		return false;
+	});
+}
+
+
+function Results (dom_node) {
+	/* Attached to the single #results-pane in the document. Receives
+	   new query parameters from Filter objects, grabs and displays new
+	   results in the contained #results element. */
+	
+	/* The current_query variable is set with the current querystring,
+	   but some filters could already have been set with Harvest's
+	   default parameters while the querystring doesn't mention them.
+	   On its own, this isn't a problem, but it may lead to some odd
+	   behaviour. We should fix it by setting current_query to include
+	   all of the defaults in Harvest's Django portion. */
+	
+	var results = this;
+	
+	this.query_countdown = null;
+	this.loading_xhr = null;
+	
+	this.current_query = {}; /* we need to figure out what this is without using the querystring */
+	this.future_query = {};
+	
+	this.container = $(dom_node);
+	this.query_url = $(dom_node).attr('data-results-url');
+	this.output = $(dom_node).children('#results');
+	this.status_bubble = $(dom_node).children('#results-status');
+	
+	this.packages = [];
+	this.expanded_pkgs = [];
+	
+	
+	this.update_packages = function () {
+		/* Perform bits of setup with a new list of sourcepackages */
+		var results_packages = this.output.find('li.sourcepackage');
+		
+		var old_expanded_pkgs = this.expanded_pkgs;
+		
+		/* dereferences existing Packages. We expect that they'll be cleaned up by the GC */
+		this.packages = [];
+		this.expanded_pkgs = [];
+		
+		results_packages.each(function () {
+			var dom_node = $(this);
+			var details_url = results.query_url + '/';
+			var opps_query = results.current_query; /* would be nice to only send properties starting with opp: */
+			
+			var pkg = new Package(dom_node, details_url, opps_query);
+			pkg.expanded = function() {
+				results.expanded_pkgs.push(this.id);
+				results.update_current_query('expand_pkg', results.expanded_pkgs.join(','));
+			}
+			pkg.collapsed = function() {
+				array_index = results.expanded_pkgs.indexOf(pkg.id);
+				if ( array_index > -1 ) {
+					results.expanded_pkgs.remove(array_index);
+					results.update_current_query('expand_pkg', results.expanded_pkgs.join(','));
+				}
+			}
+			results.packages.push(pkg);
+			
+			/* keep track of expanded packages */
+			if ( pkg.is_expanded ) {
+				results.expanded_pkgs.push(pkg.id);
+			} else if ( old_expanded_pkgs.indexOf(pkg.id) > -1 ) {
+				/* this package was expanded last time */
+				pkg.expand();
+			}
+		});
+		
+		this.update_current_query('expand_pkg', this.expanded_pkgs.join(','));
+	}
+	
+	
+	this.show_status = function (status) {
+		/* Shows the given status in the #status_bubble.
+		   Set status to 'waiting', 'loading', or null to hide the box.
+		   Note: values of status directly correlate to image filenames
+		   at MEDIA_PATH/img/results-status-*.gif */
+		this.status_bubble.stop(true,true);
+		if ( status ) {
+			var status_img = MEDIA_PATH + 'img/results-status-'+status+'.gif';
+			this.status_bubble.html('<div><img src="'+status_img+'" /></div>');
+			if ( this.visible_status == null ) {
+				this.status_bubble.animate({height: 'show', opacity: 'show'}, 250);
+			}
+		} else {
+			this.status_bubble.animate({height: 'hide', opacity: 'hide'}, 150,
+				function () { results.status_bubble.html(''); }
+			);
+		}
+		
+		this.visible_status = status;
+	}
+	
+	this.hide_status = function (status) {
+		/* Hides the status bubble if it shows the given status */
+		if ( this.visible_status == status ) this.show_status(null);
+	}
+	
+	
+	this.load_results = function () {
+		/* Begins loading results for future_query */
+		var load_query = $.extend({}, this.current_query, this.future_query);
+		
+		results.show_status('loading');
+		
+		this.loading_xhr = $.ajax({
+			type: "GET",
+			url: this.query_url,
+			data: load_query,
+			dataType: 'html',
+			complete: function (xhr, status) {
+					results.hide_status('loading');
+					results.loading_xhr = null;
+				},
+			success: function (data, status, xhr) {
+					/* We have to work around this jquery bug: http://dev.jquery.com/ticket/6173
+					   success callback is still being called after xhr.abort() */
+					if (xhr.status) {
+						/* display the (plain html) results we have receieved */
+						results.output.html(data);
+						results.current_query = load_query;
+						results.future_query = {};
+						results.update_packages();
+					
+						/* display statistics in the footer */
+						time_header = xhr.getResponseHeader('X-Django-Request-Time')
+						if (time_header) {
+							$('#requeststats').html('Results generated in '+parseFloat(time_header).toFixed(2) + ' seconds');
+						}
+					}
+				},
+			});
+	}
+	
+	this.stop_loading = function () {
+		/* stops loading, or returns silently if that is not happening */
+		if ( this.loading_xhr != null ) this.loading_xhr.abort();
+	}
+	
+	
+	this.reset_countdown = function () {
+		/* Sets the query countdown timer for 1.5s.
+		   When the timer ends, we load the results for future_query. */
+		this.stop_countdown(true);
+		this.show_status('waiting');
+		/* stop anything that is loading already */
+		this.stop_loading();
+		
+		this.query_countdown = setTimeout(
+			function (results) {
+				results.load_results();
+				results.query_countdown = null;
+			}, 1500, this);
+	}
+	
+	this.stop_countdown = function (wait_next) {
+		/* Stops the query countdown timer. */
+		clearTimeout(this.query_countdown);
+		this.query_countdown = null;
+		
+		if (! wait_next) this.hide_status('waiting');
+	}
+	
+	
+	this.post_query = function (key, value) {
+		/* Adds the given key/value pair to future_query. If it is
+		   necessary, a timer is started to get the results for
+		   future_query. */
+		if ( this.current_query[key] == value ) {
+			/* the user has reverted a change; value is the same as before */
+			delete this.future_query[key];
+			
+			if ( $.isEmptyObject(this.future_query) ) {
+				/* no point getting results, so stop and wait for new input. */
+				this.stop_countdown();
+				this.stop_loading();
+			}
+		} else {
+			this.future_query[key] = value;
+			/* start the timer from 0, waiting to apply the new future_query */
+			this.reset_countdown();
+		}
+	}
+	
+	this.update_current_query = function (key, value) {
+		/* Adds the given key/value pair as part of current_query. For
+		   example, when we first load the page it is useful to make
+		   sure we know the current state of all the filters. */
+		
+		/* TODO: do something if there is an ongoing XHR request to make
+		   sure we don't lose the new current_value... */
+		this.current_query[key] = value;
+	}
+	
+	
+	/********/
+	/* Object initialization */
+	
+	this.update_packages();
+}
+
+
+
+function create_filters () {
+	/* Creates all filters for the document at once. */
+	$('#filters').scrollStay({ offset:12 });
+	
+	var filters_list = new Array();
+	$('#filters .filter').each(function (i) {
+		filters_list.push(new Filter(this));
+	});
+	
+	return filters_list;
+}
+
+function create_results () {
+	return new Results($('#results-pane'));
+}
+
+
+
+$(document).ready(function () {
+	harvest_results = create_results();
+	harvest_filters_list = create_filters();
+	
+	$('input[placeholder]').placeHeld();
+});

=== added file 'harvest/media/js/jquery-1.4.2.min.js'
--- harvest/media/js/jquery-1.4.2.min.js	1970-01-01 00:00:00 +0000
+++ harvest/media/js/jquery-1.4.2.min.js	2010-07-14 06:16:47 +0000
@@ -0,0 +1,154 @@
+/*!
+ * jQuery JavaScript Library v1.4.2
+ * http://jquery.com/
+ *
+ * Copyright 2010, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2010, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Sat Feb 13 22:33:48 2010 -0500
+ */
+(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i?
+e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r=
+j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g,
+"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e=
+true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
+Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
+(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
+a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
+"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
+function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)||
+c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",
+L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,
+"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+
+a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f],
+d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===
+a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&&
+!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=
+true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML="   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
+var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
+parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
+false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
+s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
+applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
+else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
+a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
+w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
+cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ",
+i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ",
+" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=
+this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i=
+e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
+c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
+a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
+function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
+k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
+C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!=
+null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=
+e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
+f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
+if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
+d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this,
+"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=
+a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,
+isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit=
+{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};
+if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
+e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
+"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
+d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&
+!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},
+toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector,
+u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),
+function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];
+if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
+t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
+g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[];
+for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-
+1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
+CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
+relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]=
+l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[];
+h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
+CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
+g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
+text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
+setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
+h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m=
+m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
+"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
+h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition||
+!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m=
+h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
+q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>";
+if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
+(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
+function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/,
+gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
+c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
+{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
+"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
+d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
+a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
+1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)?
+a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
+c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
+wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
+prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
+this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
+return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
+""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
+this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]||
+u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length===
+1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
+return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
+""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
+c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
+c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
+function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
+Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
+"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
+a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
+a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==
+"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this},
+serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),
+function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,
+global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&
+e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)?
+"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===
+false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B=
+false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",
+c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E||
+d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x);
+g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===
+1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b===
+"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional;
+if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");
+this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],
+"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},
+animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing=
+j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);
+this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration===
+"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||
+c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;
+this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=
+this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,
+e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||
+c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?
+function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=
+this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle;
+k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&
+f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
+a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b);
+c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,
+d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-
+f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset":
+"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in
+e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);

=== added file 'harvest/media/js/jquery.placeheld.js'
--- harvest/media/js/jquery.placeheld.js	1970-01-01 00:00:00 +0000
+++ harvest/media/js/jquery.placeheld.js	2010-07-14 06:16:47 +0000
@@ -0,0 +1,54 @@
+// PlaceHeld jQuery plugin by [Max Wheeler](max@xxxxxxxxxxxxxxx)
+// 
+// Copyright (c) 2010 Max Wheeler. Licensed under the [WTFPL](http://sam.zoy.org/wtfpl/)
+// Dependencies: jQuery
+//
+// Changelog:
+// * v1.0.0 (2010-04-21) Initial Version
+// * v1.0.1 (2010-04-29) Minified using YUI compressor instead ofo JSMin
+// * v1.0.2 (2010-05-10) Removed default text from form submission; moved placeholder support check outside for() loop
+// * v1.0.3 (2010-05-14) Added check for "placheld" class before clearing default text on form submission
+
+(function($){
+  $.placeHeld = function(el, options){
+    var base = this;
+    base.$el = $(el);
+    base.el = el;
+    base.$el.data("placeHeld", base);
+    base.placeholderText = base.$el.attr("placeholder");
+    
+    base.init = function(){
+      base.options = $.extend({},$.placeHeld.defaultOptions, options);
+      base.$el.bind('blur', base.holdPlace).bind('focus', base.releasePlace).trigger('blur');
+      base.$el.parents('form').bind('submit', base.clearPlace);
+    };
+    // Hold with the default value attribute
+    base.holdPlace = function() {
+      var value = base.$el.val();
+      if (!value) base.$el.val(base.placeholderText).addClass(base.options.className);
+    };
+    // Refill with the default value attribute
+    base.releasePlace = function() {
+      var value = base.$el.val();
+      if (value == base.placeholderText) base.$el.val('').removeClass(base.options.className);
+    };
+    // Refill with the default value attribute
+    base.clearPlace = function() {
+      var value = base.$el.val();
+      if (value == base.placeholderText && base.$el.hasClass(base.options.className)) base.$el.val('');
+    };
+    base.init();
+  };
+  
+  $.placeHeld.defaultOptions = { className: "placeheld" };
+  
+  $.fn.placeHeld = function(options) {
+
+	// Check for placeholder attribute support
+	if (!!("placeholder" in $('<input>')[0])) return;
+	
+    return this.each(function() {
+      (new $.placeHeld(this, options));
+    });
+  };
+})(jQuery);
\ No newline at end of file

=== added file 'harvest/media/js/jquery.scrollstay.js'
--- harvest/media/js/jquery.scrollstay.js	1970-01-01 00:00:00 +0000
+++ harvest/media/js/jquery.scrollstay.js	2010-07-14 06:16:47 +0000
@@ -0,0 +1,163 @@
+/**
+ * jquery.scrollstay.js
+ * scrollStay for minimalists.
+ * Derived from jquery.scrollStay.js by R.A. Ray.
+ * Copyright (c) 2008 Net Perspective (http://kitchen.net-perspective.com/)
+ * Licensed under the MIT License (http://www.opensource.org/licenses/mit-license.php)
+ * 
+ * Removed all animation, delay, cookies and killSwitch.
+ * 
+ * @author Dylan McCall
+ *
+ * @projectDescription	jQuery plugin that quietly keeps an element visible as the user scrolls
+ * 
+ * @version 0.4.0
+ * 
+ * @requires jquery.js (tested with 1.2.6)
+ * 
+ * @param offset			int - Number of pixels box should remain from top of viewport
+ * 								default: 0
+ * @param container	string - ID of the containing div
+ * 								default: box's immediate parent
+ * @param relativeTo	string - Scroll animation can be relative to either the 'top' or 'bottom' of the viewport
+ * 								default: 'top'
+ */
+
+( function( $ ) {
+	
+	$.scrollStay = function ( box, options )
+	{ 
+		// Convert box into a jQuery object
+		box = $( box );
+		
+		// 'box' is the object to be animated
+		var position = box.css( 'position' );
+		
+		function ani()
+		{
+			// The script runs on every scroll which really means many times during a scroll.
+			// We don't want multiple slides to queue up.
+			box.queue( [ ] );
+			
+			// A bunch of values we need to determine where to animate to
+			var viewportHeight = parseInt( $( window ).height() );
+			var pageScroll =  parseInt( $( document ).scrollTop() );
+			var parentTop =  parseInt( box.cont.offset().top );
+			var parentHeight = parseInt( box.cont.attr( 'offsetHeight' ) );
+			var boxHeight = parseInt( box.attr( 'offsetHeight' ) + ( parseInt( box.css( 'marginTop' ) ) || 0 ) + ( parseInt( box.css( 'marginBottom' ) ) || 0 ) );
+			var aniTop;
+			
+			/* Make sure the user wants the animation to happen, and it
+			   will be helpful. (It isn't helpful if the user is trying
+			   to scroll within the box!) */
+			if ( isActive && viewportHeight > boxHeight )
+			{
+				// If the box should animate relative to the top of the window
+				if ( options.relativeTo == 'top' )
+				{
+					// Don't animate until the top of the window is close enough to the top of the box
+					if ( box.initialOffsetTop >= ( pageScroll + options.offset ) )
+					{
+						aniTop = box.initialTop;
+					}
+					else
+					{
+						aniTop = Math.min( ( Math.max( ( -parentTop ), ( pageScroll - box.initialOffsetTop + box.initialTop ) ) + options.offset ), ( parentHeight - boxHeight - box.paddingAdjustment ) );
+					}
+				}
+				// If the box should animate relative to the bottom of the window
+				else if ( options.relativeTo == 'bottom' )
+				{
+					// Don't animate until the bottom of the window is close enough to the bottom of the box
+					if ( ( box.initialOffsetTop + boxHeight ) >= ( pageScroll + options.offset + viewportHeight ) )
+					{
+						aniTop = box.initialTop;
+					}
+					else
+					{
+						aniTop = Math.min( ( pageScroll + viewportHeight - boxHeight - options.offset ), ( parentHeight - boxHeight ) );
+					}
+				}
+				
+				// Checks to see if the relevant scroll was the last one
+				// "-20" is to account for inaccuracy in the timeout
+				if ( ( new Date().getTime() - box.lastScroll ) >= -20 )
+				{
+					box.css({ top: aniTop });
+				}
+			}
+		};
+		
+		// For user-initiated stopping of the slide
+		var isActive = true;
+		
+		// If no parent ID was specified, and the immediate parent does not have an ID
+		// options.container will be undefined. So we need to figure out the parent element.
+		if ( options.container == '')
+		{
+			box.cont = box.parent();
+		}
+		else
+		{
+			box.cont = $( '#' + options.container );
+		}
+		
+		// Finds the default positioning of the box.
+		box.initialOffsetTop =  parseInt( box.offset().top );
+		box.initialTop = parseInt( box.css( 'top' ) ) || 0;
+		
+		// Hack to fix different treatment of boxes positioned 'absolute' and 'relative'
+		if ( box.css( 'position' ) == 'relative' )
+		{
+			box.paddingAdjustment = parseInt( box.cont.css( 'paddingTop' ) ) + parseInt( box.cont.css( 'paddingBottom' ) );
+		}
+		else
+		{
+			box.paddingAdjustment = 0;
+		}
+		
+		// Animate the box when the page is scrolled
+		$( window ).scroll( function ()
+			{
+				ani();
+				
+				// To check against right before setting the animation
+				box.lastScroll = new Date().getTime();
+			}
+		);
+		
+		// Animate the box when the page is resized
+		$( window ).resize( function ()
+			{
+				ani();
+				
+				// To check against right before setting the animation
+				box.lastScroll = new Date().getTime();
+			}
+		);
+
+		// Run an initial animation on page load
+		box.lastScroll = 0;
+		
+		ani();
+	};
+	
+	$.fn.scrollStay = function ( options )
+	{
+		options = options || {};
+		options.relativeTo = options.relativeTo || 'top';
+		options.offset = options.offset || 0;
+		options.container = options.container || this.parent().attr( 'id' );
+		
+		this.each( function() 
+			{
+				new $.scrollStay( this, options );
+			}
+		);
+		
+		return this;
+	};
+})( jQuery );
+
+
+

=== removed file 'harvest/media/js/yui-min.js'
--- harvest/media/js/yui-min.js	2010-01-05 01:47:06 +0000
+++ harvest/media/js/yui-min.js	1970-01-01 00:00:00 +0000
@@ -1,10 +0,0 @@
-/*
-Copyright (c) 2009, Yahoo! Inc. All rights reserved.
-Code licensed under the BSD License:
-http://developer.yahoo.net/yui/license.txt
-version: 3.0.0
-build: 1549
-*/
-(function(){var I={},B=new Date().getTime(),A,E,H=function(){if(window.addEventListener){return function(M,L,K,J){M.addEventListener(L,K,(!!J));};}else{if(window.attachEvent){return function(L,K,J){L.attachEvent("on"+K,J);};}else{return function(){};}}}(),F=function(){if(window.removeEventListener){return function(M,L,K,J){M.removeEventListener(L,K,!!J);};}else{if(window.detachEvent){return function(L,K,J){L.detachEvent("on"+K,J);};}else{return function(){};}}}(),D=function(){YUI.Env.windowLoaded=true;YUI.Env.DOMReady=true;F(window,"load",D);},C={"io.xdrReady":1,"io.xdrResponse":1},G=Array.prototype.slice;if(typeof YUI==="undefined"||!YUI){YUI=function(O,N,M,L,J){var K=this,R=arguments,Q,P=R.length;if(!(K instanceof YUI)){return new YUI(O,N,M,L,J);}else{K._init();for(Q=0;Q<P;Q++){K._config(R[Q]);}K._setup();return K;}};}YUI.prototype={_config:function(N){N=N||{};var O=this.config,L,K,J,M;M=O.modules;for(L in N){if(M&&L=="modules"){J=N[L];for(K in J){if(J.hasOwnProperty(K)){M[K]=J[K];}}}else{if(L=="win"){O[L]=N[L].contentWindow||N[L];O.doc=O[L].document;}else{O[L]=N[L];}}}},_init:function(){var J="3.0.0",K=this;if(J.indexOf("@")>-1){J="test";}K.version=J;K.Env={mods:{},cdn:"http://yui.yahooapis.com/"+J+"/build/",bootstrapped:false,_idx:0,_used:{},_attached:{},_yidx:0,_uidx:0,_loaded:{}};K.Env._loaded[J]={};if(YUI.Env){K.Env._yidx=(++YUI.Env._yidx);K.Env._guidp=("yui_"+J+"-"+K.Env._yidx+"-"+B).replace(/\./g,"_");K.id=K.stamp(K);I[K.id]=K;}K.constructor=YUI;K.config={win:window||{},doc:document,debug:true,useBrowserConsole:true,throwFail:true,bootstrap:true,fetchCSS:true,base:function(){var L,M,O,N;M=document.getElementsByTagName("script");for(O=0;O<M.length;O=O+1){N=M[O].src.match(/^(.*)yui\/yui[\.\-].*js(\?.*)?$/);L=N&&N[1];if(L){break;}}return L||K.Env.cdn;}(),loaderPath:"loader/loader-min.js"};},_setup:function(J){this.use("yui-base");},applyTo:function(P,O,L){if(!(O in C)){this.log(O+": applyTo not allowed","warn","yui");return null;}var K=I[P],N,J,M;if(K){N=O.split(".");J=K;for(M=0;M<N.length;M=M+1){J=J[N[M]];if(!J){this.log("applyTo not found: "+O,"warn","yui");}}return J.apply(K,L);}return null;},add:function(K,M,J,L){YUI.Env.mods[K]={name:K,fn:M,version:J,details:L||{}};return this;},_attach:function(K,O){var T=YUI.Env.mods,L=this.Env._attached,Q,P=K.length,M,N,R,S,J;for(Q=0;Q<P;Q=Q+1){M=K[Q];N=T[M];if(!L[M]&&N){L[M]=true;R=N.details;S=R.requires;J=R.use;if(S){this._attach(this.Array(S));}if(N.fn){N.fn(this);}if(J){this._attach(this.Array(J));}}}},use:function(){if(this._loading){this._useQueue=this._useQueue||new this.Queue();this._useQueue.add(G.call(arguments,0));return this;}var K=this,U=G.call(arguments,0),Z=YUI.Env.mods,b=K.Env._used,V,O=U[0],M=false,X=U[U.length-1],W=K.config.bootstrap,P,R,N,Q=[],J=[],S=K.config.fetchCSS,T=function(d){if(b[d]){return;}var Y=Z[d],c,e,a;if(Y){b[d]=true;e=Y.details.requires;a=Y.details.use;}else{if(!YUI.Env._loaded[K.version][d]){Q.push(d);}else{b[d]=true;}}if(e){if(K.Lang.isString(e)){T(e);}else{for(c=0;c<e.length;c=c+1){T(e[c]);}}}J.push(d);},L;if(typeof X==="function"){U.pop();}else{X=null;}L=function(Y){Y=Y||{success:true,msg:"not dynamic"};if(X){X(K,Y);}if(K.fire){K.fire("yui:load",K,Y);}K._loading=false;if(K._useQueue&&K._useQueue.size()&&!K._loading){K.use.apply(K,K._useQueue.next());}};if(O==="*"){U=[];for(P in Z){if(Z.hasOwnProperty(P)){U.push(P);}}if(X){U.push(X);}return K.use.apply(K,U);}if(K.Loader){M=true;V=new K.Loader(K.config);V.require(U);V.ignoreRegistered=true;V.allowRollup=false;V.calculate(null,(S)?null:"js");U=V.sorted;}N=U.length;for(R=0;R<N;R=R+1){T(U[R]);}N=Q.length;if(N){Q=K.Object.keys(K.Array.hash(Q));}if(W&&N&&K.Loader){K._loading=true;V=new K.Loader(K.config);V.onSuccess=L;V.onFailure=L;V.onTimeout=L;V.context=K;V.attaching=U;V.require((S)?Q:U);V.insert(null,(S)?null:"js");}else{if(W&&N&&K.Get&&!K.Env.bootstrapped){K._loading=true;U=K.Array(arguments,0,true);K.Get.script(K.config.base+K.config.loaderPath,{onEnd:function(){K._loading=false;K.Env.bootstrapped=true;K._attach(["loader"]);K.use.apply(K,U);}});return K;}else{if(N){}K._attach(J);L();}}return K;},namespace:function(){var J=arguments,N=null,L,K,M;for(L=0;L<J.length;L=L+1){M=(""+J[L]).split(".");N=this;for(K=(M[0]=="YAHOO")?1:0;K<M.length;K=K+1){N[M[K]]=N[M[K]]||{};N=N[M[K]];}}return N;},log:function(){},error:function(K,J){if(this.config.throwFail){throw (J||new Error(K));}else{this.message(K,"error");}return this;},guid:function(J){var K=this.Env._guidp+(++this.Env._uidx);return(J)?(J+K):K;},stamp:function(L,M){if(!L){return L;}var J=(typeof L==="string")?L:L._yuid;if(!J){J=this.guid();if(!M){try{L._yuid=J;}catch(K){J=null;}}}return J;}};A=YUI.prototype;for(E in A){YUI[E]=A[E];}YUI._init();H(window,"load",D);YUI.Env.add=H;YUI.Env.remove=F;})();YUI.add("yui-base",function(B){function A(){this._init();this.add.apply(this,arguments);}A.prototype={_init:function(){this._q=[];},next:function(){return this._q.shift();},add:function(){B.Array.each(B.Array(arguments,0,true),function(C){this._q.push(C);},this);return this;},size:function(){return this._q.length;}};B.Queue=A;(function(){B.Lang=B.Lang||{};var R=B.Lang,G="array",I="boolean",D="date",M="error",S="function",H="number",K="null",F="object",O="regexp",N="string",C=Object.prototype.toString,P="undefined",E={"undefined":P,"number":H,"boolean":I,"string":N,"[object Function]":S,"[object RegExp]":O,"[object Array]":G,"[object Date]":D,"[object Error]":M},J=/^\s+|\s+$/g,Q="";R.isArray=function(L){return R.type(L)===G;};R.isBoolean=function(L){return typeof L===I;};R.isFunction=function(L){return R.type(L)===S;};R.isDate=function(L){return R.type(L)===D;};R.isNull=function(L){return L===null;};R.isNumber=function(L){return typeof L===H&&isFinite(L);};R.isObject=function(T,L){return(T&&(typeof T===F||(!L&&R.isFunction(T))))||false;};R.isString=function(L){return typeof L===N;};R.isUndefined=function(L){return typeof L===P;};R.trim=function(L){try{return L.replace(J,Q);}catch(T){return L;}};R.isValue=function(T){var L=R.type(T);
-switch(L){case H:return isFinite(T);case K:case P:return false;default:return !!(L);}};R.type=function(L){return E[typeof L]||E[C.call(L)]||(L?F:K);};})();(function(){var C=B.Lang,D=Array.prototype,E=function(M,J,L){var I=(L)?2:B.Array.test(M),H,G,F;if(I){try{return D.slice.call(M,J||0);}catch(K){F=[];for(H=0,G=M.length;H<G;H=H+1){F.push(M[H]);}return F;}}else{return[M];}};B.Array=E;E.test=function(H){var F=0;if(C.isObject(H)){if(C.isArray(H)){F=1;}else{try{if("length" in H&&!("tagName" in H)&&!("alert" in H)&&(!B.Lang.isFunction(H.size)||H.size()>1)){F=2;}}catch(G){}}}return F;};E.each=(D.forEach)?function(F,G,H){D.forEach.call(F||[],G,H||B);return B;}:function(G,I,J){var F=(G&&G.length)||0,H;for(H=0;H<F;H=H+1){I.call(J||B,G[H],H,G);}return B;};E.hash=function(H,G){var K={},F=H.length,J=G&&G.length,I;for(I=0;I<F;I=I+1){K[H[I]]=(J&&J>I)?G[I]:true;}return K;};E.indexOf=(D.indexOf)?function(F,G){return D.indexOf.call(F,G);}:function(F,H){for(var G=0;G<F.length;G=G+1){if(F[G]===H){return G;}}return -1;};E.numericSort=function(G,F){return(G-F);};E.some=(D.some)?function(F,G,H){return D.some.call(F,G,H);}:function(G,I,J){var F=G.length,H;for(H=0;H<F;H=H+1){if(I.call(J,G[H],H,G)){return true;}}return false;};})();(function(){var D=B.Lang,C="__",E=function(H,G){var F=G.toString;if(D.isFunction(F)&&F!=Object.prototype.toString){H.toString=F;}};B.merge=function(){var G=arguments,I={},H,F=G.length;for(H=0;H<F;H=H+1){B.mix(I,G[H],true);}return I;};B.mix=function(F,O,H,N,L,M){if(!O||!F){return F||B;}if(L){switch(L){case 1:return B.mix(F.prototype,O.prototype,H,N,0,M);case 2:B.mix(F.prototype,O.prototype,H,N,0,M);break;case 3:return B.mix(F,O.prototype,H,N,0,M);case 4:return B.mix(F.prototype,O,H,N,0,M);default:}}var K=M&&D.isArray(F),J,I,G;if(N&&N.length){for(J=0,I=N.length;J<I;++J){G=N[J];if(G in O){if(M&&D.isObject(F[G],true)){B.mix(F[G],O[G]);}else{if(!K&&(H||!(G in F))){F[G]=O[G];}else{if(K){F.push(O[G]);}}}}}}else{for(J in O){if(M&&D.isObject(F[J],true)){B.mix(F[J],O[J]);}else{if(!K&&(H||!(J in F))){F[J]=O[J];}else{if(K){F.push(O[J]);}}}}if(B.UA.ie){E(F,O);}}return F;};B.cached=function(H,F,G){F=F||{};return function(L,K){var J=(K)?Array.prototype.join.call(arguments,C):L,I=F[J];if(!(J in F)||(G&&F[J]==G)){F[J]=H.apply(H,arguments);}return F[J];};};})();(function(){B.Object=function(H){var G=function(){};G.prototype=H;return new G();};var E=B.Object,D=undefined,C=function(J,I){var H=(I===2),F=(H)?0:[],G;for(G in J){if(H){F++;}else{if(J.hasOwnProperty(G)){F.push((I)?J[G]:G);}}}return F;};E.keys=function(F){return C(F);};E.values=function(F){return C(F,1);};E.size=function(F){return C(F,2);};E.hasKey=function(G,F){return(F in G);};E.hasValue=function(G,F){return(B.Array.indexOf(E.values(G),F)>-1);};E.owns=function(G,F){return(G.hasOwnProperty(F));};E.each=function(J,I,K,H){var G=K||B,F;for(F in J){if(H||J.hasOwnProperty(F)){I.call(G,J[F],F,J);}}return B;};E.getValue=function(J,I){var H=B.Array(I),F=H.length,G;for(G=0;J!==D&&G<F;G=G+1){J=J[H[G]];}return J;};E.setValue=function(L,J,K){var I=B.Array(J),H=I.length-1,F,G=L;if(H>=0){for(F=0;G!==D&&F<H;F=F+1){G=G[I[F]];}if(G!==D){G[I[F]]=K;}else{return D;}}return L;};})();B.UA=function(){var F=function(J){var K=0;return parseFloat(J.replace(/\./g,function(){return(K++==1)?"":".";}));},I=navigator,H={ie:0,opera:0,gecko:0,webkit:0,mobile:null,air:0,caja:I.cajaVersion,secure:false,os:null},E=I&&I.userAgent,G=B.config.win.location,D=G&&G.href,C;H.secure=D&&(D.toLowerCase().indexOf("https")===0);if(E){if((/windows|win32/i).test(E)){H.os="windows";}else{if((/macintosh/i).test(E)){H.os="macintosh";}}if((/KHTML/).test(E)){H.webkit=1;}C=E.match(/AppleWebKit\/([^\s]*)/);if(C&&C[1]){H.webkit=F(C[1]);if(/ Mobile\//.test(E)){H.mobile="Apple";}else{C=E.match(/NokiaN[^\/]*|Android \d\.\d|webOS\/\d\.\d/);if(C){H.mobile=C[0];}}C=E.match(/AdobeAIR\/([^\s]*)/);if(C){H.air=C[0];}}if(!H.webkit){C=E.match(/Opera[\s\/]([^\s]*)/);if(C&&C[1]){H.opera=F(C[1]);C=E.match(/Opera Mini[^;]*/);if(C){H.mobile=C[0];}}else{C=E.match(/MSIE\s([^;]*)/);if(C&&C[1]){H.ie=F(C[1]);}else{C=E.match(/Gecko\/([^\s]*)/);if(C){H.gecko=1;C=E.match(/rv:([^\s\)]*)/);if(C&&C[1]){H.gecko=F(C[1]);}}}}}}return H;}();(function(){var F=["yui-base"],D,I=B.config,H=YUI.Env.mods,G,E;B.use.apply(B,F);if(I.core){D=I.core;}else{D=[];G=["get","loader","yui-log","yui-later"];for(E=0;E<G.length;E++){if(H[G[E]]){D.push(G[E]);}}}B.use.apply(B,D);})();},"3.0.0");YUI.add("get",function(A){(function(){var C=A.UA,B=A.Lang,E="text/javascript",F="text/css",D="stylesheet";A.Get=function(){var M={},K=0,U=false,W=function(a,X,b){var Y=b||A.config.win,c=Y.document,e=c.createElement(a),Z;for(Z in X){if(X[Z]&&X.hasOwnProperty(Z)){e.setAttribute(Z,X[Z]);}}return e;},T=function(Y,Z,X){var a={id:A.guid(),type:F,rel:D,href:Y};if(X){A.mix(a,X);}return W("link",a,Z);},S=function(Y,Z,X){var a={id:A.guid(),type:E,src:Y};if(X){A.mix(a,X);}return W("script",a,Z);},N=function(c){var X=M[c],Y,a,g,e,j,b,Z,f;if(X){Y=X.nodes;a=Y.length;g=X.win.document;e=g.getElementsByTagName("head")[0];if(X.insertBefore){j=L(X.insertBefore,c);if(j){e=j.parentNode;}}for(b=0;b<a;b=b+1){Z=Y[b];if(Z.clearAttributes){Z.clearAttributes();}else{for(f in Z){delete Z[f];}}e.removeChild(Z);}}X.nodes=[];},P=function(Y,Z,X){return{tId:Y.tId,win:Y.win,data:Y.data,nodes:Y.nodes,msg:Z,statusText:X,purge:function(){N(this.tId);}};},O=function(b,a,X){var Y=M[b],Z;if(Y&&Y.onEnd){Z=Y.context||Y;Y.onEnd.call(Z,P(Y,a,X));}},V=function(a,Z){var X=M[a],Y;if(X.timer){clearTimeout(X.timer);}if(X.onFailure){Y=X.context||X;X.onFailure.call(Y,P(X,Z));}O(a,Z,"failure");},L=function(X,a){var Y=M[a],Z=(B.isString(X))?Y.win.document.getElementById(X):X;if(!Z){V(a,"target node not found: "+X);}return Z;},I=function(a){var X=M[a],Z,Y;if(X.timer){clearTimeout(X.timer);}X.finished=true;if(X.aborted){Z="transaction "+a+" was aborted";V(a,Z);return;}if(X.onSuccess){Y=X.context||X;X.onSuccess.call(Y,P(X));}O(a,Z,"OK");},Q=function(Z){var X=M[Z],Y;if(X.onTimeout){Y=X.context||X;X.onTimeout.call(Y,P(X));
-}O(Z,"timeout","timeout");},H=function(Z,c){var Y=M[Z],b,g,f,e,a,X,i;if(Y.timer){clearTimeout(Y.timer);}if(Y.aborted){b="transaction "+Z+" was aborted";V(Z,b);return;}if(c){Y.url.shift();if(Y.varName){Y.varName.shift();}}else{Y.url=(B.isString(Y.url))?[Y.url]:Y.url;if(Y.varName){Y.varName=(B.isString(Y.varName))?[Y.varName]:Y.varName;}}g=Y.win;f=g.document;e=f.getElementsByTagName("head")[0];if(Y.url.length===0){I(Z);return;}X=Y.url[0];if(!X){Y.url.shift();return H(Z);}if(Y.timeout){Y.timer=setTimeout(function(){Q(Z);},Y.timeout);}if(Y.type==="script"){a=S(X,g,Y.attributes);}else{a=T(X,g,Y.attributes);}J(Y.type,a,Z,X,g,Y.url.length);Y.nodes.push(a);if(Y.insertBefore){i=L(Y.insertBefore,Z);if(i){i.parentNode.insertBefore(a,i);}}else{e.appendChild(a);}if((C.webkit||C.gecko)&&Y.type==="css"){H(Z,X);}},G=function(){if(U){return;}U=true;var X,Y;for(X in M){if(M.hasOwnProperty(X)){Y=M[X];if(Y.autopurge&&Y.finished){N(Y.tId);delete M[X];}}}U=false;},R=function(Y,X,Z){Z=Z||{};var c="q"+(K++),a,b=Z.purgethreshold||A.Get.PURGE_THRESH;if(K%b===0){G();}M[c]=A.merge(Z,{tId:c,type:Y,url:X,finished:false,nodes:[]});a=M[c];a.win=a.win||A.config.win;a.context=a.context||a;a.autopurge=("autopurge" in a)?a.autopurge:(Y==="script")?true:false;if(Z.charset){a.attributes=a.attributes||{};a.attributes.charset=Z.charset;}setTimeout(function(){H(c);},0);return{tId:c};},J=function(Z,e,d,Y,c,b,X){var a=X||H;if(C.ie){e.onreadystatechange=function(){var f=this.readyState;if("loaded"===f||"complete"===f){e.onreadystatechange=null;a(d,Y);}};}else{if(C.webkit){if(Z==="script"){e.addEventListener("load",function(){a(d,Y);});}}else{e.onload=function(){a(d,Y);};e.onerror=function(f){V(d,f+": "+Y);};}}};return{PURGE_THRESH:20,_finalize:function(X){setTimeout(function(){I(X);},0);},abort:function(Y){var Z=(B.isString(Y))?Y:Y.tId,X=M[Z];if(X){X.aborted=true;}},script:function(X,Y){return R("script",X,Y);},css:function(X,Y){return R("css",X,Y);}};}();})();},"3.0.0");YUI.add("yui-log",function(A){(function(){var D=A,F="yui:log",B="undefined",C={debug:1,info:1,warn:1,error:1},E;D.log=function(I,Q,G,O){var H=D,P=H.config,K=false,N,L,J,M;if(P.debug){if(G){N=P.logExclude;L=P.logInclude;if(L&&!(G in L)){K=1;}else{if(N&&(G in N)){K=1;}}}if(!K){if(P.useBrowserConsole){J=(G)?G+": "+I:I;if(typeof console!=B&&console.log){M=(Q&&console[Q]&&(Q in C))?Q:"log";console[M](J);}else{if(typeof opera!=B){opera.postError(J);}}}if(H.fire&&!O){if(!E){H.publish(F,{broadcast:2,emitFacade:1});E=1;}H.fire(F,{msg:I,cat:Q,src:G});}}}return H;};D.message=function(){return D.log.apply(D,arguments);};})();},"3.0.0",{requires:["yui-base"]});YUI.add("yui-later",function(A){(function(){var B=A.Lang,C=function(K,E,L,G,H){K=K||0;E=E||{};var F=L,J=A.Array(G),I,D;if(B.isString(L)){F=E[L];}if(!F){}I=function(){F.apply(E,J);};D=(H)?setInterval(I,K):setTimeout(I,K);return{id:D,interval:H,cancel:function(){if(this.interval){clearInterval(D);}else{clearTimeout(D);}}};};A.later=C;B.later=C;})();},"3.0.0",{requires:["yui-base"]});YUI.add("yui",function(A){},"3.0.0",{use:["yui-base","get","yui-log","yui-later"]});
\ No newline at end of file

=== modified file 'harvest/opportunities/filters.py'
--- harvest/opportunities/filters.py	2010-06-24 06:53:17 +0000
+++ harvest/opportunities/filters.py	2010-07-14 06:16:47 +0000
@@ -1,4 +1,5 @@
 from harvest.filters import filters, containers
+from harvest.common.ordereddict import OrderedDict
 import models
 
 class PkgNameFilter(filters.EditFilter):
@@ -6,30 +7,30 @@
         return queryset.filter(name__startswith = self.get_value())
 
 class PkgSetFilter(filters.ChoiceFilter):
-    def __init__(self, id_str):
-        choices_dict = dict()
-        for s in models.PackageSet.objects.all():
+    def default_choices_dict(self):
+        choices_dict = OrderedDict()
+        for s in models.PackageSet.objects.all(): #TODO: find a way to sort these
             choices_dict[s.name] = s
-        super(PkgSetFilter, self).__init__(id_str, choices_dict)
+        return choices_dict
     
     def process_queryset(self, queryset):
-        return queryset.filter(packagesets__in=self.get_selected_items())
+        return queryset.filter(packagesets__in = self.get_selected_choices())
 
 
 
 class OppFeaturedFilter(filters.Filter):
     def process_queryset(self, queryset):
-        return queryset.filter(opportunitylist__featured=True)
+        return queryset.filter(opportunitylist__featured = True)
 
 class OppListFilter(filters.ChoiceFilter):
-    def __init__(self, id_str):
-        choices_dict = dict()
-        for l in models.OpportunityList.objects.all():
+    def default_choices_dict(self):
+        choices_dict = OrderedDict()
+        for l in models.OpportunityList.objects.all(): #TODO: find a way to sort these
             choices_dict[l.name] = l
-        super(OppListFilter, self).__init__(id_str, choices_dict)
+        return choices_dict
     
     def process_queryset(self, queryset):
-        return queryset.filter(opportunitylist__in=self.get_selected_items())
+        return queryset.filter(opportunitylist__in = self.get_selected_choices())
 
 
 #we don't really need to create a special type here, but it may be handy
@@ -37,17 +38,19 @@
     def __init__(self):
         super(HarvestFilters, self).__init__(
             [
-                filters.FilterGroup("pkg", [
-                    PkgNameFilter("name"),
-                    PkgSetFilter("set")
-                ] ),
-                filters.FilterGroup("opp", [
-                    OppFeaturedFilter("featured"),
-                    OppListFilter("list")
-                ] )
+                filters.FilterGroup('pkg', [
+                    PkgNameFilter('name', name='Named'),
+                    PkgSetFilter('set', name='Package sets')
+                ], name='Packages' ),
+                filters.FilterGroup('opp', [
+                    OppFeaturedFilter('featured', name='Featured'),
+                    OppListFilter('list', name='Selected')
+                ], name='Opportunities' )
             ],
-            default_parameters = { "pkg" : "name,set",
-                                   "pkg:name" : "ged",
-                                   "pkg:set" : "ubuntu-desktop" }
+            default_parameters = { 'pkg' : 'set',
+                                   'pkg:set' : 'ubuntu-desktop',
+                                   'opp' : 'list',
+                                   'opp:list' : 'bitesize' }
+            #TODO: change to no defaults, detect that case in view and templates and provide helpful instructions in the results pane.
         )
 

=== removed directory 'harvest/opportunities/templates'
=== removed directory 'harvest/opportunities/templates/opportunities'
=== removed file 'harvest/opportunities/templates/opportunities/opportunities_by_package.html'
--- harvest/opportunities/templates/opportunities/opportunities_by_package.html	2010-07-12 09:33:48 +0000
+++ harvest/opportunities/templates/opportunities/opportunities_by_package.html	1970-01-01 00:00:00 +0000
@@ -1,67 +0,0 @@
-{% extends 'base.html' %}
-{% load i18n %}
-
-{% block title %}Opportunities by Package - {{ block.super }}{% endblock %}
-
-{% block content %}
-<div class="mainpage">
-
-<h1>{% trans "Opportunities By Package" %}</h1>
-
-{% if sources.object_list %}
-  <ul class="toplevellist">
-  {% for source in sources.object_list %}
-    <li>
-      <div class="package_name threshold{{ source.opportunity_class }}">
-        <span class="name"><a href="{% url sourcepackage_detail source.name %}">{{ source.name }}</a></span>
-        <span class="count">
-	  {% blocktrans count source.valid_opportunities|length as counter %}(1 opportunity){% plural %}({{ counter }} opportunities){% endblocktrans %}
-        </span>
-      </div>
-      <div class="package_details">
-        <ul>
-        {% for opportunity in source.valid_opportunities %}
-	  {% include "opportunities/opportunity_detail.inc.html" %}
-        {% endfor %}
-        </ul>
-      </div>
-    </li>
-  {% endfor %}
-  </ul>
-
-  <div class="pagination">
-    <span class="step-links">
-    {% if sources.has_previous %}
-      <a href="?page={{ sources.previous_page_number }}">previous</a>
-    {% endif %}
-
-    <span class="current">
-      Page {{ sources.number }} of {{ sources.paginator.num_pages }}.
-    </span>
-
-    {% if sources.has_next %}
-      <a href="?page={{ sources.next_page_number }}">next</a>
-    {% endif %}
-    </span>
-  </div>
-
-{% else %}
-  <p>{% trans "There are currently no opportunities in Harvest. :(" %}</p>
-{% endif %}
-
-</div>
-
-<script type="text/javascript">
-YUI().use('node', function(Y) {
-
-  Y.all('.package_name').on('click', function(e) {
-    // XXX: rockstar: Currently, this is kinda jumpy.  It'd be nice if it was
-    // all sexy animated.
-    Y.all('.package_details').setStyle('display', 'none');
-    e.currentTarget.next().setStyle('display', 'block');
-  });
-
-});
-
-</script>
-{% endblock %}

=== removed file 'harvest/opportunities/templates/opportunities/opportunities_by_type.html'
--- harvest/opportunities/templates/opportunities/opportunities_by_type.html	2010-07-12 09:33:48 +0000
+++ harvest/opportunities/templates/opportunities/opportunities_by_type.html	1970-01-01 00:00:00 +0000
@@ -1,28 +0,0 @@
-{% extends 'base.html' %}
-{% load i18n %}
-
-{% block title %}Opportunities by Type - {{ block.super }}{% endblock %}
-
-{% block content %}
-<div class="mainpage">
-
-<h1>{% trans "Opportunities By Type" %}</h1>
-
-{% if types.object_list %}
-  <ul class="toplevellist">
-  {% for type in types.object_list %}
-    <li>
-      <div class="package_name threshold{{ type.opportunity_class }}">
-        <span class="name"><a href="{{ type.get_absolute_url }}">{{ type.name }}</a></span>
-        <span class="count">
-          {% blocktrans count source.valid_opportunities.count as counter %}(1 opportunity){% plural %}({{ counter }} opportunities){% endblocktrans %}
-        </span>
-      </div>
-  {% endfor %}
-  </ul>
-{% else %}
-  <p>{% trans "There are currently no opportunities in Harvest. :(" %}</p>
-{% endif %}
-
-</div>
-{% endblock %}

=== modified file 'harvest/opportunities/urls.py'
--- harvest/opportunities/urls.py	2010-05-28 02:11:18 +0000
+++ harvest/opportunities/urls.py	2010-07-14 06:16:47 +0000
@@ -1,34 +1,11 @@
 from django.conf.urls.defaults import *
 
 urlpatterns = patterns('',
-    url(r'^$', 'opportunities.views.opportunity_index', name='opportunity_index'),
-
     url(r'^opportunity/(?P<opportunity_id>[\d]+)/edit$', 'opportunities.views.opportunity_edit', name='opportunity_edit'),
     url(r'^opportunity/(?P<opportunity_id>[\d]+)/$', 'opportunities.views.opportunity_detail', name='opportunity_detail'),
-    url(r'^opportunity/$', 'opportunities.views.opportunity_list', name='opportunity_list'),
-
-    url(r'^opportunity-list/(?P<opportunitylist_slug>[-\w]+)/$', 'opportunities.views.opportunitylist_detail', name='opportunitylist_detail'),
-    url(r'^opportunity-list/$', 'opportunities.views.opportunitylist_list', name='opportunitylist_list'),
-
-    url(r'^source-package/(?P<sourcepackage_slug>[-\w+.]+)/$', 'opportunities.views.sourcepackage_detail', name='sourcepackage_detail'),
-    url(r'^source-package/$', 'opportunities.views.sourcepackage_list', name='sourcepackage_list'),
-    
-    url(r'^filter',
-        'opportunities.views.opportunities_filter',
-        name='opportunities_filter'),
-
-    url(r'^by-type',
-        'opportunities.views.opportunities_by_type',
-        name='opportunities_by_type'),
-    url(r'^by-package',
-        'opportunities.views.opportunities_by_package',
-        name='opportunities_by_package'),
-
-    url(r'^packagesets/$',
-        'opportunities.views.packageset_list',
-        name='packageset_list'),
-    
-    url(r'^packagesets/(?P<packageset_slug>[-\w+.]+)/$',
-        'opportunities.views.opportunities_by_package',
-        name='opportunities_by_package'),
+    
+    url(r'^filter$', 'opportunities.views.opportunities_filter', name='opportunities_filter'),
+    
+    url(r'^query/results$', 'opportunities.views.opportunities_filter_results', name='opportunities_filter_results'),
+    url(r'^query/results/(?P<package_id>[\d]+)$', 'opportunities.views.opportunities_package_details', name='opportunities_package_details'),
 )

=== modified file 'harvest/opportunities/views.py'
--- harvest/opportunities/views.py	2010-07-05 10:04:35 +0000
+++ harvest/opportunities/views.py	2010-07-14 06:16:47 +0000
@@ -16,34 +16,6 @@
 from filters import HarvestFilters
 from wrappers import PackageWrapper, PackageListWrapper
 
-def opportunity_index(request):
-    sources_list = models.SourcePackage.objects.all()
-    paginator = Paginator(sources_list, 50)
-    # Make sure page request is an int. If not, deliver first page.
-    try:
-        page = int(request.GET.get('page', '1'))
-    except ValueError:
-        page = 1
-    # If page request (9999) is out of range, deliver last page of results.
-    try:
-        sources = paginator.page(page)
-    except (EmptyPage, InvalidPage):
-        sources = paginator.page(paginator.num_pages)
-    context = {
-        'pageSection': 'opportunities',
-        'sources': sources,
-    }
-    return render('opportunities/opportunity_index.html', context,
-              context_instance=RequestContext(request))
-
-def opportunity_list(request):
-    return list_detail.object_list(
-        request,
-        queryset = models.Opportunity.objects.filter(last_updated=opportunitylist__last_updated),
-        paginate_by = 500,
-        template_object_name = 'opportunity',
-    )
-
 def opportunity_detail(request, opportunity_id):
     return list_detail.object_detail(
         request,
@@ -89,56 +61,33 @@
                     }, RequestContext(request))
 
 
-def opportunitylist_list(request):
-    return list_detail.object_list(
-        request,
-        queryset = models.OpportunityList.objects.annotate(Count('opportunity')),
-        paginate_by = 50,
-    )
-
-def opportunitylist_detail(request, opportunitylist_slug):
-    opportunitylist = get_object_or_404(models.OpportunityList, name=opportunitylist_slug)
-    return list_detail.object_list(
-        request,
-        queryset = models.Opportunity.objects.filter(opportunitylist__name=opportunitylist_slug),
-        paginate_by = 500,
-        template_name = 'opportunities/opportunitylist_detail.html',
-        extra_context = {'opportunitylist': opportunitylist},
-    )
-
-def sourcepackage_list(request):
-    return list_detail.object_list(
-        request,
-        queryset = models.SourcePackage.objects.annotate(Count('opportunity')),
-        paginate_by = 500,
-    )
-
-def sourcepackage_detail(request, sourcepackage_slug):
-    opportunities = models.Opportunity.objects.filter(sourcepackage__name=sourcepackage_slug)
-    return list_detail.object_detail(
-        request,
-        queryset = models.SourcePackage.objects.all(),
-        slug = sourcepackage_slug,
-        slug_field = 'name',
-        extra_context = {'opportunities': opportunities},
-    )
-
-def opportunities_filter(request):
-    filters = HarvestFilters()
-    filters.update_from_http(request)
-    filters_pkg = filters.find('pkg')
-    filters_opp = filters.find('opp')
+def _create_packages_list(request, filters_pkg, filters_opp):
+    # XXX: rockstar: Eep! We shouldn't be storing the None as a string.  We
+    # should re-think this model relationship.
+    #sourcepackages_list = models.SourcePackage.objects.exclude(name='None')
     
-    packages_list = models.SourcePackage.objects.distinct()
-    packages_list = filters_pkg.process_queryset(packages_list)
+    sourcepackages_list = models.SourcePackage.objects.distinct()
+    sourcepackages_list = filters_pkg.process_queryset(sourcepackages_list)
     
     #opportunities_list is filtered right away to only check opportunities belonging to selected packages
-    opportunities_list = models.Opportunity.objects.distinct().filter(sourcepackage__in=packages_list)
+    opportunities_list = models.Opportunity.objects.distinct().filter(sourcepackage__in=sourcepackages_list)
     opportunities_list = filters_opp.process_queryset(opportunities_list)
+    
     #TODO: need to filter out opportunities with valid=False again
     #TODO: would it be more efficient to group opportunities by their sourcepackages first, then run filters_opp.process_queryset() for each of those groups?
     
-    pkg_list_wrapper = PackageListWrapper(request, packages_list, opportunities_list) 
+    pkg_list_wrapper = PackageListWrapper(request, sourcepackages_list, opportunities_list)
+    
+    return pkg_list_wrapper
+
+
+def opportunities_filter(request):
+    filters = HarvestFilters()
+    filters.update_from_http(request)
+    filters_pkg = filters.find('pkg')
+    filters_opp = filters.find('opp')
+    
+    pkg_list_wrapper = _create_packages_list(request, filters_pkg, filters_opp) 
     
     context = {
         'grouping': 'package',
@@ -148,76 +97,44 @@
     }
 
     return render(
-        'opportunities/opportunities_filter.html',
-        context,
-        context_instance=RequestContext(request))
-
-#TODO: package_filter_detail(request, sourcepackage, opportunities_list)
-
-def opportunities_by_type(request):
-    types_list = models.OpportunityList.objects.filter(active=True)
-    paginator = Paginator(types_list, 50)
-
-    # Make sure page request is an int. If not, deliver first page.
-    try:
-        page = int(request.GET.get('page', '1'))
-    except ValueError:
-        page = 1
-
-    # If page request (9999) is out of range, deliver last page of results.
-    try:
-        types = paginator.page(page)
-    except (EmptyPage, InvalidPage):
-        types = paginator.page(paginator.num_pages)
-
-    context = {
-        'pageSection': 'opportunities',
-        'types': types,
-        'grouping': 'type',
-    }
-
-    return render(
-        'opportunities/opportunities_by_type.html',
-        context,
-        context_instance=RequestContext(request))
-
-def opportunities_by_package(request, packageset_slug=None):
-    # XXX: rockstar: Eep! We shouldn't be storing the None as a string.  We
-    # should re-think this model relationship.
-    sources_list = models.SourcePackage.objects.exclude(name='None')
-    if packageset_slug:
-        packageset = get_object_or_404(models.PackageSet, name=packageset_slug)
-        sources_list = sources_list.filter(packagesets=packageset)
-    paginator = Paginator(sources_list, 50)
-
-    # Make sure page request is an int. If not, deliver first page.
-    try:
-        page = int(request.GET.get('page', '1'))
-    except ValueError:
-        page = 1
-
-    # If page request (9999) is out of range, deliver last page of results.
-    try:
-        sources = paginator.page(page)
-    except (EmptyPage, InvalidPage):
-        sources = paginator.page(paginator.num_pages)
-
-    context = {
-        'pageSection': 'opportunities',
-        'sources': sources,
-        'grouping': 'package',
-    }
-
-    return render(
-        'opportunities/opportunities_by_package.html',
-        context,
-        context_instance=RequestContext(request))
-
-def packageset_list(request):
-    packagesets = models.PackageSet.objects.all()
-    context = {
-        'packagesets': packagesets
-    }
-    return render('opportunities/packageset_list.html',
-                  context,
-                  context_instance=RequestContext(request))
+        'opportunities/filter.html',
+        context,
+        context_instance=RequestContext(request))
+
+
+def opportunities_filter_results(request):
+    filters = HarvestFilters()
+    filters.update_from_http(request)
+    
+    packages_list = _create_packages_list(request, filters.find('pkg'), filters.find('opp')) 
+    
+    context = {
+        'grouping': 'package',
+        'packages_list': packages_list
+    }
+
+    return render(
+        'opportunities/filter_results.html',
+        context,
+        context_instance=RequestContext(request))
+
+
+def opportunities_package_details(request, package_id):
+    filters = HarvestFilters()
+    filters.update_from_http(request)
+    
+    package = models.SourcePackage.objects.get(id=package_id)
+    
+    opportunities_list = filters.find('opp').process_queryset(package.opportunity_set).all()
+    
+    package_wrapper = PackageWrapper(request, package, visible_opportunities = opportunities_list, expanded = True)
+    
+    context = {
+        'grouping': 'package',
+        'package': package_wrapper
+    }
+    
+    return render(
+        'opportunities/package_details.html',
+        context,
+        context_instance=RequestContext(request))

=== modified file 'harvest/opportunities/wrappers.py'
--- harvest/opportunities/wrappers.py	2010-06-23 03:14:51 +0000
+++ harvest/opportunities/wrappers.py	2010-07-14 06:16:47 +0000
@@ -17,7 +17,7 @@
         return self.package
     
     def get_expand_toggle_url(self):
-        parameter = {'expand_pkg' : self.package.name}
+        parameter = {'expand_pkg' : self.package.id}
         url = current_url_with_parameters(self.request, parameter)
         return url
     
@@ -38,7 +38,7 @@
         been hidden from view
         """
         opps_visible = self.get_visible_opportunities()
-        return self.package.opportunity_set.exclude(pk__in=opps_visible)
+        return self.package.opportunity_set.exclude(id__in=opps_visible)
 
 class PackageListWrapper(object):
     """
@@ -49,8 +49,9 @@
     
     def __init__(self, request, packages_list, opportunities_list):
         expand_list = None #list of packages to show in detail
-        if 'expand_pkg' in request.GET:
+        if 'expand_pkg' in request.GET and request.GET['expand_pkg']:
             expand_list = request.GET['expand_pkg'].split(',')
+            expand_list = [int(i) for i in expand_list]
         
         related_packages = set(opportunities_list.values_list('sourcepackage', flat=True))
         
@@ -64,7 +65,7 @@
                 opps = None
                 expand = False
                 
-                if expand_list: expand = (package.name in expand_list)
+                if expand_list: expand = (package.id in expand_list)
                 opps = opportunities_list.filter(sourcepackage=package)
                 
                 package_wrapper = PackageWrapper(request, package,

=== modified file 'harvest/settings.py'
--- harvest/settings.py	2010-07-05 10:15:55 +0000
+++ harvest/settings.py	2010-07-14 06:16:47 +0000
@@ -19,6 +19,9 @@
 VERSION_STRING = utils.get_harvest_version(
                     os.path.join(PROJECT_PATH, "version"),
                     DEBUG)
+VERSION_NAME_STRING = utils.get_harvest_version_name(
+                        os.path.join(PROJECT_PATH, "version"),
+                        DEBUG)
 
 ADMINS = ('Daniel Holbach', 'daniel.holbach@xxxxxxxxxx')
 MANAGERS = ADMINS
@@ -77,6 +80,7 @@
     'django.contrib.sessions.middleware.SessionMiddleware',
     'django.contrib.auth.middleware.AuthenticationMiddleware',
     'django.middleware.locale.LocaleMiddleware',
+    'harvest.common.middleware.timer.TimerMiddleware',
 )
 
 ROOT_URLCONF = 'harvest.urls'
@@ -95,6 +99,7 @@
     "django.core.context_processors.media",
     "django.core.context_processors.request",
     "common.context_processors.harvest_version",
+    "common.context_processors.harvest_version_name",
     "common.context_processors.login_redirect",
     )
 

=== modified file 'harvest/templates/base.html'
--- harvest/templates/base.html	2010-06-01 16:16:19 +0000
+++ harvest/templates/base.html	2010-07-14 06:16:47 +0000
@@ -1,91 +1,86 @@
 {% load i18n %}
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 strict//EN"
-     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";>
+<!DOCTYPE html>
 <html xmlns="http://www.w3.org/1999/xhtml"; xml:lang="{{ LANGUAGE_CODE }}" lang="{{ LANGUAGE_CODE }}">
+
 <head>
-  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
-  <title>{% block title %}{% trans "Harvest" %}{% endblock %}</title>
-  <link rel="stortcut icon" href="{{ MEDIA_URL }}img/favicon.ico" type="image/x-icon" />
-  <link rel="stylesheet" href="{{ MEDIA_URL }}css/style.css" type="text/css" media="screen" /> 
-
-  <script type="text/javascript" src="{{ MEDIA_URL }}js/yui-min.js"></script>
-
-{% block extrahead %}{% endblock %}
+	<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+	<title>{% block title %}{% trans "Harvest" %}{% endblock %}</title>
+	
+	<link rel="stortcut icon" href="{{ MEDIA_URL }}img/favicon.ico" type="image/x-icon" />
+	
+	<link href='http://fonts.googleapis.com/css?family=Molengo' rel='stylesheet' type='text/css' />
+	
+	<link rel="stylesheet" href="{{ MEDIA_URL }}css/reset.css" />
+	<link rel="stylesheet" href="{{ MEDIA_URL }}css/style.css" />
+
+	<script type="text/javascript" src="{{ MEDIA_URL }}js/jquery-1.4.2.min.js"></script>
+	<script type="text/javascript" src="{{ MEDIA_URL }}js/jquery.scrollstay.js"></script>
+	<script type="text/javascript" src="{{ MEDIA_URL }}js/jquery.placeheld.js"></script>
+	<script type="text/javascript" src="{{ MEDIA_URL }}js/harvest.js"></script>
+	
+	{% block extrahead %}{% endblock %}
 </head>
 
 <body>
 <div id="container">
-  <div id="content">
-    <div id="topNav">
-      <p id="whoami">
-        {% if user.is_authenticated %}
-          {{ user.username }}
-          &nbsp;
-          <a href="/logout">Log out</a>
-        {% else %}
-          <a href="/openid/login">Log in</a>
-        {% endif %}</p>
-      <a href="/"><img id="ubuntulogo" src="{{ MEDIA_URL }}img/ubuntulogo.png" alt="Ubuntu" /></a>
-    </div>
-    <div id="body">
-      <div class="content">
-{% if messages %}
-{% for message in messages %}
-<p>{{ message }}</p>
-{% endfor %}
-{% endif %}
-
-{% block content %}
-{% endblock %}
-
-{% block pagination %}
-{% if is_paginated %}
-    <div class="pagination">
-        {% if page_obj.has_previous %}
-            <a href="?page={{ page_obj.previous_page_number }}">&lt;&lt;Previous</a>
-        {% else %}
-            &lt;&lt;Previous
-        {% endif %}
-
-        <span class="pages">
-        {% for item in paginator.page_range %}
-            {% ifequal item page %}
-                <span class="current-page">{{ item }}</span>
-            {% else %}
-                <a href="?page={{ item }}">{{ item }}</a>
-            {% endifequal %}
-        {% endfor %}
-        </span>
-
-        {% if page_obj.has_next %}
-            <a href="?page={{ page_obj.next_page_number }}">Next &gt;&gt;</a>
-        {% else %}
-            Next &gt;&gt;
-        {% endif %}
-    </div>
-{% endif %}
-{% endblock %}
-
-      </div>
-
-{% if translator_credits %}
-<p class="footnote">
-{% trans "Translated by:" %} {{ translator_credits|join:", " }}
-</p>
-{% endif %}
-    </div>
-
-    <div id="footer">
-      <div class="wrapper">
-        <img src="{{ MEDIA_URL }}img/rule.png" width="740" height="1" alt="" class="rule" />
-        <p>&copy; 2008-2009 Canonical Ltd.  Ubuntu and Canonical are registered
-        trademarks of Canonical Ltd.<br />{% trans "Harvest" %} {{ harvest_version }}</p>
-      </div>
-    </div>
-    <div id="bg-right">&nbsp;</div><div id="bottom-right">&nbsp;</div> 
-  </div>
-  <div id="bg-left">&nbsp;</div><div id="bottom-left">&nbsp;</div> 
+
+<div id="header">
+	<span id="pagetitle">
+		<img id="sitelogo" src="{{ MEDIA_URL }}img/logo_humanity-search-icon.png" />
+		<h1 id="sitename">{% trans "Harvest" %}</h1>
+		{% if harvest_version_name %}<span id="releasename">{{harvest_version_name}}</span>{% endif %}
+	</span>
+	
+	<span id="userdata">
+		{% if user.is_authenticated %}
+			<span class="username">{{ user.username }}</span>
+			<br /><a class="loginbutton" href="/logout" tabindex="1">Log out</a>
+		{% else %}
+			<a class="loginbutton" href="/openid/login">Log in</a>
+		{% endif %}
+	</span>
+</div>
+
+<div id="content">
+	{% if messages %}
+		<div id="messages"><ul>
+		{% for message in messages %}
+			<li>{{ message }}</li>
+		{% endfor %}
+		</ul></div>
+	{% endif %}
+	{% block content %}
+	
+	
+	
+	{% endblock %}
+</div>
+
+<div id="footer">
+	<div id="footnav"><nav>
+		<a class="title" href="{% url home %}" tabindex="2">{% trans "Harvest" %}</a> <a href="http://answers.launchpad.net/harvest"; tabindex="2">{% trans "Help" %}</a> <a href="http://bugs.launchpad.net/harvest"; tabindex="2">{% trans "Bugs" %}</a> <a href="http://launchpad.net/harvest"; tabindex="2">{% trans "Code" %}</a>
+	</nav></div>
+	
+	<div id="smallprint" tabindex="3">
+		<span id="copyright">
+		&copy; 2008-2009 Canonical Ltd.
+		<br />Ubuntu and Canonical are registered
+        trademarks of Canonical Ltd.
+		</span>
+		
+		<span id="techdetails">
+		{% trans "Harvest" %} {{ harvest_version }}
+		{% if translator_credits %}
+		<br />{% trans "Translated by:" %} {{ translator_credits|join:", " }}
+		{% endif %}
+		<br /><span id="requeststats"></span>
+		</span>
+		
+		<div class="bottom"></div>
+	</div>
+</div>
 
 </div>
 </body>
-</html>
+
+</html>
\ No newline at end of file

=== modified file 'harvest/templates/index.html'
--- harvest/templates/index.html	2010-02-03 23:28:50 +0000
+++ harvest/templates/index.html	2010-07-14 06:16:47 +0000
@@ -8,13 +8,7 @@
 
 <h1>{% trans "Harvest" %}</h1>
 
-Find opportunities!
-
-<ul>
-  <li><a href="{% url opportunities_by_type %}">By type</a></li>
-  <li><a href="{% url opportunities_by_package %}">By package</a></li>
-  <li><a href="{% url packageset_list %}">By packageset</a></li>
-<ul>
+There is no landing page at the moment :(
 
 
 {% if translator_credits %}

=== renamed file 'harvest/templates/opportunities/opportunities_filter.html' => 'harvest/templates/opportunities/filter.html'
--- harvest/templates/opportunities/opportunities_filter.html	2010-06-22 05:18:50 +0000
+++ harvest/templates/opportunities/filter.html	2010-07-14 06:16:47 +0000
@@ -4,47 +4,19 @@
 {% block title %}{% trans "Opportunity Index" %} - {{ block.super }}{% endblock %}
 
 {% block content %}
-<div class="mainpage">
-
-<h1>{% trans "Opportunities" %}</h1>
-
-<div class="filters" style="background-color:#E0F1FF; float:left; width:15em;">
+
+<div id="filters">
 	{{filters_pkg.render}}
 	{{filters_opp.render}}
 </div>
 
-<div class="results" style="float:left;">
-{% if packages_list %}
-<ul>
-	{% for pkg in packages_list.get_visible_packages %}
-	<li><a href="{{ pkg.get_expand_toggle_url }}">{{ pkg.real.name }}</a>
-		{% if pkg.expanded %}
-		<ul>
-		{% for opportunity in pkg.get_visible_opportunities %}
-			{% include "opportunities/opportunity_detail.inc.html" %}
-		{% endfor %}
-		
-		{% with pkg.get_hidden_opportunities.count as hidden_count %}
-		{% ifnotequal hidden_count 0 %}
-		<li><small>{{ hidden_count }} {{ hidden_count|pluralize:"opportunity,opportunities"}} hidden</small></li>
-		{% endifnotequal %}
-		{% endwith %}
-		</ul>
-		{% endif %}
-	</li>
-	{% endfor %}
-	
-	{% with packages_list.get_hidden_packages|length as hidden_count %}
-	{% ifnotequal hidden_count 0 %}
-	<li><small>{{ hidden_count }} package{{ hidden_count|pluralize:"s"}} {{ hidden_count|pluralize:"has,have"}} no matching opportunities</small></li>
-	{% endifnotequal %}
-	{% endwith %}
-</ul>
-
-{% else %}
-<p>{% trans "There are currently no opportunities in Harvest. :(" %}</p>
-{% endif %}
-</div>
-
-</div>
+<div id="results-pane" data-results-url="{% url opportunities_filter_results %}">
+	<div id="results-status"></div>
+	<div id="results">
+	{% include "opportunities/filter_results.html" %}
+	</div>
+</div>
+
+<div class="bottom"></div>
+
 {% endblock %}

=== added file 'harvest/templates/opportunities/filter_results.html'
--- harvest/templates/opportunities/filter_results.html	1970-01-01 00:00:00 +0000
+++ harvest/templates/opportunities/filter_results.html	2010-07-14 06:16:47 +0000
@@ -0,0 +1,33 @@
+{% load i18n %}
+
+{% if packages_list %}
+<ul>
+	{% for package in packages_list.get_visible_packages %}
+	<li data-results-packageid="{{ package.real.id }}" class="sourcepackage {% if package.expanded %}expanded{% else %}collapsed{% endif %}">
+		<a class="sourcepackage-header" href="{{ package.get_expand_toggle_url }}">
+			<span class="sourcepackage-name">{{ package.real.name }}</span>
+			<span class="status"></span>
+			<span class="sourcepackage-summary">
+				X issues (TODO)
+			</span>
+			<div class="bottom"></div>
+		</a>
+		<div class="sourcepackage-details">
+			{% if package.expanded %}
+			{% include "opportunities/package_details.html" %}
+			{% endif %}
+		</div>
+	</li>
+	{% endfor %}
+	
+	{% with packages_list.get_hidden_packages|length as hidden_count %}
+	{% ifnotequal hidden_count 0 %}
+		<li><small>{% blocktrans count hidden_count as counter %}{{ counter }} package has no matching opportunities{% plural %}{{ counter }} packages have no matching opportunities{% endblocktrans %}</small></li>
+	{% endifnotequal %}
+	{% endwith %}
+</ul>
+
+{% else %}
+<p>{% trans "There are currently no opportunities in Harvest. :(" %}</p>
+{% endif %}
+

=== removed file 'harvest/templates/opportunities/opportunity_index.html'
--- harvest/templates/opportunities/opportunity_index.html	2010-06-07 15:04:29 +0000
+++ harvest/templates/opportunities/opportunity_index.html	1970-01-01 00:00:00 +0000
@@ -1,45 +0,0 @@
-{% extends "base.html" %}
-{% load i18n %}
-
-{% block title %}{% trans "Opportunity Index" %} - {{ block.super }}{% endblock %}
-
-{% block content %}
-<div class="mainpage">
-
-<h1>{% trans "Opportunities" %}</h1>
-
-{% if sources.object_list %}
-<ul>
-{% for source in sources.object_list %}
-<li><a href="{% url sourcepackage_detail source.name %}">{{ source.name }}</a>
-<ul>
-{% for opportunity in source.valid_opportunites %}
-    {% include "opportunities/opportunity_detail.inc.html" %}
-{% endfor %}
-</ul>
-</li>
-{% endfor %}
-</ul>
-
-<div class="pagination">
-    <span class="step-links">
-        {% if sources.has_previous %}
-            <a href="?page={{ sources.previous_page_number }}">previous</a>
-        {% endif %}
-
-        <span class="current">
-            Page {{ sources.number }} of {{ sources.paginator.num_pages }}.
-        </span>
-
-        {% if sources.has_next %}
-            <a href="?page={{ sources.next_page_number }}">next</a>
-        {% endif %}
-    </span>
-</div>
-
-{% else %}
-<p>{% trans "There are currently no opportunities in Harvest. :(" %}</p>
-{% endif %}
-
-</div>
-{% endblock %}

=== removed file 'harvest/templates/opportunities/opportunity_list.html'
--- harvest/templates/opportunities/opportunity_list.html	2010-02-22 15:43:51 +0000
+++ harvest/templates/opportunities/opportunity_list.html	1970-01-01 00:00:00 +0000
@@ -1,14 +0,0 @@
-{% extends "base.html" %}
-
-{% load i18n %}
-
-{% block title %}{% trans "Opportunities" %} - {{ block.super }}{% endblock %}
-
-{% block content %}
-    <h2>Opportunities</h2>
-    <ul>
-        {% for opportunity in opportunity_list %}
-	    {% include "opportunities/opportunity_detail.inc.html" %}
-        {% endfor %}
-    </ul>
-{% endblock %}

=== removed file 'harvest/templates/opportunities/opportunitylist_detail.html'
--- harvest/templates/opportunities/opportunitylist_detail.html	2010-02-22 15:43:51 +0000
+++ harvest/templates/opportunities/opportunitylist_detail.html	1970-01-01 00:00:00 +0000
@@ -1,13 +0,0 @@
-{% extends "base.html" %}
-
-{% block title %}{{ opportunitylist.name }} - {{ block.super }}{% endblock %}
-
-{% block content %}
-    <h2>{{ opportunitylist.name }}</h2>
-    <p>{{ opportunitylist.description }}</p>
-    <ul>
-        {% for opportunity in object_list %}
-	    {% include "opportunities/opportunity_detail.inc.html" %}
-        {% endfor %}
-    </ul>
-{% endblock %}

=== removed file 'harvest/templates/opportunities/opportunitylist_list.html'
--- harvest/templates/opportunities/opportunitylist_list.html	2010-07-12 09:33:48 +0000
+++ harvest/templates/opportunities/opportunitylist_list.html	1970-01-01 00:00:00 +0000
@@ -1,14 +0,0 @@
-{% extends "base.html" %}
-
-{% load i18n %}
-
-{% block title %}{% trans "Opportunity Lists" %} - {{ block.super }}{% endblock %}
-
-{% block content %}
-    <h2>Opportunity Lists</h2>
-    {% for opportunity_list in object_list %}
-        <h3><a href="{% url opportunitylist_detail opportunity_list %}">{{ opportunity_list.name }}</a> 
-        {% blocktrans count opportunity_list.opportunity__count as counter %}(1 opportunity){% plural %}({{ counter }} opportunities){% endblocktrans %}</h3>
-        <p>{{ opportunity_list.description }}</p>
-    {% endfor %}
-{% endblock %}

=== added file 'harvest/templates/opportunities/package_details.html'
--- harvest/templates/opportunities/package_details.html	1970-01-01 00:00:00 +0000
+++ harvest/templates/opportunities/package_details.html	2010-07-14 06:16:47 +0000
@@ -0,0 +1,13 @@
+{% load i18n %}
+
+<ul>
+	{% for opportunity in package.get_visible_opportunities %}
+		{% include "opportunities/opportunity_detail.inc.html" %}
+	{% endfor %}
+	
+	{% with package.get_hidden_opportunities.count as hidden_count %}
+		{% ifnotequal hidden_count 0 %}
+			<li><small>{% blocktrans count hidden_count as counter %}{{ counter }} opportunity hidden{% plural %}{{ counter }} opportunities hidden{% endblocktrans %}</small></li>
+		{% endifnotequal %}
+	{% endwith %}
+</ul>
\ No newline at end of file

=== removed file 'harvest/templates/opportunities/packageset_list.html'
--- harvest/templates/opportunities/packageset_list.html	2010-02-03 23:28:50 +0000
+++ harvest/templates/opportunities/packageset_list.html	1970-01-01 00:00:00 +0000
@@ -1,14 +0,0 @@
-{% extends "base.html" %}
-
-{% load i18n %}
-
-{% block title %}{% trans "Packagesets" %} - {{ block.super }}{% endblock %}
-{% block content %}
-    <h2>Packagesets</h2>
-    <ul>
-        {% for packageset in packagesets %}
-            <li><a href="{{ packageset.name }}">{{ packageset.name }}</a></li>
-        {% endfor %}
-    </ul>
-{% endblock %}
-

=== removed file 'harvest/templates/opportunities/sourcepackage_detail.html'
--- harvest/templates/opportunities/sourcepackage_detail.html	2010-02-22 15:43:51 +0000
+++ harvest/templates/opportunities/sourcepackage_detail.html	1970-01-01 00:00:00 +0000
@@ -1,12 +0,0 @@
-{% extends "base.html" %}
-
-{% block title %}{{ object.name }} - {{ block.super }}{% endblock %}
-
-{% block content %}
-    <h2>{{ object.name }}</h2>
-    <ul>
-        {% for opportunity in opportunities %}
-            {% include "opportunities/opportunity_detail.inc.html" %}
-        {% endfor %}
-    </ul>
-{% endblock %}

=== removed file 'harvest/templates/opportunities/sourcepackage_list.html'
--- harvest/templates/opportunities/sourcepackage_list.html	2010-07-12 09:33:48 +0000
+++ harvest/templates/opportunities/sourcepackage_list.html	1970-01-01 00:00:00 +0000
@@ -1,14 +0,0 @@
-{% extends "base.html" %}
-
-{% load i18n %}
-
-{% block title %}{% trans "Source Packages" %} - {{ block.super }}{% endblock %}
-
-{% block content %}
-    <h2>Source Packages</h2>
-    <ul>
-        {% for source_package in object_list %}
-            <li><a href="{% url sourcepackage_detail source_package %}">{{ source_package.name }}</a> {% blocktrans count source_package.opportunity__count as counter %}(1 opportunity){% plural %}({{ counter }} opportunities){% endblocktrans %}</li>
-        {% endfor %}
-    </ul>
-{% endblock %}

=== modified file 'harvest/version'
--- harvest/version	2010-06-01 16:16:19 +0000
+++ harvest/version	2010-07-14 06:16:47 +0000
@@ -1,2 +1,3 @@
 version: 0.2.0-pre
 revno: 182
+versionname: Alpha
\ No newline at end of file


Follow ups