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

Proposed by Daniel Holbach
Status: Merged
Merged at revision: 227
Proposed branch: lp:~dylanmccall/harvest/gsoc-client-stuff
Merge into: lp:harvest
Diff against target: 3616 lines (+2187/-888)
38 files modified
EXTERNALS (+78/-0)
TODO (+0/-2)
doc/DOM for filters.txt (+83/-0)
harvest/common/context_processors.py (+8/-2)
harvest/common/middleware/timer.py (+19/-0)
harvest/common/ordereddict.py (+127/-0)
harvest/common/utils.py (+21/-0)
harvest/filters/containers.py (+10/-9)
harvest/filters/filters.py (+164/-124)
harvest/media/css/reset.css (+50/-0)
harvest/media/css/style.css (+381/-183)
harvest/media/js/harvest.js (+622/-0)
harvest/media/js/jquery-1.4.2.min.js (+154/-0)
harvest/media/js/jquery.placeheld.js (+54/-0)
harvest/media/js/jquery.scrollstay.js (+163/-0)
harvest/media/js/yui-min.js (+0/-10)
harvest/opportunities/filters.py (+25/-22)
harvest/opportunities/management/commands/release.py (+17/-11)
harvest/opportunities/templates/opportunities/opportunities_by_package.html (+0/-67)
harvest/opportunities/templates/opportunities/opportunities_by_type.html (+0/-28)
harvest/opportunities/urls.py (+5/-28)
harvest/opportunities/views.py (+61/-144)
harvest/opportunities/wrappers.py (+6/-5)
harvest/settings.py (+4/-0)
harvest/templates/base.html (+75/-80)
harvest/templates/index.html (+1/-7)
harvest/templates/opportunities/filter.html (+11/-39)
harvest/templates/opportunities/filter_results.html (+33/-0)
harvest/templates/opportunities/opportunity_detail.inc.html (+1/-1)
harvest/templates/opportunities/opportunity_index.html (+0/-45)
harvest/templates/opportunities/opportunity_list.html (+0/-14)
harvest/templates/opportunities/opportunitylist_detail.html (+0/-13)
harvest/templates/opportunities/opportunitylist_list.html (+0/-14)
harvest/templates/opportunities/package_details.html (+13/-0)
harvest/templates/opportunities/packageset_list.html (+0/-14)
harvest/templates/opportunities/sourcepackage_detail.html (+0/-12)
harvest/templates/opportunities/sourcepackage_list.html (+0/-14)
harvest/version (+1/-0)
To merge this branch: bzr merge lp:~dylanmccall/harvest/gsoc-client-stuff
Reviewer Review Type Date Requested Status
Daniel Holbach Pending
Review via email: mp+30030@code.launchpad.net

This proposal supersedes a proposal from 2010-07-14.

Description of the change

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.

To post a comment you must log in.
Revision history for this message
Daniel Holbach (dholbach) wrote : Posted in a previous version of this proposal

Thanks a lot to your enormous, great work. This is BEAUTIFUL!

I'd love to have reviewed this in several branches, and for a short time considered breaking this up into several parts, but I don't want to claim credit for your work, so I refrained from doing that. :-)

The logical sections that I was able to make out:

--- Timer and version_name
--- harvest/common/{context_processors.py,middleware*,utils.py} and harvest/settings.py

harvest/version is written by harvest/opportunities/management/commands/release.py and the version name string would get overwritten.

--- Ordered Dict and Javascript stuff
--- harvest/common/ordereddict.py and harvest/media/js

Might be worth pointing out where you got that from. Maybe we should create ./EXTERNALS or something for that and note down URLs and licenses.

--- Filters changes
--- harvest/filters/

Only minor, but I personally prefer to avoid compound statements if possible. (PEP 8 is on my side on this too ;-))

copy import in filters.py seems unnecessary

--- Template and Views removal
Good work.

--- Login is broken
Traceback (most recent call last):

  File "/usr/lib/pymodules/python2.6/django/core/servers/basehttp.py", line 279, in run
    self.result = application(self.environ, self.start_response)

  File "/usr/lib/pymodules/python2.6/django/core/servers/basehttp.py", line 651, in __call__
    return self.application(environ, start_response)

  File "/usr/lib/pymodules/python2.6/django/core/handlers/wsgi.py", line 245, in __call__
    response = middleware_method(request, response)

  File "/usr/lib/pymodules/python2.6/django/middleware/locale.py", line 21, in process_response
    patch_vary_headers(response, ('Accept-Language',))

  File "/usr/lib/pymodules/python2.6/django/utils/cache.py", line 130, in patch_vary_headers
    if response.has_header('Vary'):

AttributeError: 'NoneType' object has no attribute 'has_header'

Thanks a lot for all your work on this. I'll have a closer look into the filters and javascript stuff later on.

Revision history for this message
Daniel Holbach (dholbach) wrote : Posted in a previous version of this proposal

The filter stuff and the changes in the templates look fine to me. I'll try to get somebody to comment on the javascript, as it's really not my area of expertise. I'll still have another look at it. :-)

Revision history for this message
Daniel Holbach (dholbach) wrote : Posted in a previous version of this proposal

In the meantime you can maybe fix the other small issues or see what we need to do about them.

review: Needs Fixing
Revision history for this message
Dylan McCall (dylanmccall) wrote : Posted in a previous version of this proposal

Okay, thanks for the comments so far, Daniel! That last commit covers the last of them.

Keep them coming :)

If it helps understand some of the reason behind the Javascript, here's a list of behaviours this is aiming for:

----- Harvest.js interaction tests for humans and ents -----

Filters

 Selected items should have checkboxes added via Javascript
 Deselected items should have checkboxes removed

 Clicking a filter's name should select it or deselect it

 Changing the value of an EditFilter should cause that filter to be selected
 Selecting an item in a deselected ChoiceFilter should select the entire ChoiceFilter
 Deselecting an item should not affect whether the ChoiceFilter itself is selected or deselected

 When an item is hovered over with the mouse or focused with the keyboard, any item that would be affected according to the above rules should have a prelight indicating what will happen. If it would be selected, there should be a checkbox. If it would be deselected, there should be a checkbox with a line through it.

 When a filter's value is changed, that value should be immediately submitted to the Results object
 All filters should submit their initial values to Results when the page is loaded

Results

 Results begin waiting (filter value is changed)
  Status bubble appears at the top (fades in and slides downwards) with an unmoving progress bar
 Results stop waiting (filter value is changed back to how it was before waiting began)
  Status bubble disappears (fades out and slides upwards)

 Results from waiting to loading (1.5 seconds after changing filter value)
  Status bubble transitions to show an animated bar
 Results finish loading
  Status bubble disappears
  Correct results for selected filters should be displayed

 Results from loading to waiting (another filter is changed while content is loading)
  Status bubble transitions from "loading" to "wating"
  Previously loading results should not appear
 Results abort loading (all filters changed back to how they were before)
  Status bubble disappears
  Previously loading results should not appear

Packages

 Clicking a collapsed package should expand it, and vice-versa
 When a collapsed package is expanded for the first time, a loading indicator should gradually fade in
 When a collapsed package is being expanded (loading indicator visible), if it is clicked again, the loading should be aborted and the package should not be expanded

 When new results are loaded, any packages that are in the new results that were also in the previous results, and were expanded, should already be expanded
 If a package is expanded while results are being loaded, it should be expanded again after the new results are shown (if it is still listed)

Revision history for this message
Daniel Holbach (dholbach) wrote : Posted in a previous version of this proposal

Fantastic, fantastic, fantastic work - awesome!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'EXTERNALS'
2--- EXTERNALS 1970-01-01 00:00:00 +0000
3+++ EXTERNALS 2010-07-15 16:29:40 +0000
4@@ -0,0 +1,78 @@
5+This document lists files from outside sources, including their copyright and license details. These files remain under their respective licenses.
6+
7+
8+./harvest/ordereddict.py
9+ Copyright (c) 2009, Raymond Hettinger
10+ Licensed under the MIT license (#1 below)
11+ <http://pypi.python.org/pypi/ordereddict>
12+
13+./harvest/common/middleware/timer.py
14+ By "metajack"
15+ <http://djangosnippets.org/snippets/797/>
16+
17+./harvest/media/css/reset.css
18+ By Eric Meyer
19+ <http://meyerweb.com/eric/tools/css/reset/>
20+
21+./harvest/media/img/pkg-status-loading.gif,
22+./harvest/media/img/results-status-loading.gif,
23+./harvest/media/img/results-status-waiting.gif
24+ <http://ajaxload.info/>
25+ results-status-waiting.gif is derived from results-status-loading.gif
26+
27+./harvest/media/js/jquery-1.4.2.min.js
28+ Copyright 2010, John Resig
29+ Dual licensed under the MIT or GPL Version 2 licenses
30+ <http://jquery.com>
31+
32+./harvest/media/js/jquery.placeheld.js
33+ Copyright (c) 2010, Max Wheeler
34+ Licensed under the WTFPL (#2 below)
35+ <http://plugins.jquery.com/project/placeheld>
36+
37+./harvest/media/js/jquery.scrollstay.js
38+ Derived from "jquery.scrollFollow.js"
39+ Copyright (c) 2008 Net Perspective (http://kitchen.net-perspective.com/)
40+ Licensed under the MIT License
41+ <http://plugins.jquery.com/project/scroll-follow>
42+
43+
44+
45+---
46+Licenses
47+
48+#1. MIT license
49+
50+ Permission is hereby granted, free of charge, to any person obtaining a copy
51+ of this software and associated documentation files (the "Software"), to deal
52+ in the Software without restriction, including without limitation the rights
53+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
54+ copies of the Software, and to permit persons to whom the Software is
55+ furnished to do so, subject to the following conditions:
56+
57+ The above copyright notice and this permission notice shall be included in
58+ all copies or substantial portions of the Software.
59+
60+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
61+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
62+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
63+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
64+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
65+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
66+ THE SOFTWARE.
67+
68+#2. WTFPL
69+
70+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
71+ Version 2, December 2004
72+
73+ Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
74+
75+ Everyone is permitted to copy and distribute verbatim or modified
76+ copies of this license document, and changing it is allowed as long
77+ as the name is changed.
78+
79+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
80+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
81+
82+ 0. You just DO WHAT THE FUCK YOU WANT TO.
83
84=== modified file 'TODO'
85--- TODO 2010-03-08 16:31:25 +0000
86+++ TODO 2010-07-15 16:29:40 +0000
87@@ -1,6 +1,4 @@
88 when people log in, get upload ACLs
89-Get graphic arrows for folding and unfolding
90-Get AJAX spinner graphic
91 On the home page, we need two large square graphics for "by type" and "by
92 package"
93 Add lazr-js library for animations and overlays
94
95=== added file 'doc/DOM for filters.txt'
96--- doc/DOM for filters.txt 1970-01-01 00:00:00 +0000
97+++ doc/DOM for filters.txt 2010-07-15 16:29:40 +0000
98@@ -0,0 +1,83 @@
99+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.
100+
101+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!
102+
103+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.
104+
105+
106+
107+
108+----- General overview -----
109+
110+Here I will define the expected DOM hierarchy to be described in HTML and what it all means.
111+
112+#container - Contains everything. This is important for CSS, to align the footer correctly.
113+ #header - The top part of the page, consistent and visible on most pages.
114+ span#pagetitle - The title, which is drawn as the leftmost part of the header with a special font.
115+ img#sitelogo - Logo for the web site.
116+ h1#sitename - The actual name of the site.
117+ 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.
118+ span#userdata - Tools specific to logging in, or the logged in user.
119+
120+
121+
122+ #content - The portion of the page that changes specific to what is being looked at.
123+ #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.
124+
125+ #results-pane - Container that holds results and surrounding widgets.
126+ #results - Holds the list of packages that results from the selected filters.
127+
128+ #footer
129+ #footnav - More technical links go in here...
130+ #smallprint - The fine print. Contents are shrunken and ellipsized (where supported) to be really unobtrusive. When moused over, they are shown in more detail.
131+ #copyright - Copyright notice.
132+ #techdetails - Stuff geeks and Harvest hackers may want to know, like page generation time and SQL queries count.
133+
134+
135+
136+
137+-----Filters-----
138+
139+A list of filters goes inside the element #filters. (These are probably FilterGroups, which contain more filters). A filter is described as follows:
140+<span class="filter editfilter pkgnamefilter" data-filter-fullname="filter-pkg:name">
141+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.
142+
143+
144+The immediate contents of each Filter object should be consistent:
145+
146+.filter
147+ .filter-label - The filter's label. This is its name, usually spanning a single line.
148+ 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.
149+ .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.
150+
151+
152+Now I will describe the different .filter-value elements that are expected.
153+
154+.filtergroup , .choicefilter
155+ .filter-value ul - List items are all possible choices for the filter.
156+ 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.
157+ .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;).
158+
159+.choicefilter
160+ 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.
161+
162+.filtergroup
163+ ul > li .filter > .filter-label > .item-toggle - Just like a.item-toggle with .choicefilter; just unfortunately placed for technical reasons.
164+
165+.editfilter
166+ .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.
167+ (##TODO##: require type="hidden" if Javascript dependency remains).
168+
169+
170+
171+
172+-----Standard Attributes-----
173+
174+For .filter:
175+ 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").
176+ 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.
177+
178+For .filtergroup > ul > li and .choicefilter > ul > li:
179+ 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").
180+ data-selected: Add if the choice is currently selected.
181+
182
183=== modified file 'harvest/common/context_processors.py'
184--- harvest/common/context_processors.py 2010-06-01 16:16:19 +0000
185+++ harvest/common/context_processors.py 2010-07-15 16:29:40 +0000
186@@ -2,14 +2,20 @@
187
188 def harvest_version(request):
189 """
190- add the harvest version to template context processor.
191+ add the version number and name to template context processor
192 """
193 try:
194 version = settings.VERSION_STRING
195 except AttributeError:
196 version = "unknown"
197+
198+ try:
199+ version_name = settings.VERSION_NAME_STRING
200+ except AttributeError:
201+ version_name = ""
202
203- return {'harvest_version': version}
204+ return {'harvest_version': version,
205+ 'harvest_version_name': version_name}
206
207 def login_redirect(request):
208 return {'login_next': request.get_full_path()}
209
210=== added directory 'harvest/common/middleware'
211=== added file 'harvest/common/middleware/__init__.py'
212=== added file 'harvest/common/middleware/timer.py'
213--- harvest/common/middleware/timer.py 1970-01-01 00:00:00 +0000
214+++ harvest/common/middleware/timer.py 2010-07-15 16:29:40 +0000
215@@ -0,0 +1,19 @@
216+# Adds an 'X-Django-Request-Time' HTTP response header
217+# that times how long django spent processing the request.
218+# From <http://djangosnippets.org/snippets/797/>
219+
220+from time import time
221+
222+class TimerMiddleware(object):
223+ def process_request(self, request):
224+ request._tm_start_time = time()
225+
226+ def process_response(self, request, response):
227+ if not hasattr(request, "_tm_start_time"):
228+ return
229+
230+ total_time = time() - request._tm_start_time
231+
232+ response['X-Django-Request-Time'] = '%fs' % total_time
233+
234+ return response
235
236=== added file 'harvest/common/ordereddict.py'
237--- harvest/common/ordereddict.py 1970-01-01 00:00:00 +0000
238+++ harvest/common/ordereddict.py 2010-07-15 16:29:40 +0000
239@@ -0,0 +1,127 @@
240+# Copyright (c) 2009 Raymond Hettinger
241+#
242+# Permission is hereby granted, free of charge, to any person
243+# obtaining a copy of this software and associated documentation files
244+# (the "Software"), to deal in the Software without restriction,
245+# including without limitation the rights to use, copy, modify, merge,
246+# publish, distribute, sublicense, and/or sell copies of the Software,
247+# and to permit persons to whom the Software is furnished to do so,
248+# subject to the following conditions:
249+#
250+# The above copyright notice and this permission notice shall be
251+# included in all copies or substantial portions of the Software.
252+#
253+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
254+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
255+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
256+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
257+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
258+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
259+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
260+# OTHER DEALINGS IN THE SOFTWARE.
261+
262+from UserDict import DictMixin
263+
264+class OrderedDict(dict, DictMixin):
265+
266+ def __init__(self, *args, **kwds):
267+ if len(args) > 1:
268+ raise TypeError('expected at most 1 arguments, got %d' % len(args))
269+ try:
270+ self.__end
271+ except AttributeError:
272+ self.clear()
273+ self.update(*args, **kwds)
274+
275+ def clear(self):
276+ self.__end = end = []
277+ end += [None, end, end] # sentinel node for doubly linked list
278+ self.__map = {} # key --> [key, prev, next]
279+ dict.clear(self)
280+
281+ def __setitem__(self, key, value):
282+ if key not in self:
283+ end = self.__end
284+ curr = end[1]
285+ curr[2] = end[1] = self.__map[key] = [key, curr, end]
286+ dict.__setitem__(self, key, value)
287+
288+ def __delitem__(self, key):
289+ dict.__delitem__(self, key)
290+ key, prev, next = self.__map.pop(key)
291+ prev[2] = next
292+ next[1] = prev
293+
294+ def __iter__(self):
295+ end = self.__end
296+ curr = end[2]
297+ while curr is not end:
298+ yield curr[0]
299+ curr = curr[2]
300+
301+ def __reversed__(self):
302+ end = self.__end
303+ curr = end[1]
304+ while curr is not end:
305+ yield curr[0]
306+ curr = curr[1]
307+
308+ def popitem(self, last=True):
309+ if not self:
310+ raise KeyError('dictionary is empty')
311+ if last:
312+ key = reversed(self).next()
313+ else:
314+ key = iter(self).next()
315+ value = self.pop(key)
316+ return key, value
317+
318+ def __reduce__(self):
319+ items = [[k, self[k]] for k in self]
320+ tmp = self.__map, self.__end
321+ del self.__map, self.__end
322+ inst_dict = vars(self).copy()
323+ self.__map, self.__end = tmp
324+ if inst_dict:
325+ return (self.__class__, (items,), inst_dict)
326+ return self.__class__, (items,)
327+
328+ def keys(self):
329+ return list(self)
330+
331+ setdefault = DictMixin.setdefault
332+ update = DictMixin.update
333+ pop = DictMixin.pop
334+ values = DictMixin.values
335+ items = DictMixin.items
336+ iterkeys = DictMixin.iterkeys
337+ itervalues = DictMixin.itervalues
338+ iteritems = DictMixin.iteritems
339+
340+ def __repr__(self):
341+ if not self:
342+ return '%s()' % (self.__class__.__name__,)
343+ return '%s(%r)' % (self.__class__.__name__, self.items())
344+
345+ def copy(self):
346+ return self.__class__(self)
347+
348+ @classmethod
349+ def fromkeys(cls, iterable, value=None):
350+ d = cls()
351+ for key in iterable:
352+ d[key] = value
353+ return d
354+
355+ def __eq__(self, other):
356+ if isinstance(other, OrderedDict):
357+ if len(self) != len(other):
358+ return False
359+ for p, q in zip(self.items(), other.items()):
360+ if p != q:
361+ return False
362+ return True
363+ return dict.__eq__(self, other)
364+
365+ def __ne__(self, other):
366+ return not self == other
367
368=== modified file 'harvest/common/utils.py'
369--- harvest/common/utils.py 2010-06-01 16:16:19 +0000
370+++ harvest/common/utils.py 2010-07-15 16:29:40 +0000
371@@ -23,3 +23,24 @@
372
373 return "version %s (rev %s)" % (version, bzr_revno)
374
375+
376+def get_harvest_version_name(version_file, debug):
377+ """
378+ return a short string describing the version of harvest
379+ """
380+
381+ version_str = ""
382+
383+ if debug:
384+ try:
385+ from bzrlib.branch import Branch
386+ branch = Branch.open_containing('.')[0]
387+ version_str = "Revision %s" % branch.revno()
388+ except:
389+ pass
390+ elif os.path.exists(version_file):
391+ f = email.message_from_file(open(version_file))
392+ if "versionname" in f:
393+ version_str = f["versionname"]
394+
395+ return version_str
396
397=== modified file 'harvest/filters/containers.py'
398--- harvest/filters/containers.py 2010-06-24 06:53:17 +0000
399+++ harvest/filters/containers.py 2010-07-15 16:29:40 +0000
400@@ -1,4 +1,5 @@
401 from harvest.common.url_tools import current_url_with_parameters
402+from harvest.common.ordereddict import OrderedDict #while we wait for Python 2.7 :)
403
404 class FilterContainer(object): #abstract
405 """
406@@ -9,17 +10,17 @@
407 to exist for the entire life of the container.
408 """
409
410- def __init__(self, filters_set):
411- self.filters_dict = dict() #refers to Filter objects by their unique IDs
412- self.add_filters(filters_set)
413+ def __init__(self, filters_list):
414+ self.filters_dict = OrderedDict() #refers to Filter objects by their unique IDs
415+ self.add_filters(filters_list)
416
417- def add_filters(self, filters_set): #final
418+ def add_filters(self, filters_list): #final
419 """
420- Adds a set of filters to be children of this one and informs
421+ Adds a list of filters to be children of this one and informs
422 each child that it belongs to this container.
423- @param filter_set: a set of Filter objects
424+ @param filter_list: a list of Filter objects
425 """
426- for child in set(filters_set):
427+ for child in list(filters_list):
428 self.filters_dict[child.get_id()] = child
429 child.set_container(self)
430
431@@ -56,8 +57,8 @@
432 update_from_http should be called with the current HttpRequest.
433 """
434
435- def __init__(self, filters_set, default_parameters = dict()):
436- FilterContainer.__init__(self, filters_set)
437+ def __init__(self, filters_list, default_parameters = dict()):
438+ FilterContainer.__init__(self, filters_list)
439 self.request = None #current http request
440 self.default_parameters = default_parameters
441
442
443=== modified file 'harvest/filters/filters.py'
444--- harvest/filters/filters.py 2010-06-27 21:05:08 +0000
445+++ harvest/filters/filters.py 2010-07-15 16:29:40 +0000
446@@ -1,9 +1,8 @@
447-#FIXME: Make ChoiceFilter a bit nicer so we don't need to call super() and all that bother from harvest.opportunities.filters.
448-#TODO: adjust Filter.render() methods for custom template tags, with django.template.Template
449+#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.
450+#TODO: adjust Filter.render() methods for custom template tags and use django.template.Template
451
452 from containers import FilterContainer, FilterSystem
453 from django.utils.safestring import mark_safe
454-from copy import copy
455
456 class Filter(object): #abstract, extend in application
457 """
458@@ -27,11 +26,24 @@
459 describing it for a user interface.
460 """
461
462- #TODO: figure out get_system and get_full_name when set_container is called and store the value
463+ #TODO: generate this automatically
464+ html_class = 'filter'
465+ """
466+ The class that this object should have in its html representation.
467+ A subclass should override this property to list all Filter classes
468+ it inherits from, separated by spaces and in lower case.
469+ """
470
471- def __init__(self, id_str): #final
472+ def __init__(self, id_str, **kwargs): #final
473 self.id_str = id_str #local name
474 self.container = None #immediate container (FilterContainer)
475+
476+ self.system = None #cache for self.get_system
477+ self.full_name = None #cache for self.get_full_name
478+
479+ self.name = self.id_str
480+ if 'name' in kwargs:
481+ self.name = kwargs['name']
482
483 def get_id(self): #final
484 """
485@@ -56,27 +68,36 @@
486
487 def get_system(self): #final
488 """
489- @return: the FilterSystem that this filter ultimately belongs to
490+ Returns the FilterSystem that this filter ultimately belongs to.
491+ All objects in the system need to be created by the time this
492+ method is called.
493+ @return: the root FilterSystem
494 """
495- container = self.get_container()
496- system = None
497- if isinstance(container, Filter):
498- system = container.get_system()
499- elif isinstance(container, FilterSystem):
500- system = container
501- return system
502+ if self.system == None:
503+ container = self.get_container()
504+ system = None
505+ if isinstance(container, Filter):
506+ system = container.get_system()
507+ elif isinstance(container, FilterSystem):
508+ system = container
509+ self.system = system
510+ return self.system
511
512 def get_full_name(self): #final
513 """
514 Returns the filter's full name, which should make sense from anywhere
515 in the application. This name is in the format parent:child:child.
516+ All objects in the system need to be created by the time this
517+ method is called.
518 @return: the filter's full name, which is a string
519 """
520- full_name = self.get_id()
521- container = self.get_container()
522- if isinstance(container, Filter):
523- full_name = "%s:%s" % (container.get_full_name(), full_name)
524- return full_name
525+ if self.full_name == None:
526+ full_name = self.get_id()
527+ container = self.get_container()
528+ if isinstance(container, Filter):
529+ full_name = "%s:%s" % (container.get_full_name(), full_name)
530+ self.full_name = full_name
531+ return self.full_name
532
533 def set_value(self, value): #abstract
534 """
535@@ -92,15 +113,6 @@
536 """
537 raise NotImplementedError(self.get_value)
538
539- def serialize_value(self, value): #abstract
540- """
541- The inverse of set_value. Returns the given value as a string that could
542- be added to an HTTP query string.
543- @param value: the value to serialize, in a format native to this Filter (see get_value)
544- @return: a unicode string formatted for set_value
545- """
546- raise NotImplementedError(self.serialize_value)
547-
548 def serialize(self, value = None): #final
549 """
550 Creates a dictionary of parameters to describe this object, either
551@@ -114,17 +126,14 @@
552 value_str = self.serialize_value(value)
553 return {key : value_str}
554
555- def get_container_toggle_parameters(self): #final
556- """
557- Helper method to get the parameter for toggling this filter's state in
558- its container, if there is one.
559- @return: a dictionary of key:value pairs to generate new GET parameters
560- """
561- container = self.get_container()
562- params = dict()
563- if isinstance(container, FilterGroup):
564- params = container.serialize(container.get_value_with_selection(self.get_id()))
565- return params
566+ def serialize_value(self, value): #abstract
567+ """
568+ The inverse of set_value. Returns the given value as a string that could
569+ be added to an HTTP query string.
570+ @param value: the value to serialize, in a format native to this Filter (see get_value)
571+ @return: a unicode string formatted for set_value
572+ """
573+ raise NotImplementedError(self.serialize_value)
574
575 def process_queryset(self, queryset): #abstract
576 """
577@@ -135,29 +144,62 @@
578 """
579 raise NotImplementedError(self.process_queryset)
580
581- def render(self): #final
582+ def render(self, **kwargs): #final
583 """
584 @return: the default rendering of the filter itself in given context
585 """
586 return self.render_html()
587
588- def render_html(self):
589+ def render_html(self, **kwargs): #final
590+ """
591+ @return: the entire filter, rendered as html
592+ """
593+ inner_html = self.render_html_inner(**kwargs)
594+
595+ #safe because we are in full control of this content
596+ return mark_safe('<span class="%s" data-filter-fullname="%s">\n%s\n</span>' \
597+ % (self.html_class,
598+ self.get_full_name(),
599+ inner_html ) )
600+
601+ def render_html_inner(self, **kwargs):
602 """
603 Extend this to return the html output for the filter itself.
604- The output should be very simple and semantically meaningful,
605- with no specific concern about formatting. It will be
606- placed within other tags that describe its context, and it is
607- up to the template to describe style.
608- @return: a unicode string containing html representing this filter
609- """
610- system = self.get_system()
611- toggle_params = self.get_container_toggle_parameters()
612- href = system.get_url_with_parameters(toggle_params)
613-
614- return mark_safe(u'<a href="%s">(%s)</a>'
615- % (href, self.get_id()))
616-
617-
618+ (The inside part, without the <span class=filter> boilerplate).
619+ The output should be simple and semantically meaningful, with no
620+ specific concern about formatting. It will be placed within other
621+ tags that describe its context.
622+ @return: the filter's contents, rendered as html
623+ """
624+ label = self.render_html_label(**kwargs)
625+ if label: label = '<span class="filter-label">%s</span>' % label
626+ else: label = ''
627+
628+ value = self.render_html_value(**kwargs)
629+ if value: value = '<span class="filter-value">%s</span>' % value
630+ else: value = ''
631+
632+ return '%s\n%s' % (label, value)
633+
634+ def render_html_label(self, **kwargs):
635+ """
636+ @return: the filter's label, rendered as html
637+ """
638+ link_url = None
639+ if 'toggle_href' in kwargs:
640+ link_url = kwargs['toggle_href']
641+
642+ label = self.name
643+ if link_url:
644+ label = '<a class="item-toggle" href="%s">%s</a>' % (link_url, label)
645+
646+ return label
647+
648+ def render_html_value(self, **kwargs):
649+ """
650+ @return: the filter's value, rendered as html
651+ """
652+ return None
653
654
655 class EditFilter(Filter): #abstract, extend in application
656@@ -167,8 +209,10 @@
657 Serialized as stored ("value")
658 """
659
660- def __init__(self, id_str):
661- Filter.__init__(self, id_str)
662+ html_class = 'filter editfilter'
663+
664+ def __init__(self, id_str, **kwargs):
665+ Filter.__init__(self, id_str, **kwargs)
666 self.input_str = ""
667
668 def set_value(self, value): #overrides Filter
669@@ -180,13 +224,11 @@
670 def serialize_value(self, value): #overrides Filter
671 return value
672
673- def render_html(self):
674- system = self.get_system()
675- toggle_params = self.get_container_toggle_parameters()
676- href = system.get_url_with_parameters(toggle_params)
677-
678- return mark_safe(u'<a href="%s">%s: %s</a>'
679- % (href, self.get_id(), self.get_value()))
680+ def render_html_value(self, **kwargs):
681+ field_value = self.get_value()
682+ if field_value:
683+ field_value = 'value="%s"' % field_value
684+ return '<input type="text" placeholder="(type here)" spellcheck="false" %s />' % field_value
685
686
687 class SetFilter(Filter): #abstract, extend in application
688@@ -196,8 +238,10 @@
689 Serialized as a comma-separated list ("dog,cat,horse,mouse")
690 """
691
692- def __init__(self, id_str):
693- Filter.__init__(self, id_str)
694+ html_class = 'filter setfilter'
695+
696+ def __init__(self, id_str, **kwargs):
697+ Filter.__init__(self, id_str, **kwargs)
698 self.selected_set = set()
699
700 def set_value(self, value): #overrides Filter
701@@ -228,7 +272,7 @@
702
703 def id_allowed(self, item_id):
704 return True
705-
706+
707
708 class ChoiceFilter(SetFilter): #abstract, extend in application
709 """
710@@ -240,79 +284,75 @@
711 Serialized as a comma-separated list, like SetFilter.
712 """
713
714- def __init__(self, id_str, choices_dict):
715- SetFilter.__init__(self, id_str)
716- self.choices_dict = choices_dict
717+ html_class = 'filter setfilter choicefilter'
718+
719+ def __init__(self, id_str, choices_dict = None, **kwargs):
720+ SetFilter.__init__(self, id_str, **kwargs)
721+ if choices_dict:
722+ self.choices_dict = choices_dict
723+ else:
724+ self.choices_dict = self.default_choices_dict()
725+
726+ def default_choices_dict(self):
727+ """
728+ @return the default dictionary of choices if none is given to __init__
729+ """
730+ return None
731
732 def id_allowed(self, item_id): #overrides SetFilter
733 return item_id in self.choices_dict
734
735- def get_selected_items(self):
736+ def get_selected_choices(self):
737 return [self.choices_dict[s] for s in self.selected_set]
738-
739- def render_html(self): #overrides Filter
740- choices = ""
741-
742- for c in self.choices_dict:
743- c_render = self._render_html_choice(c)
744- if self.id_selected(c):
745- c_render = "<b>%s</b>" % c_render
746- choices += "<li>%s</li>" % c_render
747-
748- system = self.get_system()
749- toggle_params = self.get_container_toggle_parameters()
750- self_href = system.get_url_with_parameters(toggle_params)
751-
752- return mark_safe(u'<a href="%s">%s</a>:<ul>%s</ul>' % (self_href, self.get_id(), choices))
753-
754- def _render_html_choice(self, item_id):
755- system = self.get_system()
756+
757+ def render_html_value(self, **kwargs):
758+ choices = ''
759+
760+ for c_id in self.choices_dict:
761+ c_render = self.render_html_value_choice(c_id)
762+ li_params = 'data-item-id="%s"' % c_id
763+ checkbox_inner = ''
764+ if self.id_selected(c_id):
765+ li_params = '%s data-selected' % li_params
766+ checkbox_inner = '&#10003;' #a check mark
767+ checkbox = '<span class="checkbox">%s</span>' % checkbox_inner
768+ choices += '\n<li %s>\n%s\n%s\n</li>\n' % (li_params, checkbox, c_render)
769+
770+ return '<ul>\n%s\n</ul>' % choices
771+
772+ def render_html_value_choice(self, item_id):
773 toggle_params = self.serialize(self.get_value_with_selection(item_id))
774- item_href = system.get_url_with_parameters(toggle_params)
775+ item_href = self.get_system().get_url_with_parameters(toggle_params)
776
777- return mark_safe(u'<a href="%s">%s</a>' % (item_href, item_id))
778-
779-
780-
781-
782-class FilterGroup(FilterContainer, SetFilter): #final
783+ return '<a class="item-toggle" href="%s">%s</a>' % (item_href, item_id)
784+
785+
786+class FilterGroup(FilterContainer, ChoiceFilter): #final
787 """
788 A collection of other Filters, which are selected (enabled) according to the
789- rules of SetFilter.
790-
791- The do_queryset method mixes the output from all selected Filters, so only
792- the one for this FilterGroup needs to be (or should be) called.
793-
794- Serialized as a comma-separated list, like SetFilter.
795+ rules of ChoiceFilter.
796+
797+ The do_queryset method combines the output from all selected Filters.
798+
799+ Serialized as a comma-separated list, like ChoiceFilter.
800 """
801
802- def __init__(self, id_str, filters_set):
803+ html_class = 'filter setfilter choicefilter filtergroup'
804+
805+ def __init__(self, id_str, filters_set, **kwargs):
806 FilterContainer.__init__(self, filters_set)
807- SetFilter.__init__(self, id_str)
808-
809- def id_allowed(self, item_id): #overrides SetFilter
810- return item_id in self.filters_dict
811-
812- def get_selected_filters(self, filter_id):
813- return [self.filters_dict[s] for s in self.selected_set]
814+ #self.filters_dict comes from FilterContainer's initializer
815+ ChoiceFilter.__init__(self, id_str, self.filters_dict, **kwargs)
816
817 def process_queryset(self, queryset): #overrides Filter
818- for f in self.selected_set:
819- queryset = self.filters_dict[f].process_queryset(queryset) #returns something like QuerySet.filter(blah)
820+ for f in self.get_selected_choices():
821+ queryset = f.process_queryset(queryset) #returns something like QuerySet.filter(blah)
822 return queryset
823
824- def render_html(self): #overrides Filter
825- filters = ""
826-
827- for f in self.filters_dict:
828- f_render = self._render_html_filter(f)
829- if self.id_selected(f):
830- f_render = "<em>%s</em>" % f_render
831- filters += "<li>%s</li>" % f_render
832-
833- return mark_safe(u'%s:<ul>%s</ul>' % (self.get_id(), filters))
834-
835- def _render_html_filter(self, filter_id):
836+ def render_html_value_choice(self, filter_id):
837+ toggle_params = self.serialize(self.get_value_with_selection(filter_id))
838+ toggle_href = self.get_system().get_url_with_parameters(toggle_params)
839+
840 f = self.filters_dict[filter_id]
841- return f.render_html()
842+ return f.render_html(toggle_href = toggle_href)
843
844
845=== added file 'harvest/media/css/footer-pattern.png'
846Binary files harvest/media/css/footer-pattern.png 1970-01-01 00:00:00 +0000 and harvest/media/css/footer-pattern.png 2010-07-15 16:29:40 +0000 differ
847=== added file 'harvest/media/css/reset.css'
848--- harvest/media/css/reset.css 1970-01-01 00:00:00 +0000
849+++ harvest/media/css/reset.css 2010-07-15 16:29:40 +0000
850@@ -0,0 +1,50 @@
851+html, body, div, span, applet, object, iframe,
852+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
853+a, abbr, acronym, address, big, cite, code,
854+del, dfn, em, font, img, ins, kbd, q, s, samp,
855+small, strike, strong, sub, sup, tt, var,
856+b, u, i, center,
857+dl, dt, dd, ol, ul, li,
858+fieldset, form, label, legend,
859+table, caption, tbody, tfoot, thead, tr, th, td {
860+ margin: 0;
861+ padding: 0;
862+ border: 0;
863+ outline: 0;
864+ font-size: 100%;
865+ vertical-align: baseline;
866+ background: transparent;
867+}
868+body {
869+ line-height: 1;
870+}
871+ol, ul {
872+ list-style: none;
873+}
874+blockquote, q {
875+ quotes: none;
876+}
877+blockquote:before, blockquote:after,
878+q:before, q:after {
879+ content: '';
880+ content: none;
881+}
882+
883+/* remember to define focus styles! */
884+:focus {
885+ outline: 0;
886+}
887+
888+/* remember to highlight inserts somehow! */
889+ins {
890+ text-decoration: none;
891+}
892+del {
893+ text-decoration: line-through;
894+}
895+
896+/* tables still need 'cellspacing="0"' in the markup */
897+table {
898+ border-collapse: collapse;
899+ border-spacing: 0;
900+}
901
902=== modified file 'harvest/media/css/style.css'
903--- harvest/media/css/style.css 2010-03-02 16:06:21 +0000
904+++ harvest/media/css/style.css 2010-07-15 16:29:40 +0000
905@@ -1,191 +1,389 @@
906 body {
907- background-image: url(../img/bgrepeat.jpg);
908- background-color: #D3CAAA;
909- background-repeat: repeat-x;
910- padding: 0;
911- margin: 0;
912-}
913+ background-color:rgb(255,255,255);
914+ color:rgb(51,51,51);
915+
916+ font-family:'Bitstream Vera Sans', 'DejaVu Sans', sans-serif;
917+ font-size:14px;
918+ line-height:1.2em;
919+}
920+
921+h1,h2,h3,h4,h5,h6 {
922+ color:rgb(0,0,0);
923+ font-family:'Molengo', 'Bitstream Vera Sans', 'DejaVu Sans', sans-serif;
924+}
925+
926+.bottom {
927+ display:block;
928+ clear:both;
929+}
930+
931+strong {
932+ color:rgb(0,0,0);
933+ font-weight:bold;
934+}
935+small, .small {
936+ color:rgb(80,80,80);
937+ font-size:smaller;
938+}
939+em {
940+ font-style:italic;
941+}
942+
943+*:focus {
944+ outline:rgb(244,116,33) dashed 1px;
945+}
946+
947+a {
948+ color:rgb(110,64,84);
949+ text-decoration:inherit;
950+}
951+a:hover,
952+a:focus {
953+ /*color:rgb(162,129,143);*/
954+ text-decoration:underline;
955+}
956+
957+#header a,
958+#footer a {
959+ color:rgb(0,0,0);
960+}
961+
962+input.placeheld {
963+ /* only used in browsers that don't already do placeholder text */
964+ color:rgb(180,180,180);
965+}
966+
967+
968
969 #container {
970- margin: 0 auto;
971- padding: 0 0 0 14px;
972- position: relative;
973- background-color: #fff;
974- background-image: url(../img/page-border-left-repeat.jpg);
975- background-repeat: repeat-y;
976- background-position: left;
977- width: 94%;
978- /*max-width: 950px;*/
979- min-width: 760px;
980-}
981+ display:block;
982+ position:absolute;
983+ width:100%;
984+ min-width:600px;
985+ min-height:100%;
986+}
987+
988+
989+
990+#header {
991+ display:block;
992+ width:100%;
993+ min-height:80px;
994+
995+ padding-top:12px;
996+ padding-bottom:12px;
997+}
998+#header #pagetitle {
999+ display:inline;
1000+ position:static;
1001+ margin-left:80px;
1002+ margin-right:40px;
1003+
1004+ text-transform:lowercase;
1005+ color:rgb(0,0,0);
1006+ font-family:'Molengo', 'Bitstream Vera Sans', 'DejaVu Sans', sans-serif;
1007+}
1008+#header #pagetitle #sitelogo {
1009+ width:auto; /* line up with #sitename font-size */
1010+ height:36px;
1011+}
1012+#header #pagetitle #sitename {
1013+ display:inline;
1014+ position:static;
1015+
1016+ font-size:36px;
1017+}
1018+#header #pagetitle #releasename {
1019+ display:inline;
1020+ position:static;
1021+
1022+ font-size:14px;
1023+ vertical-align:sub;
1024+}
1025+#header #userdata {
1026+ float:right;
1027+ margin-top:12px;
1028+ margin-left:40px;
1029+ margin-right:80px;
1030+
1031+ text-align:right;
1032+}
1033+#header #userdata .username {
1034+}
1035+#header #userdata .loginbutton {
1036+}
1037+
1038
1039 #content {
1040- margin: 0;
1041- padding: 0 13px 0 0;
1042- min-height: 538px;
1043- position: relative;
1044- background-color: #fff;
1045- background-image: url(../img/page-border-right-repeat.jpg);
1046- background-repeat: repeat-y;
1047- background-position: right;
1048-}
1049-
1050-#content a {
1051- text-decoration: none;
1052-}
1053-
1054-#topNav {
1055- width: 100%;
1056- position: relative;
1057- height: 70px;
1058-
1059- background-image: url(../img/top.jpg);
1060- background-repeat: repeat-x;
1061- background-position: top;
1062- padding-top: 10px;
1063- z-index: 1;
1064-}
1065-
1066-#topNav a {
1067- color: #656565;
1068- text-decoration: none;
1069- font-size: 80%;
1070- border-bottom: 1px dotted #fff;
1071-}
1072-
1073-#topNav #whoami {
1074- display: block;
1075- margin: 0;
1076- padding: 0 0px .5em 0px;
1077- position: absolute;
1078- top: 20px;
1079- right: 0px;
1080-}
1081-
1082-#topNav #ubuntulogo {
1083- margin: 0;
1084- padding: 0;
1085- border-style: none;
1086-
1087- position: absolute;
1088- top: 22px;
1089- left: 0;
1090-}
1091-#bg-left {
1092- position: absolute;
1093- top: 0;
1094- left: 0;
1095- width: 14px;
1096- height: 538px;
1097- background-image: url(../img/page-border-left.jpg);
1098- background-repeat: no-repeat;
1099- background-position: top left;
1100- z-index: 6;
1101-}
1102-#bg-right {
1103- position: absolute;
1104- top: 0;
1105- right: 0;
1106- width: 13px;
1107- height: 538px;
1108- background-image: url(../img/page-border-right.jpg);
1109- background-repeat: no-repeat;
1110- background-position: top right;
1111- z-index: 6;
1112-}
1113-#bottom-left {
1114- width: 14px;
1115- height: 34px;
1116- background-image: url(../img/footerbg-left.jpg);
1117- position: absolute;
1118- bottom: 0;
1119- left: 0;
1120- z-index: 7;
1121-}
1122-#bottom-right {
1123- width: 13px;
1124- height: 34px;
1125- background-image: url(../img/footerbg-right.jpg);
1126- position: absolute;
1127- bottom: 0;
1128- right: 0;
1129- z-index: 7;
1130-}
1131-/* bodyouter provides the borders for the left navigation */
1132-/* see http://webhost.bridgew.edu/etribou/layouts/skidoo_too/ */
1133-#body {
1134- position: relative;
1135- overflow: hidden;
1136- margin: 0 0;
1137- padding-left: 0 50px;
1138- min-height: 538px;
1139-}
1140-* html #body {
1141- height: 1%;
1142-}
1143-#leftsidebar {
1144- width: 205px;
1145- float: right;
1146- margin-left: -205px;
1147-}
1148+ clear:both;
1149+ padding-bottom:140px;
1150+}
1151+
1152+
1153+
1154+#filters {
1155+ display:block;
1156+ position:relative;
1157+ float:left;
1158+ min-width:160px;
1159+
1160+ padding:0px 20px 20px 20px;
1161+ font-size:12px;
1162+ line-height:1.4em;
1163+ color:rgb(51,51,51);
1164+}
1165+#filters a {
1166+ /* these are self-explanatory; they should disappear */
1167+ display:inline-block;
1168+ height:100%;
1169+
1170+ color:inherit;
1171+ text-decoration:inherit;
1172+ font-style:inherit;
1173+}
1174+
1175+#filters ul {
1176+ display:block;
1177+ margin-left:20px;
1178+ width:100%;
1179+}
1180+#filters ul li {
1181+ display:block;
1182+ width:100%;
1183+}
1184+
1185+
1186+#filters .checkbox {
1187+ /* checkbox element should always be the same size */
1188+ display:inline-block;
1189+ width:12px;
1190+ color:inherit;
1191+}
1192+
1193+#filters .setfilter > .filter-value > ul > li:not([data-selected]) > .filter > .filter-value {
1194+ /* parent filter is turned off */
1195+ color:rgb(140,140,140);
1196+}
1197+
1198+#filters .setfilter > .filter-value > ul > li.prelight-off > .checkbox {
1199+ /* prelight for an item about to be deselected */
1200+ color:rgb(140,140,140);
1201+ text-decoration:line-through;
1202+}
1203+#filters .setfilter > .filter-value > ul > li.prelight-on > .checkbox {
1204+ /* prelight for an item about to be selected */
1205+ color:inherit;
1206+}
1207+
1208+#filters .setfilter > .filter-value > ul > li.prelight-off > .filter > .filter-value {
1209+ /* parent filter is about to be turned off */
1210+ color:rgb(140,140,140);
1211+}
1212+#filters .setfilter > .filter-value > ul > li.prelight-on > .filter > .filter-value {
1213+ /* parent filter is about to be turned on */
1214+ color:inherit;
1215+}
1216+
1217+
1218+
1219+#filters > .filtergroup {
1220+ /* a top-level filter group */
1221+ display:block;
1222+ margin-bottom:4em;
1223+}
1224+#filters > .filtergroup > .filter-label {
1225+ display:block;
1226+ margin-bottom:.5em;
1227+ color:rgb(0,0,0);
1228+ font-size:14px;
1229+ font-weight:bold;
1230+}
1231+#filters > .filtergroup > .filter-value > ul {
1232+ margin-left:0px;
1233+}
1234+#filters > .filtergroup > .filter-value > ul > li {
1235+ padding-bottom:5px;
1236+}
1237+
1238+#filters .editfilter input {
1239+ width:8em;
1240+ border:none;
1241+ padding:0px 2px 0px 2px;
1242+ border-bottom:1px solid rgb(180,180,180);
1243+
1244+ background-color:inherit;
1245+ color:inherit;
1246+ font:inherit;
1247+}
1248+#filters .editfilter input.placeheld {
1249+ color:rgb(180,180,180);
1250+}
1251+
1252+
1253+
1254+#results-pane {
1255+ display:block;
1256+ min-width:250px;
1257+ max-width:1000px;
1258+ padding:20px 20px 0px 20px;
1259+ overflow:auto;
1260+ line-height:1.6em;
1261+}
1262+
1263+#results-pane > #results-status {
1264+ position:relative;
1265+ display:none;
1266+ text-align:center;
1267+}
1268+#results-pane > #results-status > div {
1269+ display:inline-block;
1270+ width:300px;
1271+ height:30px;
1272+}
1273+
1274+#results > ul {
1275+ margin-left:20px;
1276+ margin-bottom:10px;
1277+}
1278+
1279+#results .sourcepackage {
1280+ display:block;
1281+ margin-top:5px;
1282+ margin-bottom:5px;
1283+ border:1px solid rgb(250,250,250);
1284+ -moz-border-radius:3px 3px 0px 0px;
1285+ border-radius:3px 3px 0px 0px;
1286+}
1287+
1288+#results .sourcepackage > .sourcepackage-header {
1289+ display:block;
1290+ padding:8px 20px 8px 20px;
1291+ -moz-border-radius:3px 3px 0px 0px;
1292+ border-radius:3px 3px 0px 0px; /* to line up with .sourcepackage's border */
1293+}
1294+#results .sourcepackage > a.sourcepackage-header {
1295+ color:inherit;
1296+ text-decoration:none;
1297+}
1298+#results .sourcepackage > .sourcepackage-header > .sourcepackage-name {
1299+ margin-right:10px;
1300+ color:rgb(0,0,0);
1301+ font-size:16px;
1302+}
1303+#results .sourcepackage > .sourcepackage-header > .sourcepackage-summary {
1304+ float:right;
1305+ text-align:right;
1306+ font-size:10px;
1307+}
1308+#results .sourcepackage > .sourcepackage-details {
1309+ display:block;
1310+ padding:0px 10px 5px 50px;
1311+}
1312+
1313+/* prelights */
1314+#results .sourcepackage > a.sourcepackage-header:hover,
1315+#results .sourcepackage > a.sourcepackage-header:focus {
1316+ /* use the opportunity count or experience measure here */
1317+ background-color:rgb(240,255,243);
1318+}
1319+#results .sourcepackage > a.sourcepackage-header:hover .sourcepackage-name,
1320+#results .sourcepackage > a.sourcepackage-header:focus .sourcepackage-name {
1321+ text-decoration:underline;
1322+}
1323+
1324+#results .sourcepackage > .sourcepackage-header > .status {
1325+ display:none; /* harvest.js will override this where necessary */
1326+}
1327+#results .sourcepackage > .sourcepackage-header > .status img {
1328+ width:16px;
1329+ height:16px;
1330+}
1331+
1332+/* expanded / collapsed state */
1333+#results .sourcepackage.expanded {
1334+ margin-bottom:10px;
1335+ border-color:rgb(200,200,200);
1336+ -moz-border-radius:3px;
1337+ border-radius:3px; /* round border on bottom as well */
1338+}
1339+#results .sourcepackage.collapsed > .sourcepackage-details {
1340+ display:none;
1341+}
1342+
1343+
1344
1345 #footer {
1346- background-image: url(../img/footerbg.jpg);
1347- background-repeat: repeat-x;
1348- background-position: bottom;
1349- padding: 0 0 0 0;
1350-}
1351-#footer .wrapper {
1352- padding: 0 15px 5px 15px;
1353- color: #656565;
1354- font-size: 70%;
1355- position: relative;
1356-}
1357-#footer .wrapper a {
1358- color: #656565;
1359- text-decoration: none;
1360-}
1361-#footer .wrapper p {
1362- width: 70%;
1363- font-size: 90%;
1364-}
1365-
1366-.pagination .current-page {
1367- margin: 0px 2px;
1368- font-weight: bold;
1369-}
1370-
1371-.pagination .pages {
1372- margin: 0px 10px;
1373-}
1374-
1375-div.package_name { padding: 3px; }
1376-div.package_name span.name { font-weight: bold; }
1377-div.package_name span.count { font-size: 75%; }
1378-div.package_name:hover { background: #eee; }
1379-div.package_details { padding: 5px; display: none; }
1380-div.package_details:hover {}
1381-
1382-div.thresholdGREEN { background-color: #cfc; }
1383-div.thresholdYELLOW { background-color: #ffc; }
1384-div.thresholdRED { background-color: #fcc; }
1385-
1386-span.featureYES { font-weight: bold; }
1387-span.featureNO { font-size: 100%; }
1388-
1389-span.experience1 { float: right; content:url(../img/easy.png); }
1390-span.experience2 { float: right; content:url(../img/medium.png); }
1391-span.experience3 { float: right; content:url(../img/hard.png); }
1392-
1393-ul.toplevellist {
1394- list-style-type: none;
1395- border-bottom: 1px solid #999;
1396- padding-left: 0px;
1397- margin-left: 15px;
1398-}
1399-
1400-ul.toplevellist li div {
1401- border-top: 1px solid #999;
1402- border-left: 1px solid #999;
1403- border-right: 1px solid #999;
1404+ display:block;
1405+ position:absolute;
1406+ left:0px;
1407+ right:0px;
1408+ bottom:0px;
1409+ min-height:100px;
1410+
1411+ overflow:visible;
1412+ background-image:url('footer-pattern.png');
1413+ background-position:left bottom;
1414+ background-repeat:repeat-x;
1415+
1416+ padding-left:32px;
1417+ padding-right:32px;
1418+}
1419+#footnav {
1420+ display:block;
1421+ height:20px;
1422+
1423+ padding:2px;
1424+ white-space:nowrap;
1425+ background-color:rgb(255,255,255);
1426+ font-size:16px;
1427+}
1428+#footnav a {
1429+ margin-left:1em;
1430+ margin-right:1em;
1431+}
1432+#footnav a:last-child {
1433+}
1434+#footnav .title {
1435+ margin-left:0em;
1436+ margin-right:4em;
1437+ text-decoration:none;
1438+}
1439+
1440+#smallprint {
1441+ margin-top:40px;
1442+ bottom:3px;
1443+ left:8px;
1444+ right:8px;
1445+
1446+ color:rgb(120,120,120);
1447+ font-size:10px;
1448+ line-height:1.2em;
1449+}
1450+#smallprint #techdetails,
1451+#smallprint #copyright {
1452+ max-width:200px;
1453+
1454+ padding:5px;
1455+ overflow:hidden;
1456+ white-space:nowrap;
1457+ text-overflow:ellipsis;
1458+ background-color:rgb(255,255,255);
1459+}
1460+#smallprint:hover #techdetails,
1461+#smallprint:hover #copyright,
1462+#smallprint:focus #techdetails,
1463+#smallprint:focus #copyright {
1464+ max-width:none;
1465+ overflow:visible;
1466+}
1467+#smallprint #copyright {
1468+ float:left;
1469+
1470+ text-align:left;
1471+}
1472+#smallprint #techdetails {
1473+ float:right;
1474+
1475+ text-align:right;
1476+ text-transform:lowercase;
1477 }
1478
1479=== removed file 'harvest/media/img/bgrepeat.jpg'
1480Binary 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
1481=== removed file 'harvest/media/img/footerbg-left.jpg'
1482Binary 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
1483=== removed file 'harvest/media/img/footerbg-right.jpg'
1484Binary 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
1485=== removed file 'harvest/media/img/footerbg.jpg'
1486Binary 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
1487=== added file 'harvest/media/img/logo_humanity-search-icon.png'
1488Binary 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-15 16:29:40 +0000 differ
1489=== removed file 'harvest/media/img/page-border-left-repeat.jpg'
1490Binary 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
1491=== removed file 'harvest/media/img/page-border-left.jpg'
1492Binary 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
1493=== removed file 'harvest/media/img/page-border-right-repeat.jpg'
1494Binary 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
1495=== removed file 'harvest/media/img/page-border-right.jpg'
1496Binary 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
1497=== added file 'harvest/media/img/pkg-status-loading.gif'
1498Binary 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-15 16:29:40 +0000 differ
1499=== added file 'harvest/media/img/results-status-loading.gif'
1500Binary 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-15 16:29:40 +0000 differ
1501=== added file 'harvest/media/img/results-status-waiting.gif'
1502Binary 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-15 16:29:40 +0000 differ
1503=== removed file 'harvest/media/img/top.jpg'
1504Binary 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
1505=== removed file 'harvest/media/img/ubuntulogo.png'
1506Binary 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
1507=== added file 'harvest/media/js/harvest.js'
1508--- harvest/media/js/harvest.js 1970-01-01 00:00:00 +0000
1509+++ harvest/media/js/harvest.js 2010-07-15 16:29:40 +0000
1510@@ -0,0 +1,622 @@
1511+/* depends on:
1512+ jquery core 1.4.2 or later <http://jquery.com>
1513+ jquery scrollstay plugin
1514+ jquery placeheld plugin <http://plugins.jquery.com/project/placeheld>
1515+*/
1516+
1517+
1518+// Array Remove - By John Resig (MIT Licensed)
1519+Array.prototype.remove = function(from, to) {
1520+ var rest = this.slice((to || from) + 1 || this.length);
1521+ this.length = from < 0 ? this.length + from : from;
1522+ return this.push.apply(this, rest);
1523+};
1524+
1525+
1526+var harvest_results;
1527+var harvest_filters_list;
1528+
1529+var MEDIA_PATH = '/media/' /* we should get this from Django somehow */
1530+
1531+
1532+function Filter (dom_node) {
1533+ /* Attaches to a .filter object in the document. Handles events
1534+ specific to each type of filter and provides some extra data
1535+ and utilities. */
1536+
1537+ var filter = this; /* so we can access this from event handlers */
1538+
1539+ $(dom_node).data('filter',this); /* so we can get here from the JQuery object */
1540+
1541+ this.full_name = $(dom_node).attr('data-filter-fullname');
1542+ this.parent_filter_node = $(dom_node).parent().closest('.filter');
1543+ this.container = $(dom_node).closest('li'); /* the list item in the parent that this belongs to */
1544+ this.value_node = $(dom_node).children('.filter-value');
1545+
1546+
1547+ this.is_class = function (class_name) {
1548+ return $(dom_node).hasClass(class_name);
1549+ }
1550+
1551+
1552+ this.get_value_serialized = function () {
1553+ /* Returns the value of this filter, serialized in the same
1554+ format we would use in Harvest's Django end.
1555+ Does nothing by default. Implement this in each
1556+ "class"-specific initializer below. */
1557+
1558+ return null;
1559+ }
1560+
1561+ this.value_changed = function () {
1562+ /* Should be called when the filter's value has changed.
1563+ This posts the new value to the global Results object */
1564+
1565+ value = this.get_value_serialized();
1566+ if ( value != null ) {
1567+ harvest_results.post_query(this.full_name, value);
1568+ }
1569+ }
1570+
1571+
1572+ /********/
1573+ /* Ugly hacks for talking to the parent node */
1574+
1575+ this.get_parent_filtergroup = function () {
1576+ /* Returns the FilterGroup that is a parent of this filter.
1577+ Returns null if the parent doesn't exist or isn't a FilterGroup. */
1578+ parent = null;
1579+ if ( this.parent_filter_node ) {
1580+ parent_test = this.parent_filter_node.data('filter');
1581+ if ( parent_test && parent_test.is_class('filtergroup') ) parent = parent_test;
1582+ }
1583+ return parent;
1584+ }
1585+
1586+
1587+ this.force_enable_prelight_add = function () {
1588+ /* Tells the parent (if there is one) to create a prelight for
1589+ enabling this item.
1590+ We assume the parent is a FilterGroup, which is probably right. */
1591+ parent_filter = this.get_parent_filtergroup();
1592+ if ( parent_filter && ! parent_filter.item_is_selected(this.container) ) {
1593+ /* only do this if we weren't already selected */
1594+ parent_filter.toggle_item_prelight_add(this.container);
1595+ }
1596+ }
1597+
1598+ this.force_enable_prelight_clear = function () {
1599+ /* Tells the parent (if there is one) to remove the prelight for
1600+ enabling this item.
1601+ We assume the parent is a FilterGroup. */
1602+ parent_filter = this.get_parent_filtergroup()
1603+
1604+ if ( parent_filter ) parent_filter.toggle_item_prelight_clear(this.container);
1605+ }
1606+
1607+
1608+ this.force_enable = function () {
1609+ /* Tells the parent (if there is one) to enable this item,
1610+ because it said so!
1611+ We assume the parent is a FilterGroup. */
1612+ parent_filter = this.get_parent_filtergroup();
1613+ if ( parent_filter && ! parent_filter.item_is_selected(this.container) ) {
1614+ parent_filter.enable_item(this.container);
1615+ }
1616+ }
1617+
1618+
1619+ /* Callback functions */
1620+ this.enabled = function() {} /* called when this filter is enabled */
1621+ this.disabled = function() {} /* called when this filter is disabled */
1622+
1623+
1624+ /********/
1625+ /* "Class"-specific initialization stuff. Setting up functions and
1626+ handlers in filter.value_node */
1627+
1628+ if ( this.is_class('choicefilter') ) {
1629+ var list_items = this.value_node.children('ul').children('li');
1630+
1631+
1632+ /* Callback functions */
1633+ this.item_enabled = function(item) {} /* called after enabling an item */
1634+ this.item_disabled = function(item) {} /* called after disabling an item */
1635+
1636+
1637+ this.get_value_serialized = function () {
1638+ var item_ids = Array();
1639+ /* we add the data-item-id attribute of all selected items */
1640+ list_items.each(function () {
1641+ if ($(this).attr('data-selected') != null) {
1642+ item_ids.push($(this).attr('data-item-id'));
1643+ }
1644+ } );
1645+ return item_ids.join(',');
1646+ }
1647+
1648+
1649+ this.item_is_selected = function (item) {
1650+ return ( item.attr('data-selected') != null );
1651+ }
1652+
1653+ this.toggle_item_prelight_add = function (item) {
1654+ if ( this.item_is_selected(item) ) {
1655+ item.addClass('prelight-off');
1656+ } else {
1657+ item.addClass('prelight-on');
1658+ item.children('.checkbox').html('&#10003;'); /* decoration :) */
1659+ this.force_enable_prelight_add();
1660+ }
1661+ }
1662+
1663+ this.toggle_item_prelight_clear = function (item) {
1664+ /* remove the decoration in the checkbox if we added it */
1665+ if ( ! this.item_is_selected(item) ) {
1666+ item.children('.checkbox').html('');
1667+ }
1668+
1669+ item.removeClass('prelight-on');
1670+ item.removeClass('prelight-off');
1671+ this.force_enable_prelight_clear();
1672+ }
1673+
1674+
1675+ this.enable_item = function (item) {
1676+ item.attr('data-selected','');
1677+ item.children('.checkbox').html('&#10003;');
1678+
1679+ this.force_enable();
1680+ this.value_changed();
1681+
1682+ this.item_enabled(item);
1683+ }
1684+
1685+ this.disable_item = function (item) {
1686+ item.removeAttr('data-selected');
1687+ item.children('.checkbox').html('');
1688+
1689+ this.value_changed();
1690+
1691+ this.item_disabled(item);
1692+ }
1693+
1694+ this.toggle_item = function (item) {
1695+ if ( this.item_is_selected(item) ) {
1696+ this.disable_item(item);
1697+ } else {
1698+ this.enable_item(item);
1699+ }
1700+ }
1701+
1702+
1703+ this.get_item_toggle_node = function (item) {
1704+ /* returns the node(s) used to toggle the given item in this filter */
1705+ return item.children('a.item-toggle');
1706+ }
1707+
1708+
1709+ /* "Subclass" setup goes here because we need to do overrides before any movement happens */
1710+ if ( this.is_class('filtergroup') ) {
1711+ this.item_enabled = function (item) {
1712+ /* Tell child it has been enabled. It might do something cool! */
1713+ child_filter = item.children('.filter').data('filter');
1714+ child_filter.enabled();
1715+ }
1716+
1717+ this.item_disabled = function (item) {
1718+ /* Tell child it has been disabled. */
1719+ child_filter = item.children('.filter').data('filter');
1720+ child_filter.disabled();
1721+ }
1722+
1723+ this.get_item_toggle_node = function (item) {
1724+ return item.children('.filter').children('.filter-label').children('a.item-toggle');
1725+ }
1726+ }
1727+
1728+
1729+ /* setup the event handlers we described on all the items */
1730+ list_items.each(function () {
1731+ var item = $(this);
1732+ toggle_node = filter.get_item_toggle_node(item);
1733+ toggle_node.bind('mouseenter focusin', function () { filter.toggle_item_prelight_add(item); } );
1734+ toggle_node.bind('mouseleave focusout', function () { filter.toggle_item_prelight_clear(item); } );
1735+
1736+ toggle_node.bind('click', function () {
1737+ filter.toggle_item(item);
1738+ filter.toggle_item_prelight_clear(item);
1739+
1740+ return false; /* stops link from being followed */
1741+ } );
1742+ });
1743+ }
1744+
1745+
1746+ if ( this.is_class('editfilter') ) {
1747+ var edit_field = this.value_node.children('input');
1748+
1749+
1750+ this.edit_field_changed = function() {
1751+ this.force_enable();
1752+ this.value_changed();
1753+ }
1754+
1755+ this.get_value_serialized = function () {
1756+ return escape(edit_field.val());
1757+ }
1758+
1759+ this.enabled = function () {
1760+ edit_field.focus();
1761+ }
1762+
1763+ /* we could handle 'change' instead of 'input' to only check value when typing has stopped */
1764+ edit_field.bind('input', function () { filter.edit_field_changed(); } );
1765+ }
1766+
1767+
1768+ /* send initial state to Results object so it can behave neatly */
1769+ value = this.get_value_serialized();
1770+ if ( value != null ) {
1771+ harvest_results.update_current_query(this.full_name, value);
1772+ }
1773+}
1774+
1775+
1776+function Package (dom_node, details_url, opps_query, expanded_cb, collapsed_cb) {
1777+ /* Created for each package inside the #results element */
1778+
1779+ /* gtksourceview gives an error box around "package", so we'll have to forego the convention */
1780+ var pkg = this;
1781+
1782+ this.id = $(dom_node).attr('data-results-packageid');
1783+ this.details = $(dom_node).children('.sourcepackage-details');
1784+
1785+ this.loading_xhr = null;
1786+ this.is_expanded = false;
1787+
1788+
1789+ this.show_status = function (status) {
1790+ var indicator = dom_node.children('.sourcepackage-header').children('.status');
1791+ if ( status ) {
1792+ indicator.stop(true, true);
1793+ var status_img = MEDIA_PATH + 'img/pkg-status-'+status+'.gif';
1794+ indicator.html('<img src="'+status_img+'" />');
1795+ if ( this.visible_status == null ) {
1796+ indicator.fadeIn(1500);
1797+ }
1798+ } else {
1799+ /* stop the previous animation as it was; we don't expect it to finish usually */
1800+ indicator.stop(true, false);
1801+ indicator.fadeOut(150, function () {
1802+ indicator.html('');
1803+ });
1804+ }
1805+
1806+ this.visible_status = status;
1807+ }
1808+
1809+ this.hide_status = function (status) {
1810+ if ( this.visible_status == status ) this.show_status(null);
1811+ }
1812+
1813+
1814+ this.expand = function () {
1815+ if ( this.is_expanded ) return;
1816+
1817+ var show = function () {
1818+ /* from #"results .sourcepackage.expanded" rule in /media/css/style.css */
1819+ fadeto = 'rgb(200,200,200);';
1820+ dom_node.animate({borderTopColor: fadeto,
1821+ borderRightColor: fadeto,
1822+ borderBottomColor: fadeto,
1823+ borderLeftColor: fadeto}, 150);
1824+ pkg.details.animate({height: 'show', opacity: 'show'}, 150);
1825+ dom_node.removeClass('collapsed');
1826+ dom_node.addClass('expanded');
1827+ }
1828+
1829+ /* run the callback saying this package will be expanded */
1830+ this.is_expanded = true;
1831+ if ( expanded_cb ) expanded_cb(this);
1832+
1833+ /* first, get package details from the server if they aren't already here */
1834+ /* this poorly assumes that this.details contains no text at all if we haven't hit the server */
1835+ if ( $.trim(this.details.html()) == '' ) {
1836+ this.show_status('loading');
1837+
1838+ this.loading_xhr = $.ajax({
1839+ type: "GET",
1840+ url: details_url + this.id, dataType: 'html',
1841+ data: opps_query,
1842+ complete: function (xhr, status) {
1843+ pkg.hide_status('loading');
1844+ pkg.loading_xhr = null;
1845+ },
1846+ success: function (data, status, xhr) {
1847+ /* check that xhr.status is set. If it isn't, xhr.abort was called */
1848+ if (xhr.status) {
1849+ pkg.details.html(data);
1850+ show();
1851+ }
1852+ },
1853+ });
1854+ } else {
1855+ show();
1856+ }
1857+ }
1858+
1859+ this.stop_loading = function () {
1860+ /* stops loading package details */
1861+ if ( this.loading_xhr != null ) this.loading_xhr.abort();
1862+ }
1863+
1864+ this.collapse = function () {
1865+ this.stop_loading();
1866+ if ( ! this.is_expanded ) return;
1867+
1868+ /* run the callback saying this package will be collapsed */
1869+ this.is_expanded = false;
1870+ if ( collapsed_cb ) collapsed_cb(this);
1871+
1872+ fadeto = 'rgb(250,250,250);';
1873+ dom_node.animate({borderTopColor: fadeto,
1874+ borderRightColor: fadeto,
1875+ borderBottomColor: fadeto,
1876+ borderLeftColor: fadeto}, 150);
1877+ pkg.details.animate({height: 'hide', opacity: 'hide'}, 150);
1878+ dom_node.removeClass('expanded');
1879+ dom_node.addClass('collapsed');
1880+ }
1881+
1882+
1883+
1884+ /********/
1885+ /* Object initialization */
1886+
1887+ /* make sure the package knows it has been expanded */
1888+ if ( dom_node.hasClass('expanded') ) {
1889+ this.is_expanded = true;
1890+ if ( expanded_cb ) expanded_cb(this);
1891+ }
1892+
1893+ dom_node.children('a.sourcepackage-header').bind('click', function () {
1894+ if ( pkg.is_expanded || pkg.loading_xhr != null ) {
1895+ pkg.collapse();
1896+ } else {
1897+ pkg.expand();
1898+ }
1899+
1900+ return false;
1901+ });
1902+}
1903+
1904+
1905+function Results (dom_node) {
1906+ /* Attached to the single #results-pane in the document. Receives
1907+ new query parameters from Filter objects, grabs and displays new
1908+ results in the contained #results element. */
1909+
1910+ /* The current_query variable is set with the current querystring,
1911+ but some filters could already have been set with Harvest's
1912+ default parameters while the querystring doesn't mention them.
1913+ On its own, this isn't a problem, but it may lead to some odd
1914+ behaviour. We should fix it by setting current_query to include
1915+ all of the defaults in Harvest's Django portion. */
1916+
1917+ var results = this;
1918+
1919+ this.query_countdown = null;
1920+ this.loading_xhr = null;
1921+
1922+ this.current_query = {};
1923+ this.future_query = {};
1924+
1925+ this.container = $(dom_node);
1926+ this.query_url = $(dom_node).attr('data-results-url');
1927+ this.output = $(dom_node).children('#results');
1928+ this.status_bubble = $(dom_node).children('#results-status');
1929+
1930+ this.packages = {};
1931+ this.expanded_pkgs = [];
1932+
1933+
1934+ this.update_packages = function () {
1935+ /* Perform bits of setup with a new list of sourcepackages */
1936+ var results_packages = this.output.find('li.sourcepackage');
1937+
1938+ var old_packages = this.packages;
1939+
1940+ /* dereferences existing Packages. We expect that they'll be cleaned up by the GC */
1941+ this.packages = {};
1942+ this.expanded_pkgs = [];
1943+
1944+ var pkg_expanded_cb = function (pkg) {
1945+ results.expanded_pkgs.push(pkg.id);
1946+ results.update_current_query('expand_pkg', results.expanded_pkgs.join(','));
1947+ }
1948+
1949+ var pkg_collapsed_cb = function (pkg) {
1950+ var index = results.expanded_pkgs.indexOf(pkg.id);
1951+ if ( index > -1 ) {
1952+ results.expanded_pkgs.remove(index);
1953+ results.update_current_query('expand_pkg', results.expanded_pkgs.join(','));
1954+ }
1955+ }
1956+
1957+ results_packages.each(function () {
1958+ var dom_node = $(this);
1959+ var details_url = results.query_url + '/';
1960+ var opps_query = results.current_query; /* would be nice to only send properties starting with opp: */
1961+
1962+ var pkg = new Package(dom_node, details_url, opps_query,
1963+ pkg_expanded_cb, pkg_collapsed_cb);
1964+ results.packages[pkg.id] = pkg;
1965+
1966+ var old_pkg = old_packages[pkg.id];
1967+ if ( old_pkg ) {
1968+ /* This package was listed before. Make sure new
1969+ listing has the same expanded / collapsed state */
1970+ if ( old_pkg.is_expanded ) {
1971+ pkg.expand();
1972+ } else {
1973+ pkg.collapse();
1974+ }
1975+ }
1976+ });
1977+
1978+ this.update_current_query('expand_pkg', this.expanded_pkgs.join(','));
1979+ }
1980+
1981+
1982+ this.show_status = function (status) {
1983+ /* Shows the given status in the #status_bubble.
1984+ Set status to 'waiting', 'loading', or null to hide the box.
1985+ Note: values of status directly correlate to image filenames
1986+ at MEDIA_PATH/img/results-status-*.gif */
1987+ this.status_bubble.stop(true,true);
1988+ if ( status ) {
1989+ var status_img = MEDIA_PATH + 'img/results-status-'+status+'.gif';
1990+ this.status_bubble.html('<div><img src="'+status_img+'" /></div>');
1991+ if ( this.visible_status == null ) {
1992+ this.status_bubble.animate({height: 'show', opacity: 'show'}, 250);
1993+ }
1994+ } else {
1995+ this.status_bubble.animate({height: 'hide', opacity: 'hide'}, 150,
1996+ function () { results.status_bubble.html(''); }
1997+ );
1998+ }
1999+
2000+ this.visible_status = status;
2001+ }
2002+
2003+ this.hide_status = function (status) {
2004+ /* Hides the status bubble if it shows the given status */
2005+ if ( this.visible_status == status ) this.show_status(null);
2006+ }
2007+
2008+
2009+ this.load_results = function () {
2010+ /* Begins loading results for future_query */
2011+ var load_query = $.extend({}, this.current_query, this.future_query);
2012+
2013+ results.show_status('loading');
2014+
2015+ this.loading_xhr = $.ajax({
2016+ type: "GET",
2017+ url: this.query_url, dataType: 'html',
2018+ data: load_query,
2019+ complete: function (xhr, status) {
2020+ results.hide_status('loading');
2021+ results.loading_xhr = null;
2022+ },
2023+ success: function (data, status, xhr) {
2024+ /* We have to work around this jquery bug: http://dev.jquery.com/ticket/6173
2025+ success callback is still being called after xhr.abort() */
2026+ if (xhr.status) {
2027+ /* display the (plain html) results we have receieved */
2028+ results.output.html(data);
2029+ results.current_query = load_query;
2030+ results.future_query = {};
2031+ results.update_packages();
2032+
2033+ /* display statistics in the footer */
2034+ time_header = xhr.getResponseHeader('X-Django-Request-Time')
2035+ if (time_header) {
2036+ $('#requeststats').html('Results generated in '+parseFloat(time_header).toFixed(2) + ' seconds');
2037+ }
2038+ }
2039+ },
2040+ });
2041+ }
2042+
2043+ this.stop_loading = function () {
2044+ /* stops loading, or returns silently if that is not happening */
2045+ if ( this.loading_xhr != null ) this.loading_xhr.abort();
2046+ }
2047+
2048+
2049+ this.reset_countdown = function () {
2050+ /* Sets the query countdown timer for 1.5s.
2051+ When the timer ends, we load the results for future_query. */
2052+ this.stop_countdown(true);
2053+ this.show_status('waiting');
2054+ /* stop anything that is loading already */
2055+ this.stop_loading();
2056+
2057+ this.query_countdown = setTimeout(
2058+ function (results) {
2059+ results.load_results();
2060+ results.query_countdown = null;
2061+ }, 1500, this);
2062+ }
2063+
2064+ this.stop_countdown = function (wait_next) {
2065+ /* Stops the query countdown timer. */
2066+ clearTimeout(this.query_countdown);
2067+ this.query_countdown = null;
2068+
2069+ if (! wait_next) this.hide_status('waiting');
2070+ }
2071+
2072+
2073+ this.post_query = function (key, value) {
2074+ /* Adds the given key/value pair to future_query. If it is
2075+ necessary, a timer is started to get the results for
2076+ future_query. */
2077+ if ( this.current_query[key] == value ) {
2078+ /* the user has reverted a change; value is the same as before */
2079+ delete this.future_query[key];
2080+
2081+ if ( $.isEmptyObject(this.future_query) ) {
2082+ /* no point getting results, so stop and wait for new input. */
2083+ this.stop_countdown();
2084+ this.stop_loading();
2085+ }
2086+ } else {
2087+ this.future_query[key] = value;
2088+ /* start the timer from 0, waiting to apply the new future_query */
2089+ this.reset_countdown();
2090+ }
2091+ }
2092+
2093+ this.update_current_query = function (key, value) {
2094+ /* Adds the given key/value pair as part of current_query. For
2095+ example, when we first load the page it is useful to make
2096+ sure we know the current state of all the filters. */
2097+ this.current_query[key] = value;
2098+ }
2099+
2100+
2101+ /********/
2102+ /* Object initialization */
2103+
2104+ this.update_packages();
2105+}
2106+
2107+
2108+
2109+function create_filters () {
2110+ /* Creates all filters for the document at once. */
2111+ $('#filters').scrollStay({ offset:12 });
2112+
2113+ var filters_list = new Array();
2114+ $('#filters .filter').each(function (i) {
2115+ filters_list.push(new Filter(this));
2116+ });
2117+
2118+ return filters_list;
2119+}
2120+
2121+function create_results () {
2122+ return new Results($('#results-pane'));
2123+}
2124+
2125+
2126+
2127+$(document).ready(function () {
2128+ harvest_results = create_results();
2129+ harvest_filters_list = create_filters();
2130+
2131+ $('input[placeholder]').placeHeld();
2132+});
2133
2134=== added file 'harvest/media/js/jquery-1.4.2.min.js'
2135--- harvest/media/js/jquery-1.4.2.min.js 1970-01-01 00:00:00 +0000
2136+++ harvest/media/js/jquery-1.4.2.min.js 2010-07-15 16:29:40 +0000
2137@@ -0,0 +1,154 @@
2138+/*!
2139+ * jQuery JavaScript Library v1.4.2
2140+ * http://jquery.com/
2141+ *
2142+ * Copyright 2010, John Resig
2143+ * Dual licensed under the MIT or GPL Version 2 licenses.
2144+ * http://jquery.org/license
2145+ *
2146+ * Includes Sizzle.js
2147+ * http://sizzlejs.com/
2148+ * Copyright 2010, The Dojo Foundation
2149+ * Released under the MIT, BSD, and GPL Licenses.
2150+ *
2151+ * Date: Sat Feb 13 22:33:48 2010 -0500
2152+ */
2153+(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?
2154+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=
2155+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,
2156+"&")}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=
2157+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/,
2158+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))&&
2159+(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,
2160+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===
2161+"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,
2162+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)||
2163+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",
2164+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,
2165+"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 "+
2166+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],
2167+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]===
2168+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&&
2169+!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=
2170+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'/>";
2171+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,
2172+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=
2173+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=
2174+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,
2175+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];
2176+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,
2177+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===
2178+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,
2179+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+" ",
2180+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]+" ",
2181+" ");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=
2182+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=
2183+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=
2184+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");
2185+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,
2186+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(".");
2187+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),
2188+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!=
2189+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=
2190+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()&&
2191+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;
2192+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(" "),
2193+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||
2194+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,
2195+"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=
2196+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,
2197+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=
2198+{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")}};
2199+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",
2200+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,
2201+"_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,
2202+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"&&
2203+!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}},
2204+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,
2205+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(" "),
2206+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];
2207+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,
2208+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();
2209+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||
2210+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[];
2211+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-
2212+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-]|\\.)+)/,
2213+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")}},
2214+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]=
2215+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=[];
2216+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()},
2217+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,
2218+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)},
2219+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)}},
2220+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=
2221+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=
2222+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===
2223+"="?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,
2224+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||
2225+!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=
2226+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"&&
2227+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>";
2228+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}}();
2229+(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)}:
2230+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)/,
2231+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;
2232+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=
2233+{},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===
2234+"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",
2235+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")?
2236+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===
2237+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)?
2238+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=
2239+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},
2240+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)})},
2241+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,
2242+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);
2243+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,
2244+""):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]&&
2245+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]||
2246+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===
2247+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]);
2248+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)||["",
2249+""])[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=
2250+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]?
2251+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=
2252+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=
2253+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,
2254+"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=
2255+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=
2256+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!==
2257+"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},
2258+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(" "),
2259+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,
2260+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&&
2261+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)?
2262+"&":"?")+(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===
2263+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=
2264+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",
2265+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||
2266+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);
2267+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===
2268+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===
2269+"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;
2270+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");
2271+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],
2272+"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)},
2273+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=
2274+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([]);
2275+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===
2276+"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]||
2277+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;
2278+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=
2279+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,
2280+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||
2281+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?
2282+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=
2283+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;
2284+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&&
2285+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>";
2286+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);
2287+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,
2288+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-
2289+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":
2290+"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
2291+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);
2292
2293=== added file 'harvest/media/js/jquery.placeheld.js'
2294--- harvest/media/js/jquery.placeheld.js 1970-01-01 00:00:00 +0000
2295+++ harvest/media/js/jquery.placeheld.js 2010-07-15 16:29:40 +0000
2296@@ -0,0 +1,54 @@
2297+// PlaceHeld jQuery plugin by [Max Wheeler](max@makenosound.com)
2298+//
2299+// Copyright (c) 2010 Max Wheeler. Licensed under the [WTFPL](http://sam.zoy.org/wtfpl/)
2300+// Dependencies: jQuery
2301+//
2302+// Changelog:
2303+// * v1.0.0 (2010-04-21) Initial Version
2304+// * v1.0.1 (2010-04-29) Minified using YUI compressor instead ofo JSMin
2305+// * v1.0.2 (2010-05-10) Removed default text from form submission; moved placeholder support check outside for() loop
2306+// * v1.0.3 (2010-05-14) Added check for "placheld" class before clearing default text on form submission
2307+
2308+(function($){
2309+ $.placeHeld = function(el, options){
2310+ var base = this;
2311+ base.$el = $(el);
2312+ base.el = el;
2313+ base.$el.data("placeHeld", base);
2314+ base.placeholderText = base.$el.attr("placeholder");
2315+
2316+ base.init = function(){
2317+ base.options = $.extend({},$.placeHeld.defaultOptions, options);
2318+ base.$el.bind('blur', base.holdPlace).bind('focus', base.releasePlace).trigger('blur');
2319+ base.$el.parents('form').bind('submit', base.clearPlace);
2320+ };
2321+ // Hold with the default value attribute
2322+ base.holdPlace = function() {
2323+ var value = base.$el.val();
2324+ if (!value) base.$el.val(base.placeholderText).addClass(base.options.className);
2325+ };
2326+ // Refill with the default value attribute
2327+ base.releasePlace = function() {
2328+ var value = base.$el.val();
2329+ if (value == base.placeholderText) base.$el.val('').removeClass(base.options.className);
2330+ };
2331+ // Refill with the default value attribute
2332+ base.clearPlace = function() {
2333+ var value = base.$el.val();
2334+ if (value == base.placeholderText && base.$el.hasClass(base.options.className)) base.$el.val('');
2335+ };
2336+ base.init();
2337+ };
2338+
2339+ $.placeHeld.defaultOptions = { className: "placeheld" };
2340+
2341+ $.fn.placeHeld = function(options) {
2342+
2343+ // Check for placeholder attribute support
2344+ if (!!("placeholder" in $('<input>')[0])) return;
2345+
2346+ return this.each(function() {
2347+ (new $.placeHeld(this, options));
2348+ });
2349+ };
2350+})(jQuery);
2351
2352=== added file 'harvest/media/js/jquery.scrollstay.js'
2353--- harvest/media/js/jquery.scrollstay.js 1970-01-01 00:00:00 +0000
2354+++ harvest/media/js/jquery.scrollstay.js 2010-07-15 16:29:40 +0000
2355@@ -0,0 +1,163 @@
2356+/**
2357+ * jquery.scrollstay.js
2358+ * scrollStay for minimalists.
2359+ * Derived from jquery.scrollFollow.js by R.A. Ray.
2360+ * Copyright (c) 2008 Net Perspective (http://kitchen.net-perspective.com/)
2361+ * Licensed under the MIT License (http://www.opensource.org/licenses/mit-license.php)
2362+ *
2363+ * Removed all animation, delay, cookies and killSwitch.
2364+ *
2365+ * @author Dylan McCall
2366+ *
2367+ * @projectDescription jQuery plugin that quietly keeps an element visible as the user scrolls
2368+ *
2369+ * @version 0.4.0
2370+ *
2371+ * @requires jquery.js (tested with 1.2.6)
2372+ *
2373+ * @param offset int - Number of pixels box should remain from top of viewport
2374+ * default: 0
2375+ * @param container string - ID of the containing div
2376+ * default: box's immediate parent
2377+ * @param relativeTo string - Scroll animation can be relative to either the 'top' or 'bottom' of the viewport
2378+ * default: 'top'
2379+ */
2380+
2381+( function( $ ) {
2382+
2383+ $.scrollStay = function ( box, options )
2384+ {
2385+ // Convert box into a jQuery object
2386+ box = $( box );
2387+
2388+ // 'box' is the object to be animated
2389+ var position = box.css( 'position' );
2390+
2391+ function ani()
2392+ {
2393+ // The script runs on every scroll which really means many times during a scroll.
2394+ // We don't want multiple slides to queue up.
2395+ box.queue( [ ] );
2396+
2397+ // A bunch of values we need to determine where to animate to
2398+ var viewportHeight = parseInt( $( window ).height() );
2399+ var pageScroll = parseInt( $( document ).scrollTop() );
2400+ var parentTop = parseInt( box.cont.offset().top );
2401+ var parentHeight = parseInt( box.cont.attr( 'offsetHeight' ) );
2402+ var boxHeight = parseInt( box.attr( 'offsetHeight' ) + ( parseInt( box.css( 'marginTop' ) ) || 0 ) + ( parseInt( box.css( 'marginBottom' ) ) || 0 ) );
2403+ var aniTop;
2404+
2405+ /* Make sure the user wants the animation to happen, and it
2406+ will be helpful. (It isn't helpful if the user is trying
2407+ to scroll within the box!) */
2408+ if ( isActive && viewportHeight > boxHeight )
2409+ {
2410+ // If the box should animate relative to the top of the window
2411+ if ( options.relativeTo == 'top' )
2412+ {
2413+ // Don't animate until the top of the window is close enough to the top of the box
2414+ if ( box.initialOffsetTop >= ( pageScroll + options.offset ) )
2415+ {
2416+ aniTop = box.initialTop;
2417+ }
2418+ else
2419+ {
2420+ aniTop = Math.min( ( Math.max( ( -parentTop ), ( pageScroll - box.initialOffsetTop + box.initialTop ) ) + options.offset ), ( parentHeight - boxHeight - box.paddingAdjustment ) );
2421+ }
2422+ }
2423+ // If the box should animate relative to the bottom of the window
2424+ else if ( options.relativeTo == 'bottom' )
2425+ {
2426+ // Don't animate until the bottom of the window is close enough to the bottom of the box
2427+ if ( ( box.initialOffsetTop + boxHeight ) >= ( pageScroll + options.offset + viewportHeight ) )
2428+ {
2429+ aniTop = box.initialTop;
2430+ }
2431+ else
2432+ {
2433+ aniTop = Math.min( ( pageScroll + viewportHeight - boxHeight - options.offset ), ( parentHeight - boxHeight ) );
2434+ }
2435+ }
2436+
2437+ // Checks to see if the relevant scroll was the last one
2438+ // "-20" is to account for inaccuracy in the timeout
2439+ if ( ( new Date().getTime() - box.lastScroll ) >= -20 )
2440+ {
2441+ box.css({ top: aniTop });
2442+ }
2443+ }
2444+ };
2445+
2446+ // For user-initiated stopping of the slide
2447+ var isActive = true;
2448+
2449+ // If no parent ID was specified, and the immediate parent does not have an ID
2450+ // options.container will be undefined. So we need to figure out the parent element.
2451+ if ( options.container == '')
2452+ {
2453+ box.cont = box.parent();
2454+ }
2455+ else
2456+ {
2457+ box.cont = $( '#' + options.container );
2458+ }
2459+
2460+ // Finds the default positioning of the box.
2461+ box.initialOffsetTop = parseInt( box.offset().top );
2462+ box.initialTop = parseInt( box.css( 'top' ) ) || 0;
2463+
2464+ // Hack to fix different treatment of boxes positioned 'absolute' and 'relative'
2465+ if ( box.css( 'position' ) == 'relative' )
2466+ {
2467+ box.paddingAdjustment = parseInt( box.cont.css( 'paddingTop' ) ) + parseInt( box.cont.css( 'paddingBottom' ) );
2468+ }
2469+ else
2470+ {
2471+ box.paddingAdjustment = 0;
2472+ }
2473+
2474+ // Animate the box when the page is scrolled
2475+ $( window ).scroll( function ()
2476+ {
2477+ ani();
2478+
2479+ // To check against right before setting the animation
2480+ box.lastScroll = new Date().getTime();
2481+ }
2482+ );
2483+
2484+ // Animate the box when the page is resized
2485+ $( window ).resize( function ()
2486+ {
2487+ ani();
2488+
2489+ // To check against right before setting the animation
2490+ box.lastScroll = new Date().getTime();
2491+ }
2492+ );
2493+
2494+ // Run an initial animation on page load
2495+ box.lastScroll = 0;
2496+
2497+ ani();
2498+ };
2499+
2500+ $.fn.scrollStay = function ( options )
2501+ {
2502+ options = options || {};
2503+ options.relativeTo = options.relativeTo || 'top';
2504+ options.offset = options.offset || 0;
2505+ options.container = options.container || this.parent().attr( 'id' );
2506+
2507+ this.each( function()
2508+ {
2509+ new $.scrollStay( this, options );
2510+ }
2511+ );
2512+
2513+ return this;
2514+ };
2515+})( jQuery );
2516+
2517+
2518+
2519
2520=== removed file 'harvest/media/js/yui-min.js'
2521--- harvest/media/js/yui-min.js 2010-01-05 01:47:06 +0000
2522+++ harvest/media/js/yui-min.js 1970-01-01 00:00:00 +0000
2523@@ -1,10 +0,0 @@
2524-/*
2525-Copyright (c) 2009, Yahoo! Inc. All rights reserved.
2526-Code licensed under the BSD License:
2527-http://developer.yahoo.net/yui/license.txt
2528-version: 3.0.0
2529-build: 1549
2530-*/
2531-(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);
2532-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));
2533-}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"]});
2534\ No newline at end of file
2535
2536=== modified file 'harvest/opportunities/filters.py'
2537--- harvest/opportunities/filters.py 2010-06-24 06:53:17 +0000
2538+++ harvest/opportunities/filters.py 2010-07-15 16:29:40 +0000
2539@@ -1,4 +1,5 @@
2540 from harvest.filters import filters, containers
2541+from harvest.common.ordereddict import OrderedDict
2542 import models
2543
2544 class PkgNameFilter(filters.EditFilter):
2545@@ -6,30 +7,30 @@
2546 return queryset.filter(name__startswith = self.get_value())
2547
2548 class PkgSetFilter(filters.ChoiceFilter):
2549- def __init__(self, id_str):
2550- choices_dict = dict()
2551- for s in models.PackageSet.objects.all():
2552+ def default_choices_dict(self):
2553+ choices_dict = OrderedDict()
2554+ for s in models.PackageSet.objects.all(): #TODO: find a way to sort these
2555 choices_dict[s.name] = s
2556- super(PkgSetFilter, self).__init__(id_str, choices_dict)
2557+ return choices_dict
2558
2559 def process_queryset(self, queryset):
2560- return queryset.filter(packagesets__in=self.get_selected_items())
2561+ return queryset.filter(packagesets__in = self.get_selected_choices())
2562
2563
2564
2565 class OppFeaturedFilter(filters.Filter):
2566 def process_queryset(self, queryset):
2567- return queryset.filter(opportunitylist__featured=True)
2568+ return queryset.filter(opportunitylist__featured = True)
2569
2570 class OppListFilter(filters.ChoiceFilter):
2571- def __init__(self, id_str):
2572- choices_dict = dict()
2573- for l in models.OpportunityList.objects.all():
2574+ def default_choices_dict(self):
2575+ choices_dict = OrderedDict()
2576+ for l in models.OpportunityList.objects.all(): #TODO: find a way to sort these
2577 choices_dict[l.name] = l
2578- super(OppListFilter, self).__init__(id_str, choices_dict)
2579+ return choices_dict
2580
2581 def process_queryset(self, queryset):
2582- return queryset.filter(opportunitylist__in=self.get_selected_items())
2583+ return queryset.filter(opportunitylist__in = self.get_selected_choices())
2584
2585
2586 #we don't really need to create a special type here, but it may be handy
2587@@ -37,17 +38,19 @@
2588 def __init__(self):
2589 super(HarvestFilters, self).__init__(
2590 [
2591- filters.FilterGroup("pkg", [
2592- PkgNameFilter("name"),
2593- PkgSetFilter("set")
2594- ] ),
2595- filters.FilterGroup("opp", [
2596- OppFeaturedFilter("featured"),
2597- OppListFilter("list")
2598- ] )
2599+ filters.FilterGroup('pkg', [
2600+ PkgNameFilter('name', name='Named'),
2601+ PkgSetFilter('set', name='Package sets')
2602+ ], name='Packages' ),
2603+ filters.FilterGroup('opp', [
2604+ OppFeaturedFilter('featured', name='Featured'),
2605+ OppListFilter('list', name='Selected')
2606+ ], name='Opportunities' )
2607 ],
2608- default_parameters = { "pkg" : "name,set",
2609- "pkg:name" : "ged",
2610- "pkg:set" : "ubuntu-desktop" }
2611+ default_parameters = { 'pkg' : 'set',
2612+ 'pkg:set' : 'ubuntu-desktop',
2613+ 'opp' : 'list',
2614+ 'opp:list' : 'bitesize' }
2615+ #TODO: change to no defaults, detect that case in view and templates and provide helpful instructions in the results pane.
2616 )
2617
2618
2619=== modified file 'harvest/opportunities/management/commands/release.py'
2620--- harvest/opportunities/management/commands/release.py 2010-06-01 16:16:19 +0000
2621+++ harvest/opportunities/management/commands/release.py 2010-07-15 16:29:40 +0000
2622@@ -1,13 +1,13 @@
2623 #!/usr/bin/python
2624
2625-from django.core.management.base import LabelCommand
2626+from django.core.management.base import BaseCommand, CommandError
2627 from django.conf import settings
2628
2629 import subprocess
2630 import sys
2631 import os
2632
2633-def write_version_strings(version):
2634+def write_version_strings(version, version_name = ''):
2635 try:
2636 from bzrlib.branch import Branch
2637 branch = Branch.open_containing('.')[0]
2638@@ -20,15 +20,21 @@
2639 os.remove(file_name)
2640 f = open(file_name, "w")
2641 f.write("""version: %s
2642+versionname: %s
2643 revno: %s
2644-""" % (version, bzr_revno))
2645+""" % (version, version_name, bzr_revno))
2646 f.close()
2647- return (version, bzr_revno)
2648-
2649-class Command(LabelCommand):
2650- help = "Prepare release of Harvest. Please pass <version> as an argument."
2651-
2652- def handle_label(self, label, **options):
2653- (version, bzr_revno) = write_version_strings(label)
2654+ return (version, version_name, bzr_revno)
2655+
2656+class Command(BaseCommand):
2657+ help = "Prepare release of Harvest."
2658+ args = "<version> [version_name]"
2659+
2660+ def handle(self, *args, **options):
2661+ if len(args) < 1:
2662+ raise CommandError("Use this command with release %s" % self.args)
2663+ if len(args) > 2:
2664+ raise CommandError("Too many arguments. Remember to escape your spaces!")
2665+ (version, version_name, bzr_revno) = write_version_strings(*args)
2666 subprocess.call(["bzr", "tag", version])
2667- print >> sys.stdout, "Released %s." % label
2668+ print >> sys.stdout, "Released %s" % version
2669
2670=== removed directory 'harvest/opportunities/templates'
2671=== removed directory 'harvest/opportunities/templates/opportunities'
2672=== removed file 'harvest/opportunities/templates/opportunities/opportunities_by_package.html'
2673--- harvest/opportunities/templates/opportunities/opportunities_by_package.html 2010-07-12 09:33:48 +0000
2674+++ harvest/opportunities/templates/opportunities/opportunities_by_package.html 1970-01-01 00:00:00 +0000
2675@@ -1,67 +0,0 @@
2676-{% extends 'base.html' %}
2677-{% load i18n %}
2678-
2679-{% block title %}Opportunities by Package - {{ block.super }}{% endblock %}
2680-
2681-{% block content %}
2682-<div class="mainpage">
2683-
2684-<h1>{% trans "Opportunities By Package" %}</h1>
2685-
2686-{% if sources.object_list %}
2687- <ul class="toplevellist">
2688- {% for source in sources.object_list %}
2689- <li>
2690- <div class="package_name threshold{{ source.opportunity_class }}">
2691- <span class="name"><a href="{% url sourcepackage_detail source.name %}">{{ source.name }}</a></span>
2692- <span class="count">
2693- {% blocktrans count source.valid_opportunities|length as counter %}(1 opportunity){% plural %}({{ counter }} opportunities){% endblocktrans %}
2694- </span>
2695- </div>
2696- <div class="package_details">
2697- <ul>
2698- {% for opportunity in source.valid_opportunities %}
2699- {% include "opportunities/opportunity_detail.inc.html" %}
2700- {% endfor %}
2701- </ul>
2702- </div>
2703- </li>
2704- {% endfor %}
2705- </ul>
2706-
2707- <div class="pagination">
2708- <span class="step-links">
2709- {% if sources.has_previous %}
2710- <a href="?page={{ sources.previous_page_number }}">previous</a>
2711- {% endif %}
2712-
2713- <span class="current">
2714- Page {{ sources.number }} of {{ sources.paginator.num_pages }}.
2715- </span>
2716-
2717- {% if sources.has_next %}
2718- <a href="?page={{ sources.next_page_number }}">next</a>
2719- {% endif %}
2720- </span>
2721- </div>
2722-
2723-{% else %}
2724- <p>{% trans "There are currently no opportunities in Harvest. :(" %}</p>
2725-{% endif %}
2726-
2727-</div>
2728-
2729-<script type="text/javascript">
2730-YUI().use('node', function(Y) {
2731-
2732- Y.all('.package_name').on('click', function(e) {
2733- // XXX: rockstar: Currently, this is kinda jumpy. It'd be nice if it was
2734- // all sexy animated.
2735- Y.all('.package_details').setStyle('display', 'none');
2736- e.currentTarget.next().setStyle('display', 'block');
2737- });
2738-
2739-});
2740-
2741-</script>
2742-{% endblock %}
2743
2744=== removed file 'harvest/opportunities/templates/opportunities/opportunities_by_type.html'
2745--- harvest/opportunities/templates/opportunities/opportunities_by_type.html 2010-07-12 09:33:48 +0000
2746+++ harvest/opportunities/templates/opportunities/opportunities_by_type.html 1970-01-01 00:00:00 +0000
2747@@ -1,28 +0,0 @@
2748-{% extends 'base.html' %}
2749-{% load i18n %}
2750-
2751-{% block title %}Opportunities by Type - {{ block.super }}{% endblock %}
2752-
2753-{% block content %}
2754-<div class="mainpage">
2755-
2756-<h1>{% trans "Opportunities By Type" %}</h1>
2757-
2758-{% if types.object_list %}
2759- <ul class="toplevellist">
2760- {% for type in types.object_list %}
2761- <li>
2762- <div class="package_name threshold{{ type.opportunity_class }}">
2763- <span class="name"><a href="{{ type.get_absolute_url }}">{{ type.name }}</a></span>
2764- <span class="count">
2765- {% blocktrans count source.valid_opportunities.count as counter %}(1 opportunity){% plural %}({{ counter }} opportunities){% endblocktrans %}
2766- </span>
2767- </div>
2768- {% endfor %}
2769- </ul>
2770-{% else %}
2771- <p>{% trans "There are currently no opportunities in Harvest. :(" %}</p>
2772-{% endif %}
2773-
2774-</div>
2775-{% endblock %}
2776
2777=== modified file 'harvest/opportunities/urls.py'
2778--- harvest/opportunities/urls.py 2010-05-28 02:11:18 +0000
2779+++ harvest/opportunities/urls.py 2010-07-15 16:29:40 +0000
2780@@ -1,34 +1,11 @@
2781 from django.conf.urls.defaults import *
2782
2783 urlpatterns = patterns('',
2784- url(r'^$', 'opportunities.views.opportunity_index', name='opportunity_index'),
2785-
2786 url(r'^opportunity/(?P<opportunity_id>[\d]+)/edit$', 'opportunities.views.opportunity_edit', name='opportunity_edit'),
2787 url(r'^opportunity/(?P<opportunity_id>[\d]+)/$', 'opportunities.views.opportunity_detail', name='opportunity_detail'),
2788- url(r'^opportunity/$', 'opportunities.views.opportunity_list', name='opportunity_list'),
2789-
2790- url(r'^opportunity-list/(?P<opportunitylist_slug>[-\w]+)/$', 'opportunities.views.opportunitylist_detail', name='opportunitylist_detail'),
2791- url(r'^opportunity-list/$', 'opportunities.views.opportunitylist_list', name='opportunitylist_list'),
2792-
2793- url(r'^source-package/(?P<sourcepackage_slug>[-\w+.]+)/$', 'opportunities.views.sourcepackage_detail', name='sourcepackage_detail'),
2794- url(r'^source-package/$', 'opportunities.views.sourcepackage_list', name='sourcepackage_list'),
2795-
2796- url(r'^filter',
2797- 'opportunities.views.opportunities_filter',
2798- name='opportunities_filter'),
2799-
2800- url(r'^by-type',
2801- 'opportunities.views.opportunities_by_type',
2802- name='opportunities_by_type'),
2803- url(r'^by-package',
2804- 'opportunities.views.opportunities_by_package',
2805- name='opportunities_by_package'),
2806-
2807- url(r'^packagesets/$',
2808- 'opportunities.views.packageset_list',
2809- name='packageset_list'),
2810-
2811- url(r'^packagesets/(?P<packageset_slug>[-\w+.]+)/$',
2812- 'opportunities.views.opportunities_by_package',
2813- name='opportunities_by_package'),
2814+
2815+ url(r'^filter$', 'opportunities.views.opportunities_filter', name='opportunities_filter'),
2816+
2817+ url(r'^query/results$', 'opportunities.views.opportunities_filter_results', name='opportunities_filter_results'),
2818+ url(r'^query/results/(?P<package_id>[\d]+)$', 'opportunities.views.opportunities_package_details', name='opportunities_package_details'),
2819 )
2820
2821=== modified file 'harvest/opportunities/views.py'
2822--- harvest/opportunities/views.py 2010-07-05 10:04:35 +0000
2823+++ harvest/opportunities/views.py 2010-07-15 16:29:40 +0000
2824@@ -16,34 +16,6 @@
2825 from filters import HarvestFilters
2826 from wrappers import PackageWrapper, PackageListWrapper
2827
2828-def opportunity_index(request):
2829- sources_list = models.SourcePackage.objects.all()
2830- paginator = Paginator(sources_list, 50)
2831- # Make sure page request is an int. If not, deliver first page.
2832- try:
2833- page = int(request.GET.get('page', '1'))
2834- except ValueError:
2835- page = 1
2836- # If page request (9999) is out of range, deliver last page of results.
2837- try:
2838- sources = paginator.page(page)
2839- except (EmptyPage, InvalidPage):
2840- sources = paginator.page(paginator.num_pages)
2841- context = {
2842- 'pageSection': 'opportunities',
2843- 'sources': sources,
2844- }
2845- return render('opportunities/opportunity_index.html', context,
2846- context_instance=RequestContext(request))
2847-
2848-def opportunity_list(request):
2849- return list_detail.object_list(
2850- request,
2851- queryset = models.Opportunity.objects.filter(last_updated=opportunitylist__last_updated),
2852- paginate_by = 500,
2853- template_object_name = 'opportunity',
2854- )
2855-
2856 def opportunity_detail(request, opportunity_id):
2857 return list_detail.object_detail(
2858 request,
2859@@ -89,56 +61,33 @@
2860 }, RequestContext(request))
2861
2862
2863-def opportunitylist_list(request):
2864- return list_detail.object_list(
2865- request,
2866- queryset = models.OpportunityList.objects.annotate(Count('opportunity')),
2867- paginate_by = 50,
2868- )
2869-
2870-def opportunitylist_detail(request, opportunitylist_slug):
2871- opportunitylist = get_object_or_404(models.OpportunityList, name=opportunitylist_slug)
2872- return list_detail.object_list(
2873- request,
2874- queryset = models.Opportunity.objects.filter(opportunitylist__name=opportunitylist_slug),
2875- paginate_by = 500,
2876- template_name = 'opportunities/opportunitylist_detail.html',
2877- extra_context = {'opportunitylist': opportunitylist},
2878- )
2879-
2880-def sourcepackage_list(request):
2881- return list_detail.object_list(
2882- request,
2883- queryset = models.SourcePackage.objects.annotate(Count('opportunity')),
2884- paginate_by = 500,
2885- )
2886-
2887-def sourcepackage_detail(request, sourcepackage_slug):
2888- opportunities = models.Opportunity.objects.filter(sourcepackage__name=sourcepackage_slug)
2889- return list_detail.object_detail(
2890- request,
2891- queryset = models.SourcePackage.objects.all(),
2892- slug = sourcepackage_slug,
2893- slug_field = 'name',
2894- extra_context = {'opportunities': opportunities},
2895- )
2896-
2897-def opportunities_filter(request):
2898- filters = HarvestFilters()
2899- filters.update_from_http(request)
2900- filters_pkg = filters.find('pkg')
2901- filters_opp = filters.find('opp')
2902+def _create_packages_list(request, filters_pkg, filters_opp):
2903+ # XXX: rockstar: Eep! We shouldn't be storing the None as a string. We
2904+ # should re-think this model relationship.
2905+ #sourcepackages_list = models.SourcePackage.objects.exclude(name='None')
2906
2907- packages_list = models.SourcePackage.objects.distinct()
2908- packages_list = filters_pkg.process_queryset(packages_list)
2909+ sourcepackages_list = models.SourcePackage.objects.distinct()
2910+ sourcepackages_list = filters_pkg.process_queryset(sourcepackages_list)
2911
2912 #opportunities_list is filtered right away to only check opportunities belonging to selected packages
2913- opportunities_list = models.Opportunity.objects.distinct().filter(sourcepackage__in=packages_list)
2914+ opportunities_list = models.Opportunity.objects.distinct().filter(sourcepackage__in=sourcepackages_list)
2915 opportunities_list = filters_opp.process_queryset(opportunities_list)
2916+
2917 #TODO: need to filter out opportunities with valid=False again
2918 #TODO: would it be more efficient to group opportunities by their sourcepackages first, then run filters_opp.process_queryset() for each of those groups?
2919
2920- pkg_list_wrapper = PackageListWrapper(request, packages_list, opportunities_list)
2921+ pkg_list_wrapper = PackageListWrapper(request, sourcepackages_list, opportunities_list)
2922+
2923+ return pkg_list_wrapper
2924+
2925+
2926+def opportunities_filter(request):
2927+ filters = HarvestFilters()
2928+ filters.update_from_http(request)
2929+ filters_pkg = filters.find('pkg')
2930+ filters_opp = filters.find('opp')
2931+
2932+ pkg_list_wrapper = _create_packages_list(request, filters_pkg, filters_opp)
2933
2934 context = {
2935 'grouping': 'package',
2936@@ -148,76 +97,44 @@
2937 }
2938
2939 return render(
2940- 'opportunities/opportunities_filter.html',
2941- context,
2942- context_instance=RequestContext(request))
2943-
2944-#TODO: package_filter_detail(request, sourcepackage, opportunities_list)
2945-
2946-def opportunities_by_type(request):
2947- types_list = models.OpportunityList.objects.filter(active=True)
2948- paginator = Paginator(types_list, 50)
2949-
2950- # Make sure page request is an int. If not, deliver first page.
2951- try:
2952- page = int(request.GET.get('page', '1'))
2953- except ValueError:
2954- page = 1
2955-
2956- # If page request (9999) is out of range, deliver last page of results.
2957- try:
2958- types = paginator.page(page)
2959- except (EmptyPage, InvalidPage):
2960- types = paginator.page(paginator.num_pages)
2961-
2962- context = {
2963- 'pageSection': 'opportunities',
2964- 'types': types,
2965- 'grouping': 'type',
2966- }
2967-
2968- return render(
2969- 'opportunities/opportunities_by_type.html',
2970- context,
2971- context_instance=RequestContext(request))
2972-
2973-def opportunities_by_package(request, packageset_slug=None):
2974- # XXX: rockstar: Eep! We shouldn't be storing the None as a string. We
2975- # should re-think this model relationship.
2976- sources_list = models.SourcePackage.objects.exclude(name='None')
2977- if packageset_slug:
2978- packageset = get_object_or_404(models.PackageSet, name=packageset_slug)
2979- sources_list = sources_list.filter(packagesets=packageset)
2980- paginator = Paginator(sources_list, 50)
2981-
2982- # Make sure page request is an int. If not, deliver first page.
2983- try:
2984- page = int(request.GET.get('page', '1'))
2985- except ValueError:
2986- page = 1
2987-
2988- # If page request (9999) is out of range, deliver last page of results.
2989- try:
2990- sources = paginator.page(page)
2991- except (EmptyPage, InvalidPage):
2992- sources = paginator.page(paginator.num_pages)
2993-
2994- context = {
2995- 'pageSection': 'opportunities',
2996- 'sources': sources,
2997- 'grouping': 'package',
2998- }
2999-
3000- return render(
3001- 'opportunities/opportunities_by_package.html',
3002- context,
3003- context_instance=RequestContext(request))
3004-
3005-def packageset_list(request):
3006- packagesets = models.PackageSet.objects.all()
3007- context = {
3008- 'packagesets': packagesets
3009- }
3010- return render('opportunities/packageset_list.html',
3011- context,
3012- context_instance=RequestContext(request))
3013+ 'opportunities/filter.html',
3014+ context,
3015+ context_instance=RequestContext(request))
3016+
3017+
3018+def opportunities_filter_results(request):
3019+ filters = HarvestFilters()
3020+ filters.update_from_http(request)
3021+
3022+ packages_list = _create_packages_list(request, filters.find('pkg'), filters.find('opp'))
3023+
3024+ context = {
3025+ 'grouping': 'package',
3026+ 'packages_list': packages_list
3027+ }
3028+
3029+ return render(
3030+ 'opportunities/filter_results.html',
3031+ context,
3032+ context_instance=RequestContext(request))
3033+
3034+
3035+def opportunities_package_details(request, package_id):
3036+ filters = HarvestFilters()
3037+ filters.update_from_http(request)
3038+
3039+ package = models.SourcePackage.objects.get(id=package_id)
3040+
3041+ opportunities_list = filters.find('opp').process_queryset(package.opportunity_set).all()
3042+
3043+ package_wrapper = PackageWrapper(request, package, visible_opportunities = opportunities_list, expanded = True)
3044+
3045+ context = {
3046+ 'grouping': 'package',
3047+ 'package': package_wrapper
3048+ }
3049+
3050+ return render(
3051+ 'opportunities/package_details.html',
3052+ context,
3053+ context_instance=RequestContext(request))
3054
3055=== modified file 'harvest/opportunities/wrappers.py'
3056--- harvest/opportunities/wrappers.py 2010-06-23 03:14:51 +0000
3057+++ harvest/opportunities/wrappers.py 2010-07-15 16:29:40 +0000
3058@@ -17,7 +17,7 @@
3059 return self.package
3060
3061 def get_expand_toggle_url(self):
3062- parameter = {'expand_pkg' : self.package.name}
3063+ parameter = {'expand_pkg' : self.package.id}
3064 url = current_url_with_parameters(self.request, parameter)
3065 return url
3066
3067@@ -38,7 +38,7 @@
3068 been hidden from view
3069 """
3070 opps_visible = self.get_visible_opportunities()
3071- return self.package.opportunity_set.exclude(pk__in=opps_visible)
3072+ return self.package.opportunity_set.exclude(id__in=opps_visible)
3073
3074 class PackageListWrapper(object):
3075 """
3076@@ -48,9 +48,10 @@
3077 """
3078
3079 def __init__(self, request, packages_list, opportunities_list):
3080- expand_list = None #list of packages to show in detail
3081+ expand_list = list() #list of packages to show in detail
3082 if 'expand_pkg' in request.GET:
3083 expand_list = request.GET['expand_pkg'].split(',')
3084+ expand_list = [int(i) for i in expand_list if i.isdigit()]
3085
3086 related_packages = set(opportunities_list.values_list('sourcepackage', flat=True))
3087
3088@@ -64,7 +65,7 @@
3089 opps = None
3090 expand = False
3091
3092- if expand_list: expand = (package.name in expand_list)
3093+ expand = (package.id in expand_list)
3094 opps = opportunities_list.filter(sourcepackage=package)
3095
3096 package_wrapper = PackageWrapper(request, package,
3097@@ -87,4 +88,4 @@
3098 """
3099 Returns list of packages that have been hidden from view.
3100 """
3101- return self.hidden_packages_list
3102\ No newline at end of file
3103+ return self.hidden_packages_list
3104
3105=== modified file 'harvest/settings.py'
3106--- harvest/settings.py 2010-07-05 10:15:55 +0000
3107+++ harvest/settings.py 2010-07-15 16:29:40 +0000
3108@@ -19,6 +19,9 @@
3109 VERSION_STRING = utils.get_harvest_version(
3110 os.path.join(PROJECT_PATH, "version"),
3111 DEBUG)
3112+VERSION_NAME_STRING = utils.get_harvest_version_name(
3113+ os.path.join(PROJECT_PATH, "version"),
3114+ DEBUG)
3115
3116 ADMINS = ('Daniel Holbach', 'daniel.holbach@ubuntu.com')
3117 MANAGERS = ADMINS
3118@@ -73,6 +76,7 @@
3119 )
3120
3121 MIDDLEWARE_CLASSES = (
3122+ 'harvest.common.middleware.timer.TimerMiddleware',
3123 'django.middleware.common.CommonMiddleware',
3124 'django.contrib.sessions.middleware.SessionMiddleware',
3125 'django.contrib.auth.middleware.AuthenticationMiddleware',
3126
3127=== modified file 'harvest/templates/base.html'
3128--- harvest/templates/base.html 2010-06-01 16:16:19 +0000
3129+++ harvest/templates/base.html 2010-07-15 16:29:40 +0000
3130@@ -1,91 +1,86 @@
3131 {% load i18n %}
3132-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 strict//EN"
3133- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3134+<!DOCTYPE html>
3135 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="{{ LANGUAGE_CODE }}" lang="{{ LANGUAGE_CODE }}">
3136+
3137 <head>
3138- <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
3139- <title>{% block title %}{% trans "Harvest" %}{% endblock %}</title>
3140- <link rel="stortcut icon" href="{{ MEDIA_URL }}img/favicon.ico" type="image/x-icon" />
3141- <link rel="stylesheet" href="{{ MEDIA_URL }}css/style.css" type="text/css" media="screen" />
3142-
3143- <script type="text/javascript" src="{{ MEDIA_URL }}js/yui-min.js"></script>
3144-
3145-{% block extrahead %}{% endblock %}
3146+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
3147+ <title>{% block title %}{% trans "Harvest" %}{% endblock %}</title>
3148+
3149+ <link rel="stortcut icon" href="{{ MEDIA_URL }}img/favicon.ico" type="image/x-icon" />
3150+
3151+ <link href='http://fonts.googleapis.com/css?family=Molengo' rel='stylesheet' type='text/css' />
3152+
3153+ <link rel="stylesheet" href="{{ MEDIA_URL }}css/reset.css" />
3154+ <link rel="stylesheet" href="{{ MEDIA_URL }}css/style.css" />
3155+
3156+ <script type="text/javascript" src="{{ MEDIA_URL }}js/jquery-1.4.2.min.js"></script>
3157+ <script type="text/javascript" src="{{ MEDIA_URL }}js/jquery.scrollstay.js"></script>
3158+ <script type="text/javascript" src="{{ MEDIA_URL }}js/jquery.placeheld.js"></script>
3159+ <script type="text/javascript" src="{{ MEDIA_URL }}js/harvest.js"></script>
3160+
3161+ {% block extrahead %}{% endblock %}
3162 </head>
3163
3164 <body>
3165 <div id="container">
3166- <div id="content">
3167- <div id="topNav">
3168- <p id="whoami">
3169- {% if user.is_authenticated %}
3170- {{ user.username }}
3171- &nbsp;
3172- <a href="/logout">Log out</a>
3173- {% else %}
3174- <a href="/openid/login">Log in</a>
3175- {% endif %}</p>
3176- <a href="/"><img id="ubuntulogo" src="{{ MEDIA_URL }}img/ubuntulogo.png" alt="Ubuntu" /></a>
3177- </div>
3178- <div id="body">
3179- <div class="content">
3180-{% if messages %}
3181-{% for message in messages %}
3182-<p>{{ message }}</p>
3183-{% endfor %}
3184-{% endif %}
3185-
3186-{% block content %}
3187-{% endblock %}
3188-
3189-{% block pagination %}
3190-{% if is_paginated %}
3191- <div class="pagination">
3192- {% if page_obj.has_previous %}
3193- <a href="?page={{ page_obj.previous_page_number }}">&lt;&lt;Previous</a>
3194- {% else %}
3195- &lt;&lt;Previous
3196- {% endif %}
3197-
3198- <span class="pages">
3199- {% for item in paginator.page_range %}
3200- {% ifequal item page %}
3201- <span class="current-page">{{ item }}</span>
3202- {% else %}
3203- <a href="?page={{ item }}">{{ item }}</a>
3204- {% endifequal %}
3205- {% endfor %}
3206- </span>
3207-
3208- {% if page_obj.has_next %}
3209- <a href="?page={{ page_obj.next_page_number }}">Next &gt;&gt;</a>
3210- {% else %}
3211- Next &gt;&gt;
3212- {% endif %}
3213- </div>
3214-{% endif %}
3215-{% endblock %}
3216-
3217- </div>
3218-
3219-{% if translator_credits %}
3220-<p class="footnote">
3221-{% trans "Translated by:" %} {{ translator_credits|join:", " }}
3222-</p>
3223-{% endif %}
3224- </div>
3225-
3226- <div id="footer">
3227- <div class="wrapper">
3228- <img src="{{ MEDIA_URL }}img/rule.png" width="740" height="1" alt="" class="rule" />
3229- <p>&copy; 2008-2009 Canonical Ltd. Ubuntu and Canonical are registered
3230- trademarks of Canonical Ltd.<br />{% trans "Harvest" %} {{ harvest_version }}</p>
3231- </div>
3232- </div>
3233- <div id="bg-right">&nbsp;</div><div id="bottom-right">&nbsp;</div>
3234- </div>
3235- <div id="bg-left">&nbsp;</div><div id="bottom-left">&nbsp;</div>
3236+
3237+<div id="header">
3238+ <span id="pagetitle">
3239+ <img id="sitelogo" src="{{ MEDIA_URL }}img/logo_humanity-search-icon.png" />
3240+ <h1 id="sitename">{% trans "Harvest" %}</h1>
3241+ {% if harvest_version_name %}<span id="releasename">{{harvest_version_name}}</span>{% endif %}
3242+ </span>
3243+
3244+ <span id="userdata">
3245+ {% if user.is_authenticated %}
3246+ <span class="username">{{ user.username }}</span>
3247+ <br /><a class="loginbutton" href="/logout" tabindex="1">Log out</a>
3248+ {% else %}
3249+ <a class="loginbutton" href="/openid/login">Log in</a>
3250+ {% endif %}
3251+ </span>
3252+</div>
3253+
3254+<div id="content">
3255+ {% if messages %}
3256+ <div id="messages"><ul>
3257+ {% for message in messages %}
3258+ <li>{{ message }}</li>
3259+ {% endfor %}
3260+ </ul></div>
3261+ {% endif %}
3262+ {% block content %}
3263+
3264+
3265+
3266+ {% endblock %}
3267+</div>
3268+
3269+<div id="footer">
3270+ <div id="footnav"><nav>
3271+ <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>
3272+ </nav></div>
3273+
3274+ <div id="smallprint" tabindex="3">
3275+ <span id="copyright">
3276+ &copy; 2008-2009 Canonical Ltd.
3277+ <br />Ubuntu and Canonical are registered
3278+ trademarks of Canonical Ltd.
3279+ </span>
3280+
3281+ <span id="techdetails">
3282+ {% trans "Harvest" %} {{ harvest_version }}
3283+ {% if translator_credits %}
3284+ <br />{% trans "Translated by:" %} {{ translator_credits|join:", " }}
3285+ {% endif %}
3286+ <br /><span id="requeststats"></span>
3287+ </span>
3288+
3289+ <div class="bottom"></div>
3290+ </div>
3291+</div>
3292
3293 </div>
3294 </body>
3295+
3296 </html>
3297
3298=== modified file 'harvest/templates/index.html'
3299--- harvest/templates/index.html 2010-02-03 23:28:50 +0000
3300+++ harvest/templates/index.html 2010-07-15 16:29:40 +0000
3301@@ -8,13 +8,7 @@
3302
3303 <h1>{% trans "Harvest" %}</h1>
3304
3305-Find opportunities!
3306-
3307-<ul>
3308- <li><a href="{% url opportunities_by_type %}">By type</a></li>
3309- <li><a href="{% url opportunities_by_package %}">By package</a></li>
3310- <li><a href="{% url packageset_list %}">By packageset</a></li>
3311-<ul>
3312+There is no landing page at the moment :(
3313
3314
3315 {% if translator_credits %}
3316
3317=== renamed file 'harvest/templates/opportunities/opportunities_filter.html' => 'harvest/templates/opportunities/filter.html'
3318--- harvest/templates/opportunities/opportunities_filter.html 2010-06-22 05:18:50 +0000
3319+++ harvest/templates/opportunities/filter.html 2010-07-15 16:29:40 +0000
3320@@ -4,47 +4,19 @@
3321 {% block title %}{% trans "Opportunity Index" %} - {{ block.super }}{% endblock %}
3322
3323 {% block content %}
3324-<div class="mainpage">
3325-
3326-<h1>{% trans "Opportunities" %}</h1>
3327-
3328-<div class="filters" style="background-color:#E0F1FF; float:left; width:15em;">
3329+
3330+<div id="filters">
3331 {{filters_pkg.render}}
3332 {{filters_opp.render}}
3333 </div>
3334
3335-<div class="results" style="float:left;">
3336-{% if packages_list %}
3337-<ul>
3338- {% for pkg in packages_list.get_visible_packages %}
3339- <li><a href="{{ pkg.get_expand_toggle_url }}">{{ pkg.real.name }}</a>
3340- {% if pkg.expanded %}
3341- <ul>
3342- {% for opportunity in pkg.get_visible_opportunities %}
3343- {% include "opportunities/opportunity_detail.inc.html" %}
3344- {% endfor %}
3345-
3346- {% with pkg.get_hidden_opportunities.count as hidden_count %}
3347- {% ifnotequal hidden_count 0 %}
3348- <li><small>{{ hidden_count }} {{ hidden_count|pluralize:"opportunity,opportunities"}} hidden</small></li>
3349- {% endifnotequal %}
3350- {% endwith %}
3351- </ul>
3352- {% endif %}
3353- </li>
3354- {% endfor %}
3355-
3356- {% with packages_list.get_hidden_packages|length as hidden_count %}
3357- {% ifnotequal hidden_count 0 %}
3358- <li><small>{{ hidden_count }} package{{ hidden_count|pluralize:"s"}} {{ hidden_count|pluralize:"has,have"}} no matching opportunities</small></li>
3359- {% endifnotequal %}
3360- {% endwith %}
3361-</ul>
3362-
3363-{% else %}
3364-<p>{% trans "There are currently no opportunities in Harvest. :(" %}</p>
3365-{% endif %}
3366-</div>
3367-
3368-</div>
3369+<div id="results-pane" data-results-url="{% url opportunities_filter_results %}">
3370+ <div id="results-status"></div>
3371+ <div id="results">
3372+ {% include "opportunities/filter_results.html" %}
3373+ </div>
3374+</div>
3375+
3376+<div class="bottom"></div>
3377+
3378 {% endblock %}
3379
3380=== added file 'harvest/templates/opportunities/filter_results.html'
3381--- harvest/templates/opportunities/filter_results.html 1970-01-01 00:00:00 +0000
3382+++ harvest/templates/opportunities/filter_results.html 2010-07-15 16:29:40 +0000
3383@@ -0,0 +1,33 @@
3384+{% load i18n %}
3385+
3386+{% if packages_list %}
3387+<ul>
3388+ {% for package in packages_list.get_visible_packages %}
3389+ <li data-results-packageid="{{ package.real.id }}" class="sourcepackage {% if package.expanded %}expanded{% else %}collapsed{% endif %}">
3390+ <a class="sourcepackage-header" href="{{ package.get_expand_toggle_url }}">
3391+ <span class="sourcepackage-name">{{ package.real.name }}</span>
3392+ <span class="status"></span>
3393+ <span class="sourcepackage-summary">
3394+ X issues (TODO)
3395+ </span>
3396+ <div class="bottom"></div>
3397+ </a>
3398+ <div class="sourcepackage-details">
3399+ {% if package.expanded %}
3400+ {% include "opportunities/package_details.html" %}
3401+ {% endif %}
3402+ </div>
3403+ </li>
3404+ {% endfor %}
3405+
3406+ {% with packages_list.get_hidden_packages|length as hidden_count %}
3407+ {% ifnotequal hidden_count 0 %}
3408+ <li><small>{% blocktrans count hidden_count as counter %}{{ counter }} package has no matching opportunities{% plural %}{{ counter }} packages have no matching opportunities{% endblocktrans %}</small></li>
3409+ {% endifnotequal %}
3410+ {% endwith %}
3411+</ul>
3412+
3413+{% else %}
3414+<p>{% trans "There are currently no opportunities in Harvest. :(" %}</p>
3415+{% endif %}
3416+
3417
3418=== modified file 'harvest/templates/opportunities/opportunity_detail.inc.html'
3419--- harvest/templates/opportunities/opportunity_detail.inc.html 2010-06-08 16:21:40 +0000
3420+++ harvest/templates/opportunities/opportunity_detail.inc.html 2010-07-15 16:29:40 +0000
3421@@ -9,7 +9,7 @@
3422 ({{ opportunity.opportunitylist }})
3423 {% endifequal %}
3424 {% else %}
3425- (<a href="{% url sourcepackage_detail opportunity.sourcepackage.name %}">({{ opportunity.sourcepackage }})</a> - {{ opportunity.opportunitylist }})
3426+ (<a href="{% url opportunities_package_details opportunity.sourcepackage.id %}">({{ opportunity.sourcepackage }})</a> - {{ opportunity.opportunitylist }})
3427 {% endif %}
3428 {% if opportunity.experience %}
3429 <span class="experience{{ opportunity.experience }}"></span>
3430
3431=== removed file 'harvest/templates/opportunities/opportunity_index.html'
3432--- harvest/templates/opportunities/opportunity_index.html 2010-06-07 15:04:29 +0000
3433+++ harvest/templates/opportunities/opportunity_index.html 1970-01-01 00:00:00 +0000
3434@@ -1,45 +0,0 @@
3435-{% extends "base.html" %}
3436-{% load i18n %}
3437-
3438-{% block title %}{% trans "Opportunity Index" %} - {{ block.super }}{% endblock %}
3439-
3440-{% block content %}
3441-<div class="mainpage">
3442-
3443-<h1>{% trans "Opportunities" %}</h1>
3444-
3445-{% if sources.object_list %}
3446-<ul>
3447-{% for source in sources.object_list %}
3448-<li><a href="{% url sourcepackage_detail source.name %}">{{ source.name }}</a>
3449-<ul>
3450-{% for opportunity in source.valid_opportunites %}
3451- {% include "opportunities/opportunity_detail.inc.html" %}
3452-{% endfor %}
3453-</ul>
3454-</li>
3455-{% endfor %}
3456-</ul>
3457-
3458-<div class="pagination">
3459- <span class="step-links">
3460- {% if sources.has_previous %}
3461- <a href="?page={{ sources.previous_page_number }}">previous</a>
3462- {% endif %}
3463-
3464- <span class="current">
3465- Page {{ sources.number }} of {{ sources.paginator.num_pages }}.
3466- </span>
3467-
3468- {% if sources.has_next %}
3469- <a href="?page={{ sources.next_page_number }}">next</a>
3470- {% endif %}
3471- </span>
3472-</div>
3473-
3474-{% else %}
3475-<p>{% trans "There are currently no opportunities in Harvest. :(" %}</p>
3476-{% endif %}
3477-
3478-</div>
3479-{% endblock %}
3480
3481=== removed file 'harvest/templates/opportunities/opportunity_list.html'
3482--- harvest/templates/opportunities/opportunity_list.html 2010-02-22 15:43:51 +0000
3483+++ harvest/templates/opportunities/opportunity_list.html 1970-01-01 00:00:00 +0000
3484@@ -1,14 +0,0 @@
3485-{% extends "base.html" %}
3486-
3487-{% load i18n %}
3488-
3489-{% block title %}{% trans "Opportunities" %} - {{ block.super }}{% endblock %}
3490-
3491-{% block content %}
3492- <h2>Opportunities</h2>
3493- <ul>
3494- {% for opportunity in opportunity_list %}
3495- {% include "opportunities/opportunity_detail.inc.html" %}
3496- {% endfor %}
3497- </ul>
3498-{% endblock %}
3499
3500=== removed file 'harvest/templates/opportunities/opportunitylist_detail.html'
3501--- harvest/templates/opportunities/opportunitylist_detail.html 2010-02-22 15:43:51 +0000
3502+++ harvest/templates/opportunities/opportunitylist_detail.html 1970-01-01 00:00:00 +0000
3503@@ -1,13 +0,0 @@
3504-{% extends "base.html" %}
3505-
3506-{% block title %}{{ opportunitylist.name }} - {{ block.super }}{% endblock %}
3507-
3508-{% block content %}
3509- <h2>{{ opportunitylist.name }}</h2>
3510- <p>{{ opportunitylist.description }}</p>
3511- <ul>
3512- {% for opportunity in object_list %}
3513- {% include "opportunities/opportunity_detail.inc.html" %}
3514- {% endfor %}
3515- </ul>
3516-{% endblock %}
3517
3518=== removed file 'harvest/templates/opportunities/opportunitylist_list.html'
3519--- harvest/templates/opportunities/opportunitylist_list.html 2010-07-12 09:33:48 +0000
3520+++ harvest/templates/opportunities/opportunitylist_list.html 1970-01-01 00:00:00 +0000
3521@@ -1,14 +0,0 @@
3522-{% extends "base.html" %}
3523-
3524-{% load i18n %}
3525-
3526-{% block title %}{% trans "Opportunity Lists" %} - {{ block.super }}{% endblock %}
3527-
3528-{% block content %}
3529- <h2>Opportunity Lists</h2>
3530- {% for opportunity_list in object_list %}
3531- <h3><a href="{% url opportunitylist_detail opportunity_list %}">{{ opportunity_list.name }}</a>
3532- {% blocktrans count opportunity_list.opportunity__count as counter %}(1 opportunity){% plural %}({{ counter }} opportunities){% endblocktrans %}</h3>
3533- <p>{{ opportunity_list.description }}</p>
3534- {% endfor %}
3535-{% endblock %}
3536
3537=== added file 'harvest/templates/opportunities/package_details.html'
3538--- harvest/templates/opportunities/package_details.html 1970-01-01 00:00:00 +0000
3539+++ harvest/templates/opportunities/package_details.html 2010-07-15 16:29:40 +0000
3540@@ -0,0 +1,13 @@
3541+{% load i18n %}
3542+
3543+<ul>
3544+ {% for opportunity in package.get_visible_opportunities %}
3545+ {% include "opportunities/opportunity_detail.inc.html" %}
3546+ {% endfor %}
3547+
3548+ {% with package.get_hidden_opportunities.count as hidden_count %}
3549+ {% ifnotequal hidden_count 0 %}
3550+ <li><small>{% blocktrans count hidden_count as counter %}{{ counter }} opportunity hidden{% plural %}{{ counter }} opportunities hidden{% endblocktrans %}</small></li>
3551+ {% endifnotequal %}
3552+ {% endwith %}
3553+</ul>
3554
3555=== removed file 'harvest/templates/opportunities/packageset_list.html'
3556--- harvest/templates/opportunities/packageset_list.html 2010-02-03 23:28:50 +0000
3557+++ harvest/templates/opportunities/packageset_list.html 1970-01-01 00:00:00 +0000
3558@@ -1,14 +0,0 @@
3559-{% extends "base.html" %}
3560-
3561-{% load i18n %}
3562-
3563-{% block title %}{% trans "Packagesets" %} - {{ block.super }}{% endblock %}
3564-{% block content %}
3565- <h2>Packagesets</h2>
3566- <ul>
3567- {% for packageset in packagesets %}
3568- <li><a href="{{ packageset.name }}">{{ packageset.name }}</a></li>
3569- {% endfor %}
3570- </ul>
3571-{% endblock %}
3572-
3573
3574=== removed file 'harvest/templates/opportunities/sourcepackage_detail.html'
3575--- harvest/templates/opportunities/sourcepackage_detail.html 2010-02-22 15:43:51 +0000
3576+++ harvest/templates/opportunities/sourcepackage_detail.html 1970-01-01 00:00:00 +0000
3577@@ -1,12 +0,0 @@
3578-{% extends "base.html" %}
3579-
3580-{% block title %}{{ object.name }} - {{ block.super }}{% endblock %}
3581-
3582-{% block content %}
3583- <h2>{{ object.name }}</h2>
3584- <ul>
3585- {% for opportunity in opportunities %}
3586- {% include "opportunities/opportunity_detail.inc.html" %}
3587- {% endfor %}
3588- </ul>
3589-{% endblock %}
3590
3591=== removed file 'harvest/templates/opportunities/sourcepackage_list.html'
3592--- harvest/templates/opportunities/sourcepackage_list.html 2010-07-12 09:33:48 +0000
3593+++ harvest/templates/opportunities/sourcepackage_list.html 1970-01-01 00:00:00 +0000
3594@@ -1,14 +0,0 @@
3595-{% extends "base.html" %}
3596-
3597-{% load i18n %}
3598-
3599-{% block title %}{% trans "Source Packages" %} - {{ block.super }}{% endblock %}
3600-
3601-{% block content %}
3602- <h2>Source Packages</h2>
3603- <ul>
3604- {% for source_package in object_list %}
3605- <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>
3606- {% endfor %}
3607- </ul>
3608-{% endblock %}
3609
3610=== modified file 'harvest/version'
3611--- harvest/version 2010-06-01 16:16:19 +0000
3612+++ harvest/version 2010-07-15 16:29:40 +0000
3613@@ -1,2 +1,3 @@
3614 version: 0.2.0-pre
3615+versionname: Alpha
3616 revno: 182

Subscribers

People subscribed via source and target branches

to all changes: