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
=== added file 'EXTERNALS'
--- EXTERNALS 1970-01-01 00:00:00 +0000
+++ EXTERNALS 2010-07-15 16:29:40 +0000
@@ -0,0 +1,78 @@
1This document lists files from outside sources, including their copyright and license details. These files remain under their respective licenses.
2
3
4./harvest/ordereddict.py
5 Copyright (c) 2009, Raymond Hettinger
6 Licensed under the MIT license (#1 below)
7 <http://pypi.python.org/pypi/ordereddict>
8
9./harvest/common/middleware/timer.py
10 By "metajack"
11 <http://djangosnippets.org/snippets/797/>
12
13./harvest/media/css/reset.css
14 By Eric Meyer
15 <http://meyerweb.com/eric/tools/css/reset/>
16
17./harvest/media/img/pkg-status-loading.gif,
18./harvest/media/img/results-status-loading.gif,
19./harvest/media/img/results-status-waiting.gif
20 <http://ajaxload.info/>
21 results-status-waiting.gif is derived from results-status-loading.gif
22
23./harvest/media/js/jquery-1.4.2.min.js
24 Copyright 2010, John Resig
25 Dual licensed under the MIT or GPL Version 2 licenses
26 <http://jquery.com>
27
28./harvest/media/js/jquery.placeheld.js
29 Copyright (c) 2010, Max Wheeler
30 Licensed under the WTFPL (#2 below)
31 <http://plugins.jquery.com/project/placeheld>
32
33./harvest/media/js/jquery.scrollstay.js
34 Derived from "jquery.scrollFollow.js"
35 Copyright (c) 2008 Net Perspective (http://kitchen.net-perspective.com/)
36 Licensed under the MIT License
37 <http://plugins.jquery.com/project/scroll-follow>
38
39
40
41---
42Licenses
43
44#1. MIT license
45
46 Permission is hereby granted, free of charge, to any person obtaining a copy
47 of this software and associated documentation files (the "Software"), to deal
48 in the Software without restriction, including without limitation the rights
49 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
50 copies of the Software, and to permit persons to whom the Software is
51 furnished to do so, subject to the following conditions:
52
53 The above copyright notice and this permission notice shall be included in
54 all copies or substantial portions of the Software.
55
56 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
57 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
58 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
59 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
60 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
61 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
62 THE SOFTWARE.
63
64#2. WTFPL
65
66 DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
67 Version 2, December 2004
68
69 Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
70
71 Everyone is permitted to copy and distribute verbatim or modified
72 copies of this license document, and changing it is allowed as long
73 as the name is changed.
74
75 DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
76 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
77
78 0. You just DO WHAT THE FUCK YOU WANT TO.
079
=== modified file 'TODO'
--- TODO 2010-03-08 16:31:25 +0000
+++ TODO 2010-07-15 16:29:40 +0000
@@ -1,6 +1,4 @@
1when people log in, get upload ACLs1when people log in, get upload ACLs
2Get graphic arrows for folding and unfolding
3Get AJAX spinner graphic
4On the home page, we need two large square graphics for "by type" and "by2On the home page, we need two large square graphics for "by type" and "by
5 package"3 package"
6Add lazr-js library for animations and overlays4Add lazr-js library for animations and overlays
75
=== added file 'doc/DOM for filters.txt'
--- doc/DOM for filters.txt 1970-01-01 00:00:00 +0000
+++ doc/DOM for filters.txt 2010-07-15 16:29:40 +0000
@@ -0,0 +1,83 @@
1It 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.
2
3We 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!
4
5For 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.
6
7
8
9
10----- General overview -----
11
12Here I will define the expected DOM hierarchy to be described in HTML and what it all means.
13
14#container - Contains everything. This is important for CSS, to align the footer correctly.
15 #header - The top part of the page, consistent and visible on most pages.
16 span#pagetitle - The title, which is drawn as the leftmost part of the header with a special font.
17 img#sitelogo - Logo for the web site.
18 h1#sitename - The actual name of the site.
19 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.
20 span#userdata - Tools specific to logging in, or the logged in user.
21
22
23
24 #content - The portion of the page that changes specific to what is being looked at.
25 #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.
26
27 #results-pane - Container that holds results and surrounding widgets.
28 #results - Holds the list of packages that results from the selected filters.
29
30 #footer
31 #footnav - More technical links go in here...
32 #smallprint - The fine print. Contents are shrunken and ellipsized (where supported) to be really unobtrusive. When moused over, they are shown in more detail.
33 #copyright - Copyright notice.
34 #techdetails - Stuff geeks and Harvest hackers may want to know, like page generation time and SQL queries count.
35
36
37
38
39-----Filters-----
40
41A list of filters goes inside the element #filters. (These are probably FilterGroups, which contain more filters). A filter is described as follows:
42<span class="filter editfilter pkgnamefilter" data-filter-fullname="filter-pkg:name">
43The 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.
44
45
46The immediate contents of each Filter object should be consistent:
47
48.filter
49 .filter-label - The filter's label. This is its name, usually spanning a single line.
50 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.
51 .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.
52
53
54Now I will describe the different .filter-value elements that are expected.
55
56.filtergroup , .choicefilter
57 .filter-value ul - List items are all possible choices for the filter.
58 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.
59 .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;).
60
61.choicefilter
62 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.
63
64.filtergroup
65 ul > li .filter > .filter-label > .item-toggle - Just like a.item-toggle with .choicefilter; just unfortunately placed for technical reasons.
66
67.editfilter
68 .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.
69 (##TODO##: require type="hidden" if Javascript dependency remains).
70
71
72
73
74-----Standard Attributes-----
75
76For .filter:
77 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").
78 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.
79
80For .filtergroup > ul > li and .choicefilter > ul > li:
81 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").
82 data-selected: Add if the choice is currently selected.
83
084
=== modified file 'harvest/common/context_processors.py'
--- harvest/common/context_processors.py 2010-06-01 16:16:19 +0000
+++ harvest/common/context_processors.py 2010-07-15 16:29:40 +0000
@@ -2,14 +2,20 @@
22
3def harvest_version(request):3def harvest_version(request):
4 """4 """
5 add the harvest version to template context processor. 5 add the version number and name to template context processor
6 """6 """
7 try:7 try:
8 version = settings.VERSION_STRING8 version = settings.VERSION_STRING
9 except AttributeError:9 except AttributeError:
10 version = "unknown"10 version = "unknown"
11
12 try:
13 version_name = settings.VERSION_NAME_STRING
14 except AttributeError:
15 version_name = ""
1116
12 return {'harvest_version': version}17 return {'harvest_version': version,
18 'harvest_version_name': version_name}
1319
14def login_redirect(request):20def login_redirect(request):
15 return {'login_next': request.get_full_path()}21 return {'login_next': request.get_full_path()}
1622
=== added directory 'harvest/common/middleware'
=== added file 'harvest/common/middleware/__init__.py'
=== added file 'harvest/common/middleware/timer.py'
--- harvest/common/middleware/timer.py 1970-01-01 00:00:00 +0000
+++ harvest/common/middleware/timer.py 2010-07-15 16:29:40 +0000
@@ -0,0 +1,19 @@
1# Adds an 'X-Django-Request-Time' HTTP response header
2# that times how long django spent processing the request.
3# From <http://djangosnippets.org/snippets/797/>
4
5from time import time
6
7class TimerMiddleware(object):
8 def process_request(self, request):
9 request._tm_start_time = time()
10
11 def process_response(self, request, response):
12 if not hasattr(request, "_tm_start_time"):
13 return
14
15 total_time = time() - request._tm_start_time
16
17 response['X-Django-Request-Time'] = '%fs' % total_time
18
19 return response
020
=== added file 'harvest/common/ordereddict.py'
--- harvest/common/ordereddict.py 1970-01-01 00:00:00 +0000
+++ harvest/common/ordereddict.py 2010-07-15 16:29:40 +0000
@@ -0,0 +1,127 @@
1# Copyright (c) 2009 Raymond Hettinger
2#
3# Permission is hereby granted, free of charge, to any person
4# obtaining a copy of this software and associated documentation files
5# (the "Software"), to deal in the Software without restriction,
6# including without limitation the rights to use, copy, modify, merge,
7# publish, distribute, sublicense, and/or sell copies of the Software,
8# and to permit persons to whom the Software is furnished to do so,
9# subject to the following conditions:
10#
11# The above copyright notice and this permission notice shall be
12# included in all copies or substantial portions of the Software.
13#
14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21# OTHER DEALINGS IN THE SOFTWARE.
22
23from UserDict import DictMixin
24
25class OrderedDict(dict, DictMixin):
26
27 def __init__(self, *args, **kwds):
28 if len(args) > 1:
29 raise TypeError('expected at most 1 arguments, got %d' % len(args))
30 try:
31 self.__end
32 except AttributeError:
33 self.clear()
34 self.update(*args, **kwds)
35
36 def clear(self):
37 self.__end = end = []
38 end += [None, end, end] # sentinel node for doubly linked list
39 self.__map = {} # key --> [key, prev, next]
40 dict.clear(self)
41
42 def __setitem__(self, key, value):
43 if key not in self:
44 end = self.__end
45 curr = end[1]
46 curr[2] = end[1] = self.__map[key] = [key, curr, end]
47 dict.__setitem__(self, key, value)
48
49 def __delitem__(self, key):
50 dict.__delitem__(self, key)
51 key, prev, next = self.__map.pop(key)
52 prev[2] = next
53 next[1] = prev
54
55 def __iter__(self):
56 end = self.__end
57 curr = end[2]
58 while curr is not end:
59 yield curr[0]
60 curr = curr[2]
61
62 def __reversed__(self):
63 end = self.__end
64 curr = end[1]
65 while curr is not end:
66 yield curr[0]
67 curr = curr[1]
68
69 def popitem(self, last=True):
70 if not self:
71 raise KeyError('dictionary is empty')
72 if last:
73 key = reversed(self).next()
74 else:
75 key = iter(self).next()
76 value = self.pop(key)
77 return key, value
78
79 def __reduce__(self):
80 items = [[k, self[k]] for k in self]
81 tmp = self.__map, self.__end
82 del self.__map, self.__end
83 inst_dict = vars(self).copy()
84 self.__map, self.__end = tmp
85 if inst_dict:
86 return (self.__class__, (items,), inst_dict)
87 return self.__class__, (items,)
88
89 def keys(self):
90 return list(self)
91
92 setdefault = DictMixin.setdefault
93 update = DictMixin.update
94 pop = DictMixin.pop
95 values = DictMixin.values
96 items = DictMixin.items
97 iterkeys = DictMixin.iterkeys
98 itervalues = DictMixin.itervalues
99 iteritems = DictMixin.iteritems
100
101 def __repr__(self):
102 if not self:
103 return '%s()' % (self.__class__.__name__,)
104 return '%s(%r)' % (self.__class__.__name__, self.items())
105
106 def copy(self):
107 return self.__class__(self)
108
109 @classmethod
110 def fromkeys(cls, iterable, value=None):
111 d = cls()
112 for key in iterable:
113 d[key] = value
114 return d
115
116 def __eq__(self, other):
117 if isinstance(other, OrderedDict):
118 if len(self) != len(other):
119 return False
120 for p, q in zip(self.items(), other.items()):
121 if p != q:
122 return False
123 return True
124 return dict.__eq__(self, other)
125
126 def __ne__(self, other):
127 return not self == other
0128
=== modified file 'harvest/common/utils.py'
--- harvest/common/utils.py 2010-06-01 16:16:19 +0000
+++ harvest/common/utils.py 2010-07-15 16:29:40 +0000
@@ -23,3 +23,24 @@
2323
24 return "version %s (rev %s)" % (version, bzr_revno)24 return "version %s (rev %s)" % (version, bzr_revno)
2525
26
27def get_harvest_version_name(version_file, debug):
28 """
29 return a short string describing the version of harvest
30 """
31
32 version_str = ""
33
34 if debug:
35 try:
36 from bzrlib.branch import Branch
37 branch = Branch.open_containing('.')[0]
38 version_str = "Revision %s" % branch.revno()
39 except:
40 pass
41 elif os.path.exists(version_file):
42 f = email.message_from_file(open(version_file))
43 if "versionname" in f:
44 version_str = f["versionname"]
45
46 return version_str
2647
=== modified file 'harvest/filters/containers.py'
--- harvest/filters/containers.py 2010-06-24 06:53:17 +0000
+++ harvest/filters/containers.py 2010-07-15 16:29:40 +0000
@@ -1,4 +1,5 @@
1from harvest.common.url_tools import current_url_with_parameters1from harvest.common.url_tools import current_url_with_parameters
2from harvest.common.ordereddict import OrderedDict #while we wait for Python 2.7 :)
23
3class FilterContainer(object): #abstract4class FilterContainer(object): #abstract
4 """5 """
@@ -9,17 +10,17 @@
9 to exist for the entire life of the container.10 to exist for the entire life of the container.
10 """11 """
11 12
12 def __init__(self, filters_set): 13 def __init__(self, filters_list):
13 self.filters_dict = dict() #refers to Filter objects by their unique IDs14 self.filters_dict = OrderedDict() #refers to Filter objects by their unique IDs
14 self.add_filters(filters_set)15 self.add_filters(filters_list)
15 16
16 def add_filters(self, filters_set): #final17 def add_filters(self, filters_list): #final
17 """18 """
18 Adds a set of filters to be children of this one and informs19 Adds a list of filters to be children of this one and informs
19 each child that it belongs to this container.20 each child that it belongs to this container.
20 @param filter_set: a set of Filter objects21 @param filter_list: a list of Filter objects
21 """22 """
22 for child in set(filters_set):23 for child in list(filters_list):
23 self.filters_dict[child.get_id()] = child24 self.filters_dict[child.get_id()] = child
24 child.set_container(self)25 child.set_container(self)
25 26
@@ -56,8 +57,8 @@
56 update_from_http should be called with the current HttpRequest.57 update_from_http should be called with the current HttpRequest.
57 """58 """
58 59
59 def __init__(self, filters_set, default_parameters = dict()):60 def __init__(self, filters_list, default_parameters = dict()):
60 FilterContainer.__init__(self, filters_set)61 FilterContainer.__init__(self, filters_list)
61 self.request = None #current http request62 self.request = None #current http request
62 self.default_parameters = default_parameters63 self.default_parameters = default_parameters
63 64
6465
=== modified file 'harvest/filters/filters.py'
--- harvest/filters/filters.py 2010-06-27 21:05:08 +0000
+++ harvest/filters/filters.py 2010-07-15 16:29:40 +0000
@@ -1,9 +1,8 @@
1#FIXME: Make ChoiceFilter a bit nicer so we don't need to call super() and all that bother from harvest.opportunities.filters.1#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.
2#TODO: adjust Filter.render() methods for custom template tags, with django.template.Template2#TODO: adjust Filter.render() methods for custom template tags and use django.template.Template
33
4from containers import FilterContainer, FilterSystem4from containers import FilterContainer, FilterSystem
5from django.utils.safestring import mark_safe5from django.utils.safestring import mark_safe
6from copy import copy
76
8class Filter(object): #abstract, extend in application7class Filter(object): #abstract, extend in application
9 """8 """
@@ -27,11 +26,24 @@
27 describing it for a user interface.26 describing it for a user interface.
28 """27 """
29 28
30 #TODO: figure out get_system and get_full_name when set_container is called and store the value29 #TODO: generate this automatically
30 html_class = 'filter'
31 """
32 The class that this object should have in its html representation.
33 A subclass should override this property to list all Filter classes
34 it inherits from, separated by spaces and in lower case.
35 """
31 36
32 def __init__(self, id_str): #final37 def __init__(self, id_str, **kwargs): #final
33 self.id_str = id_str #local name38 self.id_str = id_str #local name
34 self.container = None #immediate container (FilterContainer)39 self.container = None #immediate container (FilterContainer)
40
41 self.system = None #cache for self.get_system
42 self.full_name = None #cache for self.get_full_name
43
44 self.name = self.id_str
45 if 'name' in kwargs:
46 self.name = kwargs['name']
35 47
36 def get_id(self): #final48 def get_id(self): #final
37 """49 """
@@ -56,27 +68,36 @@
56 68
57 def get_system(self): #final69 def get_system(self): #final
58 """70 """
59 @return: the FilterSystem that this filter ultimately belongs to71 Returns the FilterSystem that this filter ultimately belongs to.
72 All objects in the system need to be created by the time this
73 method is called.
74 @return: the root FilterSystem
60 """75 """
61 container = self.get_container()76 if self.system == None:
62 system = None77 container = self.get_container()
63 if isinstance(container, Filter): 78 system = None
64 system = container.get_system()79 if isinstance(container, Filter):
65 elif isinstance(container, FilterSystem):80 system = container.get_system()
66 system = container81 elif isinstance(container, FilterSystem):
67 return system82 system = container
83 self.system = system
84 return self.system
68 85
69 def get_full_name(self): #final86 def get_full_name(self): #final
70 """87 """
71 Returns the filter's full name, which should make sense from anywhere88 Returns the filter's full name, which should make sense from anywhere
72 in the application. This name is in the format parent:child:child.89 in the application. This name is in the format parent:child:child.
90 All objects in the system need to be created by the time this
91 method is called.
73 @return: the filter's full name, which is a string92 @return: the filter's full name, which is a string
74 """93 """
75 full_name = self.get_id()94 if self.full_name == None:
76 container = self.get_container()95 full_name = self.get_id()
77 if isinstance(container, Filter):96 container = self.get_container()
78 full_name = "%s:%s" % (container.get_full_name(), full_name)97 if isinstance(container, Filter):
79 return full_name98 full_name = "%s:%s" % (container.get_full_name(), full_name)
99 self.full_name = full_name
100 return self.full_name
80 101
81 def set_value(self, value): #abstract102 def set_value(self, value): #abstract
82 """103 """
@@ -92,15 +113,6 @@
92 """113 """
93 raise NotImplementedError(self.get_value)114 raise NotImplementedError(self.get_value)
94 115
95 def serialize_value(self, value): #abstract
96 """
97 The inverse of set_value. Returns the given value as a string that could
98 be added to an HTTP query string.
99 @param value: the value to serialize, in a format native to this Filter (see get_value)
100 @return: a unicode string formatted for set_value
101 """
102 raise NotImplementedError(self.serialize_value)
103
104 def serialize(self, value = None): #final116 def serialize(self, value = None): #final
105 """117 """
106 Creates a dictionary of parameters to describe this object, either118 Creates a dictionary of parameters to describe this object, either
@@ -114,17 +126,14 @@
114 value_str = self.serialize_value(value)126 value_str = self.serialize_value(value)
115 return {key : value_str}127 return {key : value_str}
116 128
117 def get_container_toggle_parameters(self): #final129 def serialize_value(self, value): #abstract
118 """130 """
119 Helper method to get the parameter for toggling this filter's state in131 The inverse of set_value. Returns the given value as a string that could
120 its container, if there is one.132 be added to an HTTP query string.
121 @return: a dictionary of key:value pairs to generate new GET parameters133 @param value: the value to serialize, in a format native to this Filter (see get_value)
122 """134 @return: a unicode string formatted for set_value
123 container = self.get_container()135 """
124 params = dict()136 raise NotImplementedError(self.serialize_value)
125 if isinstance(container, FilterGroup):
126 params = container.serialize(container.get_value_with_selection(self.get_id()))
127 return params
128 137
129 def process_queryset(self, queryset): #abstract138 def process_queryset(self, queryset): #abstract
130 """139 """
@@ -135,29 +144,62 @@
135 """144 """
136 raise NotImplementedError(self.process_queryset)145 raise NotImplementedError(self.process_queryset)
137 146
138 def render(self): #final147 def render(self, **kwargs): #final
139 """148 """
140 @return: the default rendering of the filter itself in given context149 @return: the default rendering of the filter itself in given context
141 """150 """
142 return self.render_html()151 return self.render_html()
143 152
144 def render_html(self):153 def render_html(self, **kwargs): #final
154 """
155 @return: the entire filter, rendered as html
156 """
157 inner_html = self.render_html_inner(**kwargs)
158
159 #safe because we are in full control of this content
160 return mark_safe('<span class="%s" data-filter-fullname="%s">\n%s\n</span>' \
161 % (self.html_class,
162 self.get_full_name(),
163 inner_html ) )
164
165 def render_html_inner(self, **kwargs):
145 """166 """
146 Extend this to return the html output for the filter itself.167 Extend this to return the html output for the filter itself.
147 The output should be very simple and semantically meaningful,168 (The inside part, without the <span class=filter> boilerplate).
148 with no specific concern about formatting. It will be169 The output should be simple and semantically meaningful, with no
149 placed within other tags that describe its context, and it is170 specific concern about formatting. It will be placed within other
150 up to the template to describe style.171 tags that describe its context.
151 @return: a unicode string containing html representing this filter172 @return: the filter's contents, rendered as html
152 """173 """
153 system = self.get_system()174 label = self.render_html_label(**kwargs)
154 toggle_params = self.get_container_toggle_parameters()175 if label: label = '<span class="filter-label">%s</span>' % label
155 href = system.get_url_with_parameters(toggle_params)176 else: label = ''
156 177
157 return mark_safe(u'<a href="%s">(%s)</a>'178 value = self.render_html_value(**kwargs)
158 % (href, self.get_id()))179 if value: value = '<span class="filter-value">%s</span>' % value
159180 else: value = ''
160181
182 return '%s\n%s' % (label, value)
183
184 def render_html_label(self, **kwargs):
185 """
186 @return: the filter's label, rendered as html
187 """
188 link_url = None
189 if 'toggle_href' in kwargs:
190 link_url = kwargs['toggle_href']
191
192 label = self.name
193 if link_url:
194 label = '<a class="item-toggle" href="%s">%s</a>' % (link_url, label)
195
196 return label
197
198 def render_html_value(self, **kwargs):
199 """
200 @return: the filter's value, rendered as html
201 """
202 return None
161203
162204
163class EditFilter(Filter): #abstract, extend in application205class EditFilter(Filter): #abstract, extend in application
@@ -167,8 +209,10 @@
167 Serialized as stored ("value")209 Serialized as stored ("value")
168 """210 """
169 211
170 def __init__(self, id_str):212 html_class = 'filter editfilter'
171 Filter.__init__(self, id_str)213
214 def __init__(self, id_str, **kwargs):
215 Filter.__init__(self, id_str, **kwargs)
172 self.input_str = ""216 self.input_str = ""
173 217
174 def set_value(self, value): #overrides Filter218 def set_value(self, value): #overrides Filter
@@ -180,13 +224,11 @@
180 def serialize_value(self, value): #overrides Filter224 def serialize_value(self, value): #overrides Filter
181 return value225 return value
182 226
183 def render_html(self):227 def render_html_value(self, **kwargs):
184 system = self.get_system()228 field_value = self.get_value()
185 toggle_params = self.get_container_toggle_parameters()229 if field_value:
186 href = system.get_url_with_parameters(toggle_params)230 field_value = 'value="%s"' % field_value
187 231 return '<input type="text" placeholder="(type here)" spellcheck="false" %s />' % field_value
188 return mark_safe(u'<a href="%s">%s: %s</a>'
189 % (href, self.get_id(), self.get_value()))
190232
191233
192class SetFilter(Filter): #abstract, extend in application234class SetFilter(Filter): #abstract, extend in application
@@ -196,8 +238,10 @@
196 Serialized as a comma-separated list ("dog,cat,horse,mouse")238 Serialized as a comma-separated list ("dog,cat,horse,mouse")
197 """239 """
198 240
199 def __init__(self, id_str):241 html_class = 'filter setfilter'
200 Filter.__init__(self, id_str)242
243 def __init__(self, id_str, **kwargs):
244 Filter.__init__(self, id_str, **kwargs)
201 self.selected_set = set()245 self.selected_set = set()
202 246
203 def set_value(self, value): #overrides Filter247 def set_value(self, value): #overrides Filter
@@ -228,7 +272,7 @@
228 272
229 def id_allowed(self, item_id):273 def id_allowed(self, item_id):
230 return True274 return True
231 275
232276
233class ChoiceFilter(SetFilter): #abstract, extend in application277class ChoiceFilter(SetFilter): #abstract, extend in application
234 """278 """
@@ -240,79 +284,75 @@
240 Serialized as a comma-separated list, like SetFilter.284 Serialized as a comma-separated list, like SetFilter.
241 """285 """
242 286
243 def __init__(self, id_str, choices_dict):287 html_class = 'filter setfilter choicefilter'
244 SetFilter.__init__(self, id_str)288
245 self.choices_dict = choices_dict289 def __init__(self, id_str, choices_dict = None, **kwargs):
290 SetFilter.__init__(self, id_str, **kwargs)
291 if choices_dict:
292 self.choices_dict = choices_dict
293 else:
294 self.choices_dict = self.default_choices_dict()
295
296 def default_choices_dict(self):
297 """
298 @return the default dictionary of choices if none is given to __init__
299 """
300 return None
246 301
247 def id_allowed(self, item_id): #overrides SetFilter302 def id_allowed(self, item_id): #overrides SetFilter
248 return item_id in self.choices_dict303 return item_id in self.choices_dict
249 304
250 def get_selected_items(self):305 def get_selected_choices(self):
251 return [self.choices_dict[s] for s in self.selected_set]306 return [self.choices_dict[s] for s in self.selected_set]
252 307
253 def render_html(self): #overrides Filter308 def render_html_value(self, **kwargs):
254 choices = ""309 choices = ''
255 310
256 for c in self.choices_dict:311 for c_id in self.choices_dict:
257 c_render = self._render_html_choice(c)312 c_render = self.render_html_value_choice(c_id)
258 if self.id_selected(c):313 li_params = 'data-item-id="%s"' % c_id
259 c_render = "<b>%s</b>" % c_render314 checkbox_inner = ''
260 choices += "<li>%s</li>" % c_render315 if self.id_selected(c_id):
261 316 li_params = '%s data-selected' % li_params
262 system = self.get_system()317 checkbox_inner = '&#10003;' #a check mark
263 toggle_params = self.get_container_toggle_parameters() 318 checkbox = '<span class="checkbox">%s</span>' % checkbox_inner
264 self_href = system.get_url_with_parameters(toggle_params)319 choices += '\n<li %s>\n%s\n%s\n</li>\n' % (li_params, checkbox, c_render)
265 320
266 return mark_safe(u'<a href="%s">%s</a>:<ul>%s</ul>' % (self_href, self.get_id(), choices))321 return '<ul>\n%s\n</ul>' % choices
267 322
268 def _render_html_choice(self, item_id):323 def render_html_value_choice(self, item_id):
269 system = self.get_system()
270 toggle_params = self.serialize(self.get_value_with_selection(item_id))324 toggle_params = self.serialize(self.get_value_with_selection(item_id))
271 item_href = system.get_url_with_parameters(toggle_params)325 item_href = self.get_system().get_url_with_parameters(toggle_params)
272 326
273 return mark_safe(u'<a href="%s">%s</a>' % (item_href, item_id))327 return '<a class="item-toggle" href="%s">%s</a>' % (item_href, item_id)
274328
275329
276330class FilterGroup(FilterContainer, ChoiceFilter): #final
277
278class FilterGroup(FilterContainer, SetFilter): #final
279 """331 """
280 A collection of other Filters, which are selected (enabled) according to the332 A collection of other Filters, which are selected (enabled) according to the
281 rules of SetFilter.333 rules of ChoiceFilter.
282 334
283 The do_queryset method mixes the output from all selected Filters, so only335 The do_queryset method combines the output from all selected Filters.
284 the one for this FilterGroup needs to be (or should be) called.336
285 337 Serialized as a comma-separated list, like ChoiceFilter.
286 Serialized as a comma-separated list, like SetFilter.
287 """338 """
288 339
289 def __init__(self, id_str, filters_set):340 html_class = 'filter setfilter choicefilter filtergroup'
341
342 def __init__(self, id_str, filters_set, **kwargs):
290 FilterContainer.__init__(self, filters_set)343 FilterContainer.__init__(self, filters_set)
291 SetFilter.__init__(self, id_str) 344 #self.filters_dict comes from FilterContainer's initializer
292 345 ChoiceFilter.__init__(self, id_str, self.filters_dict, **kwargs)
293 def id_allowed(self, item_id): #overrides SetFilter
294 return item_id in self.filters_dict
295
296 def get_selected_filters(self, filter_id):
297 return [self.filters_dict[s] for s in self.selected_set]
298 346
299 def process_queryset(self, queryset): #overrides Filter347 def process_queryset(self, queryset): #overrides Filter
300 for f in self.selected_set:348 for f in self.get_selected_choices():
301 queryset = self.filters_dict[f].process_queryset(queryset) #returns something like QuerySet.filter(blah)349 queryset = f.process_queryset(queryset) #returns something like QuerySet.filter(blah)
302 return queryset350 return queryset
303 351
304 def render_html(self): #overrides Filter352 def render_html_value_choice(self, filter_id):
305 filters = ""353 toggle_params = self.serialize(self.get_value_with_selection(filter_id))
306 354 toggle_href = self.get_system().get_url_with_parameters(toggle_params)
307 for f in self.filters_dict:355
308 f_render = self._render_html_filter(f)
309 if self.id_selected(f):
310 f_render = "<em>%s</em>" % f_render
311 filters += "<li>%s</li>" % f_render
312
313 return mark_safe(u'%s:<ul>%s</ul>' % (self.get_id(), filters))
314
315 def _render_html_filter(self, filter_id):
316 f = self.filters_dict[filter_id]356 f = self.filters_dict[filter_id]
317 return f.render_html()357 return f.render_html(toggle_href = toggle_href)
318358
319359
=== added file 'harvest/media/css/footer-pattern.png'
320Binary 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 differ360Binary 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
=== added file 'harvest/media/css/reset.css'
--- harvest/media/css/reset.css 1970-01-01 00:00:00 +0000
+++ harvest/media/css/reset.css 2010-07-15 16:29:40 +0000
@@ -0,0 +1,50 @@
1html, body, div, span, applet, object, iframe,
2h1, h2, h3, h4, h5, h6, p, blockquote, pre,
3a, abbr, acronym, address, big, cite, code,
4del, dfn, em, font, img, ins, kbd, q, s, samp,
5small, strike, strong, sub, sup, tt, var,
6b, u, i, center,
7dl, dt, dd, ol, ul, li,
8fieldset, form, label, legend,
9table, caption, tbody, tfoot, thead, tr, th, td {
10 margin: 0;
11 padding: 0;
12 border: 0;
13 outline: 0;
14 font-size: 100%;
15 vertical-align: baseline;
16 background: transparent;
17}
18body {
19 line-height: 1;
20}
21ol, ul {
22 list-style: none;
23}
24blockquote, q {
25 quotes: none;
26}
27blockquote:before, blockquote:after,
28q:before, q:after {
29 content: '';
30 content: none;
31}
32
33/* remember to define focus styles! */
34:focus {
35 outline: 0;
36}
37
38/* remember to highlight inserts somehow! */
39ins {
40 text-decoration: none;
41}
42del {
43 text-decoration: line-through;
44}
45
46/* tables still need 'cellspacing="0"' in the markup */
47table {
48 border-collapse: collapse;
49 border-spacing: 0;
50}
051
=== modified file 'harvest/media/css/style.css'
--- harvest/media/css/style.css 2010-03-02 16:06:21 +0000
+++ harvest/media/css/style.css 2010-07-15 16:29:40 +0000
@@ -1,191 +1,389 @@
1body {1body {
2 background-image: url(../img/bgrepeat.jpg);2 background-color:rgb(255,255,255);
3 background-color: #D3CAAA;3 color:rgb(51,51,51);
4 background-repeat: repeat-x;4
5 padding: 0;5 font-family:'Bitstream Vera Sans', 'DejaVu Sans', sans-serif;
6 margin: 0;6 font-size:14px;
7}7 line-height:1.2em;
8}
9
10h1,h2,h3,h4,h5,h6 {
11 color:rgb(0,0,0);
12 font-family:'Molengo', 'Bitstream Vera Sans', 'DejaVu Sans', sans-serif;
13}
14
15.bottom {
16 display:block;
17 clear:both;
18}
19
20strong {
21 color:rgb(0,0,0);
22 font-weight:bold;
23}
24small, .small {
25 color:rgb(80,80,80);
26 font-size:smaller;
27}
28em {
29 font-style:italic;
30}
31
32*:focus {
33 outline:rgb(244,116,33) dashed 1px;
34}
35
36a {
37 color:rgb(110,64,84);
38 text-decoration:inherit;
39}
40a:hover,
41a:focus {
42 /*color:rgb(162,129,143);*/
43 text-decoration:underline;
44}
45
46#header a,
47#footer a {
48 color:rgb(0,0,0);
49}
50
51input.placeheld {
52 /* only used in browsers that don't already do placeholder text */
53 color:rgb(180,180,180);
54}
55
56
857
9#container {58#container {
10 margin: 0 auto;59 display:block;
11 padding: 0 0 0 14px;60 position:absolute;
12 position: relative;61 width:100%;
13 background-color: #fff;62 min-width:600px;
14 background-image: url(../img/page-border-left-repeat.jpg);63 min-height:100%;
15 background-repeat: repeat-y;64}
16 background-position: left;65
17 width: 94%;66
18 /*max-width: 950px;*/67
19 min-width: 760px;68#header {
20}69 display:block;
70 width:100%;
71 min-height:80px;
72
73 padding-top:12px;
74 padding-bottom:12px;
75}
76#header #pagetitle {
77 display:inline;
78 position:static;
79 margin-left:80px;
80 margin-right:40px;
81
82 text-transform:lowercase;
83 color:rgb(0,0,0);
84 font-family:'Molengo', 'Bitstream Vera Sans', 'DejaVu Sans', sans-serif;
85}
86#header #pagetitle #sitelogo {
87 width:auto; /* line up with #sitename font-size */
88 height:36px;
89}
90#header #pagetitle #sitename {
91 display:inline;
92 position:static;
93
94 font-size:36px;
95}
96#header #pagetitle #releasename {
97 display:inline;
98 position:static;
99
100 font-size:14px;
101 vertical-align:sub;
102}
103#header #userdata {
104 float:right;
105 margin-top:12px;
106 margin-left:40px;
107 margin-right:80px;
108
109 text-align:right;
110}
111#header #userdata .username {
112}
113#header #userdata .loginbutton {
114}
115
21116
22#content {117#content {
23 margin: 0;118 clear:both;
24 padding: 0 13px 0 0;119 padding-bottom:140px;
25 min-height: 538px;120}
26 position: relative;121
27 background-color: #fff;122
28 background-image: url(../img/page-border-right-repeat.jpg);123
29 background-repeat: repeat-y;124#filters {
30 background-position: right;125 display:block;
31}126 position:relative;
32127 float:left;
33#content a {128 min-width:160px;
34 text-decoration: none;129
35}130 padding:0px 20px 20px 20px;
36131 font-size:12px;
37#topNav {132 line-height:1.4em;
38 width: 100%;133 color:rgb(51,51,51);
39 position: relative;134}
40 height: 70px;135#filters a {
41136 /* these are self-explanatory; they should disappear */
42 background-image: url(../img/top.jpg);137 display:inline-block;
43 background-repeat: repeat-x;138 height:100%;
44 background-position: top;139
45 padding-top: 10px;140 color:inherit;
46 z-index: 1;141 text-decoration:inherit;
47}142 font-style:inherit;
48143}
49#topNav a {144
50 color: #656565;145#filters ul {
51 text-decoration: none;146 display:block;
52 font-size: 80%;147 margin-left:20px;
53 border-bottom: 1px dotted #fff;148 width:100%;
54}149}
55150#filters ul li {
56#topNav #whoami {151 display:block;
57 display: block;152 width:100%;
58 margin: 0;153}
59 padding: 0 0px .5em 0px;154
60 position: absolute;155
61 top: 20px;156#filters .checkbox {
62 right: 0px;157 /* checkbox element should always be the same size */
63}158 display:inline-block;
64159 width:12px;
65#topNav #ubuntulogo {160 color:inherit;
66 margin: 0;161}
67 padding: 0;162
68 border-style: none;163#filters .setfilter > .filter-value > ul > li:not([data-selected]) > .filter > .filter-value {
69164 /* parent filter is turned off */
70 position: absolute;165 color:rgb(140,140,140);
71 top: 22px;166}
72 left: 0;167
73}168#filters .setfilter > .filter-value > ul > li.prelight-off > .checkbox {
74#bg-left {169 /* prelight for an item about to be deselected */
75 position: absolute;170 color:rgb(140,140,140);
76 top: 0;171 text-decoration:line-through;
77 left: 0;172}
78 width: 14px;173#filters .setfilter > .filter-value > ul > li.prelight-on > .checkbox {
79 height: 538px;174 /* prelight for an item about to be selected */
80 background-image: url(../img/page-border-left.jpg);175 color:inherit;
81 background-repeat: no-repeat;176}
82 background-position: top left;177
83 z-index: 6;178#filters .setfilter > .filter-value > ul > li.prelight-off > .filter > .filter-value {
84}179 /* parent filter is about to be turned off */
85#bg-right {180 color:rgb(140,140,140);
86 position: absolute;181}
87 top: 0;182#filters .setfilter > .filter-value > ul > li.prelight-on > .filter > .filter-value {
88 right: 0;183 /* parent filter is about to be turned on */
89 width: 13px;184 color:inherit;
90 height: 538px;185}
91 background-image: url(../img/page-border-right.jpg);186
92 background-repeat: no-repeat;187
93 background-position: top right;188
94 z-index: 6;189#filters > .filtergroup {
95}190 /* a top-level filter group */
96#bottom-left {191 display:block;
97 width: 14px;192 margin-bottom:4em;
98 height: 34px;193}
99 background-image: url(../img/footerbg-left.jpg);194#filters > .filtergroup > .filter-label {
100 position: absolute;195 display:block;
101 bottom: 0;196 margin-bottom:.5em;
102 left: 0;197 color:rgb(0,0,0);
103 z-index: 7;198 font-size:14px;
104}199 font-weight:bold;
105#bottom-right {200}
106 width: 13px;201#filters > .filtergroup > .filter-value > ul {
107 height: 34px;202 margin-left:0px;
108 background-image: url(../img/footerbg-right.jpg);203}
109 position: absolute;204#filters > .filtergroup > .filter-value > ul > li {
110 bottom: 0;205 padding-bottom:5px;
111 right: 0;206}
112 z-index: 7;207
113}208#filters .editfilter input {
114/* bodyouter provides the borders for the left navigation */209 width:8em;
115/* see http://webhost.bridgew.edu/etribou/layouts/skidoo_too/ */210 border:none;
116#body {211 padding:0px 2px 0px 2px;
117 position: relative;212 border-bottom:1px solid rgb(180,180,180);
118 overflow: hidden;213
119 margin: 0 0;214 background-color:inherit;
120 padding-left: 0 50px;215 color:inherit;
121 min-height: 538px;216 font:inherit;
122}217}
123* html #body {218#filters .editfilter input.placeheld {
124 height: 1%;219 color:rgb(180,180,180);
125}220}
126#leftsidebar {221
127 width: 205px;222
128 float: right;223
129 margin-left: -205px;224#results-pane {
130}225 display:block;
226 min-width:250px;
227 max-width:1000px;
228 padding:20px 20px 0px 20px;
229 overflow:auto;
230 line-height:1.6em;
231}
232
233#results-pane > #results-status {
234 position:relative;
235 display:none;
236 text-align:center;
237}
238#results-pane > #results-status > div {
239 display:inline-block;
240 width:300px;
241 height:30px;
242}
243
244#results > ul {
245 margin-left:20px;
246 margin-bottom:10px;
247}
248
249#results .sourcepackage {
250 display:block;
251 margin-top:5px;
252 margin-bottom:5px;
253 border:1px solid rgb(250,250,250);
254 -moz-border-radius:3px 3px 0px 0px;
255 border-radius:3px 3px 0px 0px;
256}
257
258#results .sourcepackage > .sourcepackage-header {
259 display:block;
260 padding:8px 20px 8px 20px;
261 -moz-border-radius:3px 3px 0px 0px;
262 border-radius:3px 3px 0px 0px; /* to line up with .sourcepackage's border */
263}
264#results .sourcepackage > a.sourcepackage-header {
265 color:inherit;
266 text-decoration:none;
267}
268#results .sourcepackage > .sourcepackage-header > .sourcepackage-name {
269 margin-right:10px;
270 color:rgb(0,0,0);
271 font-size:16px;
272}
273#results .sourcepackage > .sourcepackage-header > .sourcepackage-summary {
274 float:right;
275 text-align:right;
276 font-size:10px;
277}
278#results .sourcepackage > .sourcepackage-details {
279 display:block;
280 padding:0px 10px 5px 50px;
281}
282
283/* prelights */
284#results .sourcepackage > a.sourcepackage-header:hover,
285#results .sourcepackage > a.sourcepackage-header:focus {
286 /* use the opportunity count or experience measure here */
287 background-color:rgb(240,255,243);
288}
289#results .sourcepackage > a.sourcepackage-header:hover .sourcepackage-name,
290#results .sourcepackage > a.sourcepackage-header:focus .sourcepackage-name {
291 text-decoration:underline;
292}
293
294#results .sourcepackage > .sourcepackage-header > .status {
295 display:none; /* harvest.js will override this where necessary */
296}
297#results .sourcepackage > .sourcepackage-header > .status img {
298 width:16px;
299 height:16px;
300}
301
302/* expanded / collapsed state */
303#results .sourcepackage.expanded {
304 margin-bottom:10px;
305 border-color:rgb(200,200,200);
306 -moz-border-radius:3px;
307 border-radius:3px; /* round border on bottom as well */
308}
309#results .sourcepackage.collapsed > .sourcepackage-details {
310 display:none;
311}
312
313
131314
132#footer {315#footer {
133 background-image: url(../img/footerbg.jpg); 316 display:block;
134 background-repeat: repeat-x;317 position:absolute;
135 background-position: bottom;318 left:0px;
136 padding: 0 0 0 0;319 right:0px;
137}320 bottom:0px;
138#footer .wrapper {321 min-height:100px;
139 padding: 0 15px 5px 15px;322
140 color: #656565;323 overflow:visible;
141 font-size: 70%;324 background-image:url('footer-pattern.png');
142 position: relative;325 background-position:left bottom;
143}326 background-repeat:repeat-x;
144#footer .wrapper a {327
145 color: #656565;328 padding-left:32px;
146 text-decoration: none;329 padding-right:32px;
147}330}
148#footer .wrapper p {331#footnav {
149 width: 70%;332 display:block;
150 font-size: 90%;333 height:20px;
151}334
152335 padding:2px;
153.pagination .current-page {336 white-space:nowrap;
154 margin: 0px 2px;337 background-color:rgb(255,255,255);
155 font-weight: bold;338 font-size:16px;
156}339}
157340#footnav a {
158.pagination .pages {341 margin-left:1em;
159 margin: 0px 10px;342 margin-right:1em;
160}343}
161344#footnav a:last-child {
162div.package_name { padding: 3px; }345}
163div.package_name span.name { font-weight: bold; }346#footnav .title {
164div.package_name span.count { font-size: 75%; }347 margin-left:0em;
165div.package_name:hover { background: #eee; }348 margin-right:4em;
166div.package_details { padding: 5px; display: none; }349 text-decoration:none;
167div.package_details:hover {}350}
168351
169div.thresholdGREEN { background-color: #cfc; }352#smallprint {
170div.thresholdYELLOW { background-color: #ffc; }353 margin-top:40px;
171div.thresholdRED { background-color: #fcc; }354 bottom:3px;
172355 left:8px;
173span.featureYES { font-weight: bold; }356 right:8px;
174span.featureNO { font-size: 100%; }357
175358 color:rgb(120,120,120);
176span.experience1 { float: right; content:url(../img/easy.png); }359 font-size:10px;
177span.experience2 { float: right; content:url(../img/medium.png); }360 line-height:1.2em;
178span.experience3 { float: right; content:url(../img/hard.png); }361}
179362#smallprint #techdetails,
180ul.toplevellist {363#smallprint #copyright {
181 list-style-type: none;364 max-width:200px;
182 border-bottom: 1px solid #999;365
183 padding-left: 0px;366 padding:5px;
184 margin-left: 15px;367 overflow:hidden;
185}368 white-space:nowrap;
186369 text-overflow:ellipsis;
187ul.toplevellist li div {370 background-color:rgb(255,255,255);
188 border-top: 1px solid #999;371}
189 border-left: 1px solid #999;372#smallprint:hover #techdetails,
190 border-right: 1px solid #999;373#smallprint:hover #copyright,
374#smallprint:focus #techdetails,
375#smallprint:focus #copyright {
376 max-width:none;
377 overflow:visible;
378}
379#smallprint #copyright {
380 float:left;
381
382 text-align:left;
383}
384#smallprint #techdetails {
385 float:right;
386
387 text-align:right;
388 text-transform:lowercase;
191}389}
192390
=== removed file 'harvest/media/img/bgrepeat.jpg'
193Binary 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 differ391Binary files harvest/media/img/bgrepeat.jpg 2009-07-08 11:31:32 +0000 and harvest/media/img/bgrepeat.jpg 1970-01-01 00:00:00 +0000 differ
=== removed file 'harvest/media/img/footerbg-left.jpg'
194Binary 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 differ392Binary files harvest/media/img/footerbg-left.jpg 2009-08-26 14:19:44 +0000 and harvest/media/img/footerbg-left.jpg 1970-01-01 00:00:00 +0000 differ
=== removed file 'harvest/media/img/footerbg-right.jpg'
195Binary 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 differ393Binary files harvest/media/img/footerbg-right.jpg 2009-08-26 14:19:44 +0000 and harvest/media/img/footerbg-right.jpg 1970-01-01 00:00:00 +0000 differ
=== removed file 'harvest/media/img/footerbg.jpg'
196Binary 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 differ394Binary files harvest/media/img/footerbg.jpg 2009-08-26 14:19:44 +0000 and harvest/media/img/footerbg.jpg 1970-01-01 00:00:00 +0000 differ
=== added file 'harvest/media/img/logo_humanity-search-icon.png'
197Binary 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 differ395Binary 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
=== removed file 'harvest/media/img/page-border-left-repeat.jpg'
198Binary 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 differ396Binary files harvest/media/img/page-border-left-repeat.jpg 2009-07-08 11:31:32 +0000 and harvest/media/img/page-border-left-repeat.jpg 1970-01-01 00:00:00 +0000 differ
=== removed file 'harvest/media/img/page-border-left.jpg'
199Binary 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 differ397Binary files harvest/media/img/page-border-left.jpg 2009-07-08 11:31:32 +0000 and harvest/media/img/page-border-left.jpg 1970-01-01 00:00:00 +0000 differ
=== removed file 'harvest/media/img/page-border-right-repeat.jpg'
200Binary 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 differ398Binary files harvest/media/img/page-border-right-repeat.jpg 2009-07-08 11:31:32 +0000 and harvest/media/img/page-border-right-repeat.jpg 1970-01-01 00:00:00 +0000 differ
=== removed file 'harvest/media/img/page-border-right.jpg'
201Binary 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 differ399Binary files harvest/media/img/page-border-right.jpg 2009-07-08 11:31:32 +0000 and harvest/media/img/page-border-right.jpg 1970-01-01 00:00:00 +0000 differ
=== added file 'harvest/media/img/pkg-status-loading.gif'
202Binary 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 differ400Binary 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
=== added file 'harvest/media/img/results-status-loading.gif'
203Binary 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 differ401Binary 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
=== added file 'harvest/media/img/results-status-waiting.gif'
204Binary 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 differ402Binary 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
=== removed file 'harvest/media/img/top.jpg'
205Binary 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 differ403Binary files harvest/media/img/top.jpg 2009-08-26 14:19:44 +0000 and harvest/media/img/top.jpg 1970-01-01 00:00:00 +0000 differ
=== removed file 'harvest/media/img/ubuntulogo.png'
206Binary 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 differ404Binary files harvest/media/img/ubuntulogo.png 2009-07-08 11:31:32 +0000 and harvest/media/img/ubuntulogo.png 1970-01-01 00:00:00 +0000 differ
=== added file 'harvest/media/js/harvest.js'
--- harvest/media/js/harvest.js 1970-01-01 00:00:00 +0000
+++ harvest/media/js/harvest.js 2010-07-15 16:29:40 +0000
@@ -0,0 +1,622 @@
1/* depends on:
2 jquery core 1.4.2 or later <http://jquery.com>
3 jquery scrollstay plugin
4 jquery placeheld plugin <http://plugins.jquery.com/project/placeheld>
5*/
6
7
8// Array Remove - By John Resig (MIT Licensed)
9Array.prototype.remove = function(from, to) {
10 var rest = this.slice((to || from) + 1 || this.length);
11 this.length = from < 0 ? this.length + from : from;
12 return this.push.apply(this, rest);
13};
14
15
16var harvest_results;
17var harvest_filters_list;
18
19var MEDIA_PATH = '/media/' /* we should get this from Django somehow */
20
21
22function Filter (dom_node) {
23 /* Attaches to a .filter object in the document. Handles events
24 specific to each type of filter and provides some extra data
25 and utilities. */
26
27 var filter = this; /* so we can access this from event handlers */
28
29 $(dom_node).data('filter',this); /* so we can get here from the JQuery object */
30
31 this.full_name = $(dom_node).attr('data-filter-fullname');
32 this.parent_filter_node = $(dom_node).parent().closest('.filter');
33 this.container = $(dom_node).closest('li'); /* the list item in the parent that this belongs to */
34 this.value_node = $(dom_node).children('.filter-value');
35
36
37 this.is_class = function (class_name) {
38 return $(dom_node).hasClass(class_name);
39 }
40
41
42 this.get_value_serialized = function () {
43 /* Returns the value of this filter, serialized in the same
44 format we would use in Harvest's Django end.
45 Does nothing by default. Implement this in each
46 "class"-specific initializer below. */
47
48 return null;
49 }
50
51 this.value_changed = function () {
52 /* Should be called when the filter's value has changed.
53 This posts the new value to the global Results object */
54
55 value = this.get_value_serialized();
56 if ( value != null ) {
57 harvest_results.post_query(this.full_name, value);
58 }
59 }
60
61
62 /********/
63 /* Ugly hacks for talking to the parent node */
64
65 this.get_parent_filtergroup = function () {
66 /* Returns the FilterGroup that is a parent of this filter.
67 Returns null if the parent doesn't exist or isn't a FilterGroup. */
68 parent = null;
69 if ( this.parent_filter_node ) {
70 parent_test = this.parent_filter_node.data('filter');
71 if ( parent_test && parent_test.is_class('filtergroup') ) parent = parent_test;
72 }
73 return parent;
74 }
75
76
77 this.force_enable_prelight_add = function () {
78 /* Tells the parent (if there is one) to create a prelight for
79 enabling this item.
80 We assume the parent is a FilterGroup, which is probably right. */
81 parent_filter = this.get_parent_filtergroup();
82 if ( parent_filter && ! parent_filter.item_is_selected(this.container) ) {
83 /* only do this if we weren't already selected */
84 parent_filter.toggle_item_prelight_add(this.container);
85 }
86 }
87
88 this.force_enable_prelight_clear = function () {
89 /* Tells the parent (if there is one) to remove the prelight for
90 enabling this item.
91 We assume the parent is a FilterGroup. */
92 parent_filter = this.get_parent_filtergroup()
93
94 if ( parent_filter ) parent_filter.toggle_item_prelight_clear(this.container);
95 }
96
97
98 this.force_enable = function () {
99 /* Tells the parent (if there is one) to enable this item,
100 because it said so!
101 We assume the parent is a FilterGroup. */
102 parent_filter = this.get_parent_filtergroup();
103 if ( parent_filter && ! parent_filter.item_is_selected(this.container) ) {
104 parent_filter.enable_item(this.container);
105 }
106 }
107
108
109 /* Callback functions */
110 this.enabled = function() {} /* called when this filter is enabled */
111 this.disabled = function() {} /* called when this filter is disabled */
112
113
114 /********/
115 /* "Class"-specific initialization stuff. Setting up functions and
116 handlers in filter.value_node */
117
118 if ( this.is_class('choicefilter') ) {
119 var list_items = this.value_node.children('ul').children('li');
120
121
122 /* Callback functions */
123 this.item_enabled = function(item) {} /* called after enabling an item */
124 this.item_disabled = function(item) {} /* called after disabling an item */
125
126
127 this.get_value_serialized = function () {
128 var item_ids = Array();
129 /* we add the data-item-id attribute of all selected items */
130 list_items.each(function () {
131 if ($(this).attr('data-selected') != null) {
132 item_ids.push($(this).attr('data-item-id'));
133 }
134 } );
135 return item_ids.join(',');
136 }
137
138
139 this.item_is_selected = function (item) {
140 return ( item.attr('data-selected') != null );
141 }
142
143 this.toggle_item_prelight_add = function (item) {
144 if ( this.item_is_selected(item) ) {
145 item.addClass('prelight-off');
146 } else {
147 item.addClass('prelight-on');
148 item.children('.checkbox').html('&#10003;'); /* decoration :) */
149 this.force_enable_prelight_add();
150 }
151 }
152
153 this.toggle_item_prelight_clear = function (item) {
154 /* remove the decoration in the checkbox if we added it */
155 if ( ! this.item_is_selected(item) ) {
156 item.children('.checkbox').html('');
157 }
158
159 item.removeClass('prelight-on');
160 item.removeClass('prelight-off');
161 this.force_enable_prelight_clear();
162 }
163
164
165 this.enable_item = function (item) {
166 item.attr('data-selected','');
167 item.children('.checkbox').html('&#10003;');
168
169 this.force_enable();
170 this.value_changed();
171
172 this.item_enabled(item);
173 }
174
175 this.disable_item = function (item) {
176 item.removeAttr('data-selected');
177 item.children('.checkbox').html('');
178
179 this.value_changed();
180
181 this.item_disabled(item);
182 }
183
184 this.toggle_item = function (item) {
185 if ( this.item_is_selected(item) ) {
186 this.disable_item(item);
187 } else {
188 this.enable_item(item);
189 }
190 }
191
192
193 this.get_item_toggle_node = function (item) {
194 /* returns the node(s) used to toggle the given item in this filter */
195 return item.children('a.item-toggle');
196 }
197
198
199 /* "Subclass" setup goes here because we need to do overrides before any movement happens */
200 if ( this.is_class('filtergroup') ) {
201 this.item_enabled = function (item) {
202 /* Tell child it has been enabled. It might do something cool! */
203 child_filter = item.children('.filter').data('filter');
204 child_filter.enabled();
205 }
206
207 this.item_disabled = function (item) {
208 /* Tell child it has been disabled. */
209 child_filter = item.children('.filter').data('filter');
210 child_filter.disabled();
211 }
212
213 this.get_item_toggle_node = function (item) {
214 return item.children('.filter').children('.filter-label').children('a.item-toggle');
215 }
216 }
217
218
219 /* setup the event handlers we described on all the items */
220 list_items.each(function () {
221 var item = $(this);
222 toggle_node = filter.get_item_toggle_node(item);
223 toggle_node.bind('mouseenter focusin', function () { filter.toggle_item_prelight_add(item); } );
224 toggle_node.bind('mouseleave focusout', function () { filter.toggle_item_prelight_clear(item); } );
225
226 toggle_node.bind('click', function () {
227 filter.toggle_item(item);
228 filter.toggle_item_prelight_clear(item);
229
230 return false; /* stops link from being followed */
231 } );
232 });
233 }
234
235
236 if ( this.is_class('editfilter') ) {
237 var edit_field = this.value_node.children('input');
238
239
240 this.edit_field_changed = function() {
241 this.force_enable();
242 this.value_changed();
243 }
244
245 this.get_value_serialized = function () {
246 return escape(edit_field.val());
247 }
248
249 this.enabled = function () {
250 edit_field.focus();
251 }
252
253 /* we could handle 'change' instead of 'input' to only check value when typing has stopped */
254 edit_field.bind('input', function () { filter.edit_field_changed(); } );
255 }
256
257
258 /* send initial state to Results object so it can behave neatly */
259 value = this.get_value_serialized();
260 if ( value != null ) {
261 harvest_results.update_current_query(this.full_name, value);
262 }
263}
264
265
266function Package (dom_node, details_url, opps_query, expanded_cb, collapsed_cb) {
267 /* Created for each package inside the #results element */
268
269 /* gtksourceview gives an error box around "package", so we'll have to forego the convention */
270 var pkg = this;
271
272 this.id = $(dom_node).attr('data-results-packageid');
273 this.details = $(dom_node).children('.sourcepackage-details');
274
275 this.loading_xhr = null;
276 this.is_expanded = false;
277
278
279 this.show_status = function (status) {
280 var indicator = dom_node.children('.sourcepackage-header').children('.status');
281 if ( status ) {
282 indicator.stop(true, true);
283 var status_img = MEDIA_PATH + 'img/pkg-status-'+status+'.gif';
284 indicator.html('<img src="'+status_img+'" />');
285 if ( this.visible_status == null ) {
286 indicator.fadeIn(1500);
287 }
288 } else {
289 /* stop the previous animation as it was; we don't expect it to finish usually */
290 indicator.stop(true, false);
291 indicator.fadeOut(150, function () {
292 indicator.html('');
293 });
294 }
295
296 this.visible_status = status;
297 }
298
299 this.hide_status = function (status) {
300 if ( this.visible_status == status ) this.show_status(null);
301 }
302
303
304 this.expand = function () {
305 if ( this.is_expanded ) return;
306
307 var show = function () {
308 /* from #"results .sourcepackage.expanded" rule in /media/css/style.css */
309 fadeto = 'rgb(200,200,200);';
310 dom_node.animate({borderTopColor: fadeto,
311 borderRightColor: fadeto,
312 borderBottomColor: fadeto,
313 borderLeftColor: fadeto}, 150);
314 pkg.details.animate({height: 'show', opacity: 'show'}, 150);
315 dom_node.removeClass('collapsed');
316 dom_node.addClass('expanded');
317 }
318
319 /* run the callback saying this package will be expanded */
320 this.is_expanded = true;
321 if ( expanded_cb ) expanded_cb(this);
322
323 /* first, get package details from the server if they aren't already here */
324 /* this poorly assumes that this.details contains no text at all if we haven't hit the server */
325 if ( $.trim(this.details.html()) == '' ) {
326 this.show_status('loading');
327
328 this.loading_xhr = $.ajax({
329 type: "GET",
330 url: details_url + this.id, dataType: 'html',
331 data: opps_query,
332 complete: function (xhr, status) {
333 pkg.hide_status('loading');
334 pkg.loading_xhr = null;
335 },
336 success: function (data, status, xhr) {
337 /* check that xhr.status is set. If it isn't, xhr.abort was called */
338 if (xhr.status) {
339 pkg.details.html(data);
340 show();
341 }
342 },
343 });
344 } else {
345 show();
346 }
347 }
348
349 this.stop_loading = function () {
350 /* stops loading package details */
351 if ( this.loading_xhr != null ) this.loading_xhr.abort();
352 }
353
354 this.collapse = function () {
355 this.stop_loading();
356 if ( ! this.is_expanded ) return;
357
358 /* run the callback saying this package will be collapsed */
359 this.is_expanded = false;
360 if ( collapsed_cb ) collapsed_cb(this);
361
362 fadeto = 'rgb(250,250,250);';
363 dom_node.animate({borderTopColor: fadeto,
364 borderRightColor: fadeto,
365 borderBottomColor: fadeto,
366 borderLeftColor: fadeto}, 150);
367 pkg.details.animate({height: 'hide', opacity: 'hide'}, 150);
368 dom_node.removeClass('expanded');
369 dom_node.addClass('collapsed');
370 }
371
372
373
374 /********/
375 /* Object initialization */
376
377 /* make sure the package knows it has been expanded */
378 if ( dom_node.hasClass('expanded') ) {
379 this.is_expanded = true;
380 if ( expanded_cb ) expanded_cb(this);
381 }
382
383 dom_node.children('a.sourcepackage-header').bind('click', function () {
384 if ( pkg.is_expanded || pkg.loading_xhr != null ) {
385 pkg.collapse();
386 } else {
387 pkg.expand();
388 }
389
390 return false;
391 });
392}
393
394
395function Results (dom_node) {
396 /* Attached to the single #results-pane in the document. Receives
397 new query parameters from Filter objects, grabs and displays new
398 results in the contained #results element. */
399
400 /* The current_query variable is set with the current querystring,
401 but some filters could already have been set with Harvest's
402 default parameters while the querystring doesn't mention them.
403 On its own, this isn't a problem, but it may lead to some odd
404 behaviour. We should fix it by setting current_query to include
405 all of the defaults in Harvest's Django portion. */
406
407 var results = this;
408
409 this.query_countdown = null;
410 this.loading_xhr = null;
411
412 this.current_query = {};
413 this.future_query = {};
414
415 this.container = $(dom_node);
416 this.query_url = $(dom_node).attr('data-results-url');
417 this.output = $(dom_node).children('#results');
418 this.status_bubble = $(dom_node).children('#results-status');
419
420 this.packages = {};
421 this.expanded_pkgs = [];
422
423
424 this.update_packages = function () {
425 /* Perform bits of setup with a new list of sourcepackages */
426 var results_packages = this.output.find('li.sourcepackage');
427
428 var old_packages = this.packages;
429
430 /* dereferences existing Packages. We expect that they'll be cleaned up by the GC */
431 this.packages = {};
432 this.expanded_pkgs = [];
433
434 var pkg_expanded_cb = function (pkg) {
435 results.expanded_pkgs.push(pkg.id);
436 results.update_current_query('expand_pkg', results.expanded_pkgs.join(','));
437 }
438
439 var pkg_collapsed_cb = function (pkg) {
440 var index = results.expanded_pkgs.indexOf(pkg.id);
441 if ( index > -1 ) {
442 results.expanded_pkgs.remove(index);
443 results.update_current_query('expand_pkg', results.expanded_pkgs.join(','));
444 }
445 }
446
447 results_packages.each(function () {
448 var dom_node = $(this);
449 var details_url = results.query_url + '/';
450 var opps_query = results.current_query; /* would be nice to only send properties starting with opp: */
451
452 var pkg = new Package(dom_node, details_url, opps_query,
453 pkg_expanded_cb, pkg_collapsed_cb);
454 results.packages[pkg.id] = pkg;
455
456 var old_pkg = old_packages[pkg.id];
457 if ( old_pkg ) {
458 /* This package was listed before. Make sure new
459 listing has the same expanded / collapsed state */
460 if ( old_pkg.is_expanded ) {
461 pkg.expand();
462 } else {
463 pkg.collapse();
464 }
465 }
466 });
467
468 this.update_current_query('expand_pkg', this.expanded_pkgs.join(','));
469 }
470
471
472 this.show_status = function (status) {
473 /* Shows the given status in the #status_bubble.
474 Set status to 'waiting', 'loading', or null to hide the box.
475 Note: values of status directly correlate to image filenames
476 at MEDIA_PATH/img/results-status-*.gif */
477 this.status_bubble.stop(true,true);
478 if ( status ) {
479 var status_img = MEDIA_PATH + 'img/results-status-'+status+'.gif';
480 this.status_bubble.html('<div><img src="'+status_img+'" /></div>');
481 if ( this.visible_status == null ) {
482 this.status_bubble.animate({height: 'show', opacity: 'show'}, 250);
483 }
484 } else {
485 this.status_bubble.animate({height: 'hide', opacity: 'hide'}, 150,
486 function () { results.status_bubble.html(''); }
487 );
488 }
489
490 this.visible_status = status;
491 }
492
493 this.hide_status = function (status) {
494 /* Hides the status bubble if it shows the given status */
495 if ( this.visible_status == status ) this.show_status(null);
496 }
497
498
499 this.load_results = function () {
500 /* Begins loading results for future_query */
501 var load_query = $.extend({}, this.current_query, this.future_query);
502
503 results.show_status('loading');
504
505 this.loading_xhr = $.ajax({
506 type: "GET",
507 url: this.query_url, dataType: 'html',
508 data: load_query,
509 complete: function (xhr, status) {
510 results.hide_status('loading');
511 results.loading_xhr = null;
512 },
513 success: function (data, status, xhr) {
514 /* We have to work around this jquery bug: http://dev.jquery.com/ticket/6173
515 success callback is still being called after xhr.abort() */
516 if (xhr.status) {
517 /* display the (plain html) results we have receieved */
518 results.output.html(data);
519 results.current_query = load_query;
520 results.future_query = {};
521 results.update_packages();
522
523 /* display statistics in the footer */
524 time_header = xhr.getResponseHeader('X-Django-Request-Time')
525 if (time_header) {
526 $('#requeststats').html('Results generated in '+parseFloat(time_header).toFixed(2) + ' seconds');
527 }
528 }
529 },
530 });
531 }
532
533 this.stop_loading = function () {
534 /* stops loading, or returns silently if that is not happening */
535 if ( this.loading_xhr != null ) this.loading_xhr.abort();
536 }
537
538
539 this.reset_countdown = function () {
540 /* Sets the query countdown timer for 1.5s.
541 When the timer ends, we load the results for future_query. */
542 this.stop_countdown(true);
543 this.show_status('waiting');
544 /* stop anything that is loading already */
545 this.stop_loading();
546
547 this.query_countdown = setTimeout(
548 function (results) {
549 results.load_results();
550 results.query_countdown = null;
551 }, 1500, this);
552 }
553
554 this.stop_countdown = function (wait_next) {
555 /* Stops the query countdown timer. */
556 clearTimeout(this.query_countdown);
557 this.query_countdown = null;
558
559 if (! wait_next) this.hide_status('waiting');
560 }
561
562
563 this.post_query = function (key, value) {
564 /* Adds the given key/value pair to future_query. If it is
565 necessary, a timer is started to get the results for
566 future_query. */
567 if ( this.current_query[key] == value ) {
568 /* the user has reverted a change; value is the same as before */
569 delete this.future_query[key];
570
571 if ( $.isEmptyObject(this.future_query) ) {
572 /* no point getting results, so stop and wait for new input. */
573 this.stop_countdown();
574 this.stop_loading();
575 }
576 } else {
577 this.future_query[key] = value;
578 /* start the timer from 0, waiting to apply the new future_query */
579 this.reset_countdown();
580 }
581 }
582
583 this.update_current_query = function (key, value) {
584 /* Adds the given key/value pair as part of current_query. For
585 example, when we first load the page it is useful to make
586 sure we know the current state of all the filters. */
587 this.current_query[key] = value;
588 }
589
590
591 /********/
592 /* Object initialization */
593
594 this.update_packages();
595}
596
597
598
599function create_filters () {
600 /* Creates all filters for the document at once. */
601 $('#filters').scrollStay({ offset:12 });
602
603 var filters_list = new Array();
604 $('#filters .filter').each(function (i) {
605 filters_list.push(new Filter(this));
606 });
607
608 return filters_list;
609}
610
611function create_results () {
612 return new Results($('#results-pane'));
613}
614
615
616
617$(document).ready(function () {
618 harvest_results = create_results();
619 harvest_filters_list = create_filters();
620
621 $('input[placeholder]').placeHeld();
622});
0623
=== added file 'harvest/media/js/jquery-1.4.2.min.js'
--- harvest/media/js/jquery-1.4.2.min.js 1970-01-01 00:00:00 +0000
+++ harvest/media/js/jquery-1.4.2.min.js 2010-07-15 16:29:40 +0000
@@ -0,0 +1,154 @@
1/*!
2 * jQuery JavaScript Library v1.4.2
3 * http://jquery.com/
4 *
5 * Copyright 2010, John Resig
6 * Dual licensed under the MIT or GPL Version 2 licenses.
7 * http://jquery.org/license
8 *
9 * Includes Sizzle.js
10 * http://sizzlejs.com/
11 * Copyright 2010, The Dojo Foundation
12 * Released under the MIT, BSD, and GPL Licenses.
13 *
14 * Date: Sat Feb 13 22:33:48 2010 -0500
15 */
16(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?
17e(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=
18j.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,
19"&")}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=
20true;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/,
21Wa=/^(\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))&&
22(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,
23a)}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===
24"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,
25function(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)||
26c.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",
27L,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,
28"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 "+
29a))();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],
30d)===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]===
31a)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&&
32!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=
33true;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'/>";
34var 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,
35parentNode: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=
36false;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=
37s.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,
38applet: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];
39else 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,
40a,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===
41w)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,
42cb=/^(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+" ",
43i=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]+" ",
44" ");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=
45this.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=
46e[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=
47c.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");
48a[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,
49function(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(".");
50k=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),
51C=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!=
52null)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=
53e=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()&&
54f)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;
55if(!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(" "),
56fix: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||
57d&&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,
58"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=
59a;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,
60isImmediatePropagationStopped: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=
61{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")}};
62if(!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",
63e);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,
64"_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,
65d,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"&&
66!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}},
67toggle: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,
68u=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(" "),
69function(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];
70if(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,
71e=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();
72t=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||
73g);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[];
74for(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-
751)!=="\\"){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-]|\\.)+)/,
76CLASS:/\.((?:[\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")}},
77relative:{"+":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]=
78l?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=[];
79h=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()},
80CHILD: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,
81g);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)},
82text: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)}},
83setFilters:{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=
84h[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=
85m.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===
86"="?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,
87h){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||
88!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=
89h.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"&&
90q.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>";
91if(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}}();
92(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)}:
93function(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)/,
94gb=/,/;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;
95c.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=
96{},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===
97"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",
98d)},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")?
99a.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===
1001&&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)?
101a: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=
102c(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},
103wrapInner: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)})},
104prepend: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,
105this.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);
106return 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,
107""):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]&&
108this[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]||
109u.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===
1101?(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]);
111return 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)||["",
112""])[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=
113c.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]?
114c.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=
115function(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=
116Na.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,
117"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=
118a.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=
119a.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!==
120"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},
121serialize: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(" "),
122function(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,
123global: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&&
124e.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)?
125"&":"?")+(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===
126false&&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=
127false;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",
128c.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||
129d();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);
130g("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===
1311223||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===
132"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;
133if(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");
134this[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],
135"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)},
136animate: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=
137j.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([]);
138this.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===
139"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]||
140c.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;
141this.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=
142this.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,
143e,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||
144c.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?
145function(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=
146this[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;
147k-=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&&
148f.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>";
149a.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);
150c.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,
151d,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-
152f.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":
153"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
154e&&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);
0155
=== added file 'harvest/media/js/jquery.placeheld.js'
--- harvest/media/js/jquery.placeheld.js 1970-01-01 00:00:00 +0000
+++ harvest/media/js/jquery.placeheld.js 2010-07-15 16:29:40 +0000
@@ -0,0 +1,54 @@
1// PlaceHeld jQuery plugin by [Max Wheeler](max@makenosound.com)
2//
3// Copyright (c) 2010 Max Wheeler. Licensed under the [WTFPL](http://sam.zoy.org/wtfpl/)
4// Dependencies: jQuery
5//
6// Changelog:
7// * v1.0.0 (2010-04-21) Initial Version
8// * v1.0.1 (2010-04-29) Minified using YUI compressor instead ofo JSMin
9// * v1.0.2 (2010-05-10) Removed default text from form submission; moved placeholder support check outside for() loop
10// * v1.0.3 (2010-05-14) Added check for "placheld" class before clearing default text on form submission
11
12(function($){
13 $.placeHeld = function(el, options){
14 var base = this;
15 base.$el = $(el);
16 base.el = el;
17 base.$el.data("placeHeld", base);
18 base.placeholderText = base.$el.attr("placeholder");
19
20 base.init = function(){
21 base.options = $.extend({},$.placeHeld.defaultOptions, options);
22 base.$el.bind('blur', base.holdPlace).bind('focus', base.releasePlace).trigger('blur');
23 base.$el.parents('form').bind('submit', base.clearPlace);
24 };
25 // Hold with the default value attribute
26 base.holdPlace = function() {
27 var value = base.$el.val();
28 if (!value) base.$el.val(base.placeholderText).addClass(base.options.className);
29 };
30 // Refill with the default value attribute
31 base.releasePlace = function() {
32 var value = base.$el.val();
33 if (value == base.placeholderText) base.$el.val('').removeClass(base.options.className);
34 };
35 // Refill with the default value attribute
36 base.clearPlace = function() {
37 var value = base.$el.val();
38 if (value == base.placeholderText && base.$el.hasClass(base.options.className)) base.$el.val('');
39 };
40 base.init();
41 };
42
43 $.placeHeld.defaultOptions = { className: "placeheld" };
44
45 $.fn.placeHeld = function(options) {
46
47 // Check for placeholder attribute support
48 if (!!("placeholder" in $('<input>')[0])) return;
49
50 return this.each(function() {
51 (new $.placeHeld(this, options));
52 });
53 };
54})(jQuery);
055
=== added file 'harvest/media/js/jquery.scrollstay.js'
--- harvest/media/js/jquery.scrollstay.js 1970-01-01 00:00:00 +0000
+++ harvest/media/js/jquery.scrollstay.js 2010-07-15 16:29:40 +0000
@@ -0,0 +1,163 @@
1/**
2 * jquery.scrollstay.js
3 * scrollStay for minimalists.
4 * Derived from jquery.scrollFollow.js by R.A. Ray.
5 * Copyright (c) 2008 Net Perspective (http://kitchen.net-perspective.com/)
6 * Licensed under the MIT License (http://www.opensource.org/licenses/mit-license.php)
7 *
8 * Removed all animation, delay, cookies and killSwitch.
9 *
10 * @author Dylan McCall
11 *
12 * @projectDescription jQuery plugin that quietly keeps an element visible as the user scrolls
13 *
14 * @version 0.4.0
15 *
16 * @requires jquery.js (tested with 1.2.6)
17 *
18 * @param offset int - Number of pixels box should remain from top of viewport
19 * default: 0
20 * @param container string - ID of the containing div
21 * default: box's immediate parent
22 * @param relativeTo string - Scroll animation can be relative to either the 'top' or 'bottom' of the viewport
23 * default: 'top'
24 */
25
26( function( $ ) {
27
28 $.scrollStay = function ( box, options )
29 {
30 // Convert box into a jQuery object
31 box = $( box );
32
33 // 'box' is the object to be animated
34 var position = box.css( 'position' );
35
36 function ani()
37 {
38 // The script runs on every scroll which really means many times during a scroll.
39 // We don't want multiple slides to queue up.
40 box.queue( [ ] );
41
42 // A bunch of values we need to determine where to animate to
43 var viewportHeight = parseInt( $( window ).height() );
44 var pageScroll = parseInt( $( document ).scrollTop() );
45 var parentTop = parseInt( box.cont.offset().top );
46 var parentHeight = parseInt( box.cont.attr( 'offsetHeight' ) );
47 var boxHeight = parseInt( box.attr( 'offsetHeight' ) + ( parseInt( box.css( 'marginTop' ) ) || 0 ) + ( parseInt( box.css( 'marginBottom' ) ) || 0 ) );
48 var aniTop;
49
50 /* Make sure the user wants the animation to happen, and it
51 will be helpful. (It isn't helpful if the user is trying
52 to scroll within the box!) */
53 if ( isActive && viewportHeight > boxHeight )
54 {
55 // If the box should animate relative to the top of the window
56 if ( options.relativeTo == 'top' )
57 {
58 // Don't animate until the top of the window is close enough to the top of the box
59 if ( box.initialOffsetTop >= ( pageScroll + options.offset ) )
60 {
61 aniTop = box.initialTop;
62 }
63 else
64 {
65 aniTop = Math.min( ( Math.max( ( -parentTop ), ( pageScroll - box.initialOffsetTop + box.initialTop ) ) + options.offset ), ( parentHeight - boxHeight - box.paddingAdjustment ) );
66 }
67 }
68 // If the box should animate relative to the bottom of the window
69 else if ( options.relativeTo == 'bottom' )
70 {
71 // Don't animate until the bottom of the window is close enough to the bottom of the box
72 if ( ( box.initialOffsetTop + boxHeight ) >= ( pageScroll + options.offset + viewportHeight ) )
73 {
74 aniTop = box.initialTop;
75 }
76 else
77 {
78 aniTop = Math.min( ( pageScroll + viewportHeight - boxHeight - options.offset ), ( parentHeight - boxHeight ) );
79 }
80 }
81
82 // Checks to see if the relevant scroll was the last one
83 // "-20" is to account for inaccuracy in the timeout
84 if ( ( new Date().getTime() - box.lastScroll ) >= -20 )
85 {
86 box.css({ top: aniTop });
87 }
88 }
89 };
90
91 // For user-initiated stopping of the slide
92 var isActive = true;
93
94 // If no parent ID was specified, and the immediate parent does not have an ID
95 // options.container will be undefined. So we need to figure out the parent element.
96 if ( options.container == '')
97 {
98 box.cont = box.parent();
99 }
100 else
101 {
102 box.cont = $( '#' + options.container );
103 }
104
105 // Finds the default positioning of the box.
106 box.initialOffsetTop = parseInt( box.offset().top );
107 box.initialTop = parseInt( box.css( 'top' ) ) || 0;
108
109 // Hack to fix different treatment of boxes positioned 'absolute' and 'relative'
110 if ( box.css( 'position' ) == 'relative' )
111 {
112 box.paddingAdjustment = parseInt( box.cont.css( 'paddingTop' ) ) + parseInt( box.cont.css( 'paddingBottom' ) );
113 }
114 else
115 {
116 box.paddingAdjustment = 0;
117 }
118
119 // Animate the box when the page is scrolled
120 $( window ).scroll( function ()
121 {
122 ani();
123
124 // To check against right before setting the animation
125 box.lastScroll = new Date().getTime();
126 }
127 );
128
129 // Animate the box when the page is resized
130 $( window ).resize( function ()
131 {
132 ani();
133
134 // To check against right before setting the animation
135 box.lastScroll = new Date().getTime();
136 }
137 );
138
139 // Run an initial animation on page load
140 box.lastScroll = 0;
141
142 ani();
143 };
144
145 $.fn.scrollStay = function ( options )
146 {
147 options = options || {};
148 options.relativeTo = options.relativeTo || 'top';
149 options.offset = options.offset || 0;
150 options.container = options.container || this.parent().attr( 'id' );
151
152 this.each( function()
153 {
154 new $.scrollStay( this, options );
155 }
156 );
157
158 return this;
159 };
160})( jQuery );
161
162
163
0164
=== removed file 'harvest/media/js/yui-min.js'
--- harvest/media/js/yui-min.js 2010-01-05 01:47:06 +0000
+++ harvest/media/js/yui-min.js 1970-01-01 00:00:00 +0000
@@ -1,10 +0,0 @@
1/*
2Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3Code licensed under the BSD License:
4http://developer.yahoo.net/yui/license.txt
5version: 3.0.0
6build: 1549
7*/
8(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);
9switch(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));
10}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"]});
11\ No newline at end of file0\ No newline at end of file
121
=== modified file 'harvest/opportunities/filters.py'
--- harvest/opportunities/filters.py 2010-06-24 06:53:17 +0000
+++ harvest/opportunities/filters.py 2010-07-15 16:29:40 +0000
@@ -1,4 +1,5 @@
1from harvest.filters import filters, containers1from harvest.filters import filters, containers
2from harvest.common.ordereddict import OrderedDict
2import models3import models
34
4class PkgNameFilter(filters.EditFilter):5class PkgNameFilter(filters.EditFilter):
@@ -6,30 +7,30 @@
6 return queryset.filter(name__startswith = self.get_value())7 return queryset.filter(name__startswith = self.get_value())
78
8class PkgSetFilter(filters.ChoiceFilter):9class PkgSetFilter(filters.ChoiceFilter):
9 def __init__(self, id_str):10 def default_choices_dict(self):
10 choices_dict = dict()11 choices_dict = OrderedDict()
11 for s in models.PackageSet.objects.all():12 for s in models.PackageSet.objects.all(): #TODO: find a way to sort these
12 choices_dict[s.name] = s13 choices_dict[s.name] = s
13 super(PkgSetFilter, self).__init__(id_str, choices_dict)14 return choices_dict
14 15
15 def process_queryset(self, queryset):16 def process_queryset(self, queryset):
16 return queryset.filter(packagesets__in=self.get_selected_items())17 return queryset.filter(packagesets__in = self.get_selected_choices())
1718
1819
1920
20class OppFeaturedFilter(filters.Filter):21class OppFeaturedFilter(filters.Filter):
21 def process_queryset(self, queryset):22 def process_queryset(self, queryset):
22 return queryset.filter(opportunitylist__featured=True)23 return queryset.filter(opportunitylist__featured = True)
2324
24class OppListFilter(filters.ChoiceFilter):25class OppListFilter(filters.ChoiceFilter):
25 def __init__(self, id_str):26 def default_choices_dict(self):
26 choices_dict = dict()27 choices_dict = OrderedDict()
27 for l in models.OpportunityList.objects.all():28 for l in models.OpportunityList.objects.all(): #TODO: find a way to sort these
28 choices_dict[l.name] = l29 choices_dict[l.name] = l
29 super(OppListFilter, self).__init__(id_str, choices_dict)30 return choices_dict
30 31
31 def process_queryset(self, queryset):32 def process_queryset(self, queryset):
32 return queryset.filter(opportunitylist__in=self.get_selected_items())33 return queryset.filter(opportunitylist__in = self.get_selected_choices())
3334
3435
35#we don't really need to create a special type here, but it may be handy36#we don't really need to create a special type here, but it may be handy
@@ -37,17 +38,19 @@
37 def __init__(self):38 def __init__(self):
38 super(HarvestFilters, self).__init__(39 super(HarvestFilters, self).__init__(
39 [40 [
40 filters.FilterGroup("pkg", [41 filters.FilterGroup('pkg', [
41 PkgNameFilter("name"),42 PkgNameFilter('name', name='Named'),
42 PkgSetFilter("set")43 PkgSetFilter('set', name='Package sets')
43 ] ),44 ], name='Packages' ),
44 filters.FilterGroup("opp", [45 filters.FilterGroup('opp', [
45 OppFeaturedFilter("featured"),46 OppFeaturedFilter('featured', name='Featured'),
46 OppListFilter("list")47 OppListFilter('list', name='Selected')
47 ] )48 ], name='Opportunities' )
48 ],49 ],
49 default_parameters = { "pkg" : "name,set",50 default_parameters = { 'pkg' : 'set',
50 "pkg:name" : "ged",51 'pkg:set' : 'ubuntu-desktop',
51 "pkg:set" : "ubuntu-desktop" }52 'opp' : 'list',
53 'opp:list' : 'bitesize' }
54 #TODO: change to no defaults, detect that case in view and templates and provide helpful instructions in the results pane.
52 )55 )
5356
5457
=== modified file 'harvest/opportunities/management/commands/release.py'
--- harvest/opportunities/management/commands/release.py 2010-06-01 16:16:19 +0000
+++ harvest/opportunities/management/commands/release.py 2010-07-15 16:29:40 +0000
@@ -1,13 +1,13 @@
1#!/usr/bin/python1#!/usr/bin/python
22
3from django.core.management.base import LabelCommand3from django.core.management.base import BaseCommand, CommandError
4from django.conf import settings4from django.conf import settings
55
6import subprocess6import subprocess
7import sys7import sys
8import os8import os
99
10def write_version_strings(version):10def write_version_strings(version, version_name = ''):
11 try:11 try:
12 from bzrlib.branch import Branch12 from bzrlib.branch import Branch
13 branch = Branch.open_containing('.')[0]13 branch = Branch.open_containing('.')[0]
@@ -20,15 +20,21 @@
20 os.remove(file_name)20 os.remove(file_name)
21 f = open(file_name, "w")21 f = open(file_name, "w")
22 f.write("""version: %s22 f.write("""version: %s
23versionname: %s
23revno: %s24revno: %s
24""" % (version, bzr_revno))25""" % (version, version_name, bzr_revno))
25 f.close()26 f.close()
26 return (version, bzr_revno)27 return (version, version_name, bzr_revno)
2728
28class Command(LabelCommand):29class Command(BaseCommand):
29 help = "Prepare release of Harvest. Please pass <version> as an argument."30 help = "Prepare release of Harvest."
3031 args = "<version> [version_name]"
31 def handle_label(self, label, **options):32
32 (version, bzr_revno) = write_version_strings(label)33 def handle(self, *args, **options):
34 if len(args) < 1:
35 raise CommandError("Use this command with release %s" % self.args)
36 if len(args) > 2:
37 raise CommandError("Too many arguments. Remember to escape your spaces!")
38 (version, version_name, bzr_revno) = write_version_strings(*args)
33 subprocess.call(["bzr", "tag", version])39 subprocess.call(["bzr", "tag", version])
34 print >> sys.stdout, "Released %s." % label40 print >> sys.stdout, "Released %s" % version
3541
=== removed directory 'harvest/opportunities/templates'
=== removed directory 'harvest/opportunities/templates/opportunities'
=== removed file 'harvest/opportunities/templates/opportunities/opportunities_by_package.html'
--- harvest/opportunities/templates/opportunities/opportunities_by_package.html 2010-07-12 09:33:48 +0000
+++ harvest/opportunities/templates/opportunities/opportunities_by_package.html 1970-01-01 00:00:00 +0000
@@ -1,67 +0,0 @@
1{% extends 'base.html' %}
2{% load i18n %}
3
4{% block title %}Opportunities by Package - {{ block.super }}{% endblock %}
5
6{% block content %}
7<div class="mainpage">
8
9<h1>{% trans "Opportunities By Package" %}</h1>
10
11{% if sources.object_list %}
12 <ul class="toplevellist">
13 {% for source in sources.object_list %}
14 <li>
15 <div class="package_name threshold{{ source.opportunity_class }}">
16 <span class="name"><a href="{% url sourcepackage_detail source.name %}">{{ source.name }}</a></span>
17 <span class="count">
18 {% blocktrans count source.valid_opportunities|length as counter %}(1 opportunity){% plural %}({{ counter }} opportunities){% endblocktrans %}
19 </span>
20 </div>
21 <div class="package_details">
22 <ul>
23 {% for opportunity in source.valid_opportunities %}
24 {% include "opportunities/opportunity_detail.inc.html" %}
25 {% endfor %}
26 </ul>
27 </div>
28 </li>
29 {% endfor %}
30 </ul>
31
32 <div class="pagination">
33 <span class="step-links">
34 {% if sources.has_previous %}
35 <a href="?page={{ sources.previous_page_number }}">previous</a>
36 {% endif %}
37
38 <span class="current">
39 Page {{ sources.number }} of {{ sources.paginator.num_pages }}.
40 </span>
41
42 {% if sources.has_next %}
43 <a href="?page={{ sources.next_page_number }}">next</a>
44 {% endif %}
45 </span>
46 </div>
47
48{% else %}
49 <p>{% trans "There are currently no opportunities in Harvest. :(" %}</p>
50{% endif %}
51
52</div>
53
54<script type="text/javascript">
55YUI().use('node', function(Y) {
56
57 Y.all('.package_name').on('click', function(e) {
58 // XXX: rockstar: Currently, this is kinda jumpy. It'd be nice if it was
59 // all sexy animated.
60 Y.all('.package_details').setStyle('display', 'none');
61 e.currentTarget.next().setStyle('display', 'block');
62 });
63
64});
65
66</script>
67{% endblock %}
680
=== removed file 'harvest/opportunities/templates/opportunities/opportunities_by_type.html'
--- harvest/opportunities/templates/opportunities/opportunities_by_type.html 2010-07-12 09:33:48 +0000
+++ harvest/opportunities/templates/opportunities/opportunities_by_type.html 1970-01-01 00:00:00 +0000
@@ -1,28 +0,0 @@
1{% extends 'base.html' %}
2{% load i18n %}
3
4{% block title %}Opportunities by Type - {{ block.super }}{% endblock %}
5
6{% block content %}
7<div class="mainpage">
8
9<h1>{% trans "Opportunities By Type" %}</h1>
10
11{% if types.object_list %}
12 <ul class="toplevellist">
13 {% for type in types.object_list %}
14 <li>
15 <div class="package_name threshold{{ type.opportunity_class }}">
16 <span class="name"><a href="{{ type.get_absolute_url }}">{{ type.name }}</a></span>
17 <span class="count">
18 {% blocktrans count source.valid_opportunities.count as counter %}(1 opportunity){% plural %}({{ counter }} opportunities){% endblocktrans %}
19 </span>
20 </div>
21 {% endfor %}
22 </ul>
23{% else %}
24 <p>{% trans "There are currently no opportunities in Harvest. :(" %}</p>
25{% endif %}
26
27</div>
28{% endblock %}
290
=== modified file 'harvest/opportunities/urls.py'
--- harvest/opportunities/urls.py 2010-05-28 02:11:18 +0000
+++ harvest/opportunities/urls.py 2010-07-15 16:29:40 +0000
@@ -1,34 +1,11 @@
1from django.conf.urls.defaults import *1from django.conf.urls.defaults import *
22
3urlpatterns = patterns('',3urlpatterns = patterns('',
4 url(r'^$', 'opportunities.views.opportunity_index', name='opportunity_index'),
5
6 url(r'^opportunity/(?P<opportunity_id>[\d]+)/edit$', 'opportunities.views.opportunity_edit', name='opportunity_edit'),4 url(r'^opportunity/(?P<opportunity_id>[\d]+)/edit$', 'opportunities.views.opportunity_edit', name='opportunity_edit'),
7 url(r'^opportunity/(?P<opportunity_id>[\d]+)/$', 'opportunities.views.opportunity_detail', name='opportunity_detail'),5 url(r'^opportunity/(?P<opportunity_id>[\d]+)/$', 'opportunities.views.opportunity_detail', name='opportunity_detail'),
8 url(r'^opportunity/$', 'opportunities.views.opportunity_list', name='opportunity_list'),6
97 url(r'^filter$', 'opportunities.views.opportunities_filter', name='opportunities_filter'),
10 url(r'^opportunity-list/(?P<opportunitylist_slug>[-\w]+)/$', 'opportunities.views.opportunitylist_detail', name='opportunitylist_detail'),8
11 url(r'^opportunity-list/$', 'opportunities.views.opportunitylist_list', name='opportunitylist_list'),9 url(r'^query/results$', 'opportunities.views.opportunities_filter_results', name='opportunities_filter_results'),
1210 url(r'^query/results/(?P<package_id>[\d]+)$', 'opportunities.views.opportunities_package_details', name='opportunities_package_details'),
13 url(r'^source-package/(?P<sourcepackage_slug>[-\w+.]+)/$', 'opportunities.views.sourcepackage_detail', name='sourcepackage_detail'),
14 url(r'^source-package/$', 'opportunities.views.sourcepackage_list', name='sourcepackage_list'),
15
16 url(r'^filter',
17 'opportunities.views.opportunities_filter',
18 name='opportunities_filter'),
19
20 url(r'^by-type',
21 'opportunities.views.opportunities_by_type',
22 name='opportunities_by_type'),
23 url(r'^by-package',
24 'opportunities.views.opportunities_by_package',
25 name='opportunities_by_package'),
26
27 url(r'^packagesets/$',
28 'opportunities.views.packageset_list',
29 name='packageset_list'),
30
31 url(r'^packagesets/(?P<packageset_slug>[-\w+.]+)/$',
32 'opportunities.views.opportunities_by_package',
33 name='opportunities_by_package'),
34)11)
3512
=== modified file 'harvest/opportunities/views.py'
--- harvest/opportunities/views.py 2010-07-05 10:04:35 +0000
+++ harvest/opportunities/views.py 2010-07-15 16:29:40 +0000
@@ -16,34 +16,6 @@
16from filters import HarvestFilters16from filters import HarvestFilters
17from wrappers import PackageWrapper, PackageListWrapper17from wrappers import PackageWrapper, PackageListWrapper
1818
19def opportunity_index(request):
20 sources_list = models.SourcePackage.objects.all()
21 paginator = Paginator(sources_list, 50)
22 # Make sure page request is an int. If not, deliver first page.
23 try:
24 page = int(request.GET.get('page', '1'))
25 except ValueError:
26 page = 1
27 # If page request (9999) is out of range, deliver last page of results.
28 try:
29 sources = paginator.page(page)
30 except (EmptyPage, InvalidPage):
31 sources = paginator.page(paginator.num_pages)
32 context = {
33 'pageSection': 'opportunities',
34 'sources': sources,
35 }
36 return render('opportunities/opportunity_index.html', context,
37 context_instance=RequestContext(request))
38
39def opportunity_list(request):
40 return list_detail.object_list(
41 request,
42 queryset = models.Opportunity.objects.filter(last_updated=opportunitylist__last_updated),
43 paginate_by = 500,
44 template_object_name = 'opportunity',
45 )
46
47def opportunity_detail(request, opportunity_id):19def opportunity_detail(request, opportunity_id):
48 return list_detail.object_detail(20 return list_detail.object_detail(
49 request,21 request,
@@ -89,56 +61,33 @@
89 }, RequestContext(request))61 }, RequestContext(request))
9062
9163
92def opportunitylist_list(request):64def _create_packages_list(request, filters_pkg, filters_opp):
93 return list_detail.object_list(65 # XXX: rockstar: Eep! We shouldn't be storing the None as a string. We
94 request,66 # should re-think this model relationship.
95 queryset = models.OpportunityList.objects.annotate(Count('opportunity')),67 #sourcepackages_list = models.SourcePackage.objects.exclude(name='None')
96 paginate_by = 50,
97 )
98
99def opportunitylist_detail(request, opportunitylist_slug):
100 opportunitylist = get_object_or_404(models.OpportunityList, name=opportunitylist_slug)
101 return list_detail.object_list(
102 request,
103 queryset = models.Opportunity.objects.filter(opportunitylist__name=opportunitylist_slug),
104 paginate_by = 500,
105 template_name = 'opportunities/opportunitylist_detail.html',
106 extra_context = {'opportunitylist': opportunitylist},
107 )
108
109def sourcepackage_list(request):
110 return list_detail.object_list(
111 request,
112 queryset = models.SourcePackage.objects.annotate(Count('opportunity')),
113 paginate_by = 500,
114 )
115
116def sourcepackage_detail(request, sourcepackage_slug):
117 opportunities = models.Opportunity.objects.filter(sourcepackage__name=sourcepackage_slug)
118 return list_detail.object_detail(
119 request,
120 queryset = models.SourcePackage.objects.all(),
121 slug = sourcepackage_slug,
122 slug_field = 'name',
123 extra_context = {'opportunities': opportunities},
124 )
125
126def opportunities_filter(request):
127 filters = HarvestFilters()
128 filters.update_from_http(request)
129 filters_pkg = filters.find('pkg')
130 filters_opp = filters.find('opp')
131 68
132 packages_list = models.SourcePackage.objects.distinct()69 sourcepackages_list = models.SourcePackage.objects.distinct()
133 packages_list = filters_pkg.process_queryset(packages_list)70 sourcepackages_list = filters_pkg.process_queryset(sourcepackages_list)
134 71
135 #opportunities_list is filtered right away to only check opportunities belonging to selected packages72 #opportunities_list is filtered right away to only check opportunities belonging to selected packages
136 opportunities_list = models.Opportunity.objects.distinct().filter(sourcepackage__in=packages_list)73 opportunities_list = models.Opportunity.objects.distinct().filter(sourcepackage__in=sourcepackages_list)
137 opportunities_list = filters_opp.process_queryset(opportunities_list)74 opportunities_list = filters_opp.process_queryset(opportunities_list)
75
138 #TODO: need to filter out opportunities with valid=False again76 #TODO: need to filter out opportunities with valid=False again
139 #TODO: would it be more efficient to group opportunities by their sourcepackages first, then run filters_opp.process_queryset() for each of those groups?77 #TODO: would it be more efficient to group opportunities by their sourcepackages first, then run filters_opp.process_queryset() for each of those groups?
140 78
141 pkg_list_wrapper = PackageListWrapper(request, packages_list, opportunities_list) 79 pkg_list_wrapper = PackageListWrapper(request, sourcepackages_list, opportunities_list)
80
81 return pkg_list_wrapper
82
83
84def opportunities_filter(request):
85 filters = HarvestFilters()
86 filters.update_from_http(request)
87 filters_pkg = filters.find('pkg')
88 filters_opp = filters.find('opp')
89
90 pkg_list_wrapper = _create_packages_list(request, filters_pkg, filters_opp)
142 91
143 context = {92 context = {
144 'grouping': 'package',93 'grouping': 'package',
@@ -148,76 +97,44 @@
148 }97 }
14998
150 return render(99 return render(
151 'opportunities/opportunities_filter.html',100 'opportunities/filter.html',
152 context,101 context,
153 context_instance=RequestContext(request))102 context_instance=RequestContext(request))
154103
155#TODO: package_filter_detail(request, sourcepackage, opportunities_list)104
156105def opportunities_filter_results(request):
157def opportunities_by_type(request):106 filters = HarvestFilters()
158 types_list = models.OpportunityList.objects.filter(active=True)107 filters.update_from_http(request)
159 paginator = Paginator(types_list, 50)108
160109 packages_list = _create_packages_list(request, filters.find('pkg'), filters.find('opp'))
161 # Make sure page request is an int. If not, deliver first page.110
162 try:111 context = {
163 page = int(request.GET.get('page', '1'))112 'grouping': 'package',
164 except ValueError:113 'packages_list': packages_list
165 page = 1114 }
166115
167 # If page request (9999) is out of range, deliver last page of results.116 return render(
168 try:117 'opportunities/filter_results.html',
169 types = paginator.page(page)118 context,
170 except (EmptyPage, InvalidPage):119 context_instance=RequestContext(request))
171 types = paginator.page(paginator.num_pages)120
172121
173 context = {122def opportunities_package_details(request, package_id):
174 'pageSection': 'opportunities',123 filters = HarvestFilters()
175 'types': types,124 filters.update_from_http(request)
176 'grouping': 'type',125
177 }126 package = models.SourcePackage.objects.get(id=package_id)
178127
179 return render(128 opportunities_list = filters.find('opp').process_queryset(package.opportunity_set).all()
180 'opportunities/opportunities_by_type.html',129
181 context,130 package_wrapper = PackageWrapper(request, package, visible_opportunities = opportunities_list, expanded = True)
182 context_instance=RequestContext(request))131
183132 context = {
184def opportunities_by_package(request, packageset_slug=None):133 'grouping': 'package',
185 # XXX: rockstar: Eep! We shouldn't be storing the None as a string. We134 'package': package_wrapper
186 # should re-think this model relationship.135 }
187 sources_list = models.SourcePackage.objects.exclude(name='None')136
188 if packageset_slug:137 return render(
189 packageset = get_object_or_404(models.PackageSet, name=packageset_slug)138 'opportunities/package_details.html',
190 sources_list = sources_list.filter(packagesets=packageset)139 context,
191 paginator = Paginator(sources_list, 50)140 context_instance=RequestContext(request))
192
193 # Make sure page request is an int. If not, deliver first page.
194 try:
195 page = int(request.GET.get('page', '1'))
196 except ValueError:
197 page = 1
198
199 # If page request (9999) is out of range, deliver last page of results.
200 try:
201 sources = paginator.page(page)
202 except (EmptyPage, InvalidPage):
203 sources = paginator.page(paginator.num_pages)
204
205 context = {
206 'pageSection': 'opportunities',
207 'sources': sources,
208 'grouping': 'package',
209 }
210
211 return render(
212 'opportunities/opportunities_by_package.html',
213 context,
214 context_instance=RequestContext(request))
215
216def packageset_list(request):
217 packagesets = models.PackageSet.objects.all()
218 context = {
219 'packagesets': packagesets
220 }
221 return render('opportunities/packageset_list.html',
222 context,
223 context_instance=RequestContext(request))
224141
=== modified file 'harvest/opportunities/wrappers.py'
--- harvest/opportunities/wrappers.py 2010-06-23 03:14:51 +0000
+++ harvest/opportunities/wrappers.py 2010-07-15 16:29:40 +0000
@@ -17,7 +17,7 @@
17 return self.package17 return self.package
18 18
19 def get_expand_toggle_url(self):19 def get_expand_toggle_url(self):
20 parameter = {'expand_pkg' : self.package.name}20 parameter = {'expand_pkg' : self.package.id}
21 url = current_url_with_parameters(self.request, parameter)21 url = current_url_with_parameters(self.request, parameter)
22 return url22 return url
23 23
@@ -38,7 +38,7 @@
38 been hidden from view38 been hidden from view
39 """39 """
40 opps_visible = self.get_visible_opportunities()40 opps_visible = self.get_visible_opportunities()
41 return self.package.opportunity_set.exclude(pk__in=opps_visible)41 return self.package.opportunity_set.exclude(id__in=opps_visible)
4242
43class PackageListWrapper(object):43class PackageListWrapper(object):
44 """44 """
@@ -48,9 +48,10 @@
48 """48 """
49 49
50 def __init__(self, request, packages_list, opportunities_list):50 def __init__(self, request, packages_list, opportunities_list):
51 expand_list = None #list of packages to show in detail51 expand_list = list() #list of packages to show in detail
52 if 'expand_pkg' in request.GET:52 if 'expand_pkg' in request.GET:
53 expand_list = request.GET['expand_pkg'].split(',')53 expand_list = request.GET['expand_pkg'].split(',')
54 expand_list = [int(i) for i in expand_list if i.isdigit()]
54 55
55 related_packages = set(opportunities_list.values_list('sourcepackage', flat=True))56 related_packages = set(opportunities_list.values_list('sourcepackage', flat=True))
56 57
@@ -64,7 +65,7 @@
64 opps = None65 opps = None
65 expand = False66 expand = False
66 67
67 if expand_list: expand = (package.name in expand_list)68 expand = (package.id in expand_list)
68 opps = opportunities_list.filter(sourcepackage=package)69 opps = opportunities_list.filter(sourcepackage=package)
69 70
70 package_wrapper = PackageWrapper(request, package,71 package_wrapper = PackageWrapper(request, package,
@@ -87,4 +88,4 @@
87 """88 """
88 Returns list of packages that have been hidden from view.89 Returns list of packages that have been hidden from view.
89 """90 """
90 return self.hidden_packages_list
91\ No newline at end of file91\ No newline at end of file
92 return self.hidden_packages_list
9293
=== modified file 'harvest/settings.py'
--- harvest/settings.py 2010-07-05 10:15:55 +0000
+++ harvest/settings.py 2010-07-15 16:29:40 +0000
@@ -19,6 +19,9 @@
19VERSION_STRING = utils.get_harvest_version(19VERSION_STRING = utils.get_harvest_version(
20 os.path.join(PROJECT_PATH, "version"),20 os.path.join(PROJECT_PATH, "version"),
21 DEBUG)21 DEBUG)
22VERSION_NAME_STRING = utils.get_harvest_version_name(
23 os.path.join(PROJECT_PATH, "version"),
24 DEBUG)
2225
23ADMINS = ('Daniel Holbach', 'daniel.holbach@ubuntu.com')26ADMINS = ('Daniel Holbach', 'daniel.holbach@ubuntu.com')
24MANAGERS = ADMINS27MANAGERS = ADMINS
@@ -73,6 +76,7 @@
73)76)
7477
75MIDDLEWARE_CLASSES = (78MIDDLEWARE_CLASSES = (
79 'harvest.common.middleware.timer.TimerMiddleware',
76 'django.middleware.common.CommonMiddleware',80 'django.middleware.common.CommonMiddleware',
77 'django.contrib.sessions.middleware.SessionMiddleware',81 'django.contrib.sessions.middleware.SessionMiddleware',
78 'django.contrib.auth.middleware.AuthenticationMiddleware',82 'django.contrib.auth.middleware.AuthenticationMiddleware',
7983
=== modified file 'harvest/templates/base.html'
--- harvest/templates/base.html 2010-06-01 16:16:19 +0000
+++ harvest/templates/base.html 2010-07-15 16:29:40 +0000
@@ -1,91 +1,86 @@
1{% load i18n %}1{% load i18n %}
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 strict//EN"2<!DOCTYPE html>
3 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
4<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="{{ LANGUAGE_CODE }}" lang="{{ LANGUAGE_CODE }}">3<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="{{ LANGUAGE_CODE }}" lang="{{ LANGUAGE_CODE }}">
4
5<head>5<head>
6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 <title>{% block title %}{% trans "Harvest" %}{% endblock %}</title>7 <title>{% block title %}{% trans "Harvest" %}{% endblock %}</title>
8 <link rel="stortcut icon" href="{{ MEDIA_URL }}img/favicon.ico" type="image/x-icon" />8
9 <link rel="stylesheet" href="{{ MEDIA_URL }}css/style.css" type="text/css" media="screen" /> 9 <link rel="stortcut icon" href="{{ MEDIA_URL }}img/favicon.ico" type="image/x-icon" />
1010
11 <script type="text/javascript" src="{{ MEDIA_URL }}js/yui-min.js"></script>11 <link href='http://fonts.googleapis.com/css?family=Molengo' rel='stylesheet' type='text/css' />
1212
13{% block extrahead %}{% endblock %}13 <link rel="stylesheet" href="{{ MEDIA_URL }}css/reset.css" />
14 <link rel="stylesheet" href="{{ MEDIA_URL }}css/style.css" />
15
16 <script type="text/javascript" src="{{ MEDIA_URL }}js/jquery-1.4.2.min.js"></script>
17 <script type="text/javascript" src="{{ MEDIA_URL }}js/jquery.scrollstay.js"></script>
18 <script type="text/javascript" src="{{ MEDIA_URL }}js/jquery.placeheld.js"></script>
19 <script type="text/javascript" src="{{ MEDIA_URL }}js/harvest.js"></script>
20
21 {% block extrahead %}{% endblock %}
14</head>22</head>
1523
16<body>24<body>
17<div id="container">25<div id="container">
18 <div id="content">26
19 <div id="topNav">27<div id="header">
20 <p id="whoami">28 <span id="pagetitle">
21 {% if user.is_authenticated %}29 <img id="sitelogo" src="{{ MEDIA_URL }}img/logo_humanity-search-icon.png" />
22 {{ user.username }}30 <h1 id="sitename">{% trans "Harvest" %}</h1>
23 &nbsp;31 {% if harvest_version_name %}<span id="releasename">{{harvest_version_name}}</span>{% endif %}
24 <a href="/logout">Log out</a>32 </span>
25 {% else %}33
26 <a href="/openid/login">Log in</a>34 <span id="userdata">
27 {% endif %}</p>35 {% if user.is_authenticated %}
28 <a href="/"><img id="ubuntulogo" src="{{ MEDIA_URL }}img/ubuntulogo.png" alt="Ubuntu" /></a>36 <span class="username">{{ user.username }}</span>
29 </div>37 <br /><a class="loginbutton" href="/logout" tabindex="1">Log out</a>
30 <div id="body">38 {% else %}
31 <div class="content">39 <a class="loginbutton" href="/openid/login">Log in</a>
32{% if messages %}40 {% endif %}
33{% for message in messages %}41 </span>
34<p>{{ message }}</p>42</div>
35{% endfor %}43
36{% endif %}44<div id="content">
3745 {% if messages %}
38{% block content %}46 <div id="messages"><ul>
39{% endblock %}47 {% for message in messages %}
4048 <li>{{ message }}</li>
41{% block pagination %}49 {% endfor %}
42{% if is_paginated %}50 </ul></div>
43 <div class="pagination">51 {% endif %}
44 {% if page_obj.has_previous %}52 {% block content %}
45 <a href="?page={{ page_obj.previous_page_number }}">&lt;&lt;Previous</a>53
46 {% else %}54
47 &lt;&lt;Previous55
48 {% endif %}56 {% endblock %}
4957</div>
50 <span class="pages">58
51 {% for item in paginator.page_range %}59<div id="footer">
52 {% ifequal item page %}60 <div id="footnav"><nav>
53 <span class="current-page">{{ item }}</span>61 <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>
54 {% else %}62 </nav></div>
55 <a href="?page={{ item }}">{{ item }}</a>63
56 {% endifequal %}64 <div id="smallprint" tabindex="3">
57 {% endfor %}65 <span id="copyright">
58 </span>66 &copy; 2008-2009 Canonical Ltd.
5967 <br />Ubuntu and Canonical are registered
60 {% if page_obj.has_next %}68 trademarks of Canonical Ltd.
61 <a href="?page={{ page_obj.next_page_number }}">Next &gt;&gt;</a>69 </span>
62 {% else %}70
63 Next &gt;&gt;71 <span id="techdetails">
64 {% endif %}72 {% trans "Harvest" %} {{ harvest_version }}
65 </div>73 {% if translator_credits %}
66{% endif %}74 <br />{% trans "Translated by:" %} {{ translator_credits|join:", " }}
67{% endblock %}75 {% endif %}
6876 <br /><span id="requeststats"></span>
69 </div>77 </span>
7078
71{% if translator_credits %}79 <div class="bottom"></div>
72<p class="footnote">80 </div>
73{% trans "Translated by:" %} {{ translator_credits|join:", " }}81</div>
74</p>
75{% endif %}
76 </div>
77
78 <div id="footer">
79 <div class="wrapper">
80 <img src="{{ MEDIA_URL }}img/rule.png" width="740" height="1" alt="" class="rule" />
81 <p>&copy; 2008-2009 Canonical Ltd. Ubuntu and Canonical are registered
82 trademarks of Canonical Ltd.<br />{% trans "Harvest" %} {{ harvest_version }}</p>
83 </div>
84 </div>
85 <div id="bg-right">&nbsp;</div><div id="bottom-right">&nbsp;</div>
86 </div>
87 <div id="bg-left">&nbsp;</div><div id="bottom-left">&nbsp;</div>
8882
89</div>83</div>
90</body>84</body>
85
91</html>86</html>
9287
=== modified file 'harvest/templates/index.html'
--- harvest/templates/index.html 2010-02-03 23:28:50 +0000
+++ harvest/templates/index.html 2010-07-15 16:29:40 +0000
@@ -8,13 +8,7 @@
88
9<h1>{% trans "Harvest" %}</h1>9<h1>{% trans "Harvest" %}</h1>
1010
11Find opportunities!11There is no landing page at the moment :(
12
13<ul>
14 <li><a href="{% url opportunities_by_type %}">By type</a></li>
15 <li><a href="{% url opportunities_by_package %}">By package</a></li>
16 <li><a href="{% url packageset_list %}">By packageset</a></li>
17<ul>
1812
1913
20{% if translator_credits %}14{% if translator_credits %}
2115
=== renamed file 'harvest/templates/opportunities/opportunities_filter.html' => 'harvest/templates/opportunities/filter.html'
--- harvest/templates/opportunities/opportunities_filter.html 2010-06-22 05:18:50 +0000
+++ harvest/templates/opportunities/filter.html 2010-07-15 16:29:40 +0000
@@ -4,47 +4,19 @@
4{% block title %}{% trans "Opportunity Index" %} - {{ block.super }}{% endblock %}4{% block title %}{% trans "Opportunity Index" %} - {{ block.super }}{% endblock %}
55
6{% block content %}6{% block content %}
7<div class="mainpage">7
88<div id="filters">
9<h1>{% trans "Opportunities" %}</h1>
10
11<div class="filters" style="background-color:#E0F1FF; float:left; width:15em;">
12 {{filters_pkg.render}}9 {{filters_pkg.render}}
13 {{filters_opp.render}}10 {{filters_opp.render}}
14</div>11</div>
1512
16<div class="results" style="float:left;">13<div id="results-pane" data-results-url="{% url opportunities_filter_results %}">
17{% if packages_list %}14 <div id="results-status"></div>
18<ul>15 <div id="results">
19 {% for pkg in packages_list.get_visible_packages %}16 {% include "opportunities/filter_results.html" %}
20 <li><a href="{{ pkg.get_expand_toggle_url }}">{{ pkg.real.name }}</a>17 </div>
21 {% if pkg.expanded %}18</div>
22 <ul>19
23 {% for opportunity in pkg.get_visible_opportunities %}20<div class="bottom"></div>
24 {% include "opportunities/opportunity_detail.inc.html" %}21
25 {% endfor %}
26
27 {% with pkg.get_hidden_opportunities.count as hidden_count %}
28 {% ifnotequal hidden_count 0 %}
29 <li><small>{{ hidden_count }} {{ hidden_count|pluralize:"opportunity,opportunities"}} hidden</small></li>
30 {% endifnotequal %}
31 {% endwith %}
32 </ul>
33 {% endif %}
34 </li>
35 {% endfor %}
36
37 {% with packages_list.get_hidden_packages|length as hidden_count %}
38 {% ifnotequal hidden_count 0 %}
39 <li><small>{{ hidden_count }} package{{ hidden_count|pluralize:"s"}} {{ hidden_count|pluralize:"has,have"}} no matching opportunities</small></li>
40 {% endifnotequal %}
41 {% endwith %}
42</ul>
43
44{% else %}
45<p>{% trans "There are currently no opportunities in Harvest. :(" %}</p>
46{% endif %}
47</div>
48
49</div>
50{% endblock %}22{% endblock %}
5123
=== added file 'harvest/templates/opportunities/filter_results.html'
--- harvest/templates/opportunities/filter_results.html 1970-01-01 00:00:00 +0000
+++ harvest/templates/opportunities/filter_results.html 2010-07-15 16:29:40 +0000
@@ -0,0 +1,33 @@
1{% load i18n %}
2
3{% if packages_list %}
4<ul>
5 {% for package in packages_list.get_visible_packages %}
6 <li data-results-packageid="{{ package.real.id }}" class="sourcepackage {% if package.expanded %}expanded{% else %}collapsed{% endif %}">
7 <a class="sourcepackage-header" href="{{ package.get_expand_toggle_url }}">
8 <span class="sourcepackage-name">{{ package.real.name }}</span>
9 <span class="status"></span>
10 <span class="sourcepackage-summary">
11 X issues (TODO)
12 </span>
13 <div class="bottom"></div>
14 </a>
15 <div class="sourcepackage-details">
16 {% if package.expanded %}
17 {% include "opportunities/package_details.html" %}
18 {% endif %}
19 </div>
20 </li>
21 {% endfor %}
22
23 {% with packages_list.get_hidden_packages|length as hidden_count %}
24 {% ifnotequal hidden_count 0 %}
25 <li><small>{% blocktrans count hidden_count as counter %}{{ counter }} package has no matching opportunities{% plural %}{{ counter }} packages have no matching opportunities{% endblocktrans %}</small></li>
26 {% endifnotequal %}
27 {% endwith %}
28</ul>
29
30{% else %}
31<p>{% trans "There are currently no opportunities in Harvest. :(" %}</p>
32{% endif %}
33
034
=== modified file 'harvest/templates/opportunities/opportunity_detail.inc.html'
--- harvest/templates/opportunities/opportunity_detail.inc.html 2010-06-08 16:21:40 +0000
+++ harvest/templates/opportunities/opportunity_detail.inc.html 2010-07-15 16:29:40 +0000
@@ -9,7 +9,7 @@
9 ({{ opportunity.opportunitylist }})9 ({{ opportunity.opportunitylist }})
10 {% endifequal %}10 {% endifequal %}
11 {% else %}11 {% else %}
12 (<a href="{% url sourcepackage_detail opportunity.sourcepackage.name %}">({{ opportunity.sourcepackage }})</a> - {{ opportunity.opportunitylist }})12 (<a href="{% url opportunities_package_details opportunity.sourcepackage.id %}">({{ opportunity.sourcepackage }})</a> - {{ opportunity.opportunitylist }})
13 {% endif %}13 {% endif %}
14 {% if opportunity.experience %}14 {% if opportunity.experience %}
15 <span class="experience{{ opportunity.experience }}"></span>15 <span class="experience{{ opportunity.experience }}"></span>
1616
=== removed file 'harvest/templates/opportunities/opportunity_index.html'
--- harvest/templates/opportunities/opportunity_index.html 2010-06-07 15:04:29 +0000
+++ harvest/templates/opportunities/opportunity_index.html 1970-01-01 00:00:00 +0000
@@ -1,45 +0,0 @@
1{% extends "base.html" %}
2{% load i18n %}
3
4{% block title %}{% trans "Opportunity Index" %} - {{ block.super }}{% endblock %}
5
6{% block content %}
7<div class="mainpage">
8
9<h1>{% trans "Opportunities" %}</h1>
10
11{% if sources.object_list %}
12<ul>
13{% for source in sources.object_list %}
14<li><a href="{% url sourcepackage_detail source.name %}">{{ source.name }}</a>
15<ul>
16{% for opportunity in source.valid_opportunites %}
17 {% include "opportunities/opportunity_detail.inc.html" %}
18{% endfor %}
19</ul>
20</li>
21{% endfor %}
22</ul>
23
24<div class="pagination">
25 <span class="step-links">
26 {% if sources.has_previous %}
27 <a href="?page={{ sources.previous_page_number }}">previous</a>
28 {% endif %}
29
30 <span class="current">
31 Page {{ sources.number }} of {{ sources.paginator.num_pages }}.
32 </span>
33
34 {% if sources.has_next %}
35 <a href="?page={{ sources.next_page_number }}">next</a>
36 {% endif %}
37 </span>
38</div>
39
40{% else %}
41<p>{% trans "There are currently no opportunities in Harvest. :(" %}</p>
42{% endif %}
43
44</div>
45{% endblock %}
460
=== removed file 'harvest/templates/opportunities/opportunity_list.html'
--- harvest/templates/opportunities/opportunity_list.html 2010-02-22 15:43:51 +0000
+++ harvest/templates/opportunities/opportunity_list.html 1970-01-01 00:00:00 +0000
@@ -1,14 +0,0 @@
1{% extends "base.html" %}
2
3{% load i18n %}
4
5{% block title %}{% trans "Opportunities" %} - {{ block.super }}{% endblock %}
6
7{% block content %}
8 <h2>Opportunities</h2>
9 <ul>
10 {% for opportunity in opportunity_list %}
11 {% include "opportunities/opportunity_detail.inc.html" %}
12 {% endfor %}
13 </ul>
14{% endblock %}
150
=== removed file 'harvest/templates/opportunities/opportunitylist_detail.html'
--- harvest/templates/opportunities/opportunitylist_detail.html 2010-02-22 15:43:51 +0000
+++ harvest/templates/opportunities/opportunitylist_detail.html 1970-01-01 00:00:00 +0000
@@ -1,13 +0,0 @@
1{% extends "base.html" %}
2
3{% block title %}{{ opportunitylist.name }} - {{ block.super }}{% endblock %}
4
5{% block content %}
6 <h2>{{ opportunitylist.name }}</h2>
7 <p>{{ opportunitylist.description }}</p>
8 <ul>
9 {% for opportunity in object_list %}
10 {% include "opportunities/opportunity_detail.inc.html" %}
11 {% endfor %}
12 </ul>
13{% endblock %}
140
=== removed file 'harvest/templates/opportunities/opportunitylist_list.html'
--- harvest/templates/opportunities/opportunitylist_list.html 2010-07-12 09:33:48 +0000
+++ harvest/templates/opportunities/opportunitylist_list.html 1970-01-01 00:00:00 +0000
@@ -1,14 +0,0 @@
1{% extends "base.html" %}
2
3{% load i18n %}
4
5{% block title %}{% trans "Opportunity Lists" %} - {{ block.super }}{% endblock %}
6
7{% block content %}
8 <h2>Opportunity Lists</h2>
9 {% for opportunity_list in object_list %}
10 <h3><a href="{% url opportunitylist_detail opportunity_list %}">{{ opportunity_list.name }}</a>
11 {% blocktrans count opportunity_list.opportunity__count as counter %}(1 opportunity){% plural %}({{ counter }} opportunities){% endblocktrans %}</h3>
12 <p>{{ opportunity_list.description }}</p>
13 {% endfor %}
14{% endblock %}
150
=== added file 'harvest/templates/opportunities/package_details.html'
--- harvest/templates/opportunities/package_details.html 1970-01-01 00:00:00 +0000
+++ harvest/templates/opportunities/package_details.html 2010-07-15 16:29:40 +0000
@@ -0,0 +1,13 @@
1{% load i18n %}
2
3<ul>
4 {% for opportunity in package.get_visible_opportunities %}
5 {% include "opportunities/opportunity_detail.inc.html" %}
6 {% endfor %}
7
8 {% with package.get_hidden_opportunities.count as hidden_count %}
9 {% ifnotequal hidden_count 0 %}
10 <li><small>{% blocktrans count hidden_count as counter %}{{ counter }} opportunity hidden{% plural %}{{ counter }} opportunities hidden{% endblocktrans %}</small></li>
11 {% endifnotequal %}
12 {% endwith %}
13</ul>
014
=== removed file 'harvest/templates/opportunities/packageset_list.html'
--- harvest/templates/opportunities/packageset_list.html 2010-02-03 23:28:50 +0000
+++ harvest/templates/opportunities/packageset_list.html 1970-01-01 00:00:00 +0000
@@ -1,14 +0,0 @@
1{% extends "base.html" %}
2
3{% load i18n %}
4
5{% block title %}{% trans "Packagesets" %} - {{ block.super }}{% endblock %}
6{% block content %}
7 <h2>Packagesets</h2>
8 <ul>
9 {% for packageset in packagesets %}
10 <li><a href="{{ packageset.name }}">{{ packageset.name }}</a></li>
11 {% endfor %}
12 </ul>
13{% endblock %}
14
150
=== removed file 'harvest/templates/opportunities/sourcepackage_detail.html'
--- harvest/templates/opportunities/sourcepackage_detail.html 2010-02-22 15:43:51 +0000
+++ harvest/templates/opportunities/sourcepackage_detail.html 1970-01-01 00:00:00 +0000
@@ -1,12 +0,0 @@
1{% extends "base.html" %}
2
3{% block title %}{{ object.name }} - {{ block.super }}{% endblock %}
4
5{% block content %}
6 <h2>{{ object.name }}</h2>
7 <ul>
8 {% for opportunity in opportunities %}
9 {% include "opportunities/opportunity_detail.inc.html" %}
10 {% endfor %}
11 </ul>
12{% endblock %}
130
=== removed file 'harvest/templates/opportunities/sourcepackage_list.html'
--- harvest/templates/opportunities/sourcepackage_list.html 2010-07-12 09:33:48 +0000
+++ harvest/templates/opportunities/sourcepackage_list.html 1970-01-01 00:00:00 +0000
@@ -1,14 +0,0 @@
1{% extends "base.html" %}
2
3{% load i18n %}
4
5{% block title %}{% trans "Source Packages" %} - {{ block.super }}{% endblock %}
6
7{% block content %}
8 <h2>Source Packages</h2>
9 <ul>
10 {% for source_package in object_list %}
11 <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>
12 {% endfor %}
13 </ul>
14{% endblock %}
150
=== modified file 'harvest/version'
--- harvest/version 2010-06-01 16:16:19 +0000
+++ harvest/version 2010-07-15 16:29:40 +0000
@@ -1,2 +1,3 @@
1version: 0.2.0-pre1version: 0.2.0-pre
2versionname: Alpha
2revno: 1823revno: 182

Subscribers

People subscribed via source and target branches

to all changes: