Ticket #1200: Brians_New_Visualizer.darcs.patch

File Brians_New_Visualizer.darcs.patch, 296.0 KB (added by zooko, at 2010-11-18T08:24:39Z)
Line 
11 patch for repository /Users/zooko/playground/tahoe-lafs/trunk:
2
3Tue Aug 31 21:48:17 MDT 2010  "Brian Warner <warner@lothar.com>"
4  * Add Protovis.js-based download-status timeline visualization. Still kinda
5  rough, but illuminating.
6 
7  Also add dl-status test for /download-%s/event_json, remove
8  /download-%s?t=json
9 
10
11New patches:
12
13[Add Protovis.js-based download-status timeline visualization. Still kinda
14"Brian Warner <warner@lothar.com>"**20100901034817
15 rough, but illuminating.
16 
17 Also add dl-status test for /download-%s/event_json, remove
18 /download-%s?t=json
19 
20] {
21hunk ./src/allmydata/immutable/downloader/finder.py 140
22                       peerid=idlib.shortnodeid_b2a(peerid),
23                       level=log.NOISY, umid="Io7pyg")
24         time_sent = now()
25-        d_ev = self._download_status.add_dyhb_sent(peerid, time_sent)
26+        d_ev = self._download_status.add_dyhb_request(peerid, time_sent)
27         # TODO: get the timer from a Server object, it knows best
28         self.overdue_timers[req] = reactor.callLater(self.OVERDUE_TIMEOUT,
29                                                      self.overdue, req)
30hunk ./src/allmydata/immutable/downloader/finder.py 226
31         eventually(self.share_consumer.got_shares, shares)
32 
33     def _got_error(self, f, peerid, req, d_ev, lp):
34-        d_ev.finished("error", now())
35+        d_ev.error(now())
36         self.log(format="got error from [%(peerid)s]",
37                  peerid=idlib.shortnodeid_b2a(peerid), failure=f,
38                  level=log.UNUSUAL, parent=lp, umid="zUKdCw")
39hunk ./src/allmydata/immutable/downloader/node.py 75
40         # things to track callers that want data
41 
42         # _segment_requests can have duplicates
43-        self._segment_requests = [] # (segnum, d, cancel_handle, logparent)
44+        self._segment_requests = [] # (segnum, d, cancel_handle, seg_ev, lp)
45         self._active_segment = None # a SegmentFetcher, with .segnum
46 
47         self._segsize_observers = observer.OneShotObserverList()
48hunk ./src/allmydata/immutable/downloader/node.py 122
49     # things called by outside callers, via CiphertextFileNode. get_segment()
50     # may also be called by Segmentation.
51 
52-    def read(self, consumer, offset=0, size=None, read_ev=None):
53+    def read(self, consumer, offset, size, read_ev):
54         """I am the main entry point, from which FileNode.read() can get
55         data. I feed the consumer with the desired range of ciphertext. I
56         return a Deferred that fires (with the consumer) when the read is
57hunk ./src/allmydata/immutable/downloader/node.py 129
58         finished.
59 
60         Note that there is no notion of a 'file pointer': each call to read()
61-        uses an independent offset= value."""
62-        # for concurrent operations: each gets its own Segmentation manager
63-        if size is None:
64-            size = self._verifycap.size
65-        # clip size so offset+size does not go past EOF
66-        size = min(size, self._verifycap.size-offset)
67-        if read_ev is None:
68-            read_ev = self._download_status.add_read_event(offset, size, now())
69+        uses an independent offset= value.
70+        """
71+        assert size is not None
72+        assert read_ev is not None
73 
74         lp = log.msg(format="imm Node(%(si)s).read(%(offset)d, %(size)d)",
75                      si=base32.b2a(self._verifycap.storage_index)[:8],
76hunk ./src/allmydata/immutable/downloader/node.py 142
77             sp = self._history.stats_provider
78             sp.count("downloader.files_downloaded", 1) # really read() calls
79             sp.count("downloader.bytes_downloaded", size)
80+        # for concurrent operations, each read() gets its own Segmentation
81+        # manager
82         s = Segmentation(self, offset, size, consumer, read_ev, lp)
83hunk ./src/allmydata/immutable/downloader/node.py 145
84+
85         # this raises an interesting question: what segments to fetch? if
86         # offset=0, always fetch the first segment, and then allow
87         # Segmentation to be responsible for pulling the subsequent ones if
88hunk ./src/allmydata/immutable/downloader/node.py 183
89                      si=base32.b2a(self._verifycap.storage_index)[:8],
90                      segnum=segnum,
91                      level=log.OPERATIONAL, parent=logparent, umid="UKFjDQ")
92-        self._download_status.add_segment_request(segnum, now())
93+        seg_ev = self._download_status.add_segment_request(segnum, now())
94         d = defer.Deferred()
95         c = Cancel(self._cancel_request)
96hunk ./src/allmydata/immutable/downloader/node.py 186
97-        self._segment_requests.append( (segnum, d, c, lp) )
98+        self._segment_requests.append( (segnum, d, c, seg_ev, lp) )
99         self._start_new_segment()
100         return (d, c)
101 
102hunk ./src/allmydata/immutable/downloader/node.py 210
103 
104     def _start_new_segment(self):
105         if self._active_segment is None and self._segment_requests:
106-            segnum = self._segment_requests[0][0]
107+            (segnum, d, c, seg_ev, lp) = self._segment_requests[0]
108             k = self._verifycap.needed_shares
109hunk ./src/allmydata/immutable/downloader/node.py 212
110-            lp = self._segment_requests[0][3]
111             log.msg(format="%(node)s._start_new_segment: segnum=%(segnum)d",
112                     node=repr(self), segnum=segnum,
113                     level=log.NOISY, parent=lp, umid="wAlnHQ")
114hunk ./src/allmydata/immutable/downloader/node.py 216
115             self._active_segment = fetcher = SegmentFetcher(self, segnum, k, lp)
116+            seg_ev.activate(now())
117             active_shares = [s for s in self._shares if s.is_alive()]
118             fetcher.add_shares(active_shares) # this triggers the loop
119 
120hunk ./src/allmydata/immutable/downloader/node.py 380
121     def fetch_failed(self, sf, f):
122         assert sf is self._active_segment
123         # deliver error upwards
124-        for (d,c) in self._extract_requests(sf.segnum):
125+        for (d,c,seg_ev) in self._extract_requests(sf.segnum):
126+            seg_ev.error(now())
127             eventually(self._deliver, d, c, f)
128         self._active_segment = None
129         self._start_new_segment()
130hunk ./src/allmydata/immutable/downloader/node.py 390
131         d = defer.maybeDeferred(self._decode_blocks, segnum, blocks)
132         d.addCallback(self._check_ciphertext_hash, segnum)
133         def _deliver(result):
134-            ds = self._download_status
135-            if isinstance(result, Failure):
136-                ds.add_segment_error(segnum, now())
137-            else:
138-                (offset, segment, decodetime) = result
139-                ds.add_segment_delivery(segnum, now(),
140-                                        offset, len(segment), decodetime)
141             log.msg(format="delivering segment(%(segnum)d)",
142                     segnum=segnum,
143                     level=log.OPERATIONAL, parent=self._lp,
144hunk ./src/allmydata/immutable/downloader/node.py 394
145                     umid="j60Ojg")
146-            for (d,c) in self._extract_requests(segnum):
147-                eventually(self._deliver, d, c, result)
148+            when = now()
149+            if isinstance(result, Failure):
150+                # this catches failures in decode or ciphertext hash
151+                for (d,c,seg_ev) in self._extract_requests(segnum):
152+                    seg_ev.error(when)
153+                    eventually(self._deliver, d, c, result)
154+            else:
155+                (offset, segment, decodetime) = result
156+                for (d,c,seg_ev) in self._extract_requests(segnum):
157+                    # when we have two requests for the same segment, the
158+                    # second one will not be "activated" before the data is
159+                    # delivered, so to allow the status-reporting code to see
160+                    # consistent behavior, we activate them all now. The
161+                    # SegmentEvent will ignore duplicate activate() calls.
162+                    # Note that this will result in an infinite "receive
163+                    # speed" for the second request.
164+                    seg_ev.activate(when)
165+                    seg_ev.deliver(when, offset, len(segment), decodetime)
166+                    eventually(self._deliver, d, c, result)
167             self._active_segment = None
168             self._start_new_segment()
169         d.addBoth(_deliver)
170hunk ./src/allmydata/immutable/downloader/node.py 416
171-        d.addErrback(lambda f:
172-                     log.err("unhandled error during process_blocks",
173-                             failure=f, level=log.WEIRD,
174-                             parent=self._lp, umid="MkEsCg"))
175+        d.addErrback(log.err, "unhandled error during process_blocks",
176+                     level=log.WEIRD, parent=self._lp, umid="MkEsCg")
177 
178     def _decode_blocks(self, segnum, blocks):
179         tail = (segnum == self.num_segments-1)
180hunk ./src/allmydata/immutable/downloader/node.py 485
181     def _extract_requests(self, segnum):
182         """Remove matching requests and return their (d,c) tuples so that the
183         caller can retire them."""
184-        retire = [(d,c) for (segnum0, d, c, lp) in self._segment_requests
185+        retire = [(d,c,seg_ev)
186+                  for (segnum0,d,c,seg_ev,lp) in self._segment_requests
187                   if segnum0 == segnum]
188         self._segment_requests = [t for t in self._segment_requests
189                                   if t[0] != segnum]
190hunk ./src/allmydata/immutable/downloader/node.py 495
191     def _cancel_request(self, c):
192         self._segment_requests = [t for t in self._segment_requests
193                                   if t[2] != c]
194-        segnums = [segnum for (segnum,d,c,lp) in self._segment_requests]
195+        segnums = [segnum for (segnum,d,c,seg_ev,lp) in self._segment_requests]
196         # self._active_segment might be None in rare circumstances, so make
197         # sure we tolerate it
198         if self._active_segment and self._active_segment.segnum not in segnums:
199hunk ./src/allmydata/immutable/downloader/segmentation.py 126
200         # the consumer might call our .pauseProducing() inside that write()
201         # call, setting self._hungry=False
202         self._read_ev.update(len(desired_data), 0, 0)
203+        # note: filenode.DecryptingConsumer is responsible for calling
204+        # _read_ev.update with how much decrypt_time was consumed
205         self._maybe_fetch_next()
206 
207     def _retry_bad_segment(self, f):
208hunk ./src/allmydata/immutable/downloader/share.py 730
209                          share=repr(self),
210                          start=start, length=length,
211                          level=log.NOISY, parent=self._lp, umid="sgVAyA")
212-            req_ev = ds.add_request_sent(self._peerid, self._shnum,
213-                                         start, length, now())
214+            block_ev = ds.add_block_request(self._peerid, self._shnum,
215+                                            start, length, now())
216             d = self._send_request(start, length)
217hunk ./src/allmydata/immutable/downloader/share.py 733
218-            d.addCallback(self._got_data, start, length, req_ev, lp)
219-            d.addErrback(self._got_error, start, length, req_ev, lp)
220+            d.addCallback(self._got_data, start, length, block_ev, lp)
221+            d.addErrback(self._got_error, start, length, block_ev, lp)
222             d.addCallback(self._trigger_loop)
223             d.addErrback(lambda f:
224                          log.err(format="unhandled error during send_request",
225hunk ./src/allmydata/immutable/downloader/share.py 744
226     def _send_request(self, start, length):
227         return self._rref.callRemote("read", start, length)
228 
229-    def _got_data(self, data, start, length, req_ev, lp):
230-        req_ev.finished(len(data), now())
231+    def _got_data(self, data, start, length, block_ev, lp):
232+        block_ev.finished(len(data), now())
233         if not self._alive:
234             return
235         log.msg(format="%(share)s._got_data [%(start)d:+%(length)d] -> %(datalen)d",
236hunk ./src/allmydata/immutable/downloader/share.py 787
237         # the wanted/needed span is only "wanted" for the first pass. Once
238         # the offset table arrives, it's all "needed".
239 
240-    def _got_error(self, f, start, length, req_ev, lp):
241-        req_ev.finished("error", now())
242+    def _got_error(self, f, start, length, block_ev, lp):
243+        block_ev.error(now())
244         log.msg(format="error requesting %(start)d+%(length)d"
245                 " from %(server)s for si %(si)s",
246                 start=start, length=length,
247hunk ./src/allmydata/immutable/downloader/status.py 6
248 from zope.interface import implements
249 from allmydata.interfaces import IDownloadStatus
250 
251-class RequestEvent:
252-    def __init__(self, download_status, tag):
253-        self._download_status = download_status
254-        self._tag = tag
255-    def finished(self, received, when):
256-        self._download_status.add_request_finished(self._tag, received, when)
257+class ReadEvent:
258+    def __init__(self, ev, ds):
259+        self._ev = ev
260+        self._ds = ds
261+    def update(self, bytes, decrypttime, pausetime):
262+        self._ev["bytes_returned"] += bytes
263+        self._ev["decrypt_time"] += decrypttime
264+        self._ev["paused_time"] += pausetime
265+    def finished(self, finishtime):
266+        self._ev["finish_time"] = finishtime
267+        self._ds.update_last_timestamp(finishtime)
268+
269+class SegmentEvent:
270+    def __init__(self, ev, ds):
271+        self._ev = ev
272+        self._ds = ds
273+    def activate(self, when):
274+        if self._ev["active_time"] is None:
275+            self._ev["active_time"] = when
276+    def deliver(self, when, start, length, decodetime):
277+        assert self._ev["active_time"] is not None
278+        self._ev["finish_time"] = when
279+        self._ev["success"] = True
280+        self._ev["decode_time"] = decodetime
281+        self._ev["segment_start"] = start
282+        self._ev["segment_length"] = length
283+        self._ds.update_last_timestamp(when)
284+    def error(self, when):
285+        self._ev["finish_time"] = when
286+        self._ev["success"] = False
287+        self._ds.update_last_timestamp(when)
288 
289 class DYHBEvent:
290hunk ./src/allmydata/immutable/downloader/status.py 39
291-    def __init__(self, download_status, tag):
292-        self._download_status = download_status
293-        self._tag = tag
294+    def __init__(self, ev, ds):
295+        self._ev = ev
296+        self._ds = ds
297+    def error(self, when):
298+        self._ev["finish_time"] = when
299+        self._ev["success"] = False
300+        self._ds.update_last_timestamp(when)
301     def finished(self, shnums, when):
302hunk ./src/allmydata/immutable/downloader/status.py 47
303-        self._download_status.add_dyhb_finished(self._tag, shnums, when)
304+        self._ev["finish_time"] = when
305+        self._ev["success"] = True
306+        self._ev["response_shnums"] = shnums
307+        self._ds.update_last_timestamp(when)
308+
309+class BlockRequestEvent:
310+    def __init__(self, ev, ds):
311+        self._ev = ev
312+        self._ds = ds
313+    def finished(self, received, when):
314+        self._ev["finish_time"] = when
315+        self._ev["success"] = True
316+        self._ev["response_length"] = received
317+        self._ds.update_last_timestamp(when)
318+    def error(self, when):
319+        self._ev["finish_time"] = when
320+        self._ev["success"] = False
321+        self._ds.update_last_timestamp(when)
322 
323hunk ./src/allmydata/immutable/downloader/status.py 66
324-class ReadEvent:
325-    def __init__(self, download_status, tag):
326-        self._download_status = download_status
327-        self._tag = tag
328-    def update(self, bytes, decrypttime, pausetime):
329-        self._download_status.update_read_event(self._tag, bytes,
330-                                                decrypttime, pausetime)
331-    def finished(self, finishtime):
332-        self._download_status.finish_read_event(self._tag, finishtime)
333 
334 class DownloadStatus:
335     # There is one DownloadStatus for each CiphertextFileNode. The status
336hunk ./src/allmydata/immutable/downloader/status.py 78
337         self.size = size
338         self.counter = self.statusid_counter.next()
339         self.helper = False
340-        self.started = None
341-        # self.dyhb_requests tracks "do you have a share" requests and
342-        # responses. It maps serverid to a tuple of:
343-        #  send time
344-        #  tuple of response shnums (None if response hasn't arrived, "error")
345-        #  response time (None if response hasn't arrived yet)
346-        self.dyhb_requests = {}
347 
348hunk ./src/allmydata/immutable/downloader/status.py 79
349-        # self.requests tracks share-data requests and responses. It maps
350-        # serverid to a tuple of:
351-        #  shnum,
352-        #  start,length,  (of data requested)
353-        #  send time
354-        #  response length (None if reponse hasn't arrived yet, or "error")
355-        #  response time (None if response hasn't arrived)
356-        self.requests = {}
357+        self.first_timestamp = None
358+        self.last_timestamp = None
359 
360hunk ./src/allmydata/immutable/downloader/status.py 82
361-        # self.segment_events tracks segment requests and delivery. It is a
362-        # list of:
363-        #  type ("request", "delivery", "error")
364-        #  segment number
365-        #  event time
366-        #  segment start (file offset of first byte, None except in "delivery")
367-        #  segment length (only in "delivery")
368-        #  time spent in decode (only in "delivery")
369-        self.segment_events = []
370+        # all four of these _events lists are sorted by start_time, because
371+        # they are strictly append-only (some elements are later mutated in
372+        # place, but none are removed or inserted in the middle).
373 
374hunk ./src/allmydata/immutable/downloader/status.py 86
375-        # self.read_events tracks read() requests. It is a list of:
376+        # self.read_events tracks read() requests. It is a list of dicts,
377+        # each with the following keys:
378         #  start,length  (of data requested)
379hunk ./src/allmydata/immutable/downloader/status.py 89
380-        #  request time
381-        #  finish time (None until finished)
382-        #  bytes returned (starts at 0, grows as segments are delivered)
383-        #  time spent in decrypt (None for ciphertext-only reads)
384-        #  time spent paused
385+        #  start_time
386+        #  finish_time (None until finished)
387+        #  bytes_returned (starts at 0, grows as segments are delivered)
388+        #  decrypt_time (time spent in decrypt, None for ciphertext-only reads)
389+        #  paused_time (time spent paused by client via pauseProducing)
390         self.read_events = []
391 
392hunk ./src/allmydata/immutable/downloader/status.py 96
393-        self.known_shares = [] # (serverid, shnum)
394-        self.problems = []
395+        # self.segment_events tracks segment requests and their resolution.
396+        # It is a list of dicts:
397+        #  segment_number
398+        #  start_time
399+        #  active_time (None until work has begun)
400+        #  decode_time (time spent in decode, None until delievered)
401+        #  finish_time (None until resolved)
402+        #  success (None until resolved, then boolean)
403+        #  segment_start (file offset of first byte, None until delivered)
404+        #  segment_length (None until delivered)
405+        self.segment_events = []
406 
407hunk ./src/allmydata/immutable/downloader/status.py 108
408+        # self.dyhb_requests tracks "do you have a share" requests and
409+        # responses. It is a list of dicts:
410+        #  serverid (binary)
411+        #  start_time
412+        #  success (None until resolved, then boolean)
413+        #  response_shnums (tuple, None until successful)
414+        #  finish_time (None until resolved)
415+        self.dyhb_requests = []
416 
417hunk ./src/allmydata/immutable/downloader/status.py 117
418-    def add_dyhb_sent(self, serverid, when):
419-        r = (when, None, None)
420-        if serverid not in self.dyhb_requests:
421-            self.dyhb_requests[serverid] = []
422-        self.dyhb_requests[serverid].append(r)
423-        tag = (serverid, len(self.dyhb_requests[serverid])-1)
424-        return DYHBEvent(self, tag)
425+        # self.block_requests tracks share-data requests and responses. It is
426+        # a list of dicts:
427+        #  serverid (binary),
428+        #  shnum,
429+        #  start,length,  (of data requested)
430+        #  start_time
431+        #  finish_time (None until resolved)
432+        #  success (None until resolved, then bool)
433+        #  response_length (None until success)
434+        self.block_requests = []
435 
436hunk ./src/allmydata/immutable/downloader/status.py 128
437-    def add_dyhb_finished(self, tag, shnums, when):
438-        # received="error" on error, else tuple(shnums)
439-        (serverid, index) = tag
440-        r = self.dyhb_requests[serverid][index]
441-        (sent, _, _) = r
442-        r = (sent, shnums, when)
443-        self.dyhb_requests[serverid][index] = r
444+        self.known_shares = [] # (serverid, shnum)
445+        self.problems = []
446 
447hunk ./src/allmydata/immutable/downloader/status.py 131
448-    def add_request_sent(self, serverid, shnum, start, length, when):
449-        r = (shnum, start, length, when, None, None)
450-        if serverid not in self.requests:
451-            self.requests[serverid] = []
452-        self.requests[serverid].append(r)
453-        tag = (serverid, len(self.requests[serverid])-1)
454-        return RequestEvent(self, tag)
455 
456hunk ./src/allmydata/immutable/downloader/status.py 132
457-    def add_request_finished(self, tag, received, when):
458-        # received="error" on error, else len(data)
459-        (serverid, index) = tag
460-        r = self.requests[serverid][index]
461-        (shnum, start, length, sent, _, _) = r
462-        r = (shnum, start, length, sent, received, when)
463-        self.requests[serverid][index] = r
464+    def add_read_event(self, start, length, when):
465+        if self.first_timestamp is None:
466+            self.first_timestamp = when
467+        r = { "start": start,
468+              "length": length,
469+              "start_time": when,
470+              "finish_time": None,
471+              "bytes_returned": 0,
472+              "decrypt_time": 0,
473+              "paused_time": 0,
474+              }
475+        self.read_events.append(r)
476+        return ReadEvent(r, self)
477 
478     def add_segment_request(self, segnum, when):
479hunk ./src/allmydata/immutable/downloader/status.py 147
480-        if self.started is None:
481-            self.started = when
482-        r = ("request", segnum, when, None, None, None)
483-        self.segment_events.append(r)
484-    def add_segment_delivery(self, segnum, when, start, length, decodetime):
485-        r = ("delivery", segnum, when, start, length, decodetime)
486-        self.segment_events.append(r)
487-    def add_segment_error(self, segnum, when):
488-        r = ("error", segnum, when, None, None, None)
489+        if self.first_timestamp is None:
490+            self.first_timestamp = when
491+        r = { "segment_number": segnum,
492+              "start_time": when,
493+              "active_time": None,
494+              "finish_time": None,
495+              "success": None,
496+              "decode_time": None,
497+              "segment_start": None,
498+              "segment_length": None,
499+              }
500         self.segment_events.append(r)
501hunk ./src/allmydata/immutable/downloader/status.py 159
502+        return SegmentEvent(r, self)
503 
504hunk ./src/allmydata/immutable/downloader/status.py 161
505-    def add_read_event(self, start, length, when):
506-        if self.started is None:
507-            self.started = when
508-        r = (start, length, when, None, 0, 0, 0)
509-        self.read_events.append(r)
510-        tag = len(self.read_events)-1
511-        return ReadEvent(self, tag)
512-    def update_read_event(self, tag, bytes_d, decrypt_d, paused_d):
513-        r = self.read_events[tag]
514-        (start, length, requesttime, finishtime, bytes, decrypt, paused) = r
515-        bytes += bytes_d
516-        decrypt += decrypt_d
517-        paused += paused_d
518-        r = (start, length, requesttime, finishtime, bytes, decrypt, paused)
519-        self.read_events[tag] = r
520-    def finish_read_event(self, tag, finishtime):
521-        r = self.read_events[tag]
522-        (start, length, requesttime, _, bytes, decrypt, paused) = r
523-        r = (start, length, requesttime, finishtime, bytes, decrypt, paused)
524-        self.read_events[tag] = r
525+    def add_dyhb_request(self, serverid, when):
526+        r = { "serverid": serverid,
527+              "start_time": when,
528+              "success": None,
529+              "response_shnums": None,
530+              "finish_time": None,
531+              }
532+        self.dyhb_requests.append(r)
533+        return DYHBEvent(r, self)
534+
535+    def add_block_request(self, serverid, shnum, start, length, when):
536+        r = { "serverid": serverid,
537+              "shnum": shnum,
538+              "start": start,
539+              "length": length,
540+              "start_time": when,
541+              "finish_time": None,
542+              "success": None,
543+              "response_length": None,
544+              }
545+        self.block_requests.append(r)
546+        return BlockRequestEvent(r, self)
547+
548+    def update_last_timestamp(self, when):
549+        if self.last_timestamp is None or when > self.last_timestamp:
550+            self.last_timestamp = when
551 
552     def add_known_share(self, serverid, shnum):
553         self.known_shares.append( (serverid, shnum) )
554hunk ./src/allmydata/immutable/downloader/status.py 205
555         # mention all outstanding segment requests
556         outstanding = set()
557         errorful = set()
558-        for s_ev in self.segment_events:
559-            (etype, segnum, when, segstart, seglen, decodetime) = s_ev
560-            if etype == "request":
561-                outstanding.add(segnum)
562-            elif etype == "delivery":
563-                outstanding.remove(segnum)
564-            else: # "error"
565-                outstanding.remove(segnum)
566-                errorful.add(segnum)
567+        outstanding = set([s_ev["segment_number"]
568+                           for s_ev in self.segment_events
569+                           if s_ev["finish_time"] is None])
570+        errorful = set([s_ev["segment_number"]
571+                        for s_ev in self.segment_events
572+                        if s_ev["success"] is False])
573         def join(segnums):
574             if len(segnums) == 1:
575                 return "segment %s" % list(segnums)[0]
576hunk ./src/allmydata/immutable/downloader/status.py 233
577             return 0.0
578         total_outstanding, total_received = 0, 0
579         for r_ev in self.read_events:
580-            (start, length, ign1, finishtime, bytes, ign2, ign3) = r_ev
581-            if finishtime is None:
582-                total_outstanding += length
583-                total_received += bytes
584+            if r_ev["finish_time"] is None:
585+                total_outstanding += r_ev["length"]
586+                total_received += r_ev["bytes_returned"]
587             # else ignore completed requests
588         if not total_outstanding:
589             return 1.0
590hunk ./src/allmydata/immutable/downloader/status.py 254
591         return False
592 
593     def get_started(self):
594-        return self.started
595+        return self.first_timestamp
596     def get_results(self):
597         return None # TODO
598hunk ./src/allmydata/immutable/filenode.py 58
599         return a Deferred that fires (with the consumer) when the read is
600         finished."""
601         self._maybe_create_download_node()
602-        actual_size = size
603-        if actual_size is None:
604-            actual_size = self._verifycap.size - offset
605-        read_ev = self._download_status.add_read_event(offset, actual_size,
606-                                                       now())
607+        if size is None:
608+            size = self._verifycap.size
609+        # clip size so offset+size does not go past EOF
610+        size = min(size, self._verifycap.size-offset)
611+        read_ev = self._download_status.add_read_event(offset, size, now())
612         if IDownloadStatusHandlingConsumer.providedBy(consumer):
613             consumer.set_download_status_read_event(read_ev)
614         return self._node.read(consumer, offset, size, read_ev)
615hunk ./src/allmydata/immutable/filenode.py 180
616 
617     def __init__(self, consumer, readkey, offset):
618         self._consumer = consumer
619-        self._read_event = None
620+        self._read_ev = None
621         # TODO: pycryptopp CTR-mode needs random-access operations: I want
622         # either a=AES(readkey, offset) or better yet both of:
623         #  a=AES(readkey, offset=0)
624hunk ./src/allmydata/immutable/filenode.py 193
625         self._decryptor.process("\x00"*offset_small)
626 
627     def set_download_status_read_event(self, read_ev):
628-        self._read_event = read_ev
629+        self._read_ev = read_ev
630 
631     def registerProducer(self, producer, streaming):
632         # this passes through, so the real consumer can flow-control the real
633hunk ./src/allmydata/immutable/filenode.py 206
634     def write(self, ciphertext):
635         started = now()
636         plaintext = self._decryptor.process(ciphertext)
637-        if self._read_event:
638+        if self._read_ev:
639             elapsed = now() - started
640hunk ./src/allmydata/immutable/filenode.py 208
641-            self._read_event.update(0, elapsed, 0)
642+            self._read_ev.update(0, elapsed, 0)
643         self._consumer.write(plaintext)
644 
645 class ImmutableFileNode:
646hunk ./src/allmydata/test/test_download.py 1217
647         now = 12345.1
648         ds = DownloadStatus("si-1", 123)
649         self.failUnlessEqual(ds.get_status(), "idle")
650-        ds.add_segment_request(0, now)
651+        ev0 = ds.add_segment_request(0, now)
652         self.failUnlessEqual(ds.get_status(), "fetching segment 0")
653hunk ./src/allmydata/test/test_download.py 1219
654-        ds.add_segment_delivery(0, now+1, 0, 1000, 2.0)
655+        ev0.activate(now+0.5)
656+        ev0.deliver(now+1, 0, 1000, 2.0)
657         self.failUnlessEqual(ds.get_status(), "idle")
658hunk ./src/allmydata/test/test_download.py 1222
659-        ds.add_segment_request(2, now+2)
660-        ds.add_segment_request(1, now+2)
661+        ev2 = ds.add_segment_request(2, now+2)
662+        ev1 = ds.add_segment_request(1, now+2)
663         self.failUnlessEqual(ds.get_status(), "fetching segments 1,2")
664hunk ./src/allmydata/test/test_download.py 1225
665-        ds.add_segment_error(1, now+3)
666+        ev1.error(now+3)
667         self.failUnlessEqual(ds.get_status(),
668                              "fetching segment 2; errors on segment 1")
669hunk ./src/allmydata/test/test_download.py 1228
670+        del ev2 # hush pyflakes
671 
672     def test_progress(self):
673         now = 12345.1
674hunk ./src/allmydata/test/test_web.py 22
675 from allmydata.unknown import UnknownNode
676 from allmydata.web import status, common
677 from allmydata.scripts.debug import CorruptShareOptions, corrupt_share
678-from allmydata.util import fileutil, base32
679+from allmydata.util import fileutil, base32, hashutil
680 from allmydata.util.consumer import download_to_data
681 from allmydata.util.netstring import split_netstring
682 from allmydata.util.encodingutil import to_str
683hunk ./src/allmydata/test/test_web.py 81
684     ds = DownloadStatus("storage_index", 1234)
685     now = time.time()
686 
687-    ds.add_segment_request(0, now)
688-    # segnum, when, start,len, decodetime
689-    ds.add_segment_delivery(0, now+1, 0, 100, 0.5)
690-    ds.add_segment_request(1, now+2)
691-    ds.add_segment_error(1, now+3)
692+    serverid_a = hashutil.tagged_hash("foo", "serverid_a")[:20]
693+    serverid_b = hashutil.tagged_hash("foo", "serverid_b")[:20]
694+    storage_index = hashutil.storage_index_hash("SI")
695+    e0 = ds.add_segment_request(0, now)
696+    e0.activate(now+0.5)
697+    e0.deliver(now+1, 0, 100, 0.5) # when, start,len, decodetime
698+    e1 = ds.add_segment_request(1, now+2)
699+    e1.error(now+3)
700     # two outstanding requests
701hunk ./src/allmydata/test/test_web.py 90
702-    ds.add_segment_request(2, now+4)
703-    ds.add_segment_request(3, now+5)
704+    e2 = ds.add_segment_request(2, now+4)
705+    e3 = ds.add_segment_request(3, now+5)
706+    del e2,e3 # hush pyflakes
707 
708hunk ./src/allmydata/test/test_web.py 94
709-    # simulate a segment which gets delivered faster than a system clock tick (ticket #1166)
710-    ds.add_segment_request(4, now)
711-    ds.add_segment_delivery(4, now, 0, 140, 0.5)
712+    # simulate a segment which gets delivered faster than a system clock tick
713+    # (ticket #1166)
714+    e = ds.add_segment_request(4, now)
715+    e.activate(now)
716+    e.deliver(now, 0, 140, 0.5)
717 
718hunk ./src/allmydata/test/test_web.py 100
719-    e = ds.add_dyhb_sent("serverid_a", now)
720+    e = ds.add_dyhb_request(serverid_a, now)
721     e.finished([1,2], now+1)
722hunk ./src/allmydata/test/test_web.py 102
723-    e = ds.add_dyhb_sent("serverid_b", now+2) # left unfinished
724+    e = ds.add_dyhb_request(serverid_b, now+2) # left unfinished
725 
726     e = ds.add_read_event(0, 120, now)
727     e.update(60, 0.5, 0.1) # bytes, decrypttime, pausetime
728hunk ./src/allmydata/test/test_web.py 109
729     e.finished(now+1)
730     e = ds.add_read_event(120, 30, now+2) # left unfinished
731 
732-    e = ds.add_request_sent("serverid_a", 1, 100, 20, now)
733+    e = ds.add_block_request(serverid_a, 1, 100, 20, now)
734     e.finished(20, now+1)
735hunk ./src/allmydata/test/test_web.py 111
736-    e = ds.add_request_sent("serverid_a", 1, 120, 30, now+1) # left unfinished
737+    e = ds.add_block_request(serverid_a, 1, 120, 30, now+1) # left unfinished
738 
739     # make sure that add_read_event() can come first too
740hunk ./src/allmydata/test/test_web.py 114
741-    ds1 = DownloadStatus("storage_index", 1234)
742+    ds1 = DownloadStatus(storage_index, 1234)
743     e = ds1.add_read_event(0, 120, now)
744     e.update(60, 0.5, 0.1) # bytes, decrypttime, pausetime
745     e.finished(now+1)
746hunk ./src/allmydata/test/test_web.py 563
747         def _check_dl(res):
748             self.failUnless("File Download Status" in res, res)
749         d.addCallback(_check_dl)
750-        d.addCallback(lambda res: self.GET("/status/down-%d?t=json" % dl_num))
751+        d.addCallback(lambda res: self.GET("/status/down-%d/event_json" % dl_num))
752         def _check_dl_json(res):
753             data = simplejson.loads(res)
754             self.failUnless(isinstance(data, dict))
755hunk ./src/allmydata/test/test_web.py 567
756+            # this data comes from build_one_ds() above
757+            self.failUnlessEqual(set(data["serverids"].values()),
758+                                 set(["phwr", "cmpu"]))
759+            self.failUnlessEqual(len(data["segment"]), 5)
760+            self.failUnlessEqual(len(data["read"]), 2)
761         d.addCallback(_check_dl_json)
762         d.addCallback(lambda res: self.GET("/status/up-%d" % ul_num))
763         def _check_ul(res):
764addfile ./src/allmydata/web/download-status-timeline.xhtml
765hunk ./src/allmydata/web/download-status-timeline.xhtml 1
766+<html xmlns:n="http://nevow.com/ns/nevow/0.1">
767+  <head>
768+    <title>AllMyData - Tahoe - File Download Status Timeline</title>
769+    <link href="/tahoe_css" rel="stylesheet" type="text/css"/>
770+    <link href="/webform_css" rel="stylesheet" type="text/css"/>
771+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
772+    <script type="text/javascript" src="/jquery.js"></script>
773+    <script type="text/javascript" src="/protovis-r3.2.js"></script>
774+    <script type="text/javascript" src="/download_status_timeline.js"></script>
775+  </head>
776+  <body>
777+
778+<h1>File Download Status</h1>
779+
780+<ul>
781+  <li>Started: <span n:render="started"/></li>
782+  <li>Storage Index: <span n:render="si"/></li>
783+  <li>Helper?: <span n:render="helper"/></li>
784+  <li>Total Size: <span n:render="total_size"/></li>
785+  <li>Progress: <span n:render="progress"/></li>
786+  <li>Status: <span n:render="status"/></li>
787+</ul>
788+
789+
790+<div style="">
791+  <div id="overview" style="float:right;width:166px;height:100px; border: 1px solid #ddd">overview</div>
792+  <div id="timeline" style="width:600px;border: 1px solid #aaa">Timeline</div>
793+</div>
794+
795+<div>Return to the <a href="/">Welcome Page</a></div>
796+
797+  </body>
798+</html>
799hunk ./src/allmydata/web/download-status.xhtml 19
800   <li>Total Size: <span n:render="total_size"/></li>
801   <li>Progress: <span n:render="progress"/></li>
802   <li>Status: <span n:render="status"/></li>
803+  <li><span n:render="timeline_link"/></li>
804 </ul>
805 
806 <div n:render="events"></div>
807addfile ./src/allmydata/web/download_status_timeline.js
808hunk ./src/allmydata/web/download_status_timeline.js 1
809+
810+$(function() {
811+
812+      function onDataReceived(data) {
813+          var bounds = { min: data.bounds.min,
814+                         max: data.bounds.max
815+                       };
816+          //bounds.max = data.dyhb[data.dyhb.length-1].finish_time;
817+          var duration = bounds.max - bounds.min;
818+          var WIDTH = 600;
819+          var vis = new pv.Panel().canvas("timeline").margin(30);
820+
821+          var dyhb_top = 0;
822+          var read_top = dyhb_top + 30*data.dyhb[data.dyhb.length-1].row+60;
823+          var segment_top = read_top + 30*data.read[data.read.length-1].row+60;
824+          var block_top = segment_top + 30*data.segment[data.segment.length-1].row+60;
825+          var block_row_to_y = {};
826+          var row_y=0;
827+          for (var group=0; group < data.block_rownums.length; group++) {
828+              for (var row=0; row < data.block_rownums[group]; row++) {
829+                  block_row_to_y[group+"-"+row] = row_y;
830+                  row_y += 10;
831+              }
832+              row_y += 5;
833+          }
834+
835+          var height = block_top + row_y;
836+          var kx = bounds.min;
837+          var ky = 1;
838+          var x = pv.Scale.linear(bounds.min, bounds.max).range(0, WIDTH-40);
839+          var relx = pv.Scale.linear(0, duration).range(0, WIDTH-40);
840+          //var y = pv.Scale.linear(-ky,ky).range(0, height);
841+          //x.nice(); relx.nice();
842+
843+          /* add the invisible panel now, at the bottom of the stack, so that
844+          it won't steal mouseover events and prevent tooltips from
845+          working. */
846+          vis.add(pv.Panel)
847+              .events("all")
848+              .event("mousedown", pv.Behavior.pan())
849+              .event("mousewheel", pv.Behavior.zoom())
850+              .event("pan", transform)
851+              .event("zoom", transform)
852+          ;
853+
854+          vis.anchor("top").top(-20).add(pv.Label).text("DYHB Requests");
855+
856+          vis.add(pv.Bar)
857+              .data(data.dyhb)
858+              .height(20)
859+              .top(function (d) {return 30*d.row;})
860+              .left(function(d){return x(d.start_time);})
861+              .width(function(d){return x(d.finish_time)-x(d.start_time);})
862+              .title(function(d){return "shnums: "+d.response_shnums;})
863+              .fillStyle(function(d){return data.server_info[d.serverid].color;})
864+              .strokeStyle("black").lineWidth(1);
865+
866+          vis.add(pv.Rule)
867+              .data(data.dyhb)
868+              .top(function(d){return 30*d.row + 20/2;})
869+              .left(0).width(0)
870+              .strokeStyle("#888")
871+              .anchor("left").add(pv.Label)
872+              .text(function(d){return d.serverid.slice(0,4);});
873+
874+          /* we use a function for data=relx.ticks() here instead of
875+           simply .data(relx.ticks()) so that it will be recalculated when
876+           the scales change (by pan/zoom) */
877+          var xaxis = vis.add(pv.Rule)
878+              .data(function() {return relx.ticks();})
879+              .strokeStyle("#ccc")
880+              .left(relx)
881+              .anchor("bottom").add(pv.Label)
882+              .text(function(d){return relx.tickFormat(d)+"s";});
883+
884+          var read = vis.add(pv.Panel).top(read_top);
885+          read.anchor("top").top(-20).add(pv.Label).text("read() requests");
886+
887+          read.add(pv.Bar)
888+              .data(data.read)
889+              .height(20)
890+              .top(function (d) {return 30*d.row;})
891+              .left(function(d){return x(d.start_time);})
892+              .width(function(d){return x(d.finish_time)-x(d.start_time);})
893+              .title(function(d){return "read(start="+d.start+", len="+d.length+") -> "+d.bytes_returned+" bytes";})
894+              .fillStyle("red")
895+              .strokeStyle("black").lineWidth(1);
896+
897+          var segment = vis.add(pv.Panel).top(segment_top);
898+          segment.anchor("top").top(-20).add(pv.Label).text("segment() requests");
899+
900+          segment.add(pv.Bar)
901+              .data(data.segment)
902+              .height(20)
903+              .top(function (d) {return 30*d.row;})
904+              .left(function(d){return x(d.start_time);})
905+              .width(function(d){return x(d.finish_time)-x(d.start_time);})
906+              .title(function(d){return "seg"+d.segment_number+" ["+d.segment_start+":+"+d.segment_length+"] (took "+(d.finish_time-d.start_time)+")";})
907+              .fillStyle(function(d){if (d.success) return "#c0ffc0";
908+                                    else return "#ffc0c0";})
909+              .strokeStyle("black").lineWidth(1);
910+
911+          var block = vis.add(pv.Panel).top(block_top);
912+          block.anchor("top").top(-20).add(pv.Label).text("block() requests");
913+
914+          var shnum_colors = pv.Colors.category10();
915+          block.add(pv.Bar)
916+              .data(data.block)
917+              .height(10)
918+              .top(function (d) {return block_row_to_y[d.row[0]+"-"+d.row[1]];})
919+              .left(function(d){return x(d.start_time);})
920+              .width(function(d){return x(d.finish_time)-x(d.start_time);})
921+              .title(function(d){return "sh"+d.shnum+"-on-"+d.serverid.slice(0,4)+" ["+d.start+":+"+d.length+"] -> "+d.response_length;})
922+              .fillStyle(function(d){return data.server_info[d.serverid].color;})
923+              .strokeStyle(function(d){return shnum_colors(d.shnum).color;})
924+              .lineWidth(function(d)
925+                         {if (d.response_length > 100) return 3;
926+                         else return 1;
927+                          })
928+          ;
929+
930+
931+          vis.height(height);
932+
933+          function transform() {
934+              var t0= this.transform();
935+              var t = this.transform().invert();
936+              // when t.x=0 and t.k=1.0, left should be bounds.min
937+              x.domain(bounds.min + (t.x/WIDTH)*duration,
938+                       bounds.min + t.k*duration + (t.x/WIDTH)*duration);
939+              relx.domain(0 + t.x/WIDTH*duration,
940+                          t.k*duration + (t.x/WIDTH)*duration);
941+              vis.render();
942+          }
943+
944+          vis.render();
945+      }
946+
947+      $.ajax({url: "event_json",
948+              method: 'GET',
949+              dataType: 'json',
950+              success: onDataReceived });
951+});
952+
953addfile ./src/allmydata/web/jquery.js
954hunk ./src/allmydata/web/jquery.js 1
955+/*!
956+ * jQuery JavaScript Library v1.3.2
957+ * http://jquery.com/
958+ *
959+ * Copyright (c) 2009 John Resig
960+ * Dual licensed under the MIT and GPL licenses.
961+ * http://docs.jquery.com/License
962+ *
963+ * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
964+ * Revision: 6246
965+ */
966+(function(){
967+
968+var
969+       // Will speed up references to window, and allows munging its name.
970+       window = this,
971+       // Will speed up references to undefined, and allows munging its name.
972+       undefined,
973+       // Map over jQuery in case of overwrite
974+       _jQuery = window.jQuery,
975+       // Map over the $ in case of overwrite
976+       _$ = window.$,
977+
978+       jQuery = window.jQuery = window.$ = function( selector, context ) {
979+               // The jQuery object is actually just the init constructor 'enhanced'
980+               return new jQuery.fn.init( selector, context );
981+       },
982+
983+       // A simple way to check for HTML strings or ID strings
984+       // (both of which we optimize for)
985+       quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,
986+       // Is it a simple selector
987+       isSimple = /^.[^:#\[\.,]*$/;
988+
989+jQuery.fn = jQuery.prototype = {
990+       init: function( selector, context ) {
991+               // Make sure that a selection was provided
992+               selector = selector || document;
993+
994+               // Handle $(DOMElement)
995+               if ( selector.nodeType ) {
996+                       this[0] = selector;
997+                       this.length = 1;
998+                       this.context = selector;
999+                       return this;
1000+               }
1001+               // Handle HTML strings
1002+               if ( typeof selector === "string" ) {
1003+                       // Are we dealing with HTML string or an ID?
1004+                       var match = quickExpr.exec( selector );
1005+
1006+                       // Verify a match, and that no context was specified for #id
1007+                       if ( match && (match[1] || !context) ) {
1008+
1009+                               // HANDLE: $(html) -> $(array)
1010+                               if ( match[1] )
1011+                                       selector = jQuery.clean( [ match[1] ], context );
1012+
1013+                               // HANDLE: $("#id")
1014+                               else {
1015+                                       var elem = document.getElementById( match[3] );
1016+
1017+                                       // Handle the case where IE and Opera return items
1018+                                       // by name instead of ID
1019+                                       if ( elem && elem.id != match[3] )
1020+                                               return jQuery().find( selector );
1021+
1022+                                       // Otherwise, we inject the element directly into the jQuery object
1023+                                       var ret = jQuery( elem || [] );
1024+                                       ret.context = document;
1025+                                       ret.selector = selector;
1026+                                       return ret;
1027+                               }
1028+
1029+                       // HANDLE: $(expr, [context])
1030+                       // (which is just equivalent to: $(content).find(expr)
1031+                       } else
1032+                               return jQuery( context ).find( selector );
1033+
1034+               // HANDLE: $(function)
1035+               // Shortcut for document ready
1036+               } else if ( jQuery.isFunction( selector ) )
1037+                       return jQuery( document ).ready( selector );
1038+
1039+               // Make sure that old selector state is passed along
1040+               if ( selector.selector && selector.context ) {
1041+                       this.selector = selector.selector;
1042+                       this.context = selector.context;
1043+               }
1044+
1045+               return this.setArray(jQuery.isArray( selector ) ?
1046+                       selector :
1047+                       jQuery.makeArray(selector));
1048+       },
1049+
1050+       // Start with an empty selector
1051+       selector: "",
1052+
1053+       // The current version of jQuery being used
1054+       jquery: "1.3.2",
1055+
1056+       // The number of elements contained in the matched element set
1057+       size: function() {
1058+               return this.length;
1059+       },
1060+
1061+       // Get the Nth element in the matched element set OR
1062+       // Get the whole matched element set as a clean array
1063+       get: function( num ) {
1064+               return num === undefined ?
1065+
1066+                       // Return a 'clean' array
1067+                       Array.prototype.slice.call( this ) :
1068+
1069+                       // Return just the object
1070+                       this[ num ];
1071+       },
1072+
1073+       // Take an array of elements and push it onto the stack
1074+       // (returning the new matched element set)
1075+       pushStack: function( elems, name, selector ) {
1076+               // Build a new jQuery matched element set
1077+               var ret = jQuery( elems );
1078+
1079+               // Add the old object onto the stack (as a reference)
1080+               ret.prevObject = this;
1081+
1082+               ret.context = this.context;
1083+
1084+               if ( name === "find" )
1085+                       ret.selector = this.selector + (this.selector ? " " : "") + selector;
1086+               else if ( name )
1087+                       ret.selector = this.selector + "." + name + "(" + selector + ")";
1088+
1089+               // Return the newly-formed element set
1090+               return ret;
1091+       },
1092+
1093+       // Force the current matched set of elements to become
1094+       // the specified array of elements (destroying the stack in the process)
1095+       // You should use pushStack() in order to do this, but maintain the stack
1096+       setArray: function( elems ) {
1097+               // Resetting the length to 0, then using the native Array push
1098+               // is a super-fast way to populate an object with array-like properties
1099+               this.length = 0;
1100+               Array.prototype.push.apply( this, elems );
1101+
1102+               return this;
1103+       },
1104+
1105+       // Execute a callback for every element in the matched set.
1106+       // (You can seed the arguments with an array of args, but this is
1107+       // only used internally.)
1108+       each: function( callback, args ) {
1109+               return jQuery.each( this, callback, args );
1110+       },
1111+
1112+       // Determine the position of an element within
1113+       // the matched set of elements
1114+       index: function( elem ) {
1115+               // Locate the position of the desired element
1116+               return jQuery.inArray(
1117+                       // If it receives a jQuery object, the first element is used
1118+                       elem && elem.jquery ? elem[0] : elem
1119+               , this );
1120+       },
1121+
1122+       attr: function( name, value, type ) {
1123+               var options = name;
1124+
1125+               // Look for the case where we're accessing a style value
1126+               if ( typeof name === "string" )
1127+                       if ( value === undefined )
1128+                               return this[0] && jQuery[ type || "attr" ]( this[0], name );
1129+
1130+                       else {
1131+                               options = {};
1132+                               options[ name ] = value;
1133+                       }
1134+
1135+               // Check to see if we're setting style values
1136+               return this.each(function(i){
1137+                       // Set all the styles
1138+                       for ( name in options )
1139+                               jQuery.attr(
1140+                                       type ?
1141+                                               this.style :
1142+                                               this,
1143+                                       name, jQuery.prop( this, options[ name ], type, i, name )
1144+                               );
1145+               });
1146+       },
1147+
1148+       css: function( key, value ) {
1149+               // ignore negative width and height values
1150+               if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 )
1151+                       value = undefined;
1152+               return this.attr( key, value, "curCSS" );
1153+       },
1154+
1155+       text: function( text ) {
1156+               if ( typeof text !== "object" && text != null )
1157+                       return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
1158+
1159+               var ret = "";
1160+
1161+               jQuery.each( text || this, function(){
1162+                       jQuery.each( this.childNodes, function(){
1163+                               if ( this.nodeType != 8 )
1164+                                       ret += this.nodeType != 1 ?
1165+                                               this.nodeValue :
1166+                                               jQuery.fn.text( [ this ] );
1167+                       });
1168+               });
1169+
1170+               return ret;
1171+       },
1172+
1173+       wrapAll: function( html ) {
1174+               if ( this[0] ) {
1175+                       // The elements to wrap the target around
1176+                       var wrap = jQuery( html, this[0].ownerDocument ).clone();
1177+
1178+                       if ( this[0].parentNode )
1179+                               wrap.insertBefore( this[0] );
1180+
1181+                       wrap.map(function(){
1182+                               var elem = this;
1183+
1184+                               while ( elem.firstChild )
1185+                                       elem = elem.firstChild;
1186+
1187+                               return elem;
1188+                       }).append(this);
1189+               }
1190+
1191+               return this;
1192+       },
1193+
1194+       wrapInner: function( html ) {
1195+               return this.each(function(){
1196+                       jQuery( this ).contents().wrapAll( html );
1197+               });
1198+       },
1199+
1200+       wrap: function( html ) {
1201+               return this.each(function(){
1202+                       jQuery( this ).wrapAll( html );
1203+               });
1204+       },
1205+
1206+       append: function() {
1207+               return this.domManip(arguments, true, function(elem){
1208+                       if (this.nodeType == 1)
1209+                               this.appendChild( elem );
1210+               });
1211+       },
1212+
1213+       prepend: function() {
1214+               return this.domManip(arguments, true, function(elem){
1215+                       if (this.nodeType == 1)
1216+                               this.insertBefore( elem, this.firstChild );
1217+               });
1218+       },
1219+
1220+       before: function() {
1221+               return this.domManip(arguments, false, function(elem){
1222+                       this.parentNode.insertBefore( elem, this );
1223+               });
1224+       },
1225+
1226+       after: function() {
1227+               return this.domManip(arguments, false, function(elem){
1228+                       this.parentNode.insertBefore( elem, this.nextSibling );
1229+               });
1230+       },
1231+
1232+       end: function() {
1233+               return this.prevObject || jQuery( [] );
1234+       },
1235+
1236+       // For internal use only.
1237+       // Behaves like an Array's method, not like a jQuery method.
1238+       push: [].push,
1239+       sort: [].sort,
1240+       splice: [].splice,
1241+
1242+       find: function( selector ) {
1243+               if ( this.length === 1 ) {
1244+                       var ret = this.pushStack( [], "find", selector );
1245+                       ret.length = 0;
1246+                       jQuery.find( selector, this[0], ret );
1247+                       return ret;
1248+               } else {
1249+                       return this.pushStack( jQuery.unique(jQuery.map(this, function(elem){
1250+                               return jQuery.find( selector, elem );
1251+                       })), "find", selector );
1252+               }
1253+       },
1254+
1255+       clone: function( events ) {
1256+               // Do the clone
1257+               var ret = this.map(function(){
1258+                       if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) {
1259+                               // IE copies events bound via attachEvent when
1260+                               // using cloneNode. Calling detachEvent on the
1261+                               // clone will also remove the events from the orignal
1262+                               // In order to get around this, we use innerHTML.
1263+                               // Unfortunately, this means some modifications to
1264+                               // attributes in IE that are actually only stored
1265+                               // as properties will not be copied (such as the
1266+                               // the name attribute on an input).
1267+                               var html = this.outerHTML;
1268+                               if ( !html ) {
1269+                                       var div = this.ownerDocument.createElement("div");
1270+                                       div.appendChild( this.cloneNode(true) );
1271+                                       html = div.innerHTML;
1272+                               }
1273+
1274+                               return jQuery.clean([html.replace(/ jQuery\d+="(?:\d+|null)"/g, "").replace(/^\s*/, "")])[0];
1275+                       } else
1276+                               return this.cloneNode(true);
1277+               });
1278+
1279+               // Copy the events from the original to the clone
1280+               if ( events === true ) {
1281+                       var orig = this.find("*").andSelf(), i = 0;
1282+
1283+                       ret.find("*").andSelf().each(function(){
1284+                               if ( this.nodeName !== orig[i].nodeName )
1285+                                       return;
1286+
1287+                               var events = jQuery.data( orig[i], "events" );
1288+
1289+                               for ( var type in events ) {
1290+                                       for ( var handler in events[ type ] ) {
1291+                                               jQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data );
1292+                                       }
1293+                               }
1294+
1295+                               i++;
1296+                       });
1297+               }
1298+
1299+               // Return the cloned set
1300+               return ret;
1301+       },
1302+
1303+       filter: function( selector ) {
1304+               return this.pushStack(
1305+                       jQuery.isFunction( selector ) &&
1306+                       jQuery.grep(this, function(elem, i){
1307+                               return selector.call( elem, i );
1308+                       }) ||
1309+
1310+                       jQuery.multiFilter( selector, jQuery.grep(this, function(elem){
1311+                               return elem.nodeType === 1;
1312+                       }) ), "filter", selector );
1313+       },
1314+
1315+       closest: function( selector ) {
1316+               var pos = jQuery.expr.match.POS.test( selector ) ? jQuery(selector) : null,
1317+                       closer = 0;
1318+
1319+               return this.map(function(){
1320+                       var cur = this;
1321+                       while ( cur && cur.ownerDocument ) {
1322+                               if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selector) ) {
1323+                                       jQuery.data(cur, "closest", closer);
1324+                                       return cur;
1325+                               }
1326+                               cur = cur.parentNode;
1327+                               closer++;
1328+                       }
1329+               });
1330+       },
1331+
1332+       not: function( selector ) {
1333+               if ( typeof selector === "string" )
1334+                       // test special case where just one selector is passed in
1335+                       if ( isSimple.test( selector ) )
1336+                               return this.pushStack( jQuery.multiFilter( selector, this, true ), "not", selector );
1337+                       else
1338+                               selector = jQuery.multiFilter( selector, this );
1339+
1340+               var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType;
1341+               return this.filter(function() {
1342+                       return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector;
1343+               });
1344+       },
1345+
1346+       add: function( selector ) {
1347+               return this.pushStack( jQuery.unique( jQuery.merge(
1348+                       this.get(),
1349+                       typeof selector === "string" ?
1350+                               jQuery( selector ) :
1351+                               jQuery.makeArray( selector )
1352+               )));
1353+       },
1354+
1355+       is: function( selector ) {
1356+               return !!selector && jQuery.multiFilter( selector, this ).length > 0;
1357+       },
1358+
1359+       hasClass: function( selector ) {
1360+               return !!selector && this.is( "." + selector );
1361+       },
1362+
1363+       val: function( value ) {
1364+               if ( value === undefined ) {                   
1365+                       var elem = this[0];
1366+
1367+                       if ( elem ) {
1368+                               if( jQuery.nodeName( elem, 'option' ) )
1369+                                       return (elem.attributes.value || {}).specified ? elem.value : elem.text;
1370+                               
1371+                               // We need to handle select boxes special
1372+                               if ( jQuery.nodeName( elem, "select" ) ) {
1373+                                       var index = elem.selectedIndex,
1374+                                               values = [],
1375+                                               options = elem.options,
1376+                                               one = elem.type == "select-one";
1377+
1378+                                       // Nothing was selected
1379+                                       if ( index < 0 )
1380+                                               return null;
1381+
1382+                                       // Loop through all the selected options
1383+                                       for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
1384+                                               var option = options[ i ];
1385+
1386+                                               if ( option.selected ) {
1387+                                                       // Get the specifc value for the option
1388+                                                       value = jQuery(option).val();
1389+
1390+                                                       // We don't need an array for one selects
1391+                                                       if ( one )
1392+                                                               return value;
1393+
1394+                                                       // Multi-Selects return an array
1395+                                                       values.push( value );
1396+                                               }
1397+                                       }
1398+
1399+                                       return values;                         
1400+                               }
1401+
1402+                               // Everything else, we just grab the value
1403+                               return (elem.value || "").replace(/\r/g, "");
1404+
1405+                       }
1406+
1407+                       return undefined;
1408+               }
1409+
1410+               if ( typeof value === "number" )
1411+                       value += '';
1412+
1413+               return this.each(function(){
1414+                       if ( this.nodeType != 1 )
1415+                               return;
1416+
1417+                       if ( jQuery.isArray(value) && /radio|checkbox/.test( this.type ) )
1418+                               this.checked = (jQuery.inArray(this.value, value) >= 0 ||
1419+                                       jQuery.inArray(this.name, value) >= 0);
1420+
1421+                       else if ( jQuery.nodeName( this, "select" ) ) {
1422+                               var values = jQuery.makeArray(value);
1423+
1424+                               jQuery( "option", this ).each(function(){
1425+                                       this.selected = (jQuery.inArray( this.value, values ) >= 0 ||
1426+                                               jQuery.inArray( this.text, values ) >= 0);
1427+                               });
1428+
1429+                               if ( !values.length )
1430+                                       this.selectedIndex = -1;
1431+
1432+                       } else
1433+                               this.value = value;
1434+               });
1435+       },
1436+
1437+       html: function( value ) {
1438+               return value === undefined ?
1439+                       (this[0] ?
1440+                               this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g, "") :
1441+                               null) :
1442+                       this.empty().append( value );
1443+       },
1444+
1445+       replaceWith: function( value ) {
1446+               return this.after( value ).remove();
1447+       },
1448+
1449+       eq: function( i ) {
1450+               return this.slice( i, +i + 1 );
1451+       },
1452+
1453+       slice: function() {
1454+               return this.pushStack( Array.prototype.slice.apply( this, arguments ),
1455+                       "slice", Array.prototype.slice.call(arguments).join(",") );
1456+       },
1457+
1458+       map: function( callback ) {
1459+               return this.pushStack( jQuery.map(this, function(elem, i){
1460+                       return callback.call( elem, i, elem );
1461+               }));
1462+       },
1463+
1464+       andSelf: function() {
1465+               return this.add( this.prevObject );
1466+       },
1467+
1468+       domManip: function( args, table, callback ) {
1469+               if ( this[0] ) {
1470+                       var fragment = (this[0].ownerDocument || this[0]).createDocumentFragment(),
1471+                               scripts = jQuery.clean( args, (this[0].ownerDocument || this[0]), fragment ),
1472+                               first = fragment.firstChild;
1473+
1474+                       if ( first )
1475+                               for ( var i = 0, l = this.length; i < l; i++ )
1476+                                       callback.call( root(this[i], first), this.length > 1 || i > 0 ?
1477+                                                       fragment.cloneNode(true) : fragment );
1478+               
1479+                       if ( scripts )
1480+                               jQuery.each( scripts, evalScript );
1481+               }
1482+
1483+               return this;
1484+               
1485+               function root( elem, cur ) {
1486+                       return table && jQuery.nodeName(elem, "table") && jQuery.nodeName(cur, "tr") ?
1487+                               (elem.getElementsByTagName("tbody")[0] ||
1488+                               elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
1489+                               elem;
1490+               }
1491+       }
1492+};
1493+
1494+// Give the init function the jQuery prototype for later instantiation
1495+jQuery.fn.init.prototype = jQuery.fn;
1496+
1497+function evalScript( i, elem ) {
1498+       if ( elem.src )
1499+               jQuery.ajax({
1500+                       url: elem.src,
1501+                       async: false,
1502+                       dataType: "script"
1503+               });
1504+
1505+       else
1506+               jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
1507+
1508+       if ( elem.parentNode )
1509+               elem.parentNode.removeChild( elem );
1510+}
1511+
1512+function now(){
1513+       return +new Date;
1514+}
1515+
1516+jQuery.extend = jQuery.fn.extend = function() {
1517+       // copy reference to target object
1518+       var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;
1519+
1520+       // Handle a deep copy situation
1521+       if ( typeof target === "boolean" ) {
1522+               deep = target;
1523+               target = arguments[1] || {};
1524+               // skip the boolean and the target
1525+               i = 2;
1526+       }
1527+
1528+       // Handle case when target is a string or something (possible in deep copy)
1529+       if ( typeof target !== "object" && !jQuery.isFunction(target) )
1530+               target = {};
1531+
1532+       // extend jQuery itself if only one argument is passed
1533+       if ( length == i ) {
1534+               target = this;
1535+               --i;
1536+       }
1537+
1538+       for ( ; i < length; i++ )
1539+               // Only deal with non-null/undefined values
1540+               if ( (options = arguments[ i ]) != null )
1541+                       // Extend the base object
1542+                       for ( var name in options ) {
1543+                               var src = target[ name ], copy = options[ name ];
1544+
1545+                               // Prevent never-ending loop
1546+                               if ( target === copy )
1547+                                       continue;
1548+
1549+                               // Recurse if we're merging object values
1550+                               if ( deep && copy && typeof copy === "object" && !copy.nodeType )
1551+                                       target[ name ] = jQuery.extend( deep,
1552+                                               // Never move original objects, clone them
1553+                                               src || ( copy.length != null ? [ ] : { } )
1554+                                       , copy );
1555+
1556+                               // Don't bring in undefined values
1557+                               else if ( copy !== undefined )
1558+                                       target[ name ] = copy;
1559+
1560+                       }
1561+
1562+       // Return the modified object
1563+       return target;
1564+};
1565+
1566+// exclude the following css properties to add px
1567+var    exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,
1568+       // cache defaultView
1569+       defaultView = document.defaultView || {},
1570+       toString = Object.prototype.toString;
1571+
1572+jQuery.extend({
1573+       noConflict: function( deep ) {
1574+               window.$ = _$;
1575+
1576+               if ( deep )
1577+                       window.jQuery = _jQuery;
1578+
1579+               return jQuery;
1580+       },
1581+
1582+       // See test/unit/core.js for details concerning isFunction.
1583+       // Since version 1.3, DOM methods and functions like alert
1584+       // aren't supported. They return false on IE (#2968).
1585+       isFunction: function( obj ) {
1586+               return toString.call(obj) === "[object Function]";
1587+       },
1588+
1589+       isArray: function( obj ) {
1590+               return toString.call(obj) === "[object Array]";
1591+       },
1592+
1593+       // check if an element is in a (or is an) XML document
1594+       isXMLDoc: function( elem ) {
1595+               return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
1596+                       !!elem.ownerDocument && jQuery.isXMLDoc( elem.ownerDocument );
1597+       },
1598+
1599+       // Evalulates a script in a global context
1600+       globalEval: function( data ) {
1601+               if ( data && /\S/.test(data) ) {
1602+                       // Inspired by code by Andrea Giammarchi
1603+                       // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
1604+                       var head = document.getElementsByTagName("head")[0] || document.documentElement,
1605+                               script = document.createElement("script");
1606+
1607+                       script.type = "text/javascript";
1608+                       if ( jQuery.support.scriptEval )
1609+                               script.appendChild( document.createTextNode( data ) );
1610+                       else
1611+                               script.text = data;
1612+
1613+                       // Use insertBefore instead of appendChild  to circumvent an IE6 bug.
1614+                       // This arises when a base node is used (#2709).
1615+                       head.insertBefore( script, head.firstChild );
1616+                       head.removeChild( script );
1617+               }
1618+       },
1619+
1620+       nodeName: function( elem, name ) {
1621+               return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase();
1622+       },
1623+
1624+       // args is for internal usage only
1625+       each: function( object, callback, args ) {
1626+               var name, i = 0, length = object.length;
1627+
1628+               if ( args ) {
1629+                       if ( length === undefined ) {
1630+                               for ( name in object )
1631+                                       if ( callback.apply( object[ name ], args ) === false )
1632+                                               break;
1633+                       } else
1634+                               for ( ; i < length; )
1635+                                       if ( callback.apply( object[ i++ ], args ) === false )
1636+                                               break;
1637+
1638+               // A special, fast, case for the most common use of each
1639+               } else {
1640+                       if ( length === undefined ) {
1641+                               for ( name in object )
1642+                                       if ( callback.call( object[ name ], name, object[ name ] ) === false )
1643+                                               break;
1644+                       } else
1645+                               for ( var value = object[0];
1646+                                       i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
1647+               }
1648+
1649+               return object;
1650+       },
1651+
1652+       prop: function( elem, value, type, i, name ) {
1653+               // Handle executable functions
1654+               if ( jQuery.isFunction( value ) )
1655+                       value = value.call( elem, i );
1656+
1657+               // Handle passing in a number to a CSS property
1658+               return typeof value === "number" && type == "curCSS" && !exclude.test( name ) ?
1659+                       value + "px" :
1660+                       value;
1661+       },
1662+
1663+       className: {
1664+               // internal only, use addClass("class")
1665+               add: function( elem, classNames ) {
1666+                       jQuery.each((classNames || "").split(/\s+/), function(i, className){
1667+                               if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) )
1668+                                       elem.className += (elem.className ? " " : "") + className;
1669+                       });
1670+               },
1671+
1672+               // internal only, use removeClass("class")
1673+               remove: function( elem, classNames ) {
1674+                       if (elem.nodeType == 1)
1675+                               elem.className = classNames !== undefined ?
1676+                                       jQuery.grep(elem.className.split(/\s+/), function(className){
1677+                                               return !jQuery.className.has( classNames, className );
1678+                                       }).join(" ") :
1679+                                       "";
1680+               },
1681+
1682+               // internal only, use hasClass("class")
1683+               has: function( elem, className ) {
1684+                       return elem && jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1;
1685+               }
1686+       },
1687+
1688+       // A method for quickly swapping in/out CSS properties to get correct calculations
1689+       swap: function( elem, options, callback ) {
1690+               var old = {};
1691+               // Remember the old values, and insert the new ones
1692+               for ( var name in options ) {
1693+                       old[ name ] = elem.style[ name ];
1694+                       elem.style[ name ] = options[ name ];
1695+               }
1696+
1697+               callback.call( elem );
1698+
1699+               // Revert the old values
1700+               for ( var name in options )
1701+                       elem.style[ name ] = old[ name ];
1702+       },
1703+
1704+       css: function( elem, name, force, extra ) {
1705+               if ( name == "width" || name == "height" ) {
1706+                       var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ];
1707+
1708+                       function getWH() {
1709+                               val = name == "width" ? elem.offsetWidth : elem.offsetHeight;
1710+
1711+                               if ( extra === "border" )
1712+                                       return;
1713+
1714+                               jQuery.each( which, function() {
1715+                                       if ( !extra )
1716+                                               val -= parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
1717+                                       if ( extra === "margin" )
1718+                                               val += parseFloat(jQuery.curCSS( elem, "margin" + this, true)) || 0;
1719+                                       else
1720+                                               val -= parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
1721+                               });
1722+                       }
1723+
1724+                       if ( elem.offsetWidth !== 0 )
1725+                               getWH();
1726+                       else
1727+                               jQuery.swap( elem, props, getWH );
1728+
1729+                       return Math.max(0, Math.round(val));
1730+               }
1731+
1732+               return jQuery.curCSS( elem, name, force );
1733+       },
1734+
1735+       curCSS: function( elem, name, force ) {
1736+               var ret, style = elem.style;
1737+
1738+               // We need to handle opacity special in IE
1739+               if ( name == "opacity" && !jQuery.support.opacity ) {
1740+                       ret = jQuery.attr( style, "opacity" );
1741+
1742+                       return ret == "" ?
1743+                               "1" :
1744+                               ret;
1745+               }
1746+
1747+               // Make sure we're using the right name for getting the float value
1748+               if ( name.match( /float/i ) )
1749+                       name = styleFloat;
1750+
1751+               if ( !force && style && style[ name ] )
1752+                       ret = style[ name ];
1753+
1754+               else if ( defaultView.getComputedStyle ) {
1755+
1756+                       // Only "float" is needed here
1757+                       if ( name.match( /float/i ) )
1758+                               name = "float";
1759+
1760+                       name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase();
1761+
1762+                       var computedStyle = defaultView.getComputedStyle( elem, null );
1763+
1764+                       if ( computedStyle )
1765+                               ret = computedStyle.getPropertyValue( name );
1766+
1767+                       // We should always get a number back from opacity
1768+                       if ( name == "opacity" && ret == "" )
1769+                               ret = "1";
1770+
1771+               } else if ( elem.currentStyle ) {
1772+                       var camelCase = name.replace(/\-(\w)/g, function(all, letter){
1773+                               return letter.toUpperCase();
1774+                       });
1775+
1776+                       ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];
1777+
1778+                       // From the awesome hack by Dean Edwards
1779+                       // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
1780+
1781+                       // If we're not dealing with a regular pixel number
1782+                       // but a number that has a weird ending, we need to convert it to pixels
1783+                       if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
1784+                               // Remember the original values
1785+                               var left = style.left, rsLeft = elem.runtimeStyle.left;
1786+
1787+                               // Put in the new values to get a computed value out
1788+                               elem.runtimeStyle.left = elem.currentStyle.left;
1789+                               style.left = ret || 0;
1790+                               ret = style.pixelLeft + "px";
1791+
1792+                               // Revert the changed values
1793+                               style.left = left;
1794+                               elem.runtimeStyle.left = rsLeft;
1795+                       }
1796+               }
1797+
1798+               return ret;
1799+       },
1800+
1801+       clean: function( elems, context, fragment ) {
1802+               context = context || document;
1803+
1804+               // !context.createElement fails in IE with an error but returns typeof 'object'
1805+               if ( typeof context.createElement === "undefined" )
1806+                       context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
1807+
1808+               // If a single string is passed in and it's a single tag
1809+               // just do a createElement and skip the rest
1810+               if ( !fragment && elems.length === 1 && typeof elems[0] === "string" ) {
1811+                       var match = /^<(\w+)\s*\/?>$/.exec(elems[0]);
1812+                       if ( match )
1813+                               return [ context.createElement( match[1] ) ];
1814+               }
1815+
1816+               var ret = [], scripts = [], div = context.createElement("div");
1817+
1818+               jQuery.each(elems, function(i, elem){
1819+                       if ( typeof elem === "number" )
1820+                               elem += '';
1821+
1822+                       if ( !elem )
1823+                               return;
1824+
1825+                       // Convert html string into DOM nodes
1826+                       if ( typeof elem === "string" ) {
1827+                               // Fix "XHTML"-style tags in all browsers
1828+                               elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){
1829+                                       return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ?
1830+                                               all :
1831+                                               front + "></" + tag + ">";
1832+                               });
1833+
1834+                               // Trim whitespace, otherwise indexOf won't work as expected
1835+                               var tags = elem.replace(/^\s+/, "").substring(0, 10).toLowerCase();
1836+
1837+                               var wrap =
1838+                                       // option or optgroup
1839+                                       !tags.indexOf("<opt") &&
1840+                                       [ 1, "<select multiple='multiple'>", "</select>" ] ||
1841+
1842+                                       !tags.indexOf("<leg") &&
1843+                                       [ 1, "<fieldset>", "</fieldset>" ] ||
1844+
1845+                                       tags.match(/^<(thead|tbody|tfoot|colg|cap)/) &&
1846+                                       [ 1, "<table>", "</table>" ] ||
1847+
1848+                                       !tags.indexOf("<tr") &&
1849+                                       [ 2, "<table><tbody>", "</tbody></table>" ] ||
1850+
1851+                                       // <thead> matched above
1852+                                       (!tags.indexOf("<td") || !tags.indexOf("<th")) &&
1853+                                       [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ] ||
1854+
1855+                                       !tags.indexOf("<col") &&
1856+                                       [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ] ||
1857+
1858+                                       // IE can't serialize <link> and <script> tags normally
1859+                                       !jQuery.support.htmlSerialize &&
1860+                                       [ 1, "div<div>", "</div>" ] ||
1861+
1862+                                       [ 0, "", "" ];
1863+
1864+                               // Go to html and back, then peel off extra wrappers
1865+                               div.innerHTML = wrap[1] + elem + wrap[2];
1866+
1867+                               // Move to the right depth
1868+                               while ( wrap[0]-- )
1869+                                       div = div.lastChild;
1870+
1871+                               // Remove IE's autoinserted <tbody> from table fragments
1872+                               if ( !jQuery.support.tbody ) {
1873+
1874+                                       // String was a <table>, *may* have spurious <tbody>
1875+                                       var hasBody = /<tbody/i.test(elem),
1876+                                               tbody = !tags.indexOf("<table") && !hasBody ?
1877+                                                       div.firstChild && div.firstChild.childNodes :
1878+
1879+                                               // String was a bare <thead> or <tfoot>
1880+                                               wrap[1] == "<table>" && !hasBody ?
1881+                                                       div.childNodes :
1882+                                                       [];
1883+
1884+                                       for ( var j = tbody.length - 1; j >= 0 ; --j )
1885+                                               if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length )
1886+                                                       tbody[ j ].parentNode.removeChild( tbody[ j ] );
1887+
1888+                                       }
1889+
1890+                               // IE completely kills leading whitespace when innerHTML is used
1891+                               if ( !jQuery.support.leadingWhitespace && /^\s/.test( elem ) )
1892+                                       div.insertBefore( context.createTextNode( elem.match(/^\s*/)[0] ), div.firstChild );
1893+                               
1894+                               elem = jQuery.makeArray( div.childNodes );
1895+                       }
1896+
1897+                       if ( elem.nodeType )
1898+                               ret.push( elem );
1899+                       else
1900+                               ret = jQuery.merge( ret, elem );
1901+
1902+               });
1903+
1904+               if ( fragment ) {
1905+                       for ( var i = 0; ret[i]; i++ ) {
1906+                               if ( jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
1907+                                       scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
1908+                               } else {
1909+                                       if ( ret[i].nodeType === 1 )
1910+                                               ret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script"))) );
1911+                                       fragment.appendChild( ret[i] );
1912+                               }
1913+                       }
1914+                       
1915+                       return scripts;
1916+               }
1917+
1918+               return ret;
1919+       },
1920+
1921+       attr: function( elem, name, value ) {
1922+               // don't set attributes on text and comment nodes
1923+               if (!elem || elem.nodeType == 3 || elem.nodeType == 8)
1924+                       return undefined;
1925+
1926+               var notxml = !jQuery.isXMLDoc( elem ),
1927+                       // Whether we are setting (or getting)
1928+                       set = value !== undefined;
1929+
1930+               // Try to normalize/fix the name
1931+               name = notxml && jQuery.props[ name ] || name;
1932+
1933+               // Only do all the following if this is a node (faster for style)
1934+               // IE elem.getAttribute passes even for style
1935+               if ( elem.tagName ) {
1936+
1937+                       // These attributes require special treatment
1938+                       var special = /href|src|style/.test( name );
1939+
1940+                       // Safari mis-reports the default selected property of a hidden option
1941+                       // Accessing the parent's selectedIndex property fixes it
1942+                       if ( name == "selected" && elem.parentNode )
1943+                               elem.parentNode.selectedIndex;
1944+
1945+                       // If applicable, access the attribute via the DOM 0 way
1946+                       if ( name in elem && notxml && !special ) {
1947+                               if ( set ){
1948+                                       // We can't allow the type property to be changed (since it causes problems in IE)
1949+                                       if ( name == "type" && jQuery.nodeName( elem, "input" ) && elem.parentNode )
1950+                                               throw "type property can't be changed";
1951+
1952+                                       elem[ name ] = value;
1953+                               }
1954+
1955+                               // browsers index elements by id/name on forms, give priority to attributes.
1956+                               if( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) )
1957+                                       return elem.getAttributeNode( name ).nodeValue;
1958+
1959+                               // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
1960+                               // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
1961+                               if ( name == "tabIndex" ) {
1962+                                       var attributeNode = elem.getAttributeNode( "tabIndex" );
1963+                                       return attributeNode && attributeNode.specified
1964+                                               ? attributeNode.value
1965+                                               : elem.nodeName.match(/(button|input|object|select|textarea)/i)
1966+                                                       ? 0
1967+                                                       : elem.nodeName.match(/^(a|area)$/i) && elem.href
1968+                                                               ? 0
1969+                                                               : undefined;
1970+                               }
1971+
1972+                               return elem[ name ];
1973+                       }
1974+
1975+                       if ( !jQuery.support.style && notxml &&  name == "style" )
1976+                               return jQuery.attr( elem.style, "cssText", value );
1977+
1978+                       if ( set )
1979+                               // convert the value to a string (all browsers do this but IE) see #1070
1980+                               elem.setAttribute( name, "" + value );
1981+
1982+                       var attr = !jQuery.support.hrefNormalized && notxml && special
1983+                                       // Some attributes require a special call on IE
1984+                                       ? elem.getAttribute( name, 2 )
1985+                                       : elem.getAttribute( name );
1986+
1987+                       // Non-existent attributes return null, we normalize to undefined
1988+                       return attr === null ? undefined : attr;
1989+               }
1990+
1991+               // elem is actually elem.style ... set the style
1992+
1993+               // IE uses filters for opacity
1994+               if ( !jQuery.support.opacity && name == "opacity" ) {
1995+                       if ( set ) {
1996+                               // IE has trouble with opacity if it does not have layout
1997+                               // Force it by setting the zoom level
1998+                               elem.zoom = 1;
1999+
2000+                               // Set the alpha filter to set the opacity
2001+                               elem.filter = (elem.filter || "").replace( /alpha\([^)]*\)/, "" ) +
2002+                                       (parseInt( value ) + '' == "NaN" ? "" : "alpha(opacity=" + value * 100 + ")");
2003+                       }
2004+
2005+                       return elem.filter && elem.filter.indexOf("opacity=") >= 0 ?
2006+                               (parseFloat( elem.filter.match(/opacity=([^)]*)/)[1] ) / 100) + '':
2007+                               "";
2008+               }
2009+
2010+               name = name.replace(/-([a-z])/ig, function(all, letter){
2011+                       return letter.toUpperCase();
2012+               });
2013+
2014+               if ( set )
2015+                       elem[ name ] = value;
2016+
2017+               return elem[ name ];
2018+       },
2019+
2020+       trim: function( text ) {
2021+               return (text || "").replace( /^\s+|\s+$/g, "" );
2022+       },
2023+
2024+       makeArray: function( array ) {
2025+               var ret = [];
2026+
2027+               if( array != null ){
2028+                       var i = array.length;
2029+                       // The window, strings (and functions) also have 'length'
2030+                       if( i == null || typeof array === "string" || jQuery.isFunction(array) || array.setInterval )
2031+                               ret[0] = array;
2032+                       else
2033+                               while( i )
2034+                                       ret[--i] = array[i];
2035+               }
2036+
2037+               return ret;
2038+       },
2039+
2040+       inArray: function( elem, array ) {
2041+               for ( var i = 0, length = array.length; i < length; i++ )
2042+               // Use === because on IE, window == document
2043+                       if ( array[ i ] === elem )
2044+                               return i;
2045+
2046+               return -1;
2047+       },
2048+
2049+       merge: function( first, second ) {
2050+               // We have to loop this way because IE & Opera overwrite the length
2051+               // expando of getElementsByTagName
2052+               var i = 0, elem, pos = first.length;
2053+               // Also, we need to make sure that the correct elements are being returned
2054+               // (IE returns comment nodes in a '*' query)
2055+               if ( !jQuery.support.getAll ) {
2056+                       while ( (elem = second[ i++ ]) != null )
2057+                               if ( elem.nodeType != 8 )
2058+                                       first[ pos++ ] = elem;
2059+
2060+               } else
2061+                       while ( (elem = second[ i++ ]) != null )
2062+                               first[ pos++ ] = elem;
2063+
2064+               return first;
2065+       },
2066+
2067+       unique: function( array ) {
2068+               var ret = [], done = {};
2069+
2070+               try {
2071+
2072+                       for ( var i = 0, length = array.length; i < length; i++ ) {
2073+                               var id = jQuery.data( array[ i ] );
2074+
2075+                               if ( !done[ id ] ) {
2076+                                       done[ id ] = true;
2077+                                       ret.push( array[ i ] );
2078+                               }
2079+                       }
2080+
2081+               } catch( e ) {
2082+                       ret = array;
2083+               }
2084+
2085+               return ret;
2086+       },
2087+
2088+       grep: function( elems, callback, inv ) {
2089+               var ret = [];
2090+
2091+               // Go through the array, only saving the items
2092+               // that pass the validator function
2093+               for ( var i = 0, length = elems.length; i < length; i++ )
2094+                       if ( !inv != !callback( elems[ i ], i ) )
2095+                               ret.push( elems[ i ] );
2096+
2097+               return ret;
2098+       },
2099+
2100+       map: function( elems, callback ) {
2101+               var ret = [];
2102+
2103+               // Go through the array, translating each of the items to their
2104+               // new value (or values).
2105+               for ( var i = 0, length = elems.length; i < length; i++ ) {
2106+                       var value = callback( elems[ i ], i );
2107+
2108+                       if ( value != null )
2109+                               ret[ ret.length ] = value;
2110+               }
2111+
2112+               return ret.concat.apply( [], ret );
2113+       }
2114+});
2115+
2116+// Use of jQuery.browser is deprecated.
2117+// It's included for backwards compatibility and plugins,
2118+// although they should work to migrate away.
2119+
2120+var userAgent = navigator.userAgent.toLowerCase();
2121+
2122+// Figure out what browser is being used
2123+jQuery.browser = {
2124+       version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1],
2125+       safari: /webkit/.test( userAgent ),
2126+       opera: /opera/.test( userAgent ),
2127+       msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ),
2128+       mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )
2129+};
2130+
2131+jQuery.each({
2132+       parent: function(elem){return elem.parentNode;},
2133+       parents: function(elem){return jQuery.dir(elem,"parentNode");},
2134+       next: function(elem){return jQuery.nth(elem,2,"nextSibling");},
2135+       prev: function(elem){return jQuery.nth(elem,2,"previousSibling");},
2136+       nextAll: function(elem){return jQuery.dir(elem,"nextSibling");},
2137+       prevAll: function(elem){return jQuery.dir(elem,"previousSibling");},
2138+       siblings: function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},
2139+       children: function(elem){return jQuery.sibling(elem.firstChild);},
2140+       contents: function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}
2141+}, function(name, fn){
2142+       jQuery.fn[ name ] = function( selector ) {
2143+               var ret = jQuery.map( this, fn );
2144+
2145+               if ( selector && typeof selector == "string" )
2146+                       ret = jQuery.multiFilter( selector, ret );
2147+
2148+               return this.pushStack( jQuery.unique( ret ), name, selector );
2149+       };
2150+});
2151+
2152+jQuery.each({
2153+       appendTo: "append",
2154+       prependTo: "prepend",
2155+       insertBefore: "before",
2156+       insertAfter: "after",
2157+       replaceAll: "replaceWith"
2158+}, function(name, original){
2159+       jQuery.fn[ name ] = function( selector ) {
2160+               var ret = [], insert = jQuery( selector );
2161+
2162+               for ( var i = 0, l = insert.length; i < l; i++ ) {
2163+                       var elems = (i > 0 ? this.clone(true) : this).get();
2164+                       jQuery.fn[ original ].apply( jQuery(insert[i]), elems );
2165+                       ret = ret.concat( elems );
2166+               }
2167+
2168+               return this.pushStack( ret, name, selector );
2169+       };
2170+});
2171+
2172+jQuery.each({
2173+       removeAttr: function( name ) {
2174+               jQuery.attr( this, name, "" );
2175+               if (this.nodeType == 1)
2176+                       this.removeAttribute( name );
2177+       },
2178+
2179+       addClass: function( classNames ) {
2180+               jQuery.className.add( this, classNames );
2181+       },
2182+
2183+       removeClass: function( classNames ) {
2184+               jQuery.className.remove( this, classNames );
2185+       },
2186+
2187+       toggleClass: function( classNames, state ) {
2188+               if( typeof state !== "boolean" )
2189+                       state = !jQuery.className.has( this, classNames );
2190+               jQuery.className[ state ? "add" : "remove" ]( this, classNames );
2191+       },
2192+
2193+       remove: function( selector ) {
2194+               if ( !selector || jQuery.filter( selector, [ this ] ).length ) {
2195+                       // Prevent memory leaks
2196+                       jQuery( "*", this ).add([this]).each(function(){
2197+                               jQuery.event.remove(this);
2198+                               jQuery.removeData(this);
2199+                       });
2200+                       if (this.parentNode)
2201+                               this.parentNode.removeChild( this );
2202+               }
2203+       },
2204+
2205+       empty: function() {
2206+               // Remove element nodes and prevent memory leaks
2207+               jQuery(this).children().remove();
2208+
2209+               // Remove any remaining nodes
2210+               while ( this.firstChild )
2211+                       this.removeChild( this.firstChild );
2212+       }
2213+}, function(name, fn){
2214+       jQuery.fn[ name ] = function(){
2215+               return this.each( fn, arguments );
2216+       };
2217+});
2218+
2219+// Helper function used by the dimensions and offset modules
2220+function num(elem, prop) {
2221+       return elem[0] && parseInt( jQuery.curCSS(elem[0], prop, true), 10 ) || 0;
2222+}
2223+var expando = "jQuery" + now(), uuid = 0, windowData = {};
2224+
2225+jQuery.extend({
2226+       cache: {},
2227+
2228+       data: function( elem, name, data ) {
2229+               elem = elem == window ?
2230+                       windowData :
2231+                       elem;
2232+
2233+               var id = elem[ expando ];
2234+
2235+               // Compute a unique ID for the element
2236+               if ( !id )
2237+                       id = elem[ expando ] = ++uuid;
2238+
2239+               // Only generate the data cache if we're
2240+               // trying to access or manipulate it
2241+               if ( name && !jQuery.cache[ id ] )
2242+                       jQuery.cache[ id ] = {};
2243+
2244+               // Prevent overriding the named cache with undefined values
2245+               if ( data !== undefined )
2246+                       jQuery.cache[ id ][ name ] = data;
2247+
2248+               // Return the named cache data, or the ID for the element
2249+               return name ?
2250+                       jQuery.cache[ id ][ name ] :
2251+                       id;
2252+       },
2253+
2254+       removeData: function( elem, name ) {
2255+               elem = elem == window ?
2256+                       windowData :
2257+                       elem;
2258+
2259+               var id = elem[ expando ];
2260+
2261+               // If we want to remove a specific section of the element's data
2262+               if ( name ) {
2263+                       if ( jQuery.cache[ id ] ) {
2264+                               // Remove the section of cache data
2265+                               delete jQuery.cache[ id ][ name ];
2266+
2267+                               // If we've removed all the data, remove the element's cache
2268+                               name = "";
2269+
2270+                               for ( name in jQuery.cache[ id ] )
2271+                                       break;
2272+
2273+                               if ( !name )
2274+                                       jQuery.removeData( elem );
2275+                       }
2276+
2277+               // Otherwise, we want to remove all of the element's data
2278+               } else {
2279+                       // Clean up the element expando
2280+                       try {
2281+                               delete elem[ expando ];
2282+                       } catch(e){
2283+                               // IE has trouble directly removing the expando
2284+                               // but it's ok with using removeAttribute
2285+                               if ( elem.removeAttribute )
2286+                                       elem.removeAttribute( expando );
2287+                       }
2288+
2289+                       // Completely remove the data cache
2290+                       delete jQuery.cache[ id ];
2291+               }
2292+       },
2293+       queue: function( elem, type, data ) {
2294+               if ( elem ){
2295+       
2296+                       type = (type || "fx") + "queue";
2297+       
2298+                       var q = jQuery.data( elem, type );
2299+       
2300+                       if ( !q || jQuery.isArray(data) )
2301+                               q = jQuery.data( elem, type, jQuery.makeArray(data) );
2302+                       else if( data )
2303+                               q.push( data );
2304+       
2305+               }
2306+               return q;
2307+       },
2308+
2309+       dequeue: function( elem, type ){
2310+               var queue = jQuery.queue( elem, type ),
2311+                       fn = queue.shift();
2312+               
2313+               if( !type || type === "fx" )
2314+                       fn = queue[0];
2315+                       
2316+               if( fn !== undefined )
2317+                       fn.call(elem);
2318+       }
2319+});
2320+
2321+jQuery.fn.extend({
2322+       data: function( key, value ){
2323+               var parts = key.split(".");
2324+               parts[1] = parts[1] ? "." + parts[1] : "";
2325+
2326+               if ( value === undefined ) {
2327+                       var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
2328+
2329+                       if ( data === undefined && this.length )
2330+                               data = jQuery.data( this[0], key );
2331+
2332+                       return data === undefined && parts[1] ?
2333+                               this.data( parts[0] ) :
2334+                               data;
2335+               } else
2336+                       return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){
2337+                               jQuery.data( this, key, value );
2338+                       });
2339+       },
2340+
2341+       removeData: function( key ){
2342+               return this.each(function(){
2343+                       jQuery.removeData( this, key );
2344+               });
2345+       },
2346+       queue: function(type, data){
2347+               if ( typeof type !== "string" ) {
2348+                       data = type;
2349+                       type = "fx";
2350+               }
2351+
2352+               if ( data === undefined )
2353+                       return jQuery.queue( this[0], type );
2354+
2355+               return this.each(function(){
2356+                       var queue = jQuery.queue( this, type, data );
2357+                       
2358+                        if( type == "fx" && queue.length == 1 )
2359+                               queue[0].call(this);
2360+               });
2361+       },
2362+       dequeue: function(type){
2363+               return this.each(function(){
2364+                       jQuery.dequeue( this, type );
2365+               });
2366+       }
2367+});/*!
2368+ * Sizzle CSS Selector Engine - v0.9.3
2369+ *  Copyright 2009, The Dojo Foundation
2370+ *  Released under the MIT, BSD, and GPL Licenses.
2371+ *  More information: http://sizzlejs.com/
2372+ */
2373+(function(){
2374+
2375+var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,
2376+       done = 0,
2377+       toString = Object.prototype.toString;
2378+
2379+var Sizzle = function(selector, context, results, seed) {
2380+       results = results || [];
2381+       context = context || document;
2382+
2383+       if ( context.nodeType !== 1 && context.nodeType !== 9 )
2384+               return [];
2385+       
2386+       if ( !selector || typeof selector !== "string" ) {
2387+               return results;
2388+       }
2389+
2390+       var parts = [], m, set, checkSet, check, mode, extra, prune = true;
2391+       
2392+       // Reset the position of the chunker regexp (start from head)
2393+       chunker.lastIndex = 0;
2394+       
2395+       while ( (m = chunker.exec(selector)) !== null ) {
2396+               parts.push( m[1] );
2397+               
2398+               if ( m[2] ) {
2399+                       extra = RegExp.rightContext;
2400+                       break;
2401+               }
2402+       }
2403+
2404+       if ( parts.length > 1 && origPOS.exec( selector ) ) {
2405+               if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
2406+                       set = posProcess( parts[0] + parts[1], context );
2407+               } else {
2408+                       set = Expr.relative[ parts[0] ] ?
2409+                               [ context ] :
2410+                               Sizzle( parts.shift(), context );
2411+
2412+                       while ( parts.length ) {
2413+                               selector = parts.shift();
2414+
2415+                               if ( Expr.relative[ selector ] )
2416+                                       selector += parts.shift();
2417+
2418+                               set = posProcess( selector, set );
2419+                       }
2420+               }
2421+       } else {
2422+               var ret = seed ?
2423+                       { expr: parts.pop(), set: makeArray(seed) } :
2424+                       Sizzle.find( parts.pop(), parts.length === 1 && context.parentNode ? context.parentNode : context, isXML(context) );
2425+               set = Sizzle.filter( ret.expr, ret.set );
2426+
2427+               if ( parts.length > 0 ) {
2428+                       checkSet = makeArray(set);
2429+               } else {
2430+                       prune = false;
2431+               }
2432+
2433+               while ( parts.length ) {
2434+                       var cur = parts.pop(), pop = cur;
2435+
2436+                       if ( !Expr.relative[ cur ] ) {
2437+                               cur = "";
2438+                       } else {
2439+                               pop = parts.pop();
2440+                       }
2441+
2442+                       if ( pop == null ) {
2443+                               pop = context;
2444+                       }
2445+
2446+                       Expr.relative[ cur ]( checkSet, pop, isXML(context) );
2447+               }
2448+       }
2449+
2450+       if ( !checkSet ) {
2451+               checkSet = set;
2452+       }
2453+
2454+       if ( !checkSet ) {
2455+               throw "Syntax error, unrecognized expression: " + (cur || selector);
2456+       }
2457+
2458+       if ( toString.call(checkSet) === "[object Array]" ) {
2459+               if ( !prune ) {
2460+                       results.push.apply( results, checkSet );
2461+               } else if ( context.nodeType === 1 ) {
2462+                       for ( var i = 0; checkSet[i] != null; i++ ) {
2463+                               if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
2464+                                       results.push( set[i] );
2465+                               }
2466+                       }
2467+               } else {
2468+                       for ( var i = 0; checkSet[i] != null; i++ ) {
2469+                               if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
2470+                                       results.push( set[i] );
2471+                               }
2472+                       }
2473+               }
2474+       } else {
2475+               makeArray( checkSet, results );
2476+       }
2477+
2478+       if ( extra ) {
2479+               Sizzle( extra, context, results, seed );
2480+
2481+               if ( sortOrder ) {
2482+                       hasDuplicate = false;
2483+                       results.sort(sortOrder);
2484+
2485+                       if ( hasDuplicate ) {
2486+                               for ( var i = 1; i < results.length; i++ ) {
2487+                                       if ( results[i] === results[i-1] ) {
2488+                                               results.splice(i--, 1);
2489+                                       }
2490+                               }
2491+                       }
2492+               }
2493+       }
2494+
2495+       return results;
2496+};
2497+
2498+Sizzle.matches = function(expr, set){
2499+       return Sizzle(expr, null, null, set);
2500+};
2501+
2502+Sizzle.find = function(expr, context, isXML){
2503+       var set, match;
2504+
2505+       if ( !expr ) {
2506+               return [];
2507+       }
2508+
2509+       for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
2510+               var type = Expr.order[i], match;
2511+               
2512+               if ( (match = Expr.match[ type ].exec( expr )) ) {
2513+                       var left = RegExp.leftContext;
2514+
2515+                       if ( left.substr( left.length - 1 ) !== "\\" ) {
2516+                               match[1] = (match[1] || "").replace(/\\/g, "");
2517+                               set = Expr.find[ type ]( match, context, isXML );
2518+                               if ( set != null ) {
2519+                                       expr = expr.replace( Expr.match[ type ], "" );
2520+                                       break;
2521+                               }
2522+                       }
2523+               }
2524+       }
2525+
2526+       if ( !set ) {
2527+               set = context.getElementsByTagName("*");
2528+       }
2529+
2530+       return {set: set, expr: expr};
2531+};
2532+
2533+Sizzle.filter = function(expr, set, inplace, not){
2534+       var old = expr, result = [], curLoop = set, match, anyFound,
2535+               isXMLFilter = set && set[0] && isXML(set[0]);
2536+
2537+       while ( expr && set.length ) {
2538+               for ( var type in Expr.filter ) {
2539+                       if ( (match = Expr.match[ type ].exec( expr )) != null ) {
2540+                               var filter = Expr.filter[ type ], found, item;
2541+                               anyFound = false;
2542+
2543+                               if ( curLoop == result ) {
2544+                                       result = [];
2545+                               }
2546+
2547+                               if ( Expr.preFilter[ type ] ) {
2548+                                       match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
2549+
2550+                                       if ( !match ) {
2551+                                               anyFound = found = true;
2552+                                       } else if ( match === true ) {
2553+                                               continue;
2554+                                       }
2555+                               }
2556+
2557+                               if ( match ) {
2558+                                       for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
2559+                                               if ( item ) {
2560+                                                       found = filter( item, match, i, curLoop );
2561+                                                       var pass = not ^ !!found;
2562+
2563+                                                       if ( inplace && found != null ) {
2564+                                                               if ( pass ) {
2565+                                                                       anyFound = true;
2566+                                                               } else {
2567+                                                                       curLoop[i] = false;
2568+                                                               }
2569+                                                       } else if ( pass ) {
2570+                                                               result.push( item );
2571+                                                               anyFound = true;
2572+                                                       }
2573+                                               }
2574+                                       }
2575+                               }
2576+
2577+                               if ( found !== undefined ) {
2578+                                       if ( !inplace ) {
2579+                                               curLoop = result;
2580+                                       }
2581+
2582+                                       expr = expr.replace( Expr.match[ type ], "" );
2583+
2584+                                       if ( !anyFound ) {
2585+                                               return [];
2586+                                       }
2587+
2588+                                       break;
2589+                               }
2590+                       }
2591+               }
2592+
2593+               // Improper expression
2594+               if ( expr == old ) {
2595+                       if ( anyFound == null ) {
2596+                               throw "Syntax error, unrecognized expression: " + expr;
2597+                       } else {
2598+                               break;
2599+                       }
2600+               }
2601+
2602+               old = expr;
2603+       }
2604+
2605+       return curLoop;
2606+};
2607+
2608+var Expr = Sizzle.selectors = {
2609+       order: [ "ID", "NAME", "TAG" ],
2610+       match: {
2611+               ID: /#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,
2612+               CLASS: /\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,
2613+               NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,
2614+               ATTR: /\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
2615+               TAG: /^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,
2616+               CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
2617+               POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
2618+               PSEUDO: /:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/
2619+       },
2620+       attrMap: {
2621+               "class": "className",
2622+               "for": "htmlFor"
2623+       },
2624+       attrHandle: {
2625+               href: function(elem){
2626+                       return elem.getAttribute("href");
2627+               }
2628+       },
2629+       relative: {
2630+               "+": function(checkSet, part, isXML){
2631+                       var isPartStr = typeof part === "string",
2632+                               isTag = isPartStr && !/\W/.test(part),
2633+                               isPartStrNotTag = isPartStr && !isTag;
2634+
2635+                       if ( isTag && !isXML ) {
2636+                               part = part.toUpperCase();
2637+                       }
2638+
2639+                       for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
2640+                               if ( (elem = checkSet[i]) ) {
2641+                                       while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
2642+
2643+                                       checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ?
2644+                                               elem || false :
2645+                                               elem === part;
2646+                               }
2647+                       }
2648+
2649+                       if ( isPartStrNotTag ) {
2650+                               Sizzle.filter( part, checkSet, true );
2651+                       }
2652+               },
2653+               ">": function(checkSet, part, isXML){
2654+                       var isPartStr = typeof part === "string";
2655+
2656+                       if ( isPartStr && !/\W/.test(part) ) {
2657+                               part = isXML ? part : part.toUpperCase();
2658+
2659+                               for ( var i = 0, l = checkSet.length; i < l; i++ ) {
2660+                                       var elem = checkSet[i];
2661+                                       if ( elem ) {
2662+                                               var parent = elem.parentNode;
2663+                                               checkSet[i] = parent.nodeName === part ? parent : false;
2664+                                       }
2665+                               }
2666+                       } else {
2667+                               for ( var i = 0, l = checkSet.length; i < l; i++ ) {
2668+                                       var elem = checkSet[i];
2669+                                       if ( elem ) {
2670+                                               checkSet[i] = isPartStr ?
2671+                                                       elem.parentNode :
2672+                                                       elem.parentNode === part;
2673+                                       }
2674+                               }
2675+
2676+                               if ( isPartStr ) {
2677+                                       Sizzle.filter( part, checkSet, true );
2678+                               }
2679+                       }
2680+               },
2681+               "": function(checkSet, part, isXML){
2682+                       var doneName = done++, checkFn = dirCheck;
2683+
2684+                       if ( !part.match(/\W/) ) {
2685+                               var nodeCheck = part = isXML ? part : part.toUpperCase();
2686+                               checkFn = dirNodeCheck;
2687+                       }
2688+
2689+                       checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
2690+               },
2691+               "~": function(checkSet, part, isXML){
2692+                       var doneName = done++, checkFn = dirCheck;
2693+
2694+                       if ( typeof part === "string" && !part.match(/\W/) ) {
2695+                               var nodeCheck = part = isXML ? part : part.toUpperCase();
2696+                               checkFn = dirNodeCheck;
2697+                       }
2698+
2699+                       checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
2700+               }
2701+       },
2702+       find: {
2703+               ID: function(match, context, isXML){
2704+                       if ( typeof context.getElementById !== "undefined" && !isXML ) {
2705+                               var m = context.getElementById(match[1]);
2706+                               return m ? [m] : [];
2707+                       }
2708+               },
2709+               NAME: function(match, context, isXML){
2710+                       if ( typeof context.getElementsByName !== "undefined" ) {
2711+                               var ret = [], results = context.getElementsByName(match[1]);
2712+
2713+                               for ( var i = 0, l = results.length; i < l; i++ ) {
2714+                                       if ( results[i].getAttribute("name") === match[1] ) {
2715+                                               ret.push( results[i] );
2716+                                       }
2717+                               }
2718+
2719+                               return ret.length === 0 ? null : ret;
2720+                       }
2721+               },
2722+               TAG: function(match, context){
2723+                       return context.getElementsByTagName(match[1]);
2724+               }
2725+       },
2726+       preFilter: {
2727+               CLASS: function(match, curLoop, inplace, result, not, isXML){
2728+                       match = " " + match[1].replace(/\\/g, "") + " ";
2729+
2730+                       if ( isXML ) {
2731+                               return match;
2732+                       }
2733+
2734+                       for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
2735+                               if ( elem ) {
2736+                                       if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) {
2737+                                               if ( !inplace )
2738+                                                       result.push( elem );
2739+                                       } else if ( inplace ) {
2740+                                               curLoop[i] = false;
2741+                                       }
2742+                               }
2743+                       }
2744+
2745+                       return false;
2746+               },
2747+               ID: function(match){
2748+                       return match[1].replace(/\\/g, "");
2749+               },
2750+               TAG: function(match, curLoop){
2751+                       for ( var i = 0; curLoop[i] === false; i++ ){}
2752+                       return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();
2753+               },
2754+               CHILD: function(match){
2755+                       if ( match[1] == "nth" ) {
2756+                               // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
2757+                               var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
2758+                                       match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" ||
2759+                                       !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
2760+
2761+                               // calculate the numbers (first)n+(last) including if they are negative
2762+                               match[2] = (test[1] + (test[2] || 1)) - 0;
2763+                               match[3] = test[3] - 0;
2764+                       }
2765+
2766+                       // TODO: Move to normal caching system
2767+                       match[0] = done++;
2768+
2769+                       return match;
2770+               },
2771+               ATTR: function(match, curLoop, inplace, result, not, isXML){
2772+                       var name = match[1].replace(/\\/g, "");
2773+                       
2774+                       if ( !isXML && Expr.attrMap[name] ) {
2775+                               match[1] = Expr.attrMap[name];
2776+                       }
2777+
2778+                       if ( match[2] === "~=" ) {
2779+                               match[4] = " " + match[4] + " ";
2780+                       }
2781+
2782+                       return match;
2783+               },
2784+               PSEUDO: function(match, curLoop, inplace, result, not){
2785+                       if ( match[1] === "not" ) {
2786+                               // If we're dealing with a complex expression, or a simple one
2787+                               if ( match[3].match(chunker).length > 1 || /^\w/.test(match[3]) ) {
2788+                                       match[3] = Sizzle(match[3], null, null, curLoop);
2789+                               } else {
2790+                                       var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
2791+                                       if ( !inplace ) {
2792+                                               result.push.apply( result, ret );
2793+                                       }
2794+                                       return false;
2795+                               }
2796+                       } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
2797+                               return true;
2798+                       }
2799+                       
2800+                       return match;
2801+               },
2802+               POS: function(match){
2803+                       match.unshift( true );
2804+                       return match;
2805+               }
2806+       },
2807+       filters: {
2808+               enabled: function(elem){
2809+                       return elem.disabled === false && elem.type !== "hidden";
2810+               },
2811+               disabled: function(elem){
2812+                       return elem.disabled === true;
2813+               },
2814+               checked: function(elem){
2815+                       return elem.checked === true;
2816+               },
2817+               selected: function(elem){
2818+                       // Accessing this property makes selected-by-default
2819+                       // options in Safari work properly
2820+                       elem.parentNode.selectedIndex;
2821+                       return elem.selected === true;
2822+               },
2823+               parent: function(elem){
2824+                       return !!elem.firstChild;
2825+               },
2826+               empty: function(elem){
2827+                       return !elem.firstChild;
2828+               },
2829+               has: function(elem, i, match){
2830+                       return !!Sizzle( match[3], elem ).length;
2831+               },
2832+               header: function(elem){
2833+                       return /h\d/i.test( elem.nodeName );
2834+               },
2835+               text: function(elem){
2836+                       return "text" === elem.type;
2837+               },
2838+               radio: function(elem){
2839+                       return "radio" === elem.type;
2840+               },
2841+               checkbox: function(elem){
2842+                       return "checkbox" === elem.type;
2843+               },
2844+               file: function(elem){
2845+                       return "file" === elem.type;
2846+               },
2847+               password: function(elem){
2848+                       return "password" === elem.type;
2849+               },
2850+               submit: function(elem){
2851+                       return "submit" === elem.type;
2852+               },
2853+               image: function(elem){
2854+                       return "image" === elem.type;
2855+               },
2856+               reset: function(elem){
2857+                       return "reset" === elem.type;
2858+               },
2859+               button: function(elem){
2860+                       return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON";
2861+               },
2862+               input: function(elem){
2863+                       return /input|select|textarea|button/i.test(elem.nodeName);
2864+               }
2865+       },
2866+       setFilters: {
2867+               first: function(elem, i){
2868+                       return i === 0;
2869+               },
2870+               last: function(elem, i, match, array){
2871+                       return i === array.length - 1;
2872+               },
2873+               even: function(elem, i){
2874+                       return i % 2 === 0;
2875+               },
2876+               odd: function(elem, i){
2877+                       return i % 2 === 1;
2878+               },
2879+               lt: function(elem, i, match){
2880+                       return i < match[3] - 0;
2881+               },
2882+               gt: function(elem, i, match){
2883+                       return i > match[3] - 0;
2884+               },
2885+               nth: function(elem, i, match){
2886+                       return match[3] - 0 == i;
2887+               },
2888+               eq: function(elem, i, match){
2889+                       return match[3] - 0 == i;
2890+               }
2891+       },
2892+       filter: {
2893+               PSEUDO: function(elem, match, i, array){
2894+                       var name = match[1], filter = Expr.filters[ name ];
2895+
2896+                       if ( filter ) {
2897+                               return filter( elem, i, match, array );
2898+                       } else if ( name === "contains" ) {
2899+                               return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0;
2900+                       } else if ( name === "not" ) {
2901+                               var not = match[3];
2902+
2903+                               for ( var i = 0, l = not.length; i < l; i++ ) {
2904+                                       if ( not[i] === elem ) {
2905+                                               return false;
2906+                                       }
2907+                               }
2908+
2909+                               return true;
2910+                       }
2911+               },
2912+               CHILD: function(elem, match){
2913+                       var type = match[1], node = elem;
2914+                       switch (type) {
2915+                               case 'only':
2916+                               case 'first':
2917+                                       while (node = node.previousSibling)  {
2918+                                               if ( node.nodeType === 1 ) return false;
2919+                                       }
2920+                                       if ( type == 'first') return true;
2921+                                       node = elem;
2922+                               case 'last':
2923+                                       while (node = node.nextSibling)  {
2924+                                               if ( node.nodeType === 1 ) return false;
2925+                                       }
2926+                                       return true;
2927+                               case 'nth':
2928+                                       var first = match[2], last = match[3];
2929+
2930+                                       if ( first == 1 && last == 0 ) {
2931+                                               return true;
2932+                                       }
2933+                                       
2934+                                       var doneName = match[0],
2935+                                               parent = elem.parentNode;
2936+       
2937+                                       if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
2938+                                               var count = 0;
2939+                                               for ( node = parent.firstChild; node; node = node.nextSibling ) {
2940+                                                       if ( node.nodeType === 1 ) {
2941+                                                               node.nodeIndex = ++count;
2942+                                                       }
2943+                                               }
2944+                                               parent.sizcache = doneName;
2945+                                       }
2946+                                       
2947+                                       var diff = elem.nodeIndex - last;
2948+                                       if ( first == 0 ) {
2949+                                               return diff == 0;
2950+                                       } else {
2951+                                               return ( diff % first == 0 && diff / first >= 0 );
2952+                                       }
2953+                       }
2954+               },
2955+               ID: function(elem, match){
2956+                       return elem.nodeType === 1 && elem.getAttribute("id") === match;
2957+               },
2958+               TAG: function(elem, match){
2959+                       return (match === "*" && elem.nodeType === 1) || elem.nodeName === match;
2960+               },
2961+               CLASS: function(elem, match){
2962+                       return (" " + (elem.className || elem.getAttribute("class")) + " ")
2963+                               .indexOf( match ) > -1;
2964+               },
2965+               ATTR: function(elem, match){
2966+                       var name = match[1],
2967+                               result = Expr.attrHandle[ name ] ?
2968+                                       Expr.attrHandle[ name ]( elem ) :
2969+                                       elem[ name ] != null ?
2970+                                               elem[ name ] :
2971+                                               elem.getAttribute( name ),
2972+                               value = result + "",
2973+                               type = match[2],
2974+                               check = match[4];
2975+
2976+                       return result == null ?
2977+                               type === "!=" :
2978+                               type === "=" ?
2979+                               value === check :
2980+                               type === "*=" ?
2981+                               value.indexOf(check) >= 0 :
2982+                               type === "~=" ?
2983+                               (" " + value + " ").indexOf(check) >= 0 :
2984+                               !check ?
2985+                               value && result !== false :
2986+                               type === "!=" ?
2987+                               value != check :
2988+                               type === "^=" ?
2989+                               value.indexOf(check) === 0 :
2990+                               type === "$=" ?
2991+                               value.substr(value.length - check.length) === check :
2992+                               type === "|=" ?
2993+                               value === check || value.substr(0, check.length + 1) === check + "-" :
2994+                               false;
2995+               },
2996+               POS: function(elem, match, i, array){
2997+                       var name = match[2], filter = Expr.setFilters[ name ];
2998+
2999+                       if ( filter ) {
3000+                               return filter( elem, i, match, array );
3001+                       }
3002+               }
3003+       }
3004+};
3005+
3006+var origPOS = Expr.match.POS;
3007+
3008+for ( var type in Expr.match ) {
3009+       Expr.match[ type ] = RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
3010+}
3011+
3012+var makeArray = function(array, results) {
3013+       array = Array.prototype.slice.call( array );
3014+
3015+       if ( results ) {
3016+               results.push.apply( results, array );
3017+               return results;
3018+       }
3019+       
3020+       return array;
3021+};
3022+
3023+// Perform a simple check to determine if the browser is capable of
3024+// converting a NodeList to an array using builtin methods.
3025+try {
3026+       Array.prototype.slice.call( document.documentElement.childNodes );
3027+
3028+// Provide a fallback method if it does not work
3029+} catch(e){
3030+       makeArray = function(array, results) {
3031+               var ret = results || [];
3032+
3033+               if ( toString.call(array) === "[object Array]" ) {
3034+                       Array.prototype.push.apply( ret, array );
3035+               } else {
3036+                       if ( typeof array.length === "number" ) {
3037+                               for ( var i = 0, l = array.length; i < l; i++ ) {
3038+                                       ret.push( array[i] );
3039+                               }
3040+                       } else {
3041+                               for ( var i = 0; array[i]; i++ ) {
3042+                                       ret.push( array[i] );
3043+                               }
3044+                       }
3045+               }
3046+
3047+               return ret;
3048+       };
3049+}
3050+
3051+var sortOrder;
3052+
3053+if ( document.documentElement.compareDocumentPosition ) {
3054+       sortOrder = function( a, b ) {
3055+               var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
3056+               if ( ret === 0 ) {
3057+                       hasDuplicate = true;
3058+               }
3059+               return ret;
3060+       };
3061+} else if ( "sourceIndex" in document.documentElement ) {
3062+       sortOrder = function( a, b ) {
3063+               var ret = a.sourceIndex - b.sourceIndex;
3064+               if ( ret === 0 ) {
3065+                       hasDuplicate = true;
3066+               }
3067+               return ret;
3068+       };
3069+} else if ( document.createRange ) {
3070+       sortOrder = function( a, b ) {
3071+               var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
3072+               aRange.selectNode(a);
3073+               aRange.collapse(true);
3074+               bRange.selectNode(b);
3075+               bRange.collapse(true);
3076+               var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
3077+               if ( ret === 0 ) {
3078+                       hasDuplicate = true;
3079+               }
3080+               return ret;
3081+       };
3082+}
3083+
3084+// Check to see if the browser returns elements by name when
3085+// querying by getElementById (and provide a workaround)
3086+(function(){
3087+       // We're going to inject a fake input element with a specified name
3088+       var form = document.createElement("form"),
3089+               id = "script" + (new Date).getTime();
3090+       form.innerHTML = "<input name='" + id + "'/>";
3091+
3092+       // Inject it into the root element, check its status, and remove it quickly
3093+       var root = document.documentElement;
3094+       root.insertBefore( form, root.firstChild );
3095+
3096+       // The workaround has to do additional checks after a getElementById
3097+       // Which slows things down for other browsers (hence the branching)
3098+       if ( !!document.getElementById( id ) ) {
3099+               Expr.find.ID = function(match, context, isXML){
3100+                       if ( typeof context.getElementById !== "undefined" && !isXML ) {
3101+                               var m = context.getElementById(match[1]);
3102+                               return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
3103+                       }
3104+               };
3105+
3106+               Expr.filter.ID = function(elem, match){
3107+                       var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
3108+                       return elem.nodeType === 1 && node && node.nodeValue === match;
3109+               };
3110+       }
3111+
3112+       root.removeChild( form );
3113+})();
3114+
3115+(function(){
3116+       // Check to see if the browser returns only elements
3117+       // when doing getElementsByTagName("*")
3118+
3119+       // Create a fake element
3120+       var div = document.createElement("div");
3121+       div.appendChild( document.createComment("") );
3122+
3123+       // Make sure no comments are found
3124+       if ( div.getElementsByTagName("*").length > 0 ) {
3125+               Expr.find.TAG = function(match, context){
3126+                       var results = context.getElementsByTagName(match[1]);
3127+
3128+                       // Filter out possible comments
3129+                       if ( match[1] === "*" ) {
3130+                               var tmp = [];
3131+
3132+                               for ( var i = 0; results[i]; i++ ) {
3133+                                       if ( results[i].nodeType === 1 ) {
3134+                                               tmp.push( results[i] );
3135+                                       }
3136+                               }
3137+
3138+                               results = tmp;
3139+                       }
3140+
3141+                       return results;
3142+               };
3143+       }
3144+
3145+       // Check to see if an attribute returns normalized href attributes
3146+       div.innerHTML = "<a href='#'></a>";
3147+       if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
3148+                       div.firstChild.getAttribute("href") !== "#" ) {
3149+               Expr.attrHandle.href = function(elem){
3150+                       return elem.getAttribute("href", 2);
3151+               };
3152+       }
3153+})();
3154+
3155+if ( document.querySelectorAll ) (function(){
3156+       var oldSizzle = Sizzle, div = document.createElement("div");
3157+       div.innerHTML = "<p class='TEST'></p>";
3158+
3159+       // Safari can't handle uppercase or unicode characters when
3160+       // in quirks mode.
3161+       if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
3162+               return;
3163+       }
3164+       
3165+       Sizzle = function(query, context, extra, seed){
3166+               context = context || document;
3167+
3168+               // Only use querySelectorAll on non-XML documents
3169+               // (ID selectors don't work in non-HTML documents)
3170+               if ( !seed && context.nodeType === 9 && !isXML(context) ) {
3171+                       try {
3172+                               return makeArray( context.querySelectorAll(query), extra );
3173+                       } catch(e){}
3174+               }
3175+               
3176+               return oldSizzle(query, context, extra, seed);
3177+       };
3178+
3179+       Sizzle.find = oldSizzle.find;
3180+       Sizzle.filter = oldSizzle.filter;
3181+       Sizzle.selectors = oldSizzle.selectors;
3182+       Sizzle.matches = oldSizzle.matches;
3183+})();
3184+
3185+if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){
3186+       var div = document.createElement("div");
3187+       div.innerHTML = "<div class='test e'></div><div class='test'></div>";
3188+
3189+       // Opera can't find a second classname (in 9.6)
3190+       if ( div.getElementsByClassName("e").length === 0 )
3191+               return;
3192+
3193+       // Safari caches class attributes, doesn't catch changes (in 3.2)
3194+       div.lastChild.className = "e";
3195+
3196+       if ( div.getElementsByClassName("e").length === 1 )
3197+               return;
3198+
3199+       Expr.order.splice(1, 0, "CLASS");
3200+       Expr.find.CLASS = function(match, context, isXML) {
3201+               if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
3202+                       return context.getElementsByClassName(match[1]);
3203+               }
3204+       };
3205+})();
3206+
3207+function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
3208+       var sibDir = dir == "previousSibling" && !isXML;
3209+       for ( var i = 0, l = checkSet.length; i < l; i++ ) {
3210+               var elem = checkSet[i];
3211+               if ( elem ) {
3212+                       if ( sibDir && elem.nodeType === 1 ){
3213+                               elem.sizcache = doneName;
3214+                               elem.sizset = i;
3215+                       }
3216+                       elem = elem[dir];
3217+                       var match = false;
3218+
3219+                       while ( elem ) {
3220+                               if ( elem.sizcache === doneName ) {
3221+                                       match = checkSet[elem.sizset];
3222+                                       break;
3223+                               }
3224+
3225+                               if ( elem.nodeType === 1 && !isXML ){
3226+                                       elem.sizcache = doneName;
3227+                                       elem.sizset = i;
3228+                               }
3229+
3230+                               if ( elem.nodeName === cur ) {
3231+                                       match = elem;
3232+                                       break;
3233+                               }
3234+
3235+                               elem = elem[dir];
3236+                       }
3237+
3238+                       checkSet[i] = match;
3239+               }
3240+       }
3241+}
3242+
3243+function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
3244+       var sibDir = dir == "previousSibling" && !isXML;
3245+       for ( var i = 0, l = checkSet.length; i < l; i++ ) {
3246+               var elem = checkSet[i];
3247+               if ( elem ) {
3248+                       if ( sibDir && elem.nodeType === 1 ) {
3249+                               elem.sizcache = doneName;
3250+                               elem.sizset = i;
3251+                       }
3252+                       elem = elem[dir];
3253+                       var match = false;
3254+
3255+                       while ( elem ) {
3256+                               if ( elem.sizcache === doneName ) {
3257+                                       match = checkSet[elem.sizset];
3258+                                       break;
3259+                               }
3260+
3261+                               if ( elem.nodeType === 1 ) {
3262+                                       if ( !isXML ) {
3263+                                               elem.sizcache = doneName;
3264+                                               elem.sizset = i;
3265+                                       }
3266+                                       if ( typeof cur !== "string" ) {
3267+                                               if ( elem === cur ) {
3268+                                                       match = true;
3269+                                                       break;
3270+                                               }
3271+
3272+                                       } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
3273+                                               match = elem;
3274+                                               break;
3275+                                       }
3276+                               }
3277+
3278+                               elem = elem[dir];
3279+                       }
3280+
3281+                       checkSet[i] = match;
3282+               }
3283+       }
3284+}
3285+
3286+var contains = document.compareDocumentPosition ?  function(a, b){
3287+       return a.compareDocumentPosition(b) & 16;
3288+} : function(a, b){
3289+       return a !== b && (a.contains ? a.contains(b) : true);
3290+};
3291+
3292+var isXML = function(elem){
3293+       return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
3294+               !!elem.ownerDocument && isXML( elem.ownerDocument );
3295+};
3296+
3297+var posProcess = function(selector, context){
3298+       var tmpSet = [], later = "", match,
3299+               root = context.nodeType ? [context] : context;
3300+
3301+       // Position selectors must be done after the filter
3302+       // And so must :not(positional) so we move all PSEUDOs to the end
3303+       while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
3304+               later += match[0];
3305+               selector = selector.replace( Expr.match.PSEUDO, "" );
3306+       }
3307+
3308+       selector = Expr.relative[selector] ? selector + "*" : selector;
3309+
3310+       for ( var i = 0, l = root.length; i < l; i++ ) {
3311+               Sizzle( selector, root[i], tmpSet );
3312+       }
3313+
3314+       return Sizzle.filter( later, tmpSet );
3315+};
3316+
3317+// EXPOSE
3318+jQuery.find = Sizzle;
3319+jQuery.filter = Sizzle.filter;
3320+jQuery.expr = Sizzle.selectors;
3321+jQuery.expr[":"] = jQuery.expr.filters;
3322+
3323+Sizzle.selectors.filters.hidden = function(elem){
3324+       return elem.offsetWidth === 0 || elem.offsetHeight === 0;
3325+};
3326+
3327+Sizzle.selectors.filters.visible = function(elem){
3328+       return elem.offsetWidth > 0 || elem.offsetHeight > 0;
3329+};
3330+
3331+Sizzle.selectors.filters.animated = function(elem){
3332+       return jQuery.grep(jQuery.timers, function(fn){
3333+               return elem === fn.elem;
3334+       }).length;
3335+};
3336+
3337+jQuery.multiFilter = function( expr, elems, not ) {
3338+       if ( not ) {
3339+               expr = ":not(" + expr + ")";
3340+       }
3341+
3342+       return Sizzle.matches(expr, elems);
3343+};
3344+
3345+jQuery.dir = function( elem, dir ){
3346+       var matched = [], cur = elem[dir];
3347+       while ( cur && cur != document ) {
3348+               if ( cur.nodeType == 1 )
3349+                       matched.push( cur );
3350+               cur = cur[dir];
3351+       }
3352+       return matched;
3353+};
3354+
3355+jQuery.nth = function(cur, result, dir, elem){
3356+       result = result || 1;
3357+       var num = 0;
3358+
3359+       for ( ; cur; cur = cur[dir] )
3360+               if ( cur.nodeType == 1 && ++num == result )
3361+                       break;
3362+
3363+       return cur;
3364+};
3365+
3366+jQuery.sibling = function(n, elem){
3367+       var r = [];
3368+
3369+       for ( ; n; n = n.nextSibling ) {
3370+               if ( n.nodeType == 1 && n != elem )
3371+                       r.push( n );
3372+       }
3373+
3374+       return r;
3375+};
3376+
3377+return;
3378+
3379+window.Sizzle = Sizzle;
3380+
3381+})();
3382+/*
3383+ * A number of helper functions used for managing events.
3384+ * Many of the ideas behind this code originated from
3385+ * Dean Edwards' addEvent library.
3386+ */
3387+jQuery.event = {
3388+
3389+       // Bind an event to an element
3390+       // Original by Dean Edwards
3391+       add: function(elem, types, handler, data) {
3392+               if ( elem.nodeType == 3 || elem.nodeType == 8 )
3393+                       return;
3394+
3395+               // For whatever reason, IE has trouble passing the window object
3396+               // around, causing it to be cloned in the process
3397+               if ( elem.setInterval && elem != window )
3398+                       elem = window;
3399+
3400+               // Make sure that the function being executed has a unique ID
3401+               if ( !handler.guid )
3402+                       handler.guid = this.guid++;
3403+
3404+               // if data is passed, bind to handler
3405+               if ( data !== undefined ) {
3406+                       // Create temporary function pointer to original handler
3407+                       var fn = handler;
3408+
3409+                       // Create unique handler function, wrapped around original handler
3410+                       handler = this.proxy( fn );
3411+
3412+                       // Store data in unique handler
3413+                       handler.data = data;
3414+               }
3415+
3416+               // Init the element's event structure
3417+               var events = jQuery.data(elem, "events") || jQuery.data(elem, "events", {}),
3418+                       handle = jQuery.data(elem, "handle") || jQuery.data(elem, "handle", function(){
3419+                               // Handle the second event of a trigger and when
3420+                               // an event is called after a page has unloaded
3421+                               return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
3422+                                       jQuery.event.handle.apply(arguments.callee.elem, arguments) :
3423+                                       undefined;
3424+                       });
3425+               // Add elem as a property of the handle function
3426+               // This is to prevent a memory leak with non-native
3427+               // event in IE.
3428+               handle.elem = elem;
3429+
3430+               // Handle multiple events separated by a space
3431+               // jQuery(...).bind("mouseover mouseout", fn);
3432+               jQuery.each(types.split(/\s+/), function(index, type) {
3433+                       // Namespaced event handlers
3434+                       var namespaces = type.split(".");
3435+                       type = namespaces.shift();
3436+                       handler.type = namespaces.slice().sort().join(".");
3437+
3438+                       // Get the current list of functions bound to this event
3439+                       var handlers = events[type];
3440+                       
3441+                       if ( jQuery.event.specialAll[type] )
3442+                               jQuery.event.specialAll[type].setup.call(elem, data, namespaces);
3443+
3444+                       // Init the event handler queue
3445+                       if (!handlers) {
3446+                               handlers = events[type] = {};
3447+
3448+                               // Check for a special event handler
3449+                               // Only use addEventListener/attachEvent if the special
3450+                               // events handler returns false
3451+                               if ( !jQuery.event.special[type] || jQuery.event.special[type].setup.call(elem, data, namespaces) === false ) {
3452+                                       // Bind the global event handler to the element
3453+                                       if (elem.addEventListener)
3454+                                               elem.addEventListener(type, handle, false);
3455+                                       else if (elem.attachEvent)
3456+                                               elem.attachEvent("on" + type, handle);
3457+                               }
3458+                       }
3459+
3460+                       // Add the function to the element's handler list
3461+                       handlers[handler.guid] = handler;
3462+
3463+                       // Keep track of which events have been used, for global triggering
3464+                       jQuery.event.global[type] = true;
3465+               });
3466+
3467+               // Nullify elem to prevent memory leaks in IE
3468+               elem = null;
3469+       },
3470+
3471+       guid: 1,
3472+       global: {},
3473+
3474+       // Detach an event or set of events from an element
3475+       remove: function(elem, types, handler) {
3476+               // don't do events on text and comment nodes
3477+               if ( elem.nodeType == 3 || elem.nodeType == 8 )
3478+                       return;
3479+
3480+               var events = jQuery.data(elem, "events"), ret, index;
3481+
3482+               if ( events ) {
3483+                       // Unbind all events for the element
3484+                       if ( types === undefined || (typeof types === "string" && types.charAt(0) == ".") )
3485+                               for ( var type in events )
3486+                                       this.remove( elem, type + (types || "") );
3487+                       else {
3488+                               // types is actually an event object here
3489+                               if ( types.type ) {
3490+                                       handler = types.handler;
3491+                                       types = types.type;
3492+                               }
3493+
3494+                               // Handle multiple events seperated by a space
3495+                               // jQuery(...).unbind("mouseover mouseout", fn);
3496+                               jQuery.each(types.split(/\s+/), function(index, type){
3497+                                       // Namespaced event handlers
3498+                                       var namespaces = type.split(".");
3499+                                       type = namespaces.shift();
3500+                                       var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");
3501+
3502+                                       if ( events[type] ) {
3503+                                               // remove the given handler for the given type
3504+                                               if ( handler )
3505+                                                       delete events[type][handler.guid];
3506+
3507+                                               // remove all handlers for the given type
3508+                                               else
3509+                                                       for ( var handle in events[type] )
3510+                                                               // Handle the removal of namespaced events
3511+                                                               if ( namespace.test(events[type][handle].type) )
3512+                                                                       delete events[type][handle];
3513+                                                                       
3514+                                               if ( jQuery.event.specialAll[type] )
3515+                                                       jQuery.event.specialAll[type].teardown.call(elem, namespaces);
3516+
3517+                                               // remove generic event handler if no more handlers exist
3518+                                               for ( ret in events[type] ) break;
3519+                                               if ( !ret ) {
3520+                                                       if ( !jQuery.event.special[type] || jQuery.event.special[type].teardown.call(elem, namespaces) === false ) {
3521+                                                               if (elem.removeEventListener)
3522+                                                                       elem.removeEventListener(type, jQuery.data(elem, "handle"), false);
3523+                                                               else if (elem.detachEvent)
3524+                                                                       elem.detachEvent("on" + type, jQuery.data(elem, "handle"));
3525+                                                       }
3526+                                                       ret = null;
3527+                                                       delete events[type];
3528+                                               }
3529+                                       }
3530+                               });
3531+                       }
3532+
3533+                       // Remove the expando if it's no longer used
3534+                       for ( ret in events ) break;
3535+                       if ( !ret ) {
3536+                               var handle = jQuery.data( elem, "handle" );
3537+                               if ( handle ) handle.elem = null;
3538+                               jQuery.removeData( elem, "events" );
3539+                               jQuery.removeData( elem, "handle" );
3540+                       }
3541+               }
3542+       },
3543+
3544+       // bubbling is internal
3545+       trigger: function( event, data, elem, bubbling ) {
3546+               // Event object or event type
3547+               var type = event.type || event;
3548+
3549+               if( !bubbling ){
3550+                       event = typeof event === "object" ?
3551+                               // jQuery.Event object
3552+                               event[expando] ? event :
3553+                               // Object literal
3554+                               jQuery.extend( jQuery.Event(type), event ) :
3555+                               // Just the event type (string)
3556+                               jQuery.Event(type);
3557+
3558+                       if ( type.indexOf("!") >= 0 ) {
3559+                               event.type = type = type.slice(0, -1);
3560+                               event.exclusive = true;
3561+                       }
3562+
3563+                       // Handle a global trigger
3564+                       if ( !elem ) {
3565+                               // Don't bubble custom events when global (to avoid too much overhead)
3566+                               event.stopPropagation();
3567+                               // Only trigger if we've ever bound an event for it
3568+                               if ( this.global[type] )
3569+                                       jQuery.each( jQuery.cache, function(){
3570+                                               if ( this.events && this.events[type] )
3571+                                                       jQuery.event.trigger( event, data, this.handle.elem );
3572+                                       });
3573+                       }
3574+
3575+                       // Handle triggering a single element
3576+
3577+                       // don't do events on text and comment nodes
3578+                       if ( !elem || elem.nodeType == 3 || elem.nodeType == 8 )
3579+                               return undefined;
3580+                       
3581+                       // Clean up in case it is reused
3582+                       event.result = undefined;
3583+                       event.target = elem;
3584+                       
3585+                       // Clone the incoming data, if any
3586+                       data = jQuery.makeArray(data);
3587+                       data.unshift( event );
3588+               }
3589+
3590+               event.currentTarget = elem;
3591+
3592+               // Trigger the event, it is assumed that "handle" is a function
3593+               var handle = jQuery.data(elem, "handle");
3594+               if ( handle )
3595+                       handle.apply( elem, data );
3596+
3597+               // Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
3598+               if ( (!elem[type] || (jQuery.nodeName(elem, 'a') && type == "click")) && elem["on"+type] && elem["on"+type].apply( elem, data ) === false )
3599+                       event.result = false;
3600+
3601+               // Trigger the native events (except for clicks on links)
3602+               if ( !bubbling && elem[type] && !event.isDefaultPrevented() && !(jQuery.nodeName(elem, 'a') && type == "click") ) {
3603+                       this.triggered = true;
3604+                       try {
3605+                               elem[ type ]();
3606+                       // prevent IE from throwing an error for some hidden elements
3607+                       } catch (e) {}
3608+               }
3609+
3610+               this.triggered = false;
3611+
3612+               if ( !event.isPropagationStopped() ) {
3613+                       var parent = elem.parentNode || elem.ownerDocument;
3614+                       if ( parent )
3615+                               jQuery.event.trigger(event, data, parent, true);
3616+               }
3617+       },
3618+
3619+       handle: function(event) {
3620+               // returned undefined or false
3621+               var all, handlers;
3622+
3623+               event = arguments[0] = jQuery.event.fix( event || window.event );
3624+               event.currentTarget = this;
3625+               
3626+               // Namespaced event handlers
3627+               var namespaces = event.type.split(".");
3628+               event.type = namespaces.shift();
3629+
3630+               // Cache this now, all = true means, any handler
3631+               all = !namespaces.length && !event.exclusive;
3632+               
3633+               var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");
3634+
3635+               handlers = ( jQuery.data(this, "events") || {} )[event.type];
3636+
3637+               for ( var j in handlers ) {
3638+                       var handler = handlers[j];
3639+
3640+                       // Filter the functions by class
3641+                       if ( all || namespace.test(handler.type) ) {
3642+                               // Pass in a reference to the handler function itself
3643+                               // So that we can later remove it
3644+                               event.handler = handler;
3645+                               event.data = handler.data;
3646+
3647+                               var ret = handler.apply(this, arguments);
3648+
3649+                               if( ret !== undefined ){
3650+                                       event.result = ret;
3651+                                       if ( ret === false ) {
3652+                                               event.preventDefault();
3653+                                               event.stopPropagation();
3654+                                       }
3655+                               }
3656+
3657+                               if( event.isImmediatePropagationStopped() )
3658+                                       break;
3659+
3660+                       }
3661+               }
3662+       },
3663+
3664+       props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
3665+
3666+       fix: function(event) {
3667+               if ( event[expando] )
3668+                       return event;
3669+
3670+               // store a copy of the original event object
3671+               // and "clone" to set read-only properties
3672+               var originalEvent = event;
3673+               event = jQuery.Event( originalEvent );
3674+
3675+               for ( var i = this.props.length, prop; i; ){
3676+                       prop = this.props[ --i ];
3677+                       event[ prop ] = originalEvent[ prop ];
3678+               }
3679+
3680+               // Fix target property, if necessary
3681+               if ( !event.target )
3682+                       event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
3683+
3684+               // check if target is a textnode (safari)
3685+               if ( event.target.nodeType == 3 )
3686+                       event.target = event.target.parentNode;
3687+
3688+               // Add relatedTarget, if necessary
3689+               if ( !event.relatedTarget && event.fromElement )
3690+                       event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;
3691+
3692+               // Calculate pageX/Y if missing and clientX/Y available
3693+               if ( event.pageX == null && event.clientX != null ) {
3694+                       var doc = document.documentElement, body = document.body;
3695+                       event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0);
3696+                       event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc.clientTop || 0);
3697+               }
3698+
3699+               // Add which for key events
3700+               if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) )
3701+                       event.which = event.charCode || event.keyCode;
3702+
3703+               // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
3704+               if ( !event.metaKey && event.ctrlKey )
3705+                       event.metaKey = event.ctrlKey;
3706+
3707+               // Add which for click: 1 == left; 2 == middle; 3 == right
3708+               // Note: button is not normalized, so don't use it
3709+               if ( !event.which && event.button )
3710+                       event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
3711+
3712+               return event;
3713+       },
3714+
3715+       proxy: function( fn, proxy ){
3716+               proxy = proxy || function(){ return fn.apply(this, arguments); };
3717+               // Set the guid of unique handler to the same of original handler, so it can be removed
3718+               proxy.guid = fn.guid = fn.guid || proxy.guid || this.guid++;
3719+               // So proxy can be declared as an argument
3720+               return proxy;
3721+       },
3722+
3723+       special: {
3724+               ready: {
3725+                       // Make sure the ready event is setup
3726+                       setup: bindReady,
3727+                       teardown: function() {}
3728+               }
3729+       },
3730+       
3731+       specialAll: {
3732+               live: {
3733+                       setup: function( selector, namespaces ){
3734+                               jQuery.event.add( this, namespaces[0], liveHandler );
3735+                       },
3736+                       teardown:  function( namespaces ){
3737+                               if ( namespaces.length ) {
3738+                                       var remove = 0, name = RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)");
3739+                                       
3740+                                       jQuery.each( (jQuery.data(this, "events").live || {}), function(){
3741+                                               if ( name.test(this.type) )
3742+                                                       remove++;
3743+                                       });
3744+                                       
3745+                                       if ( remove < 1 )
3746+                                               jQuery.event.remove( this, namespaces[0], liveHandler );
3747+                               }
3748+                       }
3749+               }
3750+       }
3751+};
3752+
3753+jQuery.Event = function( src ){
3754+       // Allow instantiation without the 'new' keyword
3755+       if( !this.preventDefault )
3756+               return new jQuery.Event(src);
3757+       
3758+       // Event object
3759+       if( src && src.type ){
3760+               this.originalEvent = src;
3761+               this.type = src.type;
3762+       // Event type
3763+       }else
3764+               this.type = src;
3765+
3766+       // timeStamp is buggy for some events on Firefox(#3843)
3767+       // So we won't rely on the native value
3768+       this.timeStamp = now();
3769+       
3770+       // Mark it as fixed
3771+       this[expando] = true;
3772+};
3773+
3774+function returnFalse(){
3775+       return false;
3776+}
3777+function returnTrue(){
3778+       return true;
3779+}
3780+
3781+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
3782+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
3783+jQuery.Event.prototype = {
3784+       preventDefault: function() {
3785+               this.isDefaultPrevented = returnTrue;
3786+
3787+               var e = this.originalEvent;
3788+               if( !e )
3789+                       return;
3790+               // if preventDefault exists run it on the original event
3791+               if (e.preventDefault)
3792+                       e.preventDefault();
3793+               // otherwise set the returnValue property of the original event to false (IE)
3794+               e.returnValue = false;
3795+       },
3796+       stopPropagation: function() {
3797+               this.isPropagationStopped = returnTrue;
3798+
3799+               var e = this.originalEvent;
3800+               if( !e )
3801+                       return;
3802+               // if stopPropagation exists run it on the original event
3803+               if (e.stopPropagation)
3804+                       e.stopPropagation();
3805+               // otherwise set the cancelBubble property of the original event to true (IE)
3806+               e.cancelBubble = true;
3807+       },
3808+       stopImmediatePropagation:function(){
3809+               this.isImmediatePropagationStopped = returnTrue;
3810+               this.stopPropagation();
3811+       },
3812+       isDefaultPrevented: returnFalse,
3813+       isPropagationStopped: returnFalse,
3814+       isImmediatePropagationStopped: returnFalse
3815+};
3816+// Checks if an event happened on an element within another element
3817+// Used in jQuery.event.special.mouseenter and mouseleave handlers
3818+var withinElement = function(event) {
3819+       // Check if mouse(over|out) are still within the same parent element
3820+       var parent = event.relatedTarget;
3821+       // Traverse up the tree
3822+       while ( parent && parent != this )
3823+               try { parent = parent.parentNode; }
3824+               catch(e) { parent = this; }
3825+       
3826+       if( parent != this ){
3827+               // set the correct event type
3828+               event.type = event.data;
3829+               // handle event if we actually just moused on to a non sub-element
3830+               jQuery.event.handle.apply( this, arguments );
3831+       }
3832+};
3833+       
3834+jQuery.each({
3835+       mouseover: 'mouseenter',
3836+       mouseout: 'mouseleave'
3837+}, function( orig, fix ){
3838+       jQuery.event.special[ fix ] = {
3839+               setup: function(){
3840+                       jQuery.event.add( this, orig, withinElement, fix );
3841+               },
3842+               teardown: function(){
3843+                       jQuery.event.remove( this, orig, withinElement );
3844+               }
3845+       };                         
3846+});
3847+
3848+jQuery.fn.extend({
3849+       bind: function( type, data, fn ) {
3850+               return type == "unload" ? this.one(type, data, fn) : this.each(function(){
3851+                       jQuery.event.add( this, type, fn || data, fn && data );
3852+               });
3853+       },
3854+
3855+       one: function( type, data, fn ) {
3856+               var one = jQuery.event.proxy( fn || data, function(event) {
3857+                       jQuery(this).unbind(event, one);
3858+                       return (fn || data).apply( this, arguments );
3859+               });
3860+               return this.each(function(){
3861+                       jQuery.event.add( this, type, one, fn && data);
3862+               });
3863+       },
3864+
3865+       unbind: function( type, fn ) {
3866+               return this.each(function(){
3867+                       jQuery.event.remove( this, type, fn );
3868+               });
3869+       },
3870+
3871+       trigger: function( type, data ) {
3872+               return this.each(function(){
3873+                       jQuery.event.trigger( type, data, this );
3874+               });
3875+       },
3876+
3877+       triggerHandler: function( type, data ) {
3878+               if( this[0] ){
3879+                       var event = jQuery.Event(type);
3880+                       event.preventDefault();
3881+                       event.stopPropagation();
3882+                       jQuery.event.trigger( event, data, this[0] );
3883+                       return event.result;
3884+               }               
3885+       },
3886+
3887+       toggle: function( fn ) {
3888+               // Save reference to arguments for access in closure
3889+               var args = arguments, i = 1;
3890+
3891+               // link all the functions, so any of them can unbind this click handler
3892+               while( i < args.length )
3893+                       jQuery.event.proxy( fn, args[i++] );
3894+
3895+               return this.click( jQuery.event.proxy( fn, function(event) {
3896+                       // Figure out which function to execute
3897+                       this.lastToggle = ( this.lastToggle || 0 ) % i;
3898+
3899+                       // Make sure that clicks stop
3900+                       event.preventDefault();
3901+
3902+                       // and execute the function
3903+                       return args[ this.lastToggle++ ].apply( this, arguments ) || false;
3904+               }));
3905+       },
3906+
3907+       hover: function(fnOver, fnOut) {
3908+               return this.mouseenter(fnOver).mouseleave(fnOut);
3909+       },
3910+
3911+       ready: function(fn) {
3912+               // Attach the listeners
3913+               bindReady();
3914+
3915+               // If the DOM is already ready
3916+               if ( jQuery.isReady )
3917+                       // Execute the function immediately
3918+                       fn.call( document, jQuery );
3919+
3920+               // Otherwise, remember the function for later
3921+               else
3922+                       // Add the function to the wait list
3923+                       jQuery.readyList.push( fn );
3924+
3925+               return this;
3926+       },
3927+       
3928+       live: function( type, fn ){
3929+               var proxy = jQuery.event.proxy( fn );
3930+               proxy.guid += this.selector + type;
3931+
3932+               jQuery(document).bind( liveConvert(type, this.selector), this.selector, proxy );
3933+
3934+               return this;
3935+       },
3936+       
3937+       die: function( type, fn ){
3938+               jQuery(document).unbind( liveConvert(type, this.selector), fn ? { guid: fn.guid + this.selector + type } : null );
3939+               return this;
3940+       }
3941+});
3942+
3943+function liveHandler( event ){
3944+       var check = RegExp("(^|\\.)" + event.type + "(\\.|$)"),
3945+               stop = true,
3946+               elems = [];
3947+
3948+       jQuery.each(jQuery.data(this, "events").live || [], function(i, fn){
3949+               if ( check.test(fn.type) ) {
3950+                       var elem = jQuery(event.target).closest(fn.data)[0];
3951+                       if ( elem )
3952+                               elems.push({ elem: elem, fn: fn });
3953+               }
3954+       });
3955+
3956+       elems.sort(function(a,b) {
3957+               return jQuery.data(a.elem, "closest") - jQuery.data(b.elem, "closest");
3958+       });
3959+       
3960+       jQuery.each(elems, function(){
3961+               if ( this.fn.call(this.elem, event, this.fn.data) === false )
3962+                       return (stop = false);
3963+       });
3964+
3965+       return stop;
3966+}
3967+
3968+function liveConvert(type, selector){
3969+       return ["live", type, selector.replace(/\./g, "`").replace(/ /g, "|")].join(".");
3970+}
3971+
3972+jQuery.extend({
3973+       isReady: false,
3974+       readyList: [],
3975+       // Handle when the DOM is ready
3976+       ready: function() {
3977+               // Make sure that the DOM is not already loaded
3978+               if ( !jQuery.isReady ) {
3979+                       // Remember that the DOM is ready
3980+                       jQuery.isReady = true;
3981+
3982+                       // If there are functions bound, to execute
3983+                       if ( jQuery.readyList ) {
3984+                               // Execute all of them
3985+                               jQuery.each( jQuery.readyList, function(){
3986+                                       this.call( document, jQuery );
3987+                               });
3988+
3989+                               // Reset the list of functions
3990+                               jQuery.readyList = null;
3991+                       }
3992+
3993+                       // Trigger any bound ready events
3994+                       jQuery(document).triggerHandler("ready");
3995+               }
3996+       }
3997+});
3998+
3999+var readyBound = false;
4000+
4001+function bindReady(){
4002+       if ( readyBound ) return;
4003+       readyBound = true;
4004+
4005+       // Mozilla, Opera and webkit nightlies currently support this event
4006+       if ( document.addEventListener ) {
4007+               // Use the handy event callback
4008+               document.addEventListener( "DOMContentLoaded", function(){
4009+                       document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
4010+                       jQuery.ready();
4011+               }, false );
4012+
4013+       // If IE event model is used
4014+       } else if ( document.attachEvent ) {
4015+               // ensure firing before onload,
4016+               // maybe late but safe also for iframes
4017+               document.attachEvent("onreadystatechange", function(){
4018+                       if ( document.readyState === "complete" ) {
4019+                               document.detachEvent( "onreadystatechange", arguments.callee );
4020+                               jQuery.ready();
4021+                       }
4022+               });
4023+
4024+               // If IE and not an iframe
4025+               // continually check to see if the document is ready
4026+               if ( document.documentElement.doScroll && window == window.top ) (function(){
4027+                       if ( jQuery.isReady ) return;
4028+
4029+                       try {
4030+                               // If IE is used, use the trick by Diego Perini
4031+                               // http://javascript.nwbox.com/IEContentLoaded/
4032+                               document.documentElement.doScroll("left");
4033+                       } catch( error ) {
4034+                               setTimeout( arguments.callee, 0 );
4035+                               return;
4036+                       }
4037+
4038+                       // and execute any waiting functions
4039+                       jQuery.ready();
4040+               })();
4041+       }
4042+
4043+       // A fallback to window.onload, that will always work
4044+       jQuery.event.add( window, "load", jQuery.ready );
4045+}
4046+
4047+jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," +
4048+       "mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave," +
4049+       "change,select,submit,keydown,keypress,keyup,error").split(","), function(i, name){
4050+
4051+       // Handle event binding
4052+       jQuery.fn[name] = function(fn){
4053+               return fn ? this.bind(name, fn) : this.trigger(name);
4054+       };
4055+});
4056+
4057+// Prevent memory leaks in IE
4058+// And prevent errors on refresh with events like mouseover in other browsers
4059+// Window isn't included so as not to unbind existing unload events
4060+jQuery( window ).bind( 'unload', function(){
4061+       for ( var id in jQuery.cache )
4062+               // Skip the window
4063+               if ( id != 1 && jQuery.cache[ id ].handle )
4064+                       jQuery.event.remove( jQuery.cache[ id ].handle.elem );
4065+});
4066+(function(){
4067+
4068+       jQuery.support = {};
4069+
4070+       var root = document.documentElement,
4071+               script = document.createElement("script"),
4072+               div = document.createElement("div"),
4073+               id = "script" + (new Date).getTime();
4074+
4075+       div.style.display = "none";
4076+       div.innerHTML = '   <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';
4077+
4078+       var all = div.getElementsByTagName("*"),
4079+               a = div.getElementsByTagName("a")[0];
4080+
4081+       // Can't get basic test support
4082+       if ( !all || !all.length || !a ) {
4083+               return;
4084+       }
4085+
4086+       jQuery.support = {
4087+               // IE strips leading whitespace when .innerHTML is used
4088+               leadingWhitespace: div.firstChild.nodeType == 3,
4089+               
4090+               // Make sure that tbody elements aren't automatically inserted
4091+               // IE will insert them into empty tables
4092+               tbody: !div.getElementsByTagName("tbody").length,
4093+               
4094+               // Make sure that you can get all elements in an <object> element
4095+               // IE 7 always returns no results
4096+               objectAll: !!div.getElementsByTagName("object")[0]
4097+                       .getElementsByTagName("*").length,
4098+               
4099+               // Make sure that link elements get serialized correctly by innerHTML
4100+               // This requires a wrapper element in IE
4101+               htmlSerialize: !!div.getElementsByTagName("link").length,
4102+               
4103+               // Get the style information from getAttribute
4104+               // (IE uses .cssText insted)
4105+               style: /red/.test( a.getAttribute("style") ),
4106+               
4107+               // Make sure that URLs aren't manipulated
4108+               // (IE normalizes it by default)
4109+               hrefNormalized: a.getAttribute("href") === "/a",
4110+               
4111+               // Make sure that element opacity exists
4112+               // (IE uses filter instead)
4113+               opacity: a.style.opacity === "0.5",
4114+               
4115+               // Verify style float existence
4116+               // (IE uses styleFloat instead of cssFloat)
4117+               cssFloat: !!a.style.cssFloat,
4118+
4119+               // Will be defined later
4120+               scriptEval: false,
4121+               noCloneEvent: true,
4122+               boxModel: null
4123+       };
4124+       
4125+       script.type = "text/javascript";
4126+       try {
4127+               script.appendChild( document.createTextNode( "window." + id + "=1;" ) );
4128+       } catch(e){}
4129+
4130+       root.insertBefore( script, root.firstChild );
4131+       
4132+       // Make sure that the execution of code works by injecting a script
4133+       // tag with appendChild/createTextNode
4134+       // (IE doesn't support this, fails, and uses .text instead)
4135+       if ( window[ id ] ) {
4136+               jQuery.support.scriptEval = true;
4137+               delete window[ id ];
4138+       }
4139+
4140+       root.removeChild( script );
4141+
4142+       if ( div.attachEvent && div.fireEvent ) {
4143+               div.attachEvent("onclick", function(){
4144+                       // Cloning a node shouldn't copy over any
4145+                       // bound event handlers (IE does this)
4146+                       jQuery.support.noCloneEvent = false;
4147+                       div.detachEvent("onclick", arguments.callee);
4148+               });
4149+               div.cloneNode(true).fireEvent("onclick");
4150+       }
4151+
4152+       // Figure out if the W3C box model works as expected
4153+       // document.body must exist before we can do this
4154+       jQuery(function(){
4155+               var div = document.createElement("div");
4156+               div.style.width = div.style.paddingLeft = "1px";
4157+
4158+               document.body.appendChild( div );
4159+               jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2;
4160+               document.body.removeChild( div ).style.display = 'none';
4161+       });
4162+})();
4163+
4164+var styleFloat = jQuery.support.cssFloat ? "cssFloat" : "styleFloat";
4165+
4166+jQuery.props = {
4167+       "for": "htmlFor",
4168+       "class": "className",
4169+       "float": styleFloat,
4170+       cssFloat: styleFloat,
4171+       styleFloat: styleFloat,
4172+       readonly: "readOnly",
4173+       maxlength: "maxLength",
4174+       cellspacing: "cellSpacing",
4175+       rowspan: "rowSpan",
4176+       tabindex: "tabIndex"
4177+};
4178+jQuery.fn.extend({
4179+       // Keep a copy of the old load
4180+       _load: jQuery.fn.load,
4181+
4182+       load: function( url, params, callback ) {
4183+               if ( typeof url !== "string" )
4184+                       return this._load( url );
4185+
4186+               var off = url.indexOf(" ");
4187+               if ( off >= 0 ) {
4188+                       var selector = url.slice(off, url.length);
4189+                       url = url.slice(0, off);
4190+               }
4191+
4192+               // Default to a GET request
4193+               var type = "GET";
4194+
4195+               // If the second parameter was provided
4196+               if ( params )
4197+                       // If it's a function
4198+                       if ( jQuery.isFunction( params ) ) {
4199+                               // We assume that it's the callback
4200+                               callback = params;
4201+                               params = null;
4202+
4203+                       // Otherwise, build a param string
4204+                       } else if( typeof params === "object" ) {
4205+                               params = jQuery.param( params );
4206+                               type = "POST";
4207+                       }
4208+
4209+               var self = this;
4210+
4211+               // Request the remote document
4212+               jQuery.ajax({
4213+                       url: url,
4214+                       type: type,
4215+                       dataType: "html",
4216+                       data: params,
4217+                       complete: function(res, status){
4218+                               // If successful, inject the HTML into all the matched elements
4219+                               if ( status == "success" || status == "notmodified" )
4220+                                       // See if a selector was specified
4221+                                       self.html( selector ?
4222+                                               // Create a dummy div to hold the results
4223+                                               jQuery("<div/>")
4224+                                                       // inject the contents of the document in, removing the scripts
4225+                                                       // to avoid any 'Permission Denied' errors in IE
4226+                                                       .append(res.responseText.replace(/<script(.|\s)*?\/script>/g, ""))
4227+
4228+                                                       // Locate the specified elements
4229+                                                       .find(selector) :
4230+
4231+                                               // If not, just inject the full result
4232+                                               res.responseText );
4233+
4234+                               if( callback )
4235+                                       self.each( callback, [res.responseText, status, res] );
4236+                       }
4237+               });
4238+               return this;
4239+       },
4240+
4241+       serialize: function() {
4242+               return jQuery.param(this.serializeArray());
4243+       },
4244+       serializeArray: function() {
4245+               return this.map(function(){
4246+                       return this.elements ? jQuery.makeArray(this.elements) : this;
4247+               })
4248+               .filter(function(){
4249+                       return this.name && !this.disabled &&
4250+                               (this.checked || /select|textarea/i.test(this.nodeName) ||
4251+                                       /text|hidden|password|search/i.test(this.type));
4252+               })
4253+               .map(function(i, elem){
4254+                       var val = jQuery(this).val();
4255+                       return val == null ? null :
4256+                               jQuery.isArray(val) ?
4257+                                       jQuery.map( val, function(val, i){
4258+                                               return {name: elem.name, value: val};
4259+                                       }) :
4260+                                       {name: elem.name, value: val};
4261+               }).get();
4262+       }
4263+});
4264+
4265+// Attach a bunch of functions for handling common AJAX events
4266+jQuery.each( "ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","), function(i,o){
4267+       jQuery.fn[o] = function(f){
4268+               return this.bind(o, f);
4269+       };
4270+});
4271+
4272+var jsc = now();
4273+
4274+jQuery.extend({
4275
4276+       get: function( url, data, callback, type ) {
4277+               // shift arguments if data argument was ommited
4278+               if ( jQuery.isFunction( data ) ) {
4279+                       callback = data;
4280+                       data = null;
4281+               }
4282+
4283+               return jQuery.ajax({
4284+                       type: "GET",
4285+                       url: url,
4286+                       data: data,
4287+                       success: callback,
4288+                       dataType: type
4289+               });
4290+       },
4291+
4292+       getScript: function( url, callback ) {
4293+               return jQuery.get(url, null, callback, "script");
4294+       },
4295+
4296+       getJSON: function( url, data, callback ) {
4297+               return jQuery.get(url, data, callback, "json");
4298+       },
4299+
4300+       post: function( url, data, callback, type ) {
4301+               if ( jQuery.isFunction( data ) ) {
4302+                       callback = data;
4303+                       data = {};
4304+               }
4305+
4306+               return jQuery.ajax({
4307+                       type: "POST",
4308+                       url: url,
4309+                       data: data,
4310+                       success: callback,
4311+                       dataType: type
4312+               });
4313+       },
4314+
4315+       ajaxSetup: function( settings ) {
4316+               jQuery.extend( jQuery.ajaxSettings, settings );
4317+       },
4318+
4319+       ajaxSettings: {
4320+               url: location.href,
4321+               global: true,
4322+               type: "GET",
4323+               contentType: "application/x-www-form-urlencoded",
4324+               processData: true,
4325+               async: true,
4326+               /*
4327+               timeout: 0,
4328+               data: null,
4329+               username: null,
4330+               password: null,
4331+               */
4332+               // Create the request object; Microsoft failed to properly
4333+               // implement the XMLHttpRequest in IE7, so we use the ActiveXObject when it is available
4334+               // This function can be overriden by calling jQuery.ajaxSetup
4335+               xhr:function(){
4336+                       return window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
4337+               },
4338+               accepts: {
4339+                       xml: "application/xml, text/xml",
4340+                       html: "text/html",
4341+                       script: "text/javascript, application/javascript",
4342+                       json: "application/json, text/javascript",
4343+                       text: "text/plain",
4344+                       _default: "*/*"
4345+               }
4346+       },
4347+
4348+       // Last-Modified header cache for next request
4349+       lastModified: {},
4350+
4351+       ajax: function( s ) {
4352+               // Extend the settings, but re-extend 's' so that it can be
4353+               // checked again later (in the test suite, specifically)
4354+               s = jQuery.extend(true, s, jQuery.extend(true, {}, jQuery.ajaxSettings, s));
4355+
4356+               var jsonp, jsre = /=\?(&|$)/g, status, data,
4357+                       type = s.type.toUpperCase();
4358+
4359+               // convert data if not already a string
4360+               if ( s.data && s.processData && typeof s.data !== "string" )
4361+                       s.data = jQuery.param(s.data);
4362+
4363+               // Handle JSONP Parameter Callbacks
4364+               if ( s.dataType == "jsonp" ) {
4365+                       if ( type == "GET" ) {
4366+                               if ( !s.url.match(jsre) )
4367+                                       s.url += (s.url.match(/\?/) ? "&" : "?") + (s.jsonp || "callback") + "=?";
4368+                       } else if ( !s.data || !s.data.match(jsre) )
4369+                               s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?";
4370+                       s.dataType = "json";
4371+               }
4372+
4373+               // Build temporary JSONP function
4374+               if ( s.dataType == "json" && (s.data && s.data.match(jsre) || s.url.match(jsre)) ) {
4375+                       jsonp = "jsonp" + jsc++;
4376+
4377+                       // Replace the =? sequence both in the query string and the data
4378+                       if ( s.data )
4379+                               s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
4380+                       s.url = s.url.replace(jsre, "=" + jsonp + "$1");
4381+
4382+                       // We need to make sure
4383+                       // that a JSONP style response is executed properly
4384+                       s.dataType = "script";
4385+
4386+                       // Handle JSONP-style loading
4387+                       window[ jsonp ] = function(tmp){
4388+                               data = tmp;
4389+                               success();
4390+                               complete();
4391+                               // Garbage collect
4392+                               window[ jsonp ] = undefined;
4393+                               try{ delete window[ jsonp ]; } catch(e){}
4394+                               if ( head )
4395+                                       head.removeChild( script );
4396+                       };
4397+               }
4398+
4399+               if ( s.dataType == "script" && s.cache == null )
4400+                       s.cache = false;
4401+
4402+               if ( s.cache === false && type == "GET" ) {
4403+                       var ts = now();
4404+                       // try replacing _= if it is there
4405+                       var ret = s.url.replace(/(\?|&)_=.*?(&|$)/, "$1_=" + ts + "$2");
4406+                       // if nothing was replaced, add timestamp to the end
4407+                       s.url = ret + ((ret == s.url) ? (s.url.match(/\?/) ? "&" : "?") + "_=" + ts : "");
4408+               }
4409+
4410+               // If data is available, append data to url for get requests
4411+               if ( s.data && type == "GET" ) {
4412+                       s.url += (s.url.match(/\?/) ? "&" : "?") + s.data;
4413+
4414+                       // IE likes to send both get and post data, prevent this
4415+                       s.data = null;
4416+               }
4417+
4418+               // Watch for a new set of requests
4419+               if ( s.global && ! jQuery.active++ )
4420+                       jQuery.event.trigger( "ajaxStart" );
4421+
4422+               // Matches an absolute URL, and saves the domain
4423+               var parts = /^(\w+:)?\/\/([^\/?#]+)/.exec( s.url );
4424+
4425+               // If we're requesting a remote document
4426+               // and trying to load JSON or Script with a GET
4427+               if ( s.dataType == "script" && type == "GET" && parts
4428+                       && ( parts[1] && parts[1] != location.protocol || parts[2] != location.host )){
4429+
4430+                       var head = document.getElementsByTagName("head")[0];
4431+                       var script = document.createElement("script");
4432+                       script.src = s.url;
4433+                       if (s.scriptCharset)
4434+                               script.charset = s.scriptCharset;
4435+
4436+                       // Handle Script loading
4437+                       if ( !jsonp ) {
4438+                               var done = false;
4439+
4440+                               // Attach handlers for all browsers
4441+                               script.onload = script.onreadystatechange = function(){
4442+                                       if ( !done && (!this.readyState ||
4443+                                                       this.readyState == "loaded" || this.readyState == "complete") ) {
4444+                                               done = true;
4445+                                               success();
4446+                                               complete();
4447+
4448+                                               // Handle memory leak in IE
4449+                                               script.onload = script.onreadystatechange = null;
4450+                                               head.removeChild( script );
4451+                                       }
4452+                               };
4453+                       }
4454+
4455+                       head.appendChild(script);
4456+
4457+                       // We handle everything using the script element injection
4458+                       return undefined;
4459+               }
4460+
4461+               var requestDone = false;
4462+
4463+               // Create the request object
4464+               var xhr = s.xhr();
4465+
4466+               // Open the socket
4467+               // Passing null username, generates a login popup on Opera (#2865)
4468+               if( s.username )
4469+                       xhr.open(type, s.url, s.async, s.username, s.password);
4470+               else
4471+                       xhr.open(type, s.url, s.async);
4472+
4473+               // Need an extra try/catch for cross domain requests in Firefox 3
4474+               try {
4475+                       // Set the correct header, if data is being sent
4476+                       if ( s.data )
4477+                               xhr.setRequestHeader("Content-Type", s.contentType);
4478+
4479+                       // Set the If-Modified-Since header, if ifModified mode.
4480+                       if ( s.ifModified )
4481+                               xhr.setRequestHeader("If-Modified-Since",
4482+                                       jQuery.lastModified[s.url] || "Thu, 01 Jan 1970 00:00:00 GMT" );
4483+
4484+                       // Set header so the called script knows that it's an XMLHttpRequest
4485+                       xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
4486+
4487+                       // Set the Accepts header for the server, depending on the dataType
4488+                       xhr.setRequestHeader("Accept", s.dataType && s.accepts[ s.dataType ] ?
4489+                               s.accepts[ s.dataType ] + ", */*" :
4490+                               s.accepts._default );
4491+               } catch(e){}
4492+
4493+               // Allow custom headers/mimetypes and early abort
4494+               if ( s.beforeSend && s.beforeSend(xhr, s) === false ) {
4495+                       // Handle the global AJAX counter
4496+                       if ( s.global && ! --jQuery.active )
4497+                               jQuery.event.trigger( "ajaxStop" );
4498+                       // close opended socket
4499+                       xhr.abort();
4500+                       return false;
4501+               }
4502+
4503+               if ( s.global )
4504+                       jQuery.event.trigger("ajaxSend", [xhr, s]);
4505+
4506+               // Wait for a response to come back
4507+               var onreadystatechange = function(isTimeout){
4508+                       // The request was aborted, clear the interval and decrement jQuery.active
4509+                       if (xhr.readyState == 0) {
4510+                               if (ival) {
4511+                                       // clear poll interval
4512+                                       clearInterval(ival);
4513+                                       ival = null;
4514+                                       // Handle the global AJAX counter
4515+                                       if ( s.global && ! --jQuery.active )
4516+                                               jQuery.event.trigger( "ajaxStop" );
4517+                               }
4518+                       // The transfer is complete and the data is available, or the request timed out
4519+                       } else if ( !requestDone && xhr && (xhr.readyState == 4 || isTimeout == "timeout") ) {
4520+                               requestDone = true;
4521+
4522+                               // clear poll interval
4523+                               if (ival) {
4524+                                       clearInterval(ival);
4525+                                       ival = null;
4526+                               }
4527+
4528+                               status = isTimeout == "timeout" ? "timeout" :
4529+                                       !jQuery.httpSuccess( xhr ) ? "error" :
4530+                                       s.ifModified && jQuery.httpNotModified( xhr, s.url ) ? "notmodified" :
4531+                                       "success";
4532+
4533+                               if ( status == "success" ) {
4534+                                       // Watch for, and catch, XML document parse errors
4535+                                       try {
4536+                                               // process the data (runs the xml through httpData regardless of callback)
4537+                                               data = jQuery.httpData( xhr, s.dataType, s );
4538+                                       } catch(e) {
4539+                                               status = "parsererror";
4540+                                       }
4541+                               }
4542+
4543+                               // Make sure that the request was successful or notmodified
4544+                               if ( status == "success" ) {
4545+                                       // Cache Last-Modified header, if ifModified mode.
4546+                                       var modRes;
4547+                                       try {
4548+                                               modRes = xhr.getResponseHeader("Last-Modified");
4549+                                       } catch(e) {} // swallow exception thrown by FF if header is not available
4550+
4551+                                       if ( s.ifModified && modRes )
4552+                                               jQuery.lastModified[s.url] = modRes;
4553+
4554+                                       // JSONP handles its own success callback
4555+                                       if ( !jsonp )
4556+                                               success();
4557+                               } else
4558+                                       jQuery.handleError(s, xhr, status);
4559+
4560+                               // Fire the complete handlers
4561+                               complete();
4562+
4563+                               if ( isTimeout )
4564+                                       xhr.abort();
4565+
4566+                               // Stop memory leaks
4567+                               if ( s.async )
4568+                                       xhr = null;
4569+                       }
4570+               };
4571+
4572+               if ( s.async ) {
4573+                       // don't attach the handler to the request, just poll it instead
4574+                       var ival = setInterval(onreadystatechange, 13);
4575+
4576+                       // Timeout checker
4577+                       if ( s.timeout > 0 )
4578+                               setTimeout(function(){
4579+                                       // Check to see if the request is still happening
4580+                                       if ( xhr && !requestDone )
4581+                                               onreadystatechange( "timeout" );
4582+                               }, s.timeout);
4583+               }
4584+
4585+               // Send the data
4586+               try {
4587+                       xhr.send(s.data);
4588+               } catch(e) {
4589+                       jQuery.handleError(s, xhr, null, e);
4590+               }
4591+
4592+               // firefox 1.5 doesn't fire statechange for sync requests
4593+               if ( !s.async )
4594+                       onreadystatechange();
4595+
4596+               function success(){
4597+                       // If a local callback was specified, fire it and pass it the data
4598+                       if ( s.success )
4599+                               s.success( data, status );
4600+
4601+                       // Fire the global callback
4602+                       if ( s.global )
4603+                               jQuery.event.trigger( "ajaxSuccess", [xhr, s] );
4604+               }
4605+
4606+               function complete(){
4607+                       // Process result
4608+                       if ( s.complete )
4609+                               s.complete(xhr, status);
4610+
4611+                       // The request was completed
4612+                       if ( s.global )
4613+                               jQuery.event.trigger( "ajaxComplete", [xhr, s] );
4614+
4615+                       // Handle the global AJAX counter
4616+                       if ( s.global && ! --jQuery.active )
4617+                               jQuery.event.trigger( "ajaxStop" );
4618+               }
4619+
4620+               // return XMLHttpRequest to allow aborting the request etc.
4621+               return xhr;
4622+       },
4623+
4624+       handleError: function( s, xhr, status, e ) {
4625+               // If a local callback was specified, fire it
4626+               if ( s.error ) s.error( xhr, status, e );
4627+
4628+               // Fire the global callback
4629+               if ( s.global )
4630+                       jQuery.event.trigger( "ajaxError", [xhr, s, e] );
4631+       },
4632+
4633+       // Counter for holding the number of active queries
4634+       active: 0,
4635+
4636+       // Determines if an XMLHttpRequest was successful or not
4637+       httpSuccess: function( xhr ) {
4638+               try {
4639+                       // IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
4640+                       return !xhr.status && location.protocol == "file:" ||
4641+                               ( xhr.status >= 200 && xhr.status < 300 ) || xhr.status == 304 || xhr.status == 1223;
4642+               } catch(e){}
4643+               return false;
4644+       },
4645+
4646+       // Determines if an XMLHttpRequest returns NotModified
4647+       httpNotModified: function( xhr, url ) {
4648+               try {
4649+                       var xhrRes = xhr.getResponseHeader("Last-Modified");
4650+
4651+                       // Firefox always returns 200. check Last-Modified date
4652+                       return xhr.status == 304 || xhrRes == jQuery.lastModified[url];
4653+               } catch(e){}
4654+               return false;
4655+       },
4656+
4657+       httpData: function( xhr, type, s ) {
4658+               var ct = xhr.getResponseHeader("content-type"),
4659+                       xml = type == "xml" || !type && ct && ct.indexOf("xml") >= 0,
4660+                       data = xml ? xhr.responseXML : xhr.responseText;
4661+
4662+               if ( xml && data.documentElement.tagName == "parsererror" )
4663+                       throw "parsererror";
4664+                       
4665+               // Allow a pre-filtering function to sanitize the response
4666+               // s != null is checked to keep backwards compatibility
4667+               if( s && s.dataFilter )
4668+                       data = s.dataFilter( data, type );
4669+
4670+               // The filter can actually parse the response
4671+               if( typeof data === "string" ){
4672+
4673+                       // If the type is "script", eval it in global context
4674+                       if ( type == "script" )
4675+                               jQuery.globalEval( data );
4676+
4677+                       // Get the JavaScript object, if JSON is used.
4678+                       if ( type == "json" )
4679+                               data = window["eval"]("(" + data + ")");
4680+               }
4681+               
4682+               return data;
4683+       },
4684+
4685+       // Serialize an array of form elements or a set of
4686+       // key/values into a query string
4687+       param: function( a ) {
4688+               var s = [ ];
4689+
4690+               function add( key, value ){
4691+                       s[ s.length ] = encodeURIComponent(key) + '=' + encodeURIComponent(value);
4692+               };
4693+
4694+               // If an array was passed in, assume that it is an array
4695+               // of form elements
4696+               if ( jQuery.isArray(a) || a.jquery )
4697+                       // Serialize the form elements
4698+                       jQuery.each( a, function(){
4699+                               add( this.name, this.value );
4700+                       });
4701+
4702+               // Otherwise, assume that it's an object of key/value pairs
4703+               else
4704+                       // Serialize the key/values
4705+                       for ( var j in a )
4706+                               // If the value is an array then the key names need to be repeated
4707+                               if ( jQuery.isArray(a[j]) )
4708+                                       jQuery.each( a[j], function(){
4709+                                               add( j, this );
4710+                                       });
4711+                               else
4712+                                       add( j, jQuery.isFunction(a[j]) ? a[j]() : a[j] );
4713+
4714+               // Return the resulting serialization
4715+               return s.join("&").replace(/%20/g, "+");
4716+       }
4717+
4718+});
4719+var elemdisplay = {},
4720+       timerId,
4721+       fxAttrs = [
4722+               // height animations
4723+               [ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
4724+               // width animations
4725+               [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
4726+               // opacity animations
4727+               [ "opacity" ]
4728+       ];
4729+
4730+function genFx( type, num ){
4731+       var obj = {};
4732+       jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function(){
4733+               obj[ this ] = type;
4734+       });
4735+       return obj;
4736+}
4737+
4738+jQuery.fn.extend({
4739+       show: function(speed,callback){
4740+               if ( speed ) {
4741+                       return this.animate( genFx("show", 3), speed, callback);
4742+               } else {
4743+                       for ( var i = 0, l = this.length; i < l; i++ ){
4744+                               var old = jQuery.data(this[i], "olddisplay");
4745+                               
4746+                               this[i].style.display = old || "";
4747+                               
4748+                               if ( jQuery.css(this[i], "display") === "none" ) {
4749+                                       var tagName = this[i].tagName, display;
4750+                                       
4751+                                       if ( elemdisplay[ tagName ] ) {
4752+                                               display = elemdisplay[ tagName ];
4753+                                       } else {
4754+                                               var elem = jQuery("<" + tagName + " />").appendTo("body");
4755+                                               
4756+                                               display = elem.css("display");
4757+                                               if ( display === "none" )
4758+                                                       display = "block";
4759+                                               
4760+                                               elem.remove();
4761+                                               
4762+                                               elemdisplay[ tagName ] = display;
4763+                                       }
4764+                                       
4765+                                       jQuery.data(this[i], "olddisplay", display);
4766+                               }
4767+                       }
4768+
4769+                       // Set the display of the elements in a second loop
4770+                       // to avoid the constant reflow
4771+                       for ( var i = 0, l = this.length; i < l; i++ ){
4772+                               this[i].style.display = jQuery.data(this[i], "olddisplay") || "";
4773+                       }
4774+                       
4775+                       return this;
4776+               }
4777+       },
4778+
4779+       hide: function(speed,callback){
4780+               if ( speed ) {
4781+                       return this.animate( genFx("hide", 3), speed, callback);
4782+               } else {
4783+                       for ( var i = 0, l = this.length; i < l; i++ ){
4784+                               var old = jQuery.data(this[i], "olddisplay");
4785+                               if ( !old && old !== "none" )
4786+                                       jQuery.data(this[i], "olddisplay", jQuery.css(this[i], "display"));
4787+                       }
4788+
4789+                       // Set the display of the elements in a second loop
4790+                       // to avoid the constant reflow
4791+                       for ( var i = 0, l = this.length; i < l; i++ ){
4792+                               this[i].style.display = "none";
4793+                       }
4794+
4795+                       return this;
4796+               }
4797+       },
4798+
4799+       // Save the old toggle function
4800+       _toggle: jQuery.fn.toggle,
4801+
4802+       toggle: function( fn, fn2 ){
4803+               var bool = typeof fn === "boolean";
4804+
4805+               return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ?
4806+                       this._toggle.apply( this, arguments ) :
4807+                       fn == null || bool ?
4808+                               this.each(function(){
4809+                                       var state = bool ? fn : jQuery(this).is(":hidden");
4810+                                       jQuery(this)[ state ? "show" : "hide" ]();
4811+                               }) :
4812+                               this.animate(genFx("toggle", 3), fn, fn2);
4813+       },
4814+
4815+       fadeTo: function(speed,to,callback){
4816+               return this.animate({opacity: to}, speed, callback);
4817+       },
4818+
4819+       animate: function( prop, speed, easing, callback ) {
4820+               var optall = jQuery.speed(speed, easing, callback);
4821+
4822+               return this[ optall.queue === false ? "each" : "queue" ](function(){
4823+               
4824+                       var opt = jQuery.extend({}, optall), p,
4825+                               hidden = this.nodeType == 1 && jQuery(this).is(":hidden"),
4826+                               self = this;
4827+       
4828+                       for ( p in prop ) {
4829+                               if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden )
4830+                                       return opt.complete.call(this);
4831+
4832+                               if ( ( p == "height" || p == "width" ) && this.style ) {
4833+                                       // Store display property
4834+                                       opt.display = jQuery.css(this, "display");
4835+
4836+                                       // Make sure that nothing sneaks out
4837+                                       opt.overflow = this.style.overflow;
4838+                               }
4839+                       }
4840+
4841+                       if ( opt.overflow != null )
4842+                               this.style.overflow = "hidden";
4843+
4844+                       opt.curAnim = jQuery.extend({}, prop);
4845+
4846+                       jQuery.each( prop, function(name, val){
4847+                               var e = new jQuery.fx( self, opt, name );
4848+
4849+                               if ( /toggle|show|hide/.test(val) )
4850+                                       e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop );
4851+                               else {
4852+                                       var parts = val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),
4853+                                               start = e.cur(true) || 0;
4854+
4855+                                       if ( parts ) {
4856+                                               var end = parseFloat(parts[2]),
4857+                                                       unit = parts[3] || "px";
4858+
4859+                                               // We need to compute starting value
4860+                                               if ( unit != "px" ) {
4861+                                                       self.style[ name ] = (end || 1) + unit;
4862+                                                       start = ((end || 1) / e.cur(true)) * start;
4863+                                                       self.style[ name ] = start + unit;
4864+                                               }
4865+
4866+                                               // If a +=/-= token was provided, we're doing a relative animation
4867+                                               if ( parts[1] )
4868+                                                       end = ((parts[1] == "-=" ? -1 : 1) * end) + start;
4869+
4870+                                               e.custom( start, end, unit );
4871+                                       } else
4872+                                               e.custom( start, val, "" );
4873+                               }
4874+                       });
4875+
4876+                       // For JS strict compliance
4877+                       return true;
4878+               });
4879+       },
4880+
4881+       stop: function(clearQueue, gotoEnd){
4882+               var timers = jQuery.timers;
4883+
4884+               if (clearQueue)
4885+                       this.queue([]);
4886+
4887+               this.each(function(){
4888+                       // go in reverse order so anything added to the queue during the loop is ignored
4889+                       for ( var i = timers.length - 1; i >= 0; i-- )
4890+                               if ( timers[i].elem == this ) {
4891+                                       if (gotoEnd)
4892+                                               // force the next step to be the last
4893+                                               timers[i](true);
4894+                                       timers.splice(i, 1);
4895+                               }
4896+               });
4897+
4898+               // start the next in the queue if the last step wasn't forced
4899+               if (!gotoEnd)
4900+                       this.dequeue();
4901+
4902+               return this;
4903+       }
4904+
4905+});
4906+
4907+// Generate shortcuts for custom animations
4908+jQuery.each({
4909+       slideDown: genFx("show", 1),
4910+       slideUp: genFx("hide", 1),
4911+       slideToggle: genFx("toggle", 1),
4912+       fadeIn: { opacity: "show" },
4913+       fadeOut: { opacity: "hide" }
4914+}, function( name, props ){
4915+       jQuery.fn[ name ] = function( speed, callback ){
4916+               return this.animate( props, speed, callback );
4917+       };
4918+});
4919+
4920+jQuery.extend({
4921+
4922+       speed: function(speed, easing, fn) {
4923+               var opt = typeof speed === "object" ? speed : {
4924+                       complete: fn || !fn && easing ||
4925+                               jQuery.isFunction( speed ) && speed,
4926+                       duration: speed,
4927+                       easing: fn && easing || easing && !jQuery.isFunction(easing) && easing
4928+               };
4929+
4930+               opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
4931+                       jQuery.fx.speeds[opt.duration] || jQuery.fx.speeds._default;
4932+
4933+               // Queueing
4934+               opt.old = opt.complete;
4935+               opt.complete = function(){
4936+                       if ( opt.queue !== false )
4937+                               jQuery(this).dequeue();
4938+                       if ( jQuery.isFunction( opt.old ) )
4939+                               opt.old.call( this );
4940+               };
4941+
4942+               return opt;
4943+       },
4944+
4945+       easing: {
4946+               linear: function( p, n, firstNum, diff ) {
4947+                       return firstNum + diff * p;
4948+               },
4949+               swing: function( p, n, firstNum, diff ) {
4950+                       return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
4951+               }
4952+       },
4953+
4954+       timers: [],
4955+
4956+       fx: function( elem, options, prop ){
4957+               this.options = options;
4958+               this.elem = elem;
4959+               this.prop = prop;
4960+
4961+               if ( !options.orig )
4962+                       options.orig = {};
4963+       }
4964+
4965+});
4966+
4967+jQuery.fx.prototype = {
4968+
4969+       // Simple function for setting a style value
4970+       update: function(){
4971+               if ( this.options.step )
4972+                       this.options.step.call( this.elem, this.now, this );
4973+
4974+               (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
4975+
4976+               // Set display property to block for height/width animations
4977+               if ( ( this.prop == "height" || this.prop == "width" ) && this.elem.style )
4978+                       this.elem.style.display = "block";
4979+       },
4980+
4981+       // Get the current size
4982+       cur: function(force){
4983+               if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) )
4984+                       return this.elem[ this.prop ];
4985+
4986+               var r = parseFloat(jQuery.css(this.elem, this.prop, force));
4987+               return r && r > -10000 ? r : parseFloat(jQuery.curCSS(this.elem, this.prop)) || 0;
4988+       },
4989+
4990+       // Start an animation from one number to another
4991+       custom: function(from, to, unit){
4992+               this.startTime = now();
4993+               this.start = from;
4994+               this.end = to;
4995+               this.unit = unit || this.unit || "px";
4996+               this.now = this.start;
4997+               this.pos = this.state = 0;
4998+
4999+               var self = this;
5000+               function t(gotoEnd){
5001+                       return self.step(gotoEnd);
5002+               }
5003+
5004+               t.elem = this.elem;
5005+
5006+               if ( t() && jQuery.timers.push(t) && !timerId ) {
5007+                       timerId = setInterval(function(){
5008+                               var timers = jQuery.timers;
5009+
5010+                               for ( var i = 0; i < timers.length; i++ )
5011+                                       if ( !timers[i]() )
5012+                                               timers.splice(i--, 1);
5013+
5014+                               if ( !timers.length ) {
5015+                                       clearInterval( timerId );
5016+                                       timerId = undefined;
5017+                               }
5018+                       }, 13);
5019+               }
5020+       },
5021+
5022+       // Simple 'show' function
5023+       show: function(){
5024+               // Remember where we started, so that we can go back to it later
5025+               this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
5026+               this.options.show = true;
5027+
5028+               // Begin the animation
5029+               // Make sure that we start at a small width/height to avoid any
5030+               // flash of content
5031+               this.custom(this.prop == "width" || this.prop == "height" ? 1 : 0, this.cur());
5032+
5033+               // Start by showing the element
5034+               jQuery(this.elem).show();
5035+       },
5036+
5037+       // Simple 'hide' function
5038+       hide: function(){
5039+               // Remember where we started, so that we can go back to it later
5040+               this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
5041+               this.options.hide = true;
5042+
5043+               // Begin the animation
5044+               this.custom(this.cur(), 0);
5045+       },
5046+
5047+       // Each step of an animation
5048+       step: function(gotoEnd){
5049+               var t = now();
5050+
5051+               if ( gotoEnd || t >= this.options.duration + this.startTime ) {
5052+                       this.now = this.end;
5053+                       this.pos = this.state = 1;
5054+                       this.update();
5055+
5056+                       this.options.curAnim[ this.prop ] = true;
5057+
5058+                       var done = true;
5059+                       for ( var i in this.options.curAnim )
5060+                               if ( this.options.curAnim[i] !== true )
5061+                                       done = false;
5062+
5063+                       if ( done ) {
5064+                               if ( this.options.display != null ) {
5065+                                       // Reset the overflow
5066+                                       this.elem.style.overflow = this.options.overflow;
5067+
5068+                                       // Reset the display
5069+                                       this.elem.style.display = this.options.display;
5070+                                       if ( jQuery.css(this.elem, "display") == "none" )
5071+                                               this.elem.style.display = "block";
5072+                               }
5073+
5074+                               // Hide the element if the "hide" operation was done
5075+                               if ( this.options.hide )
5076+                                       jQuery(this.elem).hide();
5077+
5078+                               // Reset the properties, if the item has been hidden or shown
5079+                               if ( this.options.hide || this.options.show )
5080+                                       for ( var p in this.options.curAnim )
5081+                                               jQuery.attr(this.elem.style, p, this.options.orig[p]);
5082+                                       
5083+                               // Execute the complete function
5084+                               this.options.complete.call( this.elem );
5085+                       }
5086+
5087+                       return false;
5088+               } else {
5089+                       var n = t - this.startTime;
5090+                       this.state = n / this.options.duration;
5091+
5092+                       // Perform the easing function, defaults to swing
5093+                       this.pos = jQuery.easing[this.options.easing || (jQuery.easing.swing ? "swing" : "linear")](this.state, n, 0, 1, this.options.duration);
5094+                       this.now = this.start + ((this.end - this.start) * this.pos);
5095+
5096+                       // Perform the next step of the animation
5097+                       this.update();
5098+               }
5099+
5100+               return true;
5101+       }
5102+
5103+};
5104+
5105+jQuery.extend( jQuery.fx, {
5106+       speeds:{
5107+               slow: 600,
5108+               fast: 200,
5109+               // Default speed
5110+               _default: 400
5111+       },
5112+       step: {
5113+
5114+               opacity: function(fx){
5115+                       jQuery.attr(fx.elem.style, "opacity", fx.now);
5116+               },
5117+
5118+               _default: function(fx){
5119+                       if ( fx.elem.style && fx.elem.style[ fx.prop ] != null )
5120+                               fx.elem.style[ fx.prop ] = fx.now + fx.unit;
5121+                       else
5122+                               fx.elem[ fx.prop ] = fx.now;
5123+               }
5124+       }
5125+});
5126+if ( document.documentElement["getBoundingClientRect"] )
5127+       jQuery.fn.offset = function() {
5128+               if ( !this[0] ) return { top: 0, left: 0 };
5129+               if ( this[0] === this[0].ownerDocument.body ) return jQuery.offset.bodyOffset( this[0] );
5130+               var box  = this[0].getBoundingClientRect(), doc = this[0].ownerDocument, body = doc.body, docElem = doc.documentElement,
5131+                       clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
5132+                       top  = box.top  + (self.pageYOffset || jQuery.boxModel && docElem.scrollTop  || body.scrollTop ) - clientTop,
5133+                       left = box.left + (self.pageXOffset || jQuery.boxModel && docElem.scrollLeft || body.scrollLeft) - clientLeft;
5134+               return { top: top, left: left };
5135+       };
5136+else
5137+       jQuery.fn.offset = function() {
5138+               if ( !this[0] ) return { top: 0, left: 0 };
5139+               if ( this[0] === this[0].ownerDocument.body ) return jQuery.offset.bodyOffset( this[0] );
5140+               jQuery.offset.initialized || jQuery.offset.initialize();
5141+
5142+               var elem = this[0], offsetParent = elem.offsetParent, prevOffsetParent = elem,
5143+                       doc = elem.ownerDocument, computedStyle, docElem = doc.documentElement,
5144+                       body = doc.body, defaultView = doc.defaultView,
5145+                       prevComputedStyle = defaultView.getComputedStyle(elem, null),
5146+                       top = elem.offsetTop, left = elem.offsetLeft;
5147+
5148+               while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
5149+                       computedStyle = defaultView.getComputedStyle(elem, null);
5150+                       top -= elem.scrollTop, left -= elem.scrollLeft;
5151+                       if ( elem === offsetParent ) {
5152+                               top += elem.offsetTop, left += elem.offsetLeft;
5153+                               if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && /^t(able|d|h)$/i.test(elem.tagName)) )
5154+                                       top  += parseInt( computedStyle.borderTopWidth,  10) || 0,
5155+                                       left += parseInt( computedStyle.borderLeftWidth, 10) || 0;
5156+                               prevOffsetParent = offsetParent, offsetParent = elem.offsetParent;
5157+                       }
5158+                       if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" )
5159+                               top  += parseInt( computedStyle.borderTopWidth,  10) || 0,
5160+                               left += parseInt( computedStyle.borderLeftWidth, 10) || 0;
5161+                       prevComputedStyle = computedStyle;
5162+               }
5163+
5164+               if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" )
5165+                       top  += body.offsetTop,
5166+                       left += body.offsetLeft;
5167+
5168+               if ( prevComputedStyle.position === "fixed" )
5169+                       top  += Math.max(docElem.scrollTop, body.scrollTop),
5170+                       left += Math.max(docElem.scrollLeft, body.scrollLeft);
5171+
5172+               return { top: top, left: left };
5173+       };
5174+
5175+jQuery.offset = {
5176+       initialize: function() {
5177+               if ( this.initialized ) return;
5178+               var body = document.body, container = document.createElement('div'), innerDiv, checkDiv, table, td, rules, prop, bodyMarginTop = body.style.marginTop,
5179+                       html = '<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>';
5180+
5181+               rules = { position: 'absolute', top: 0, left: 0, margin: 0, border: 0, width: '1px', height: '1px', visibility: 'hidden' };
5182+               for ( prop in rules ) container.style[prop] = rules[prop];
5183+
5184+               container.innerHTML = html;
5185+               body.insertBefore(container, body.firstChild);
5186+               innerDiv = container.firstChild, checkDiv = innerDiv.firstChild, td = innerDiv.nextSibling.firstChild.firstChild;
5187+
5188+               this.doesNotAddBorder = (checkDiv.offsetTop !== 5);
5189+               this.doesAddBorderForTableAndCells = (td.offsetTop === 5);
5190+
5191+               innerDiv.style.overflow = 'hidden', innerDiv.style.position = 'relative';
5192+               this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);
5193+
5194+               body.style.marginTop = '1px';
5195+               this.doesNotIncludeMarginInBodyOffset = (body.offsetTop === 0);
5196+               body.style.marginTop = bodyMarginTop;
5197+
5198+               body.removeChild(container);
5199+               this.initialized = true;
5200+       },
5201+
5202+       bodyOffset: function(body) {
5203+               jQuery.offset.initialized || jQuery.offset.initialize();
5204+               var top = body.offsetTop, left = body.offsetLeft;
5205+               if ( jQuery.offset.doesNotIncludeMarginInBodyOffset )
5206+                       top  += parseInt( jQuery.curCSS(body, 'marginTop',  true), 10 ) || 0,
5207+                       left += parseInt( jQuery.curCSS(body, 'marginLeft', true), 10 ) || 0;
5208+               return { top: top, left: left };
5209+       }
5210+};
5211+
5212+
5213+jQuery.fn.extend({
5214+       position: function() {
5215+               var left = 0, top = 0, results;
5216+
5217+               if ( this[0] ) {
5218+                       // Get *real* offsetParent
5219+                       var offsetParent = this.offsetParent(),
5220+
5221+                       // Get correct offsets
5222+                       offset       = this.offset(),
5223+                       parentOffset = /^body|html$/i.test(offsetParent[0].tagName) ? { top: 0, left: 0 } : offsetParent.offset();
5224+
5225+                       // Subtract element margins
5226+                       // note: when an element has margin: auto the offsetLeft and marginLeft
5227+                       // are the same in Safari causing offset.left to incorrectly be 0
5228+                       offset.top  -= num( this, 'marginTop'  );
5229+                       offset.left -= num( this, 'marginLeft' );
5230+
5231+                       // Add offsetParent borders
5232+                       parentOffset.top  += num( offsetParent, 'borderTopWidth'  );
5233+                       parentOffset.left += num( offsetParent, 'borderLeftWidth' );
5234+
5235+                       // Subtract the two offsets
5236+                       results = {
5237+                               top:  offset.top  - parentOffset.top,
5238+                               left: offset.left - parentOffset.left
5239+                       };
5240+               }
5241+
5242+               return results;
5243+       },
5244+
5245+       offsetParent: function() {
5246+               var offsetParent = this[0].offsetParent || document.body;
5247+               while ( offsetParent && (!/^body|html$/i.test(offsetParent.tagName) && jQuery.css(offsetParent, 'position') == 'static') )
5248+                       offsetParent = offsetParent.offsetParent;
5249+               return jQuery(offsetParent);
5250+       }
5251+});
5252+
5253+
5254+// Create scrollLeft and scrollTop methods
5255+jQuery.each( ['Left', 'Top'], function(i, name) {
5256+       var method = 'scroll' + name;
5257+       
5258+       jQuery.fn[ method ] = function(val) {
5259+               if (!this[0]) return null;
5260+
5261+               return val !== undefined ?
5262+
5263+                       // Set the scroll offset
5264+                       this.each(function() {
5265+                               this == window || this == document ?
5266+                                       window.scrollTo(
5267+                                               !i ? val : jQuery(window).scrollLeft(),
5268+                                                i ? val : jQuery(window).scrollTop()
5269+                                       ) :
5270+                                       this[ method ] = val;
5271+                       }) :
5272+
5273+                       // Return the scroll offset
5274+                       this[0] == window || this[0] == document ?
5275+                               self[ i ? 'pageYOffset' : 'pageXOffset' ] ||
5276+                                       jQuery.boxModel && document.documentElement[ method ] ||
5277+                                       document.body[ method ] :
5278+                               this[0][ method ];
5279+       };
5280+});
5281+// Create innerHeight, innerWidth, outerHeight and outerWidth methods
5282+jQuery.each([ "Height", "Width" ], function(i, name){
5283+
5284+       var tl = i ? "Left"  : "Top",  // top or left
5285+               br = i ? "Right" : "Bottom", // bottom or right
5286+               lower = name.toLowerCase();
5287+
5288+       // innerHeight and innerWidth
5289+       jQuery.fn["inner" + name] = function(){
5290+               return this[0] ?
5291+                       jQuery.css( this[0], lower, false, "padding" ) :
5292+                       null;
5293+       };
5294+
5295+       // outerHeight and outerWidth
5296+       jQuery.fn["outer" + name] = function(margin) {
5297+               return this[0] ?
5298+                       jQuery.css( this[0], lower, false, margin ? "margin" : "border" ) :
5299+                       null;
5300+       };
5301+       
5302+       var type = name.toLowerCase();
5303+
5304+       jQuery.fn[ type ] = function( size ) {
5305+               // Get window width or height
5306+               return this[0] == window ?
5307+                       // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
5308+                       document.compatMode == "CSS1Compat" && document.documentElement[ "client" + name ] ||
5309+                       document.body[ "client" + name ] :
5310+
5311+                       // Get document width or height
5312+                       this[0] == document ?
5313+                               // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
5314+                               Math.max(
5315+                                       document.documentElement["client" + name],
5316+                                       document.body["scroll" + name], document.documentElement["scroll" + name],
5317+                                       document.body["offset" + name], document.documentElement["offset" + name]
5318+                               ) :
5319+
5320+                               // Get or set width or height on the element
5321+                               size === undefined ?
5322+                                       // Get width or height on the element
5323+                                       (this.length ? jQuery.css( this[0], type ) : null) :
5324+
5325+                                       // Set the width or height on the element (default to pixels if value is unitless)
5326+                                       this.css( type, typeof size === "string" ? size : size + "px" );
5327+       };
5328+
5329+});
5330+})();
5331addfile ./src/allmydata/web/protovis-r3.2.js
5332hunk ./src/allmydata/web/protovis-r3.2.js 1
5333+// fba9dc2
5334+var a;if(!Array.prototype.map)Array.prototype.map=function(b,c){for(var d=this.length,f=new Array(d),g=0;g<d;g++)if(g in this)f[g]=b.call(c,this[g],g,this);return f};if(!Array.prototype.filter)Array.prototype.filter=function(b,c){for(var d=this.length,f=[],g=0;g<d;g++)if(g in this){var h=this[g];b.call(c,h,g,this)&&f.push(h)}return f};if(!Array.prototype.forEach)Array.prototype.forEach=function(b,c){for(var d=this.length>>>0,f=0;f<d;f++)f in this&&b.call(c,this[f],f,this)};
5335+if(!Array.prototype.reduce)Array.prototype.reduce=function(b,c){var d=this.length;if(!d&&arguments.length==1)throw new Error("reduce: empty array, no initial value");var f=0;if(arguments.length<2)for(;;){if(f in this){c=this[f++];break}if(++f>=d)throw new Error("reduce: no values, no initial value");}for(;f<d;f++)if(f in this)c=b(c,this[f],f,this);return c};var pv={};pv.version={major:3,minor:2};pv.identity=function(b){return b};pv.index=function(){return this.index};pv.child=function(){return this.childIndex};
5336+pv.parent=function(){return this.parent.index};pv.extend=function(b){function c(){}c.prototype=b.prototype||b;return new c};
5337+try{eval("pv.parse = function(x) x;")}catch(e){pv.parse=function(b){for(var c=new RegExp("function\\s*(\\b\\w+)?\\s*\\([^)]*\\)\\s*","mg"),d,f,g=0,h="";d=c.exec(b);){d=d.index+d[0].length;if(b.charAt(d)!="{"){h+=b.substring(g,d)+"{return ";g=d;for(var i=0;i>=0&&d<b.length;d++){var j=b.charAt(d);switch(j){case '"':case "'":for(;++d<b.length&&(f=b.charAt(d))!=j;)f=="\\"&&d++;break;case "[":case "(":i++;break;case "]":case ")":i--;break;case ";":case ",":i==0&&i--;break}}h+=pv.parse(b.substring(g,--d))+
5338+";}";g=d}c.lastIndex=d}h+=b.substring(g);return h}}pv.css=function(b,c){return window.getComputedStyle?window.getComputedStyle(b,null).getPropertyValue(c):b.currentStyle[c]};pv.error=function(b){typeof console=="undefined"?alert(b):console.error(b)};pv.listen=function(b,c,d){d=pv.listener(d);return b.addEventListener?b.addEventListener(c,d,false):b.attachEvent("on"+c,d)};pv.listener=function(b){return b.$listener||(b.$listener=function(c){try{pv.event=c;return b.call(this,c)}finally{delete pv.event}})};
5339+pv.ancestor=function(b,c){for(;c;){if(c==b)return true;c=c.parentNode}return false};pv.id=function(){var b=1;return function(){return b++}}();pv.functor=function(b){return typeof b=="function"?b:function(){return b}};pv.listen(window,"load",function(){for(pv.$={i:0,x:document.getElementsByTagName("script")};pv.$.i<pv.$.x.length;pv.$.i++){pv.$.s=pv.$.x[pv.$.i];if(pv.$.s.type=="text/javascript+protovis")try{window.eval(pv.parse(pv.$.s.text))}catch(b){pv.error(b)}}delete pv.$});pv.Format={};
5340+pv.Format.re=function(b){return b.replace(/[\\\^\$\*\+\?\[\]\(\)\.\{\}]/g,"\\$&")};pv.Format.pad=function(b,c,d){c=c-String(d).length;return c<1?d:(new Array(c+1)).join(b)+d};
5341+pv.Format.date=function(b){function c(f){return b.replace(/%[a-zA-Z0-9]/g,function(g){switch(g){case "%a":return["Sun","Mon","Tue","Wed","Thu","Fri","Sat"][f.getDay()];case "%A":return["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"][f.getDay()];case "%h":case "%b":return["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"][f.getMonth()];case "%B":return["January","February","March","April","May","June","July","August","September","October","November","December"][f.getMonth()];
5342+case "%c":return f.toLocaleString();case "%C":return d("0",2,Math.floor(f.getFullYear()/100)%100);case "%d":return d("0",2,f.getDate());case "%x":case "%D":return d("0",2,f.getMonth()+1)+"/"+d("0",2,f.getDate())+"/"+d("0",2,f.getFullYear()%100);case "%e":return d(" ",2,f.getDate());case "%H":return d("0",2,f.getHours());case "%I":return(g=f.getHours()%12)?d("0",2,g):12;case "%m":return d("0",2,f.getMonth()+1);case "%M":return d("0",2,f.getMinutes());case "%n":return"\n";case "%p":return f.getHours()<
5343+12?"AM":"PM";case "%T":case "%X":case "%r":g=f.getHours()%12;return(g?d("0",2,g):12)+":"+d("0",2,f.getMinutes())+":"+d("0",2,f.getSeconds())+" "+(f.getHours()<12?"AM":"PM");case "%R":return d("0",2,f.getHours())+":"+d("0",2,f.getMinutes());case "%S":return d("0",2,f.getSeconds());case "%Q":return d("0",3,f.getMilliseconds());case "%t":return"\t";case "%u":return(g=f.getDay())?g:1;case "%w":return f.getDay();case "%y":return d("0",2,f.getFullYear()%100);case "%Y":return f.getFullYear();case "%%":return"%"}return g})}
5344+var d=pv.Format.pad;c.format=c;c.parse=function(f){var g=1970,h=0,i=1,j=0,l=0,k=0,q=[function(){}],o=pv.Format.re(b).replace(/%[a-zA-Z0-9]/g,function(n){switch(n){case "%b":q.push(function(m){h={Jan:0,Feb:1,Mar:2,Apr:3,May:4,Jun:5,Jul:6,Aug:7,Sep:8,Oct:9,Nov:10,Dec:11}[m]});return"([A-Za-z]+)";case "%h":case "%B":q.push(function(m){h={January:0,February:1,March:2,April:3,May:4,June:5,July:6,August:7,September:8,October:9,November:10,December:11}[m]});return"([A-Za-z]+)";case "%e":case "%d":q.push(function(m){i=
5345+m});return"([0-9]+)";case "%I":case "%H":q.push(function(m){j=m});return"([0-9]+)";case "%m":q.push(function(m){h=m-1});return"([0-9]+)";case "%M":q.push(function(m){l=m});return"([0-9]+)";case "%p":q.push(function(m){if(j==12){if(m=="am")j=0}else if(m=="pm")j=Number(j)+12});return"(am|pm)";case "%S":q.push(function(m){k=m});return"([0-9]+)";case "%y":q.push(function(m){m=Number(m);g=m+(0<=m&&m<69?2E3:m>=69&&m<100?1900:0)});return"([0-9]+)";case "%Y":q.push(function(m){g=m});return"([0-9]+)";case "%%":q.push(function(){});
5346+return"%"}return n});(f=f.match(o))&&f.forEach(function(n,m){q[m](n)});return new Date(g,h,i,j,l,k)};return c};
5347+pv.Format.time=function(b){function c(f){f=Number(f);switch(b){case "short":if(f>=31536E6)return(f/31536E6).toFixed(1)+" years";else if(f>=6048E5)return(f/6048E5).toFixed(1)+" weeks";else if(f>=864E5)return(f/864E5).toFixed(1)+" days";else if(f>=36E5)return(f/36E5).toFixed(1)+" hours";else if(f>=6E4)return(f/6E4).toFixed(1)+" minutes";return(f/1E3).toFixed(1)+" seconds";case "long":var g=[],h=f%36E5/6E4>>0;g.push(d("0",2,f%6E4/1E3>>0));if(f>=36E5){var i=f%864E5/36E5>>0;g.push(d("0",2,h));if(f>=864E5){g.push(d("0",
5348+2,i));g.push(Math.floor(f/864E5).toFixed())}else g.push(i.toFixed())}else g.push(h.toFixed());return g.reverse().join(":")}}var d=pv.Format.pad;c.format=c;c.parse=function(f){switch(b){case "short":for(var g=/([0-9,.]+)\s*([a-z]+)/g,h,i=0;h=g.exec(f);){var j=parseFloat(h[0].replace(",","")),l=0;switch(h[2].toLowerCase()){case "year":case "years":l=31536E6;break;case "week":case "weeks":l=6048E5;break;case "day":case "days":l=864E5;break;case "hour":case "hours":l=36E5;break;case "minute":case "minutes":l=
5349+6E4;break;case "second":case "seconds":l=1E3;break}i+=j*l}return i;case "long":h=f.replace(",","").split(":").reverse();i=0;if(h.length)i+=parseFloat(h[0])*1E3;if(h.length>1)i+=parseFloat(h[1])*6E4;if(h.length>2)i+=parseFloat(h[2])*36E5;if(h.length>3)i+=parseFloat(h[3])*864E5;return i}};return c};
5350+pv.Format.number=function(){function b(n){if(Infinity>h)n=Math.round(n*i)/i;var m=String(Math.abs(n)).split("."),r=m[0];n=n<0?"-":"";if(r.length>d)r=r.substring(r.length-d);if(k&&r.length<c)r=n+(new Array(c-r.length+1)).join(j)+r;if(r.length>3)r=r.replace(/\B(?=(?:\d{3})+(?!\d))/g,o);if(!k&&r.length<f)r=(new Array(f-r.length+1)).join(j)+n+r;m[0]=r;r=m[1]||"";if(r.length<g)m[1]=r+(new Array(g-r.length+1)).join(l);return m.join(q)}var c=0,d=Infinity,f=0,g=0,h=0,i=1,j="0",l="0",k=true,q=".",o=",";b.format=
5351+b;b.parse=function(n){var m=pv.Format.re;n=String(n).replace(new RegExp("^("+m(j)+")*"),"").replace(new RegExp("("+m(l)+")*$"),"").split(q);m=n[0].replace(new RegExp(m(o),"g"),"");if(m.length>d)m=m.substring(m.length-d);n=n[1]?Number("0."+n[1]):0;if(Infinity>h)n=Math.round(n*i)/i;return Math.round(m)+n};b.integerDigits=function(n,m){if(arguments.length){c=Number(n);d=arguments.length>1?Number(m):c;f=c+Math.floor(c/3)*o.length;return this}return[c,d]};b.fractionDigits=function(n,m){if(arguments.length){g=
5352+Number(n);h=arguments.length>1?Number(m):g;i=Math.pow(10,h);return this}return[g,h]};b.integerPad=function(n){if(arguments.length){j=String(n);k=/\d/.test(j);return this}return j};b.fractionPad=function(n){if(arguments.length){l=String(n);return this}return l};b.decimal=function(n){if(arguments.length){q=String(n);return this}return q};b.group=function(n){if(arguments.length){o=n?String(n):"";f=c+Math.floor(c/3)*o.length;return this}return o};return b};
5353+pv.map=function(b,c){var d={};return c?b.map(function(f,g){d.index=g;return c.call(d,f)}):b.slice()};pv.repeat=function(b,c){if(arguments.length==1)c=2;return pv.blend(pv.range(c).map(function(){return b}))};pv.cross=function(b,c){for(var d=[],f=0,g=b.length,h=c.length;f<g;f++)for(var i=0,j=b[f];i<h;i++)d.push([j,c[i]]);return d};pv.blend=function(b){return Array.prototype.concat.apply([],b)};
5354+pv.transpose=function(b){var c=b.length,d=pv.max(b,function(i){return i.length});if(d>c){b.length=d;for(var f=c;f<d;f++)b[f]=new Array(c);for(f=0;f<c;f++)for(var g=f+1;g<d;g++){var h=b[f][g];b[f][g]=b[g][f];b[g][f]=h}}else{for(f=0;f<d;f++)b[f].length=c;for(f=0;f<c;f++)for(g=0;g<f;g++){h=b[f][g];b[f][g]=b[g][f];b[g][f]=h}}b.length=d;for(f=0;f<d;f++)b[f].length=c;return b};pv.normalize=function(b,c){b=pv.map(b,c);c=pv.sum(b);for(var d=0;d<b.length;d++)b[d]/=c;return b};
5355+pv.permute=function(b,c,d){if(!d)d=pv.identity;var f=new Array(c.length),g={};c.forEach(function(h,i){g.index=h;f[i]=d.call(g,b[h])});return f};pv.numerate=function(b,c){if(!c)c=pv.identity;var d={},f={};b.forEach(function(g,h){f.index=h;d[c.call(f,g)]=h});return d};pv.uniq=function(b,c){if(!c)c=pv.identity;var d={},f=[],g={},h;b.forEach(function(i,j){g.index=j;h=c.call(g,i);h in d||(d[h]=f.push(h))});return f};pv.naturalOrder=function(b,c){return b<c?-1:b>c?1:0};
5356+pv.reverseOrder=function(b,c){return c<b?-1:c>b?1:0};pv.search=function(b,c,d){if(!d)d=pv.identity;for(var f=0,g=b.length-1;f<=g;){var h=f+g>>1,i=d(b[h]);if(i<c)f=h+1;else if(i>c)g=h-1;else return h}return-f-1};pv.search.index=function(b,c,d){b=pv.search(b,c,d);return b<0?-b-1:b};
5357+pv.range=function(b,c,d){if(arguments.length==1){c=b;b=0}if(d==undefined)d=1;if((c-b)/d==Infinity)throw new Error("range must be finite");var f=[],g=0,h;if(d<0)for(;(h=b+d*g++)>c;)f.push(h);else for(;(h=b+d*g++)<c;)f.push(h);return f};pv.random=function(b,c,d){if(arguments.length==1){c=b;b=0}if(d==undefined)d=1;return d?Math.floor(Math.random()*(c-b)/d)*d+b:Math.random()*(c-b)+b};
5358+pv.sum=function(b,c){var d={};return b.reduce(c?function(f,g,h){d.index=h;return f+c.call(d,g)}:function(f,g){return f+g},0)};pv.max=function(b,c){if(c==pv.index)return b.length-1;return Math.max.apply(null,c?pv.map(b,c):b)};pv.max.index=function(b,c){if(!b.length)return-1;if(c==pv.index)return b.length-1;if(!c)c=pv.identity;for(var d=0,f=-Infinity,g={},h=0;h<b.length;h++){g.index=h;var i=c.call(g,b[h]);if(i>f){f=i;d=h}}return d};
5359+pv.min=function(b,c){if(c==pv.index)return 0;return Math.min.apply(null,c?pv.map(b,c):b)};pv.min.index=function(b,c){if(!b.length)return-1;if(c==pv.index)return 0;if(!c)c=pv.identity;for(var d=0,f=Infinity,g={},h=0;h<b.length;h++){g.index=h;var i=c.call(g,b[h]);if(i<f){f=i;d=h}}return d};pv.mean=function(b,c){return pv.sum(b,c)/b.length};
5360+pv.median=function(b,c){if(c==pv.index)return(b.length-1)/2;b=pv.map(b,c).sort(pv.naturalOrder);if(b.length%2)return b[Math.floor(b.length/2)];c=b.length/2;return(b[c-1]+b[c])/2};pv.variance=function(b,c){if(b.length<1)return NaN;if(b.length==1)return 0;var d=pv.mean(b,c),f=0,g={};if(!c)c=pv.identity;for(var h=0;h<b.length;h++){g.index=h;var i=c.call(g,b[h])-d;f+=i*i}return f};pv.deviation=function(b,c){return Math.sqrt(pv.variance(b,c)/(b.length-1))};pv.log=function(b,c){return Math.log(b)/Math.log(c)};
5361+pv.logSymmetric=function(b,c){return b==0?0:b<0?-pv.log(-b,c):pv.log(b,c)};pv.logAdjusted=function(b,c){if(!isFinite(b))return b;var d=b<0;if(b<c)b+=(c-b)/c;return d?-pv.log(b,c):pv.log(b,c)};pv.logFloor=function(b,c){return b>0?Math.pow(c,Math.floor(pv.log(b,c))):-Math.pow(c,-Math.floor(-pv.log(-b,c)))};pv.logCeil=function(b,c){return b>0?Math.pow(c,Math.ceil(pv.log(b,c))):-Math.pow(c,-Math.ceil(-pv.log(-b,c)))};
5362+(function(){var b=Math.PI/180,c=180/Math.PI;pv.radians=function(d){return b*d};pv.degrees=function(d){return c*d}})();pv.keys=function(b){var c=[];for(var d in b)c.push(d);return c};pv.entries=function(b){var c=[];for(var d in b)c.push({key:d,value:b[d]});return c};pv.values=function(b){var c=[];for(var d in b)c.push(b[d]);return c};pv.dict=function(b,c){for(var d={},f={},g=0;g<b.length;g++)if(g in b){var h=b[g];f.index=g;d[h]=c.call(f,h)}return d};pv.dom=function(b){return new pv.Dom(b)};
5363+pv.Dom=function(b){this.$map=b};pv.Dom.prototype.$leaf=function(b){return typeof b!="object"};pv.Dom.prototype.leaf=function(b){if(arguments.length){this.$leaf=b;return this}return this.$leaf};pv.Dom.prototype.root=function(b){function c(g){var h=new pv.Dom.Node;for(var i in g){var j=g[i];h.appendChild(d(j)?new pv.Dom.Node(j):c(j)).nodeName=i}return h}var d=this.$leaf,f=c(this.$map);f.nodeName=b;return f};pv.Dom.prototype.nodes=function(){return this.root().nodes()};
5364+pv.Dom.Node=function(b){this.nodeValue=b;this.childNodes=[]};a=pv.Dom.Node.prototype;a.parentNode=null;a.firstChild=null;a.lastChild=null;a.previousSibling=null;a.nextSibling=null;
5365+a.removeChild=function(b){var c=this.childNodes.indexOf(b);if(c==-1)throw new Error("child not found");this.childNodes.splice(c,1);if(b.previousSibling)b.previousSibling.nextSibling=b.nextSibling;else this.firstChild=b.nextSibling;if(b.nextSibling)b.nextSibling.previousSibling=b.previousSibling;else this.lastChild=b.previousSibling;delete b.nextSibling;delete b.previousSibling;delete b.parentNode;return b};
5366+a.appendChild=function(b){b.parentNode&&b.parentNode.removeChild(b);b.parentNode=this;if(b.previousSibling=this.lastChild)this.lastChild.nextSibling=b;else this.firstChild=b;this.lastChild=b;this.childNodes.push(b);return b};
5367+a.insertBefore=function(b,c){if(!c)return this.appendChild(b);var d=this.childNodes.indexOf(c);if(d==-1)throw new Error("child not found");b.parentNode&&b.parentNode.removeChild(b);b.parentNode=this;b.nextSibling=c;if(b.previousSibling=c.previousSibling)c.previousSibling.nextSibling=b;else{if(c==this.lastChild)this.lastChild=b;this.firstChild=b}this.childNodes.splice(d,0,b);return b};
5368+a.replaceChild=function(b,c){var d=this.childNodes.indexOf(c);if(d==-1)throw new Error("child not found");b.parentNode&&b.parentNode.removeChild(b);b.parentNode=this;b.nextSibling=c.nextSibling;if(b.previousSibling=c.previousSibling)c.previousSibling.nextSibling=b;else this.firstChild=b;if(c.nextSibling)c.nextSibling.previousSibling=b;else this.lastChild=b;this.childNodes[d]=b;return c};a.visitBefore=function(b){function c(d,f){b(d,f);for(d=d.firstChild;d;d=d.nextSibling)c(d,f+1)}c(this,0)};
5369+a.visitAfter=function(b){function c(d,f){for(var g=d.firstChild;g;g=g.nextSibling)c(g,f+1);b(d,f)}c(this,0)};a.sort=function(b){if(this.firstChild){this.childNodes.sort(b);var c=this.firstChild=this.childNodes[0],d;delete c.previousSibling;for(var f=1;f<this.childNodes.length;f++){c.sort(b);d=this.childNodes[f];d.previousSibling=c;c=c.nextSibling=d}this.lastChild=c;delete c.nextSibling;c.sort(b)}return this};
5370+a.reverse=function(){var b=[];this.visitAfter(function(c){for(;c.lastChild;)b.push(c.removeChild(c.lastChild));for(var d;d=b.pop();)c.insertBefore(d,c.firstChild)});return this};a.nodes=function(){function b(d){c.push(d);d.childNodes.forEach(b)}var c=[];b(this,c);return c};
5371+a.toggle=function(b){if(b)return this.toggled?this.visitBefore(function(d){d.toggled&&d.toggle()}):this.visitAfter(function(d){d.toggled||d.toggle()});b=this;if(b.toggled){for(var c;c=b.toggled.pop();)b.appendChild(c);delete b.toggled}else if(b.lastChild)for(b.toggled=[];b.lastChild;)b.toggled.push(b.removeChild(b.lastChild))};pv.nodes=function(b){for(var c=new pv.Dom.Node,d=0;d<b.length;d++)c.appendChild(new pv.Dom.Node(b[d]));return c.nodes()};pv.tree=function(b){return new pv.Tree(b)};
5372+pv.Tree=function(b){this.array=b};pv.Tree.prototype.keys=function(b){this.k=b;return this};pv.Tree.prototype.value=function(b){this.v=b;return this};pv.Tree.prototype.map=function(){for(var b={},c={},d=0;d<this.array.length;d++){c.index=d;for(var f=this.array[d],g=this.k.call(c,f),h=b,i=0;i<g.length-1;i++)h=h[g[i]]||(h[g[i]]={});h[g[i]]=this.v?this.v.call(c,f):f}return b};pv.nest=function(b){return new pv.Nest(b)};pv.Nest=function(b){this.array=b;this.keys=[]};a=pv.Nest.prototype;
5373+a.key=function(b){this.keys.push(b);return this};a.sortKeys=function(b){this.keys[this.keys.length-1].order=b||pv.naturalOrder;return this};a.sortValues=function(b){this.order=b||pv.naturalOrder;return this};a.map=function(){for(var b={},c=[],d,f=0;f<this.array.length;f++){var g=this.array[f],h=b;for(d=0;d<this.keys.length-1;d++){var i=this.keys[d](g);h[i]||(h[i]={});h=h[i]}i=this.keys[d](g);if(!h[i]){d=[];c.push(d);h[i]=d}h[i].push(g)}if(this.order)for(d=0;d<c.length;d++)c[d].sort(this.order);return b};
5374+a.entries=function(){function b(d){var f=[];for(var g in d){var h=d[g];f.push({key:g,values:h instanceof Array?h:b(h)})}return f}function c(d,f){var g=this.keys[f].order;g&&d.sort(function(i,j){return g(i.key,j.key)});if(++f<this.keys.length)for(var h=0;h<d.length;h++)c.call(this,d[h].values,f);return d}return c.call(this,b(this.map()),0)};a.rollup=function(b){function c(d){for(var f in d){var g=d[f];if(g instanceof Array)d[f]=b(g);else c(g)}return d}return c(this.map())};pv.flatten=function(b){return new pv.Flatten(b)};
5375+pv.Flatten=function(b){this.map=b;this.keys=[]};pv.Flatten.prototype.key=function(b,c){this.keys.push({name:b,value:c});delete this.$leaf;return this};pv.Flatten.prototype.leaf=function(b){this.keys.length=0;this.$leaf=b;return this};
5376+pv.Flatten.prototype.array=function(){function b(i,j){if(j<f.length-1)for(var l in i){d.push(l);b(i[l],j+1);d.pop()}else c.push(d.concat(i))}var c=[],d=[],f=this.keys,g=this.$leaf;if(g){function h(i,j){if(g(i))c.push({keys:d.slice(),value:i});else for(var l in i){d.push(l);h(i[l],j+1);d.pop()}}h(this.map,0);return c}b(this.map,0);return c.map(function(i){for(var j={},l=0;l<f.length;l++){var k=f[l],q=i[l];j[k.name]=k.value?k.value.call(null,q):q}return j})};
5377+pv.vector=function(b,c){return new pv.Vector(b,c)};pv.Vector=function(b,c){this.x=b;this.y=c};a=pv.Vector.prototype;a.perp=function(){return new pv.Vector(-this.y,this.x)};a.norm=function(){var b=this.length();return this.times(b?1/b:1)};a.length=function(){return Math.sqrt(this.x*this.x+this.y*this.y)};a.times=function(b){return new pv.Vector(this.x*b,this.y*b)};a.plus=function(b,c){return arguments.length==1?new pv.Vector(this.x+b.x,this.y+b.y):new pv.Vector(this.x+b,this.y+c)};
5378+a.minus=function(b,c){return arguments.length==1?new pv.Vector(this.x-b.x,this.y-b.y):new pv.Vector(this.x-b,this.y-c)};a.dot=function(b,c){return arguments.length==1?this.x*b.x+this.y*b.y:this.x*b+this.y*c};pv.Transform=function(){};pv.Transform.prototype={k:1,x:0,y:0};pv.Transform.identity=new pv.Transform;pv.Transform.prototype.translate=function(b,c){var d=new pv.Transform;d.k=this.k;d.x=this.k*b+this.x;d.y=this.k*c+this.y;return d};
5379+pv.Transform.prototype.scale=function(b){var c=new pv.Transform;c.k=this.k*b;c.x=this.x;c.y=this.y;return c};pv.Transform.prototype.invert=function(){var b=new pv.Transform,c=1/this.k;b.k=c;b.x=-this.x*c;b.y=-this.y*c;return b};pv.Transform.prototype.times=function(b){var c=new pv.Transform;c.k=this.k*b.k;c.x=this.k*b.x+this.x;c.y=this.k*b.y+this.y;return c};pv.Scale=function(){};
5380+pv.Scale.interpolator=function(b,c){if(typeof b=="number")return function(d){return d*(c-b)+b};b=pv.color(b).rgb();c=pv.color(c).rgb();return function(d){var f=b.a*(1-d)+c.a*d;if(f<1.0E-5)f=0;return b.a==0?pv.rgb(c.r,c.g,c.b,f):c.a==0?pv.rgb(b.r,b.g,b.b,f):pv.rgb(Math.round(b.r*(1-d)+c.r*d),Math.round(b.g*(1-d)+c.g*d),Math.round(b.b*(1-d)+c.b*d),f)}};
5381+pv.Scale.quantitative=function(){function b(o){return new Date(o)}function c(o){var n=pv.search(d,o);if(n<0)n=-n-2;n=Math.max(0,Math.min(h.length-1,n));return h[n]((l(o)-f[n])/(f[n+1]-f[n]))}var d=[0,1],f=[0,1],g=[0,1],h=[pv.identity],i=Number,j=false,l=pv.identity,k=pv.identity,q=String;c.transform=function(o,n){l=function(m){return j?-o(-m):o(m)};k=function(m){return j?-n(-m):n(m)};f=d.map(l);return this};c.domain=function(o,n,m){if(arguments.length){var r;if(o instanceof Array){if(arguments.length<
5382+2)n=pv.identity;if(arguments.length<3)m=n;r=o.length&&n(o[0]);d=o.length?[pv.min(o,n),pv.max(o,m)]:[]}else{r=o;d=Array.prototype.slice.call(arguments).map(Number)}if(d.length){if(d.length==1)d=[d[0],d[0]]}else d=[-Infinity,Infinity];j=(d[0]||d[d.length-1])<0;f=d.map(l);i=r instanceof Date?b:Number;return this}return d.map(i)};c.range=function(){if(arguments.length){g=Array.prototype.slice.call(arguments);if(g.length){if(g.length==1)g=[g[0],g[0]]}else g=[-Infinity,Infinity];h=[];for(var o=0;o<g.length-
5383+1;o++)h.push(pv.Scale.interpolator(g[o],g[o+1]));return this}return g};c.invert=function(o){var n=pv.search(g,o);if(n<0)n=-n-2;n=Math.max(0,Math.min(h.length-1,n));return i(k(f[n]+(o-g[n])/(g[n+1]-g[n])*(f[n+1]-f[n])))};c.ticks=function(o){var n=d[0],m=d[d.length-1],r=m<n,s=r?m:n;m=r?n:m;var u=m-s;if(!u||!isFinite(u)){if(i==b)q=pv.Format.date("%x");return[i(s)]}if(i==b){function x(w,y){switch(y){case 31536E6:w.setMonth(0);case 2592E6:w.setDate(1);case 6048E5:y==6048E5&&w.setDate(w.getDate()-w.getDay());
5384+case 864E5:w.setHours(0);case 36E5:w.setMinutes(0);case 6E4:w.setSeconds(0);case 1E3:w.setMilliseconds(0)}}var t,p,v=1;if(u>=94608E6){n=31536E6;t="%Y";p=function(w){w.setFullYear(w.getFullYear()+v)}}else if(u>=7776E6){n=2592E6;t="%m/%Y";p=function(w){w.setMonth(w.getMonth()+v)}}else if(u>=18144E5){n=6048E5;t="%m/%d";p=function(w){w.setDate(w.getDate()+7*v)}}else if(u>=2592E5){n=864E5;t="%m/%d";p=function(w){w.setDate(w.getDate()+v)}}else if(u>=108E5){n=36E5;t="%I:%M %p";p=function(w){w.setHours(w.getHours()+
5385+v)}}else if(u>=18E4){n=6E4;t="%I:%M %p";p=function(w){w.setMinutes(w.getMinutes()+v)}}else if(u>=3E3){n=1E3;t="%I:%M:%S";p=function(w){w.setSeconds(w.getSeconds()+v)}}else{n=1;t="%S.%Qs";p=function(w){w.setTime(w.getTime()+v)}}q=pv.Format.date(t);s=new Date(s);t=[];x(s,n);u=u/n;if(u>10)switch(n){case 36E5:v=u>20?6:3;s.setHours(Math.floor(s.getHours()/v)*v);break;case 2592E6:v=3;s.setMonth(Math.floor(s.getMonth()/v)*v);break;case 6E4:v=u>30?15:u>15?10:5;s.setMinutes(Math.floor(s.getMinutes()/v)*v);
5386+break;case 1E3:v=u>90?15:u>60?10:5;s.setSeconds(Math.floor(s.getSeconds()/v)*v);break;case 1:v=u>1E3?250:u>200?100:u>100?50:u>50?25:5;s.setMilliseconds(Math.floor(s.getMilliseconds()/v)*v);break;default:v=pv.logCeil(u/15,10);if(u/v<2)v/=5;else if(u/v<5)v/=2;s.setFullYear(Math.floor(s.getFullYear()/v)*v);break}for(;;){p(s);if(s>m)break;t.push(new Date(s))}return r?t.reverse():t}arguments.length||(o=10);v=pv.logFloor(u/o,10);n=o/(u/v);if(n<=0.15)v*=10;else if(n<=0.35)v*=5;else if(n<=0.75)v*=2;n=Math.ceil(s/
5387+v)*v;m=Math.floor(m/v)*v;q=pv.Format.number().fractionDigits(Math.max(0,-Math.floor(pv.log(v,10)+0.01)));m=pv.range(n,m+v,v);return r?m.reverse():m};c.tickFormat=function(o){return q(o)};c.nice=function(){if(d.length!=2)return this;var o=d[0],n=d[d.length-1],m=n<o,r=m?n:o;o=m?o:n;n=o-r;if(!n||!isFinite(n))return this;n=Math.pow(10,Math.round(Math.log(n)/Math.log(10))-1);d=[Math.floor(r/n)*n,Math.ceil(o/n)*n];m&&d.reverse();f=d.map(l);return this};c.by=function(o){function n(){return c(o.apply(this,
5388+arguments))}for(var m in c)n[m]=c[m];return n};c.domain.apply(c,arguments);return c};pv.Scale.linear=function(){var b=pv.Scale.quantitative();b.domain.apply(b,arguments);return b};
5389+pv.Scale.log=function(){var b=pv.Scale.quantitative(1,10),c,d,f=function(h){return Math.log(h)/d},g=function(h){return Math.pow(c,h)};b.ticks=function(){var h=b.domain(),i=h[0]<0,j=Math.floor(i?-f(-h[0]):f(h[0])),l=Math.ceil(i?-f(-h[1]):f(h[1])),k=[];if(i)for(k.push(-g(-j));j++<l;)for(i=c-1;i>0;i--)k.push(-g(-j)*i);else{for(;j<l;j++)for(i=1;i<c;i++)k.push(g(j)*i);k.push(g(j))}for(j=0;k[j]<h[0];j++);for(l=k.length;k[l-1]>h[1];l--);return k.slice(j,l)};b.tickFormat=function(h){return h.toPrecision(1)};
5390+b.nice=function(){var h=b.domain();return b.domain(pv.logFloor(h[0],c),pv.logCeil(h[1],c))};b.base=function(h){if(arguments.length){c=Number(h);d=Math.log(c);b.transform(f,g);return this}return c};b.domain.apply(b,arguments);return b.base(10)};pv.Scale.root=function(){var b=pv.Scale.quantitative();b.power=function(c){if(arguments.length){var d=Number(c),f=1/d;b.transform(function(g){return Math.pow(g,f)},function(g){return Math.pow(g,d)});return this}return d};b.domain.apply(b,arguments);return b.power(2)};
5391+pv.Scale.ordinal=function(){function b(g){g in d||(d[g]=c.push(g)-1);return f[d[g]%f.length]}var c=[],d={},f=[];b.domain=function(g,h){if(arguments.length){g=g instanceof Array?arguments.length>1?pv.map(g,h):g:Array.prototype.slice.call(arguments);c=[];for(var i={},j=0;j<g.length;j++){var l=g[j];if(!(l in i)){i[l]=true;c.push(l)}}d=pv.numerate(c);return this}return c};b.range=function(g,h){if(arguments.length){f=g instanceof Array?arguments.length>1?pv.map(g,h):g:Array.prototype.slice.call(arguments);
5392+if(typeof f[0]=="string")f=f.map(pv.color);return this}return f};b.split=function(g,h){var i=(h-g)/this.domain().length;f=pv.range(g+i/2,h,i);return this};b.splitFlush=function(g,h){var i=this.domain().length,j=(h-g)/(i-1);f=i==1?[(g+h)/2]:pv.range(g,h+j/2,j);return this};b.splitBanded=function(g,h,i){if(arguments.length<3)i=1;if(i<0){var j=this.domain().length;j=(h-g- -i*j)/(j+1);f=pv.range(g+j,h,j-i);f.band=-i}else{j=(h-g)/(this.domain().length+(1-i));f=pv.range(g+j*(1-i),h,j);f.band=j*i}return this};
5393+b.by=function(g){function h(){return b(g.apply(this,arguments))}for(var i in b)h[i]=b[i];return h};b.domain.apply(b,arguments);return b};
5394+pv.Scale.quantile=function(){function b(i){return h(Math.max(0,Math.min(d,pv.search.index(f,i)-1))/d)}var c=-1,d=-1,f=[],g=[],h=pv.Scale.linear();b.quantiles=function(i){if(arguments.length){c=Number(i);if(c<0){f=[g[0]].concat(g);d=g.length-1}else{f=[];f[0]=g[0];for(var j=1;j<=c;j++)f[j]=g[~~(j*(g.length-1)/c)];d=c-1}return this}return f};b.domain=function(i,j){if(arguments.length){g=i instanceof Array?pv.map(i,j):Array.prototype.slice.call(arguments);g.sort(pv.naturalOrder);b.quantiles(c);return this}return g};
5395+b.range=function(){if(arguments.length){h.range.apply(h,arguments);return this}return h.range()};b.by=function(i){function j(){return b(i.apply(this,arguments))}for(var l in b)j[l]=b[l];return j};b.domain.apply(b,arguments);return b};
5396+pv.histogram=function(b,c){var d=true;return{bins:function(f){var g=pv.map(b,c),h=[];arguments.length||(f=pv.Scale.linear(g).ticks());for(var i=0;i<f.length-1;i++){var j=h[i]=[];j.x=f[i];j.dx=f[i+1]-f[i];j.y=0}for(i=0;i<g.length;i++){j=pv.search.index(f,g[i])-1;j=h[Math.max(0,Math.min(h.length-1,j))];j.y++;j.push(b[i])}if(!d)for(i=0;i<h.length;i++)h[i].y/=g.length;return h},frequency:function(f){if(arguments.length){d=Boolean(f);return this}return d}}};
5397+pv.color=function(b){if(b.rgb)return b.rgb();var c=/([a-z]+)\((.*)\)/i.exec(b);if(c){var d=c[2].split(","),f=1;switch(c[1]){case "hsla":case "rgba":f=parseFloat(d[3]);if(!f)return pv.Color.transparent;break}switch(c[1]){case "hsla":case "hsl":b=parseFloat(d[0]);var g=parseFloat(d[1])/100;d=parseFloat(d[2])/100;return(new pv.Color.Hsl(b,g,d,f)).rgb();case "rgba":case "rgb":function h(l){var k=parseFloat(l);return l[l.length-1]=="%"?Math.round(k*2.55):k}g=h(d[0]);var i=h(d[1]),j=h(d[2]);return pv.rgb(g,
5398+i,j,f)}}if(f=pv.Color.names[b])return f;if(b.charAt(0)=="#"){if(b.length==4){g=b.charAt(1);g+=g;i=b.charAt(2);i+=i;j=b.charAt(3);j+=j}else if(b.length==7){g=b.substring(1,3);i=b.substring(3,5);j=b.substring(5,7)}return pv.rgb(parseInt(g,16),parseInt(i,16),parseInt(j,16),1)}return new pv.Color(b,1)};pv.Color=function(b,c){this.color=b;this.opacity=c};pv.Color.prototype.brighter=function(b){return this.rgb().brighter(b)};pv.Color.prototype.darker=function(b){return this.rgb().darker(b)};
5399+pv.rgb=function(b,c,d,f){return new pv.Color.Rgb(b,c,d,arguments.length==4?f:1)};pv.Color.Rgb=function(b,c,d,f){pv.Color.call(this,f?"rgb("+b+","+c+","+d+")":"none",f);this.r=b;this.g=c;this.b=d;this.a=f};pv.Color.Rgb.prototype=pv.extend(pv.Color);a=pv.Color.Rgb.prototype;a.red=function(b){return pv.rgb(b,this.g,this.b,this.a)};a.green=function(b){return pv.rgb(this.r,b,this.b,this.a)};a.blue=function(b){return pv.rgb(this.r,this.g,b,this.a)};
5400+a.alpha=function(b){return pv.rgb(this.r,this.g,this.b,b)};a.rgb=function(){return this};a.brighter=function(b){b=Math.pow(0.7,arguments.length?b:1);var c=this.r,d=this.g,f=this.b;if(!c&&!d&&!f)return pv.rgb(30,30,30,this.a);if(c&&c<30)c=30;if(d&&d<30)d=30;if(f&&f<30)f=30;return pv.rgb(Math.min(255,Math.floor(c/b)),Math.min(255,Math.floor(d/b)),Math.min(255,Math.floor(f/b)),this.a)};
5401+a.darker=function(b){b=Math.pow(0.7,arguments.length?b:1);return pv.rgb(Math.max(0,Math.floor(b*this.r)),Math.max(0,Math.floor(b*this.g)),Math.max(0,Math.floor(b*this.b)),this.a)};pv.hsl=function(b,c,d,f){return new pv.Color.Hsl(b,c,d,arguments.length==4?f:1)};pv.Color.Hsl=function(b,c,d,f){pv.Color.call(this,"hsl("+b+","+c*100+"%,"+d*100+"%)",f);this.h=b;this.s=c;this.l=d;this.a=f};pv.Color.Hsl.prototype=pv.extend(pv.Color);a=pv.Color.Hsl.prototype;
5402+a.hue=function(b){return pv.hsl(b,this.s,this.l,this.a)};a.saturation=function(b){return pv.hsl(this.h,b,this.l,this.a)};a.lightness=function(b){return pv.hsl(this.h,this.s,b,this.a)};a.alpha=function(b){return pv.hsl(this.h,this.s,this.l,b)};
5403+a.rgb=function(){function b(j){if(j>360)j-=360;else if(j<0)j+=360;if(j<60)return i+(h-i)*j/60;if(j<180)return h;if(j<240)return i+(h-i)*(240-j)/60;return i}function c(j){return Math.round(b(j)*255)}var d=this.h,f=this.s,g=this.l;d%=360;if(d<0)d+=360;f=Math.max(0,Math.min(f,1));g=Math.max(0,Math.min(g,1));var h=g<=0.5?g*(1+f):g+f-g*f,i=2*g-h;return pv.rgb(c(d+120),c(d),c(d-120),this.a)};
5404+pv.Color.names={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",
5405+darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",
5406+ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",
5407+lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",
5408+moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",
5409+seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32",transparent:pv.Color.transparent=pv.rgb(0,0,0,0)};(function(){var b=pv.Color.names;for(var c in b)b[c]=pv.color(b[c])})();
5410+pv.colors=function(){var b=pv.Scale.ordinal();b.range.apply(b,arguments);return b};pv.Colors={};pv.Colors.category10=function(){var b=pv.colors("#1f77b4","#ff7f0e","#2ca02c","#d62728","#9467bd","#8c564b","#e377c2","#7f7f7f","#bcbd22","#17becf");b.domain.apply(b,arguments);return b};
5411+pv.Colors.category20=function(){var b=pv.colors("#1f77b4","#aec7e8","#ff7f0e","#ffbb78","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5","#8c564b","#c49c94","#e377c2","#f7b6d2","#7f7f7f","#c7c7c7","#bcbd22","#dbdb8d","#17becf","#9edae5");b.domain.apply(b,arguments);return b};
5412+pv.Colors.category19=function(){var b=pv.colors("#9c9ede","#7375b5","#4a5584","#cedb9c","#b5cf6b","#8ca252","#637939","#e7cb94","#e7ba52","#bd9e39","#8c6d31","#e7969c","#d6616b","#ad494a","#843c39","#de9ed6","#ce6dbd","#a55194","#7b4173");b.domain.apply(b,arguments);return b};pv.ramp=function(){var b=pv.Scale.linear();b.range.apply(b,arguments);return b};
5413+pv.Scene=pv.SvgScene={svg:"http://www.w3.org/2000/svg",xmlns:"http://www.w3.org/2000/xmlns",xlink:"http://www.w3.org/1999/xlink",xhtml:"http://www.w3.org/1999/xhtml",scale:1,events:["DOMMouseScroll","mousewheel","mousedown","mouseup","mouseover","mouseout","mousemove","click","dblclick"],implicit:{svg:{"shape-rendering":"auto","pointer-events":"painted",x:0,y:0,dy:0,"text-anchor":"start",transform:"translate(0,0)",fill:"none","fill-opacity":1,stroke:"none","stroke-opacity":1,"stroke-width":1.5,"stroke-linejoin":"miter"},
5414+css:{font:"10px sans-serif"}}};pv.SvgScene.updateAll=function(b){if(b.length&&b[0].reverse&&b.type!="line"&&b.type!="area"){for(var c=pv.extend(b),d=0,f=b.length-1;f>=0;d++,f--)c[d]=b[f];b=c}this.removeSiblings(this[b.type](b))};pv.SvgScene.create=function(b){return document.createElementNS(this.svg,b)};
5415+pv.SvgScene.expect=function(b,c,d,f){if(b){if(b.tagName=="a")b=b.firstChild;if(b.tagName!=c){c=this.create(c);b.parentNode.replaceChild(c,b);b=c}}else b=this.create(c);for(var g in d){c=d[g];if(c==this.implicit.svg[g])c=null;c==null?b.removeAttribute(g):b.setAttribute(g,c)}for(g in f){c=f[g];if(c==this.implicit.css[g])c=null;if(c==null)b.style.removeProperty(g);else b.style[g]=c}return b};
5416+pv.SvgScene.append=function(b,c,d){b.$scene={scenes:c,index:d};b=this.title(b,c[d]);b.parentNode||c.$g.appendChild(b);return b.nextSibling};pv.SvgScene.title=function(b,c){var d=b.parentNode;if(d&&d.tagName!="a")d=null;if(c.title){if(!d){d=this.create("a");b.parentNode&&b.parentNode.replaceChild(d,b);d.appendChild(b)}d.setAttributeNS(this.xlink,"title",c.title);return d}d&&d.parentNode.replaceChild(b,d);return b};
5417+pv.SvgScene.dispatch=pv.listener(function(b){var c=b.target.$scene;if(c){var d=b.type;switch(d){case "DOMMouseScroll":d="mousewheel";b.wheel=-480*b.detail;break;case "mousewheel":b.wheel=(window.opera?12:1)*b.wheelDelta;break}pv.Mark.dispatch(d,c.scenes,c.index)&&b.preventDefault()}});pv.SvgScene.removeSiblings=function(b){for(;b;){var c=b.nextSibling;b.parentNode.removeChild(b);b=c}};pv.SvgScene.undefined=function(){};
5418+pv.SvgScene.pathBasis=function(){function b(f,g,h,i,j){return{x:f[0]*g.left+f[1]*h.left+f[2]*i.left+f[3]*j.left,y:f[0]*g.top+f[1]*h.top+f[2]*i.top+f[3]*j.top}}var c=[[1/6,2/3,1/6,0],[0,2/3,1/3,0],[0,1/3,2/3,0],[0,1/6,2/3,1/6]],d=function(f,g,h,i){var j=b(c[1],f,g,h,i),l=b(c[2],f,g,h,i);f=b(c[3],f,g,h,i);return"C"+j.x+","+j.y+","+l.x+","+l.y+","+f.x+","+f.y};d.segment=function(f,g,h,i){var j=b(c[0],f,g,h,i),l=b(c[1],f,g,h,i),k=b(c[2],f,g,h,i);f=b(c[3],f,g,h,i);return"M"+j.x+","+j.y+"C"+l.x+","+l.y+
5419+","+k.x+","+k.y+","+f.x+","+f.y};return d}();pv.SvgScene.curveBasis=function(b){if(b.length<=2)return"";var c="",d=b[0],f=d,g=d,h=b[1];c+=this.pathBasis(d,f,g,h);for(var i=2;i<b.length;i++){d=f;f=g;g=h;h=b[i];c+=this.pathBasis(d,f,g,h)}c+=this.pathBasis(f,g,h,h);c+=this.pathBasis(g,h,h,h);return c};
5420+pv.SvgScene.curveBasisSegments=function(b){if(b.length<=2)return"";var c=[],d=b[0],f=d,g=d,h=b[1],i=this.pathBasis.segment(d,f,g,h);d=f;f=g;g=h;h=b[2];c.push(i+this.pathBasis(d,f,g,h));for(i=3;i<b.length;i++){d=f;f=g;g=h;h=b[i];c.push(this.pathBasis.segment(d,f,g,h))}c.push(this.pathBasis.segment(f,g,h,h)+this.pathBasis(g,h,h,h));return c};
5421+pv.SvgScene.curveHermite=function(b,c){if(c.length<1||b.length!=c.length&&b.length!=c.length+2)return"";var d=b.length!=c.length,f="",g=b[0],h=b[1],i=c[0],j=i,l=1;if(d){f+="Q"+(h.left-i.x*2/3)+","+(h.top-i.y*2/3)+","+h.left+","+h.top;g=b[1];l=2}if(c.length>1){j=c[1];h=b[l];l++;f+="C"+(g.left+i.x)+","+(g.top+i.y)+","+(h.left-j.x)+","+(h.top-j.y)+","+h.left+","+h.top;for(g=2;g<c.length;g++,l++){h=b[l];j=c[g];f+="S"+(h.left-j.x)+","+(h.top-j.y)+","+h.left+","+h.top}}if(d){b=b[l];f+="Q"+(h.left+j.x*2/
5422+3)+","+(h.top+j.y*2/3)+","+b.left+","+b.top}return f};
5423+pv.SvgScene.curveHermiteSegments=function(b,c){if(c.length<1||b.length!=c.length&&b.length!=c.length+2)return[];var d=b.length!=c.length,f=[],g=b[0],h=g,i=c[0],j=i,l=1;if(d){h=b[1];f.push("M"+g.left+","+g.top+"Q"+(h.left-j.x*2/3)+","+(h.top-j.y*2/3)+","+h.left+","+h.top);l=2}for(var k=1;k<c.length;k++,l++){g=h;i=j;h=b[l];j=c[k];f.push("M"+g.left+","+g.top+"C"+(g.left+i.x)+","+(g.top+i.y)+","+(h.left-j.x)+","+(h.top-j.y)+","+h.left+","+h.top)}if(d){b=b[l];f.push("M"+h.left+","+h.top+"Q"+(h.left+j.x*
5424+2/3)+","+(h.top+j.y*2/3)+","+b.left+","+b.top)}return f};pv.SvgScene.cardinalTangents=function(b,c){var d=[];c=(1-c)/2;for(var f=b[0],g=b[1],h=b[2],i=3;i<b.length;i++){d.push({x:c*(h.left-f.left),y:c*(h.top-f.top)});f=g;g=h;h=b[i]}d.push({x:c*(h.left-f.left),y:c*(h.top-f.top)});return d};pv.SvgScene.curveCardinal=function(b,c){if(b.length<=2)return"";return this.curveHermite(b,this.cardinalTangents(b,c))};
5425+pv.SvgScene.curveCardinalSegments=function(b,c){if(b.length<=2)return"";return this.curveHermiteSegments(b,this.cardinalTangents(b,c))};
5426+pv.SvgScene.monotoneTangents=function(b){var c=[],d=[],f=[],g=[],h=0;for(h=0;h<b.length-1;h++)d[h]=(b[h+1].top-b[h].top)/(b[h+1].left-b[h].left);f[0]=d[0];g[0]=b[1].left-b[0].left;for(h=1;h<b.length-1;h++){f[h]=(d[h-1]+d[h])/2;g[h]=(b[h+1].left-b[h-1].left)/2}f[h]=d[h-1];g[h]=b[h].left-b[h-1].left;for(h=0;h<b.length-1;h++)if(d[h]==0){f[h]=0;f[h+1]=0}for(h=0;h<b.length-1;h++)if(!(Math.abs(f[h])<1.0E-5||Math.abs(f[h+1])<1.0E-5)){var i=f[h]/d[h],j=f[h+1]/d[h],l=i*i+j*j;if(l>9){l=3/Math.sqrt(l);f[h]=
5427+l*i*d[h];f[h+1]=l*j*d[h]}}for(h=0;h<b.length;h++){d=1+f[h]*f[h];c.push({x:g[h]/3/d,y:f[h]*g[h]/3/d})}return c};pv.SvgScene.curveMonotone=function(b){if(b.length<=2)return"";return this.curveHermite(b,this.monotoneTangents(b))};pv.SvgScene.curveMonotoneSegments=function(b){if(b.length<=2)return"";return this.curveHermiteSegments(b,this.monotoneTangents(b))};
5428+pv.SvgScene.area=function(b){function c(o,n){for(var m=[],r=[],s=n;o<=s;o++,n--){var u=b[o],x=b[n];u=u.left+","+u.top;x=x.left+x.width+","+(x.top+x.height);if(o<s){var t=b[o+1],p=b[n-1];switch(g.interpolate){case "step-before":u+="V"+t.top;x+="H"+(p.left+p.width);break;case "step-after":u+="H"+t.left;x+="V"+(p.top+p.height);break}}m.push(u);r.push(x)}return m.concat(r).join("L")}function d(o,n){for(var m=[],r=[],s=n;o<=s;o++,n--){var u=b[n];m.push(b[o]);r.push({left:u.left+u.width,top:u.top+u.height})}if(g.interpolate==
5429+"basis"){o=pv.SvgScene.curveBasis(m);n=pv.SvgScene.curveBasis(r)}else if(g.interpolate=="cardinal"){o=pv.SvgScene.curveCardinal(m,g.tension);n=pv.SvgScene.curveCardinal(r,g.tension)}else{o=pv.SvgScene.curveMonotone(m);n=pv.SvgScene.curveMonotone(r)}return m[0].left+","+m[0].top+o+"L"+r[0].left+","+r[0].top+n}var f=b.$g.firstChild;if(!b.length)return f;var g=b[0];if(g.segmented)return this.areaSegment(b);if(!g.visible)return f;var h=g.fillStyle,i=g.strokeStyle;if(!h.opacity&&!i.opacity)return f;for(var j=
5430+[],l,k=0;k<b.length;k++){l=b[k];if(l.width||l.height){for(var q=k+1;q<b.length;q++){l=b[q];if(!l.width&&!l.height)break}k&&g.interpolate!="step-after"&&k--;q<b.length&&g.interpolate!="step-before"&&q++;j.push((q-k>2&&(g.interpolate=="basis"||g.interpolate=="cardinal"||g.interpolate=="monotone")?d:c)(k,q-1));k=q-1}}if(!j.length)return f;f=this.expect(f,"path",{"shape-rendering":g.antialias?null:"crispEdges","pointer-events":g.events,cursor:g.cursor,d:"M"+j.join("ZM")+"Z",fill:h.color,"fill-opacity":h.opacity||
5431+null,stroke:i.color,"stroke-opacity":i.opacity||null,"stroke-width":i.opacity?g.lineWidth/this.scale:null});return this.append(f,b,0)};
5432+pv.SvgScene.areaSegment=function(b){var c=b.$g.firstChild,d=b[0],f,g;if(d.interpolate=="basis"||d.interpolate=="cardinal"||d.interpolate=="monotone"){f=[];g=[];for(var h=0,i=b.length;h<i;h++){var j=b[i-h-1];f.push(b[h]);g.push({left:j.left+j.width,top:j.top+j.height})}if(d.interpolate=="basis"){f=this.curveBasisSegments(f);g=this.curveBasisSegments(g)}else if(d.interpolate=="cardinal"){f=this.curveCardinalSegments(f,d.tension);g=this.curveCardinalSegments(g,d.tension)}else{f=this.curveMonotoneSegments(f);
5433+g=this.curveMonotoneSegments(g)}}h=0;for(i=b.length-1;h<i;h++){d=b[h];var l=b[h+1];if(d.visible&&l.visible){var k=d.fillStyle,q=d.strokeStyle;if(k.opacity||q.opacity){if(f){j=f[h];l="L"+g[i-h-1].substr(1);j=j+l+"Z"}else{var o=d;j=l;switch(d.interpolate){case "step-before":o=l;break;case "step-after":j=d;break}j="M"+d.left+","+o.top+"L"+l.left+","+j.top+"L"+(l.left+l.width)+","+(j.top+j.height)+"L"+(d.left+d.width)+","+(o.top+o.height)+"Z"}c=this.expect(c,"path",{"shape-rendering":d.antialias?null:
5434+"crispEdges","pointer-events":d.events,cursor:d.cursor,d:j,fill:k.color,"fill-opacity":k.opacity||null,stroke:q.color,"stroke-opacity":q.opacity||null,"stroke-width":q.opacity?d.lineWidth/this.scale:null});c=this.append(c,b,h)}}}return c};
5435+pv.SvgScene.bar=function(b){for(var c=b.$g.firstChild,d=0;d<b.length;d++){var f=b[d];if(f.visible){var g=f.fillStyle,h=f.strokeStyle;if(g.opacity||h.opacity){c=this.expect(c,"rect",{"shape-rendering":f.antialias?null:"crispEdges","pointer-events":f.events,cursor:f.cursor,x:f.left,y:f.top,width:Math.max(1.0E-10,f.width),height:Math.max(1.0E-10,f.height),fill:g.color,"fill-opacity":g.opacity||null,stroke:h.color,"stroke-opacity":h.opacity||null,"stroke-width":h.opacity?f.lineWidth/this.scale:null});
5436+c=this.append(c,b,d)}}}return c};
5437+pv.SvgScene.dot=function(b){for(var c=b.$g.firstChild,d=0;d<b.length;d++){var f=b[d];if(f.visible){var g=f.fillStyle,h=f.strokeStyle;if(g.opacity||h.opacity){var i=f.radius,j=null;switch(f.shape){case "cross":j="M"+-i+","+-i+"L"+i+","+i+"M"+i+","+-i+"L"+-i+","+i;break;case "triangle":j=i;var l=i*1.1547;j="M0,"+j+"L"+l+","+-j+" "+-l+","+-j+"Z";break;case "diamond":i*=Math.SQRT2;j="M0,"+-i+"L"+i+",0 0,"+i+" "+-i+",0Z";break;case "square":j="M"+-i+","+-i+"L"+i+","+-i+" "+i+","+i+" "+-i+","+i+"Z";break;
5438+case "tick":j="M0,0L0,"+-f.size;break;case "bar":j="M0,"+f.size/2+"L0,"+-(f.size/2);break}g={"shape-rendering":f.antialias?null:"crispEdges","pointer-events":f.events,cursor:f.cursor,fill:g.color,"fill-opacity":g.opacity||null,stroke:h.color,"stroke-opacity":h.opacity||null,"stroke-width":h.opacity?f.lineWidth/this.scale:null};if(j){g.transform="translate("+f.left+","+f.top+")";if(f.angle)g.transform+=" rotate("+180*f.angle/Math.PI+")";g.d=j;c=this.expect(c,"path",g)}else{g.cx=f.left;g.cy=f.top;g.r=
5439+i;c=this.expect(c,"circle",g)}c=this.append(c,b,d)}}}return c};
5440+pv.SvgScene.image=function(b){for(var c=b.$g.firstChild,d=0;d<b.length;d++){var f=b[d];if(f.visible){c=this.fill(c,b,d);if(f.image){c=this.expect(c,"foreignObject",{cursor:f.cursor,x:f.left,y:f.top,width:f.width,height:f.height});var g=c.firstChild||c.appendChild(document.createElementNS(this.xhtml,"canvas"));g.$scene={scenes:b,index:d};g.style.width=f.width;g.style.height=f.height;g.width=f.imageWidth;g.height=f.imageHeight;g.getContext("2d").putImageData(f.image,0,0)}else{c=this.expect(c,"image",
5441+{preserveAspectRatio:"none",cursor:f.cursor,x:f.left,y:f.top,width:f.width,height:f.height});c.setAttributeNS(this.xlink,"href",f.url)}c=this.append(c,b,d);c=this.stroke(c,b,d)}}return c};
5442+pv.SvgScene.label=function(b){for(var c=b.$g.firstChild,d=0;d<b.length;d++){var f=b[d];if(f.visible){var g=f.textStyle;if(g.opacity&&f.text){var h=0,i=0,j=0,l="start";switch(f.textBaseline){case "middle":j=".35em";break;case "top":j=".71em";i=f.textMargin;break;case "bottom":i="-"+f.textMargin;break}switch(f.textAlign){case "right":l="end";h="-"+f.textMargin;break;case "center":l="middle";break;case "left":h=f.textMargin;break}c=this.expect(c,"text",{"pointer-events":f.events,cursor:f.cursor,x:h,
5443+y:i,dy:j,transform:"translate("+f.left+","+f.top+")"+(f.textAngle?" rotate("+180*f.textAngle/Math.PI+")":"")+(this.scale!=1?" scale("+1/this.scale+")":""),fill:g.color,"fill-opacity":g.opacity||null,"text-anchor":l},{font:f.font,"text-shadow":f.textShadow,"text-decoration":f.textDecoration});if(c.firstChild)c.firstChild.nodeValue=f.text;else c.appendChild(document.createTextNode(f.text));c=this.append(c,b,d)}}}return c};
5444+pv.SvgScene.line=function(b){var c=b.$g.firstChild;if(b.length<2)return c;var d=b[0];if(d.segmented)return this.lineSegment(b);if(!d.visible)return c;var f=d.fillStyle,g=d.strokeStyle;if(!f.opacity&&!g.opacity)return c;var h="M"+d.left+","+d.top;if(b.length>2&&(d.interpolate=="basis"||d.interpolate=="cardinal"||d.interpolate=="monotone"))switch(d.interpolate){case "basis":h+=this.curveBasis(b);break;case "cardinal":h+=this.curveCardinal(b,d.tension);break;case "monotone":h+=this.curveMonotone(b);
5445+break}else for(var i=1;i<b.length;i++)h+=this.pathSegment(b[i-1],b[i]);c=this.expect(c,"path",{"shape-rendering":d.antialias?null:"crispEdges","pointer-events":d.events,cursor:d.cursor,d:h,fill:f.color,"fill-opacity":f.opacity||null,stroke:g.color,"stroke-opacity":g.opacity||null,"stroke-width":g.opacity?d.lineWidth/this.scale:null,"stroke-linejoin":d.lineJoin});return this.append(c,b,0)};
5446+pv.SvgScene.lineSegment=function(b){var c=b.$g.firstChild,d=b[0],f;switch(d.interpolate){case "basis":f=this.curveBasisSegments(b);break;case "cardinal":f=this.curveCardinalSegments(b,d.tension);break;case "monotone":f=this.curveMonotoneSegments(b);break}d=0;for(var g=b.length-1;d<g;d++){var h=b[d],i=b[d+1];if(h.visible&&i.visible){var j=h.strokeStyle,l=pv.Color.transparent;if(j.opacity){if(h.interpolate=="linear"&&h.lineJoin=="miter"){l=j;j=pv.Color.transparent;i=this.pathJoin(b[d-1],h,i,b[d+2])}else i=
5447+f?f[d]:"M"+h.left+","+h.top+this.pathSegment(h,i);c=this.expect(c,"path",{"shape-rendering":h.antialias?null:"crispEdges","pointer-events":h.events,cursor:h.cursor,d:i,fill:l.color,"fill-opacity":l.opacity||null,stroke:j.color,"stroke-opacity":j.opacity||null,"stroke-width":j.opacity?h.lineWidth/this.scale:null,"stroke-linejoin":h.lineJoin});c=this.append(c,b,d)}}}return c};
5448+pv.SvgScene.pathSegment=function(b,c){var d=1;switch(b.interpolate){case "polar-reverse":d=0;case "polar":var f=c.left-b.left,g=c.top-b.top;b=1-b.eccentricity;f=Math.sqrt(f*f+g*g)/(2*b);if(b<=0||b>1)break;return"A"+f+","+f+" 0 0,"+d+" "+c.left+","+c.top;case "step-before":return"V"+c.top+"H"+c.left;case "step-after":return"H"+c.left+"V"+c.top}return"L"+c.left+","+c.top};pv.SvgScene.lineIntersect=function(b,c,d,f){return b.plus(c.times(d.minus(b).dot(f.perp())/c.dot(f.perp())))};
5449+pv.SvgScene.pathJoin=function(b,c,d,f){var g=pv.vector(c.left,c.top);d=pv.vector(d.left,d.top);var h=d.minus(g),i=h.perp().norm(),j=i.times(c.lineWidth/(2*this.scale));c=g.plus(j);var l=d.plus(j),k=d.minus(j);j=g.minus(j);if(b&&b.visible){b=g.minus(b.left,b.top).perp().norm().plus(i);j=this.lineIntersect(g,b,j,h);c=this.lineIntersect(g,b,c,h)}if(f&&f.visible){f=pv.vector(f.left,f.top).minus(d).perp().norm().plus(i);k=this.lineIntersect(d,f,k,h);l=this.lineIntersect(d,f,l,h)}return"M"+c.x+","+c.y+
5450+"L"+l.x+","+l.y+" "+k.x+","+k.y+" "+j.x+","+j.y};
5451+pv.SvgScene.panel=function(b){for(var c=b.$g,d=c&&c.firstChild,f=0;f<b.length;f++){var g=b[f];if(g.visible){if(!b.parent){g.canvas.style.display="inline-block";if(c&&c.parentNode!=g.canvas)d=(c=g.canvas.firstChild)&&c.firstChild;if(!c){c=g.canvas.appendChild(this.create("svg"));c.setAttribute("font-size","10px");c.setAttribute("font-family","sans-serif");c.setAttribute("fill","none");c.setAttribute("stroke","none");c.setAttribute("stroke-width",1.5);for(var h=0;h<this.events.length;h++)c.addEventListener(this.events[h],
5452+this.dispatch,false);d=c.firstChild}b.$g=c;c.setAttribute("width",g.width+g.left+g.right);c.setAttribute("height",g.height+g.top+g.bottom)}if(g.overflow=="hidden"){h=pv.id().toString(36);var i=this.expect(d,"g",{"clip-path":"url(#"+h+")"});i.parentNode||c.appendChild(i);b.$g=c=i;d=i.firstChild;d=this.expect(d,"clipPath",{id:h});h=d.firstChild||d.appendChild(this.create("rect"));h.setAttribute("x",g.left);h.setAttribute("y",g.top);h.setAttribute("width",g.width);h.setAttribute("height",g.height);d.parentNode||
5453+c.appendChild(d);d=d.nextSibling}d=this.fill(d,b,f);var j=this.scale,l=g.transform,k=g.left+l.x,q=g.top+l.y;this.scale*=l.k;for(h=0;h<g.children.length;h++){g.children[h].$g=d=this.expect(d,"g",{transform:"translate("+k+","+q+")"+(l.k!=1?" scale("+l.k+")":"")});this.updateAll(g.children[h]);d.parentNode||c.appendChild(d);d=d.nextSibling}this.scale=j;d=this.stroke(d,b,f);if(g.overflow=="hidden"){b.$g=c=i.parentNode;d=i.nextSibling}}}return d};
5454+pv.SvgScene.fill=function(b,c,d){var f=c[d],g=f.fillStyle;if(g.opacity||f.events=="all"){b=this.expect(b,"rect",{"shape-rendering":f.antialias?null:"crispEdges","pointer-events":f.events,cursor:f.cursor,x:f.left,y:f.top,width:f.width,height:f.height,fill:g.color,"fill-opacity":g.opacity,stroke:null});b=this.append(b,c,d)}return b};
5455+pv.SvgScene.stroke=function(b,c,d){var f=c[d],g=f.strokeStyle;if(g.opacity||f.events=="all"){b=this.expect(b,"rect",{"shape-rendering":f.antialias?null:"crispEdges","pointer-events":f.events=="all"?"stroke":f.events,cursor:f.cursor,x:f.left,y:f.top,width:Math.max(1.0E-10,f.width),height:Math.max(1.0E-10,f.height),fill:null,stroke:g.color,"stroke-opacity":g.opacity,"stroke-width":f.lineWidth/this.scale});b=this.append(b,c,d)}return b};
5456+pv.SvgScene.rule=function(b){for(var c=b.$g.firstChild,d=0;d<b.length;d++){var f=b[d];if(f.visible){var g=f.strokeStyle;if(g.opacity){c=this.expect(c,"line",{"shape-rendering":f.antialias?null:"crispEdges","pointer-events":f.events,cursor:f.cursor,x1:f.left,y1:f.top,x2:f.left+f.width,y2:f.top+f.height,stroke:g.color,"stroke-opacity":g.opacity,"stroke-width":f.lineWidth/this.scale});c=this.append(c,b,d)}}}return c};
5457+pv.SvgScene.wedge=function(b){for(var c=b.$g.firstChild,d=0;d<b.length;d++){var f=b[d];if(f.visible){var g=f.fillStyle,h=f.strokeStyle;if(g.opacity||h.opacity){var i=f.innerRadius,j=f.outerRadius,l=Math.abs(f.angle);if(l>=2*Math.PI)i=i?"M0,"+j+"A"+j+","+j+" 0 1,1 0,"+-j+"A"+j+","+j+" 0 1,1 0,"+j+"M0,"+i+"A"+i+","+i+" 0 1,1 0,"+-i+"A"+i+","+i+" 0 1,1 0,"+i+"Z":"M0,"+j+"A"+j+","+j+" 0 1,1 0,"+-j+"A"+j+","+j+" 0 1,1 0,"+j+"Z";else{var k=Math.min(f.startAngle,f.endAngle),q=Math.max(f.startAngle,f.endAngle),
5458+o=Math.cos(k),n=Math.cos(q);k=Math.sin(k);q=Math.sin(q);i=i?"M"+j*o+","+j*k+"A"+j+","+j+" 0 "+(l<Math.PI?"0":"1")+",1 "+j*n+","+j*q+"L"+i*n+","+i*q+"A"+i+","+i+" 0 "+(l<Math.PI?"0":"1")+",0 "+i*o+","+i*k+"Z":"M"+j*o+","+j*k+"A"+j+","+j+" 0 "+(l<Math.PI?"0":"1")+",1 "+j*n+","+j*q+"L0,0Z"}c=this.expect(c,"path",{"shape-rendering":f.antialias?null:"crispEdges","pointer-events":f.events,cursor:f.cursor,transform:"translate("+f.left+","+f.top+")",d:i,fill:g.color,"fill-rule":"evenodd","fill-opacity":g.opacity||
5459+null,stroke:h.color,"stroke-opacity":h.opacity||null,"stroke-width":h.opacity?f.lineWidth/this.scale:null});c=this.append(c,b,d)}}}return c};pv.Mark=function(){this.$properties=[];this.$handlers={}};pv.Mark.prototype.properties={};pv.Mark.cast={};pv.Mark.prototype.property=function(b,c){if(!this.hasOwnProperty("properties"))this.properties=pv.extend(this.properties);this.properties[b]=true;pv.Mark.prototype.propertyMethod(b,false,pv.Mark.cast[b]=c);return this};
5460+pv.Mark.prototype.propertyMethod=function(b,c,d){d||(d=pv.Mark.cast[b]);this[b]=function(f){if(c&&this.scene){var g=this.scene.defs;if(arguments.length){g[b]={id:f==null?0:pv.id(),value:f!=null&&d?d(f):f};return this}return g[b]?g[b].value:null}if(arguments.length){g=!c<<1|typeof f=="function";this.propertyValue(b,g&1&&d?function(){var h=f.apply(this,arguments);return h!=null?d(h):null}:f!=null&&d?d(f):f).type=g;return this}return this.instance()[b]}};
5461+pv.Mark.prototype.propertyValue=function(b,c){var d=this.$properties;c={name:b,id:pv.id(),value:c};for(var f=0;f<d.length;f++)if(d[f].name==b){d.splice(f,1);break}d.push(c);return c};pv.Mark.prototype.property("data").property("visible",Boolean).property("left",Number).property("right",Number).property("top",Number).property("bottom",Number).property("cursor",String).property("title",String).property("reverse",Boolean).property("antialias",Boolean).property("events",String);a=pv.Mark.prototype;
5462+a.childIndex=-1;a.index=-1;a.scale=1;a.defaults=(new pv.Mark).data(function(b){return[b]}).visible(true).antialias(true).events("painted");a.extend=function(b){this.proto=b;return this};a.add=function(b){return this.parent.add(b).extend(this)};a.def=function(b,c){this.propertyMethod(b,true);return this[b](arguments.length>1?c:null)};
5463+a.anchor=function(b){function c(g){for(var h=d,i=[];!(f=h.scene);){g=g.parent;i.push({index:g.index,childIndex:h.childIndex});h=h.parent}for(;i.length;){g=i.pop();f=f[g.index].children[g.childIndex]}if(d.hasOwnProperty("index")){i=pv.extend(f[d.index]);i.right=i.top=i.left=i.bottom=0;return[i]}return f}var d=this,f;b||(b="center");return(new pv.Anchor(this)).name(b).def("$mark.anchor",function(){f=this.scene.target=c(this)}).data(function(){return f.map(function(g){return g.data})}).visible(function(){return f[this.index].visible}).left(function(){var g=
5464+f[this.index],h=g.width||0;switch(this.name()){case "bottom":case "top":case "center":return g.left+h/2;case "left":return null}return g.left+h}).top(function(){var g=f[this.index],h=g.height||0;switch(this.name()){case "left":case "right":case "center":return g.top+h/2;case "top":return null}return g.top+h}).right(function(){var g=f[this.index];return this.name()=="left"?g.right+(g.width||0):null}).bottom(function(){var g=f[this.index];return this.name()=="top"?g.bottom+(g.height||0):null}).textAlign(function(){switch(this.name()){case "bottom":case "top":case "center":return"center";
5465+case "right":return"right"}return"left"}).textBaseline(function(){switch(this.name()){case "right":case "left":case "center":return"middle";case "top":return"top"}return"bottom"})};a.anchorTarget=function(){return this.proto.anchorTarget()};a.margin=function(b){return this.left(b).right(b).top(b).bottom(b)};a.instance=function(b){var c=this.scene||this.parent.instance(-1).children[this.childIndex],d=!arguments.length||this.hasOwnProperty("index")?this.index:b;return c[d<0?c.length-1:d]};a.first=function(){return this.scene[0]};
5466+a.last=function(){return this.scene[this.scene.length-1]};a.sibling=function(){return this.index==0?null:this.scene[this.index-1]};a.cousin=function(){var b=this.parent;return(b=b&&b.sibling())&&b.children?b.children[this.childIndex][this.index]:null};
5467+a.render=function(){function b(i,j,l){i.scale=l;if(j<g.length){f.unshift(null);if(i.hasOwnProperty("index"))c(i,j,l);else{for(var k=0,q=i.scene.length;k<q;k++){i.index=k;c(i,j,l)}delete i.index}f.shift()}else{i.build();pv.Scene.scale=l;pv.Scene.updateAll(i.scene)}delete i.scale}function c(i,j,l){var k=i.scene[i.index],q;if(k.visible){var o=g[j],n=i.children[o];for(q=0;q<o;q++)i.children[q].scene=k.children[q];f[0]=k.data;if(n.scene)b(n,j+1,l*k.transform.k);else{n.scene=k.children[o];b(n,j+1,l*k.transform.k);
5468+delete n.scene}for(q=0;q<o;q++)delete i.children[q].scene}}var d=this.parent,f=pv.Mark.stack;if(d&&!this.root.scene)this.root.render();else{for(var g=[],h=this;h.parent;h=h.parent)g.unshift(h.childIndex);for(this.bind();d&&!d.hasOwnProperty("index");)d=d.parent;this.context(d?d.scene:undefined,d?d.index:-1,function(){b(this.root,0,1)})}};pv.Mark.stack=[];a=pv.Mark.prototype;
5469+a.bind=function(){function b(j){do for(var l=j.$properties,k=l.length-1;k>=0;k--){var q=l[k];if(!(q.name in c)){c[q.name]=q;switch(q.name){case "data":f=q;break;case "visible":g=q;break;default:d[q.type].push(q);break}}}while(j=j.proto)}var c={},d=[[],[],[],[]],f,g;b(this);b(this.defaults);d[1].reverse();d[3].reverse();var h=this;do for(var i in h.properties)i in c||d[2].push(c[i]={name:i,type:2,value:null});while(h=h.proto);h=d[0].concat(d[1]);for(i=0;i<h.length;i++)this.propertyMethod(h[i].name,
5470+true);this.binds={properties:c,data:f,defs:h,required:[g],optional:pv.blend(d)}};
5471+a.build=function(){var b=this.scene,c=pv.Mark.stack;if(!b){b=this.scene=[];b.mark=this;b.type=this.type;b.childIndex=this.childIndex;if(this.parent){b.parent=this.parent.scene;b.parentIndex=this.parent.index}}if(this.binds.defs.length){var d=b.defs;if(!d)b.defs=d={};for(var f=0;f<this.binds.defs.length;f++){var g=this.binds.defs[f],h=d[g.name];if(!h||g.id>h.id)d[g.name]={id:0,value:g.type&1?g.value.apply(this,c):g.value}}}d=this.binds.data;d=d.type&1?d.value.apply(this,c):d.value;c.unshift(null);
5472+b.length=d.length;for(f=0;f<d.length;f++){pv.Mark.prototype.index=this.index=f;(g=b[f])||(b[f]=g={});g.data=c[0]=d[f];this.buildInstance(g)}pv.Mark.prototype.index=-1;delete this.index;c.shift();return this};a.buildProperties=function(b,c){for(var d=0,f=c.length;d<f;d++){var g=c[d],h=g.value;switch(g.type){case 0:case 1:h=this.scene.defs[g.name].value;break;case 3:h=h.apply(this,pv.Mark.stack);break}b[g.name]=h}};
5473+a.buildInstance=function(b){this.buildProperties(b,this.binds.required);if(b.visible){this.buildProperties(b,this.binds.optional);this.buildImplied(b)}};
5474+a.buildImplied=function(b){var c=b.left,d=b.right,f=b.top,g=b.bottom,h=this.properties,i=h.width?b.width:0,j=h.height?b.height:0,l=this.parent?this.parent.width():i+c+d;if(i==null)i=l-(d=d||0)-(c=c||0);else if(d==null)d=l-i-(c=c||0);else if(c==null)c=l-i-(d=d||0);l=this.parent?this.parent.height():j+f+g;if(j==null)j=l-(f=f||0)-(g=g||0);else if(g==null)g=l-j-(f=f||0);else if(f==null)f=l-j-(g=g||0);b.left=c;b.right=d;b.top=f;b.bottom=g;if(h.width)b.width=i;if(h.height)b.height=j;if(h.textStyle&&!b.textStyle)b.textStyle=
5475+pv.Color.transparent;if(h.fillStyle&&!b.fillStyle)b.fillStyle=pv.Color.transparent;if(h.strokeStyle&&!b.strokeStyle)b.strokeStyle=pv.Color.transparent};
5476+a.mouse=function(){var b=pv.event.pageX||0,c=pv.event.pageY||0,d=this.root.canvas();do{b-=d.offsetLeft;c-=d.offsetTop}while(d=d.offsetParent);d=pv.Transform.identity;var f=this.properties.transform?this:this.parent,g=[];do g.push(f);while(f=f.parent);for(;f=g.pop();)d=d.translate(f.left(),f.top()).times(f.transform());d=d.invert();return pv.vector(b*d.k+d.x,c*d.k+d.y)};a.event=function(b,c){this.$handlers[b]=pv.functor(c);return this};
5477+a.context=function(b,c,d){function f(k,q){pv.Mark.scene=k;h.index=q;if(k){var o=k.mark,n=o,m=[];do{m.push(n);i.push(k[q].data);n.index=q;n.scene=k;q=k.parentIndex;k=k.parent}while(n=n.parent);k=m.length-1;for(q=1;k>0;k--){n=m[k];n.scale=q;q*=n.scene[n.index].transform.k}if(o.children){k=0;for(m=o.children.length;k<m;k++){n=o.children[k];n.scene=o.scene[o.index].children[k];n.scale=q}}}}function g(k){if(k){k=k.mark;var q;if(k.children)for(var o=0,n=k.children.length;o<n;o++){q=k.children[o];delete q.scene;
5478+delete q.scale}q=k;do{i.pop();if(q.parent){delete q.scene;delete q.scale}delete q.index}while(q=q.parent)}}var h=pv.Mark.prototype,i=pv.Mark.stack,j=pv.Mark.scene,l=h.index;g(j,l);f(b,c);try{d.apply(this,i)}finally{g(b,c);f(j,l)}};pv.Mark.dispatch=function(b,c,d){var f=c.mark,g=c.parent,h=f.$handlers[b];if(!h)return g&&pv.Mark.dispatch(b,g,c.parentIndex);f.context(c,d,function(){(f=h.apply(f,pv.Mark.stack))&&f.render&&f.render()});return true};
5479+pv.Anchor=function(b){pv.Mark.call(this);this.target=b;this.parent=b.parent};pv.Anchor.prototype=pv.extend(pv.Mark).property("name",String);pv.Anchor.prototype.anchorTarget=function(){return this.target};pv.Area=function(){pv.Mark.call(this)};
5480+pv.Area.prototype=pv.extend(pv.Mark).property("width",Number).property("height",Number).property("lineWidth",Number).property("strokeStyle",pv.color).property("fillStyle",pv.color).property("segmented",Boolean).property("interpolate",String).property("tension",Number);pv.Area.prototype.type="area";pv.Area.prototype.defaults=(new pv.Area).extend(pv.Mark.prototype.defaults).lineWidth(1.5).fillStyle(pv.Colors.category20().by(pv.parent)).interpolate("linear").tension(0.7);
5481+pv.Area.prototype.buildImplied=function(b){if(b.height==null)b.height=0;if(b.width==null)b.width=0;pv.Mark.prototype.buildImplied.call(this,b)};pv.Area.fixed={lineWidth:1,lineJoin:1,strokeStyle:1,fillStyle:1,segmented:1,interpolate:1,tension:1};
5482+pv.Area.prototype.bind=function(){pv.Mark.prototype.bind.call(this);var b=this.binds,c=b.required;b=b.optional;for(var d=0,f=b.length;d<f;d++){var g=b[d];g.fixed=g.name in pv.Area.fixed;if(g.name=="segmented"){c.push(g);b.splice(d,1);d--;f--}}this.binds.$required=c;this.binds.$optional=b};
5483+pv.Area.prototype.buildInstance=function(b){var c=this.binds;if(this.index){var d=c.fixed;if(!d){d=c.fixed=[];function f(i){return!i.fixed||(d.push(i),false)}c.required=c.required.filter(f);if(!this.scene[0].segmented)c.optional=c.optional.filter(f)}c=0;for(var g=d.length;c<g;c++){var h=d[c].name;b[h]=this.scene[0][h]}}else{c.required=c.$required;c.optional=c.$optional;c.fixed=null}pv.Mark.prototype.buildInstance.call(this,b)};
5484+pv.Area.prototype.anchor=function(b){var c;return pv.Mark.prototype.anchor.call(this,b).def("$area.anchor",function(){c=this.scene.target}).interpolate(function(){return c[this.index].interpolate}).eccentricity(function(){return c[this.index].eccentricity}).tension(function(){return c[this.index].tension})};pv.Bar=function(){pv.Mark.call(this)};
5485+pv.Bar.prototype=pv.extend(pv.Mark).property("width",Number).property("height",Number).property("lineWidth",Number).property("strokeStyle",pv.color).property("fillStyle",pv.color);pv.Bar.prototype.type="bar";pv.Bar.prototype.defaults=(new pv.Bar).extend(pv.Mark.prototype.defaults).lineWidth(1.5).fillStyle(pv.Colors.category20().by(pv.parent));pv.Dot=function(){pv.Mark.call(this)};
5486+pv.Dot.prototype=pv.extend(pv.Mark).property("size",Number).property("radius",Number).property("shape",String).property("angle",Number).property("lineWidth",Number).property("strokeStyle",pv.color).property("fillStyle",pv.color);pv.Dot.prototype.type="dot";pv.Dot.prototype.defaults=(new pv.Dot).extend(pv.Mark.prototype.defaults).size(20).shape("circle").lineWidth(1.5).strokeStyle(pv.Colors.category10().by(pv.parent));
5487+pv.Dot.prototype.anchor=function(b){var c;return pv.Mark.prototype.anchor.call(this,b).def("$wedge.anchor",function(){c=this.scene.target}).left(function(){var d=c[this.index];switch(this.name()){case "bottom":case "top":case "center":return d.left;case "left":return null}return d.left+d.radius}).right(function(){var d=c[this.index];return this.name()=="left"?d.right+d.radius:null}).top(function(){var d=c[this.index];switch(this.name()){case "left":case "right":case "center":return d.top;case "top":return null}return d.top+
5488+d.radius}).bottom(function(){var d=c[this.index];return this.name()=="top"?d.bottom+d.radius:null}).textAlign(function(){switch(this.name()){case "left":return"right";case "bottom":case "top":case "center":return"center"}return"left"}).textBaseline(function(){switch(this.name()){case "right":case "left":case "center":return"middle";case "bottom":return"top"}return"bottom"})};
5489+pv.Dot.prototype.buildImplied=function(b){if(b.radius==null)b.radius=Math.sqrt(b.size);else if(b.size==null)b.size=b.radius*b.radius;pv.Mark.prototype.buildImplied.call(this,b)};pv.Label=function(){pv.Mark.call(this)};
5490+pv.Label.prototype=pv.extend(pv.Mark).property("text",String).property("font",String).property("textAngle",Number).property("textStyle",pv.color).property("textAlign",String).property("textBaseline",String).property("textMargin",Number).property("textDecoration",String).property("textShadow",String);pv.Label.prototype.type="label";pv.Label.prototype.defaults=(new pv.Label).extend(pv.Mark.prototype.defaults).events("none").text(pv.identity).font("10px sans-serif").textAngle(0).textStyle("black").textAlign("left").textBaseline("bottom").textMargin(3);
5491+pv.Line=function(){pv.Mark.call(this)};pv.Line.prototype=pv.extend(pv.Mark).property("lineWidth",Number).property("lineJoin",String).property("strokeStyle",pv.color).property("fillStyle",pv.color).property("segmented",Boolean).property("interpolate",String).property("eccentricity",Number).property("tension",Number);a=pv.Line.prototype;a.type="line";a.defaults=(new pv.Line).extend(pv.Mark.prototype.defaults).lineJoin("miter").lineWidth(1.5).strokeStyle(pv.Colors.category10().by(pv.parent)).interpolate("linear").eccentricity(0).tension(0.7);
5492+a.bind=pv.Area.prototype.bind;a.buildInstance=pv.Area.prototype.buildInstance;a.anchor=function(b){return pv.Area.prototype.anchor.call(this,b).textAlign(function(){switch(this.name()){case "left":return"right";case "bottom":case "top":case "center":return"center";case "right":return"left"}}).textBaseline(function(){switch(this.name()){case "right":case "left":case "center":return"middle";case "top":return"bottom";case "bottom":return"top"}})};pv.Rule=function(){pv.Mark.call(this)};
5493+pv.Rule.prototype=pv.extend(pv.Mark).property("width",Number).property("height",Number).property("lineWidth",Number).property("strokeStyle",pv.color);pv.Rule.prototype.type="rule";pv.Rule.prototype.defaults=(new pv.Rule).extend(pv.Mark.prototype.defaults).lineWidth(1).strokeStyle("black").antialias(false);pv.Rule.prototype.anchor=pv.Line.prototype.anchor;
5494+pv.Rule.prototype.buildImplied=function(b){var c=b.left,d=b.right;if(b.width!=null||c==null&&d==null||d!=null&&c!=null)b.height=0;else b.width=0;pv.Mark.prototype.buildImplied.call(this,b)};pv.Panel=function(){pv.Bar.call(this);this.children=[];this.root=this;this.$dom=pv.$&&pv.$.s};pv.Panel.prototype=pv.extend(pv.Bar).property("transform").property("overflow",String).property("canvas",function(b){return typeof b=="string"?document.getElementById(b):b});a=pv.Panel.prototype;a.type="panel";
5495+a.defaults=(new pv.Panel).extend(pv.Bar.prototype.defaults).fillStyle(null).overflow("visible");a.anchor=function(b){b=pv.Bar.prototype.anchor.call(this,b);b.parent=this;return b};a.add=function(b){b=new b;b.parent=this;b.root=this.root;b.childIndex=this.children.length;this.children.push(b);return b};a.bind=function(){pv.Mark.prototype.bind.call(this);for(var b=0;b<this.children.length;b++)this.children[b].bind()};
5496+a.buildInstance=function(b){pv.Bar.prototype.buildInstance.call(this,b);if(b.visible){if(!b.children)b.children=[];var c=this.scale*b.transform.k,d,f=this.children.length;pv.Mark.prototype.index=-1;for(var g=0;g<f;g++){d=this.children[g];d.scene=b.children[g];d.scale=c;d.build()}for(g=0;g<f;g++){d=this.children[g];b.children[g]=d.scene;delete d.scene;delete d.scale}b.children.length=f}};
5497+a.buildImplied=function(b){if(!this.parent){var c=b.canvas;if(c){if(c.$panel!=this)for(c.$panel=this;c.lastChild;)c.removeChild(c.lastChild);var d;if(b.width==null){d=parseFloat(pv.css(c,"width"));b.width=d-b.left-b.right}if(b.height==null){d=parseFloat(pv.css(c,"height"));b.height=d-b.top-b.bottom}}else{d=this.$canvas||(this.$canvas=[]);if(!(c=d[this.index])){c=d[this.index]=document.createElement("span");if(this.$dom)this.$dom.parentNode.insertBefore(c,this.$dom);else{for(d=document.body;d.lastChild&&
5498+d.lastChild.tagName;)d=d.lastChild;if(d!=document.body)d=d.parentNode;d.appendChild(c)}}}b.canvas=c}if(!b.transform)b.transform=pv.Transform.identity;pv.Mark.prototype.buildImplied.call(this,b)};pv.Image=function(){pv.Bar.call(this)};pv.Image.prototype=pv.extend(pv.Bar).property("url",String).property("imageWidth",Number).property("imageHeight",Number);a=pv.Image.prototype;a.type="image";a.defaults=(new pv.Image).extend(pv.Bar.prototype.defaults).fillStyle(null);
5499+a.image=function(b){this.$image=function(){var c=b.apply(this,arguments);return c==null?pv.Color.transparent:typeof c=="string"?pv.color(c):c};return this};a.bind=function(){pv.Bar.prototype.bind.call(this);var b=this.binds,c=this;do b.image=c.$image;while(!b.image&&(c=c.proto))};
5500+a.buildImplied=function(b){pv.Bar.prototype.buildImplied.call(this,b);if(b.visible){if(b.imageWidth==null)b.imageWidth=b.width;if(b.imageHeight==null)b.imageHeight=b.height;if(b.url==null&&this.binds.image){var c=this.$canvas||(this.$canvas=document.createElement("canvas")),d=c.getContext("2d"),f=b.imageWidth,g=b.imageHeight,h=pv.Mark.stack;c.width=f;c.height=g;b=(b.image=d.createImageData(f,g)).data;h.unshift(null,null);for(d=c=0;c<g;c++){h[1]=c;for(var i=0;i<f;i++){h[0]=i;var j=this.binds.image.apply(this,
5501+h);b[d++]=j.r;b[d++]=j.g;b[d++]=j.b;b[d++]=255*j.a}}h.splice(0,2)}}};pv.Wedge=function(){pv.Mark.call(this)};pv.Wedge.prototype=pv.extend(pv.Mark).property("startAngle",Number).property("endAngle",Number).property("angle",Number).property("innerRadius",Number).property("outerRadius",Number).property("lineWidth",Number).property("strokeStyle",pv.color).property("fillStyle",pv.color);a=pv.Wedge.prototype;a.type="wedge";
5502+a.defaults=(new pv.Wedge).extend(pv.Mark.prototype.defaults).startAngle(function(){var b=this.sibling();return b?b.endAngle:-Math.PI/2}).innerRadius(0).lineWidth(1.5).strokeStyle(null).fillStyle(pv.Colors.category20().by(pv.index));a.midRadius=function(){return(this.innerRadius()+this.outerRadius())/2};a.midAngle=function(){return(this.startAngle()+this.endAngle())/2};
5503+a.anchor=function(b){function c(h){return h.innerRadius||h.angle<2*Math.PI}function d(h){return(h.innerRadius+h.outerRadius)/2}function f(h){return(h.startAngle+h.endAngle)/2}var g;return pv.Mark.prototype.anchor.call(this,b).def("$wedge.anchor",function(){g=this.scene.target}).left(function(){var h=g[this.index];if(c(h))switch(this.name()){case "outer":return h.left+h.outerRadius*Math.cos(f(h));case "inner":return h.left+h.innerRadius*Math.cos(f(h));case "start":return h.left+d(h)*Math.cos(h.startAngle);
5504+case "center":return h.left+d(h)*Math.cos(f(h));case "end":return h.left+d(h)*Math.cos(h.endAngle)}return h.left}).top(function(){var h=g[this.index];if(c(h))switch(this.name()){case "outer":return h.top+h.outerRadius*Math.sin(f(h));case "inner":return h.top+h.innerRadius*Math.sin(f(h));case "start":return h.top+d(h)*Math.sin(h.startAngle);case "center":return h.top+d(h)*Math.sin(f(h));case "end":return h.top+d(h)*Math.sin(h.endAngle)}return h.top}).textAlign(function(){var h=g[this.index];if(c(h))switch(this.name()){case "outer":return pv.Wedge.upright(f(h))?
5505+"right":"left";case "inner":return pv.Wedge.upright(f(h))?"left":"right"}return"center"}).textBaseline(function(){var h=g[this.index];if(c(h))switch(this.name()){case "start":return pv.Wedge.upright(h.startAngle)?"top":"bottom";case "end":return pv.Wedge.upright(h.endAngle)?"bottom":"top"}return"middle"}).textAngle(function(){var h=g[this.index],i=0;if(c(h))switch(this.name()){case "center":case "inner":case "outer":i=f(h);break;case "start":i=h.startAngle;break;case "end":i=h.endAngle;break}return pv.Wedge.upright(i)?
5506+i:i+Math.PI})};pv.Wedge.upright=function(b){b%=2*Math.PI;b=b<0?2*Math.PI+b:b;return b<Math.PI/2||b>=3*Math.PI/2};pv.Wedge.prototype.buildImplied=function(b){if(b.angle==null)b.angle=b.endAngle-b.startAngle;else if(b.endAngle==null)b.endAngle=b.startAngle+b.angle;pv.Mark.prototype.buildImplied.call(this,b)};pv.simulation=function(b){return new pv.Simulation(b)};pv.Simulation=function(b){for(var c=0;c<b.length;c++)this.particle(b[c])};a=pv.Simulation.prototype;
5507+a.particle=function(b){b.next=this.particles;if(isNaN(b.px))b.px=b.x;if(isNaN(b.py))b.py=b.y;if(isNaN(b.fx))b.fx=0;if(isNaN(b.fy))b.fy=0;this.particles=b;return this};a.force=function(b){b.next=this.forces;this.forces=b;return this};a.constraint=function(b){b.next=this.constraints;this.constraints=b;return this};
5508+a.stabilize=function(b){var c;arguments.length||(b=3);for(var d=0;d<b;d++){var f=new pv.Quadtree(this.particles);for(c=this.constraints;c;c=c.next)c.apply(this.particles,f)}for(c=this.particles;c;c=c.next){c.px=c.x;c.py=c.y}return this};
5509+a.step=function(){var b;for(b=this.particles;b;b=b.next){var c=b.px,d=b.py;b.px=b.x;b.py=b.y;b.x+=b.vx=b.x-c+b.fx;b.y+=b.vy=b.y-d+b.fy}c=new pv.Quadtree(this.particles);for(b=this.constraints;b;b=b.next)b.apply(this.particles,c);for(b=this.particles;b;b=b.next)b.fx=b.fy=0;for(b=this.forces;b;b=b.next)b.apply(this.particles,c)};
5510+pv.Quadtree=function(b){function c(k,q,o,n,m,r){if(!(isNaN(q.x)||isNaN(q.y)))if(k.leaf)if(k.p){if(!(Math.abs(k.p.x-q.x)+Math.abs(k.p.y-q.y)<0.01)){var s=k.p;k.p=null;d(k,s,o,n,m,r)}d(k,q,o,n,m,r)}else k.p=q;else d(k,q,o,n,m,r)}function d(k,q,o,n,m,r){var s=(o+m)*0.5,u=(n+r)*0.5,x=q.x>=s,t=q.y>=u;k.leaf=false;switch((t<<1)+x){case 0:k=k.c1||(k.c1=new pv.Quadtree.Node);break;case 1:k=k.c2||(k.c2=new pv.Quadtree.Node);break;case 2:k=k.c3||(k.c3=new pv.Quadtree.Node);break;case 3:k=k.c4||(k.c4=new pv.Quadtree.Node);
5511+break}if(x)o=s;else m=s;if(t)n=u;else r=u;c(k,q,o,n,m,r)}var f,g=Number.POSITIVE_INFINITY,h=g,i=Number.NEGATIVE_INFINITY,j=i;for(f=b;f;f=f.next){if(f.x<g)g=f.x;if(f.y<h)h=f.y;if(f.x>i)i=f.x;if(f.y>j)j=f.y}f=i-g;var l=j-h;if(f>l)j=h+f;else i=g+l;this.xMin=g;this.yMin=h;this.xMax=i;this.yMax=j;this.root=new pv.Quadtree.Node;for(f=b;f;f=f.next)c(this.root,f,g,h,i,j)};pv.Quadtree.Node=function(){this.leaf=true;this.p=this.c4=this.c3=this.c2=this.c1=null};pv.Force={};
5512+pv.Force.charge=function(b){function c(k){function q(m){c(m);k.cn+=m.cn;o+=m.cn*m.cx;n+=m.cn*m.cy}var o=0,n=0;k.cn=0;if(!k.leaf){k.c1&&q(k.c1);k.c2&&q(k.c2);k.c3&&q(k.c3);k.c4&&q(k.c4)}if(k.p){k.cn+=b;o+=b*k.p.x;n+=b*k.p.y}k.cx=o/k.cn;k.cy=n/k.cn}function d(k,q,o,n,m,r){var s=k.cx-q.x,u=k.cy-q.y,x=1/Math.sqrt(s*s+u*u);if(k.leaf&&k.p!=q||(m-o)*x<j){if(!(x<i)){if(x>g)x=g;k=k.cn*x*x*x;s=s*k;u=u*k;q.fx+=s;q.fy+=u}}else if(!k.leaf){var t=(o+m)*0.5,p=(n+r)*0.5;k.c1&&d(k.c1,q,o,n,t,p);k.c2&&d(k.c2,q,t,n,
5513+m,p);k.c3&&d(k.c3,q,o,p,t,r);k.c4&&d(k.c4,q,t,p,m,r);if(!(x<i)){if(x>g)x=g;if(k.p&&k.p!=q){k=b*x*x*x;s=s*k;u=u*k;q.fx+=s;q.fy+=u}}}}var f=2,g=1/f,h=500,i=1/h,j=0.9,l={};arguments.length||(b=-40);l.constant=function(k){if(arguments.length){b=Number(k);return l}return b};l.domain=function(k,q){if(arguments.length){f=Number(k);g=1/f;h=Number(q);i=1/h;return l}return[f,h]};l.theta=function(k){if(arguments.length){j=Number(k);return l}return j};l.apply=function(k,q){c(q.root);for(k=k;k;k=k.next)d(q.root,
5514+k,q.xMin,q.yMin,q.xMax,q.yMax)};return l};pv.Force.drag=function(b){var c={};arguments.length||(b=0.1);c.constant=function(d){if(arguments.length){b=d;return c}return b};c.apply=function(d){if(b)for(d=d;d;d=d.next){d.fx-=b*d.vx;d.fy-=b*d.vy}};return c};
5515+pv.Force.spring=function(b){var c=0.1,d=20,f,g,h={};arguments.length||(b=0.1);h.links=function(i){if(arguments.length){f=i;g=i.map(function(j){return 1/Math.sqrt(Math.max(j.sourceNode.linkDegree,j.targetNode.linkDegree))});return h}return f};h.constant=function(i){if(arguments.length){b=Number(i);return h}return b};h.damping=function(i){if(arguments.length){c=Number(i);return h}return c};h.length=function(i){if(arguments.length){d=Number(i);return h}return d};h.apply=function(){for(var i=0;i<f.length;i++){var j=
5516+f[i].sourceNode,l=f[i].targetNode,k=j.x-l.x,q=j.y-l.y,o=Math.sqrt(k*k+q*q),n=o?1/o:1;n=(b*g[i]*(o-d)+c*g[i]*(k*(j.vx-l.vx)+q*(j.vy-l.vy))*n)*n;k=-n*(o?k:0.01*(0.5-Math.random()));q=-n*(o?q:0.01*(0.5-Math.random()));j.fx+=k;j.fy+=q;l.fx-=k;l.fy-=q}};return h};pv.Constraint={};
5517+pv.Constraint.collision=function(b){function c(k,q,o,n,m,r){if(!k.leaf){var s=(o+m)*0.5,u=(n+r)*0.5,x=u<j,t=s>g,p=s<i;if(u>h){k.c1&&t&&c(k.c1,q,o,n,s,u);k.c2&&p&&c(k.c2,q,s,n,m,u)}if(x){k.c3&&t&&c(k.c3,q,o,u,s,r);k.c4&&p&&c(k.c4,q,s,u,m,r)}}if(k.p&&k.p!=q){o=q.x-k.p.x;n=q.y-k.p.y;m=Math.sqrt(o*o+n*n);r=f+b(k.p);if(m<r){m=(m-r)/m*0.5;o*=m;n*=m;q.x-=o;q.y-=n;k.p.x+=o;k.p.y+=n}}}var d=1,f,g,h,i,j,l={};arguments.length||(f=10);l.repeat=function(k){if(arguments.length){d=Number(k);return l}return d};l.apply=
5518+function(k,q){var o,n,m=-Infinity;for(o=k;o;o=o.next){n=b(o);if(n>m)m=n}for(var r=0;r<d;r++)for(o=k;o;o=o.next){n=(f=b(o))+m;g=o.x-n;i=o.x+n;h=o.y-n;j=o.y+n;c(q.root,o,q.xMin,q.yMin,q.xMax,q.yMax)}};return l};pv.Constraint.position=function(b){var c=1,d={};arguments.length||(b=function(f){return f.fix});d.alpha=function(f){if(arguments.length){c=Number(f);return d}return c};d.apply=function(f){for(f=f;f;f=f.next){var g=b(f);if(g){f.x+=(g.x-f.x)*c;f.y+=(g.y-f.y)*c;f.fx=f.fy=f.vx=f.vy=0}}};return d};
5519+pv.Constraint.bound=function(){var b={},c,d;b.x=function(f,g){if(arguments.length){c={min:Math.min(f,g),max:Math.max(f,g)};return this}return c};b.y=function(f,g){if(arguments.length){d={min:Math.min(f,g),max:Math.max(f,g)};return this}return d};b.apply=function(f){if(c)for(var g=f;g;g=g.next)g.x=g.x<c.min?c.min:g.x>c.max?c.max:g.x;if(d)for(g=f;g;g=g.next)g.y=g.y<d.min?d.min:g.y>d.max?d.max:g.y};return b};pv.Layout=function(){pv.Panel.call(this)};pv.Layout.prototype=pv.extend(pv.Panel);
5520+pv.Layout.prototype.property=function(b,c){if(!this.hasOwnProperty("properties"))this.properties=pv.extend(this.properties);this.properties[b]=true;this.propertyMethod(b,false,pv.Mark.cast[b]=c);return this};
5521+pv.Layout.Network=function(){pv.Layout.call(this);var b=this;this.$id=pv.id();(this.node=(new pv.Mark).data(function(){return b.nodes()}).strokeStyle("#1f77b4").fillStyle("#fff").left(function(c){return c.x}).top(function(c){return c.y})).parent=this;this.link=(new pv.Mark).extend(this.node).data(function(c){return[c.sourceNode,c.targetNode]}).fillStyle(null).lineWidth(function(c,d){return d.linkValue*1.5}).strokeStyle("rgba(0,0,0,.2)");this.link.add=function(c){return b.add(pv.Panel).data(function(){return b.links()}).add(c).extend(this)};
5522+(this.label=(new pv.Mark).extend(this.node).textMargin(7).textBaseline("middle").text(function(c){return c.nodeName||c.nodeValue}).textAngle(function(c){c=c.midAngle;return pv.Wedge.upright(c)?c:c+Math.PI}).textAlign(function(c){return pv.Wedge.upright(c.midAngle)?"left":"right"})).parent=this};
5523+pv.Layout.Network.prototype=pv.extend(pv.Layout).property("nodes",function(b){return b.map(function(c,d){if(typeof c!="object")c={nodeValue:c};c.index=d;c.linkDegree=0;return c})}).property("links",function(b){return b.map(function(c){if(isNaN(c.linkValue))c.linkValue=isNaN(c.value)?1:c.value;return c})});pv.Layout.Network.prototype.reset=function(){this.$id=pv.id();return this};
5524+pv.Layout.Network.prototype.buildProperties=function(b,c){if((b.$id||0)<this.$id)pv.Layout.prototype.buildProperties.call(this,b,c)};pv.Layout.Network.prototype.buildImplied=function(b){pv.Layout.prototype.buildImplied.call(this,b);if(b.$id>=this.$id)return true;b.$id=this.$id;b.links.forEach(function(c){var d=c.linkValue;(c.sourceNode||(c.sourceNode=b.nodes[c.source])).linkDegree+=d;(c.targetNode||(c.targetNode=b.nodes[c.target])).linkDegree+=d})};
5525+pv.Layout.Hierarchy=function(){pv.Layout.Network.call(this);this.link.strokeStyle("#ccc")};pv.Layout.Hierarchy.prototype=pv.extend(pv.Layout.Network);pv.Layout.Hierarchy.prototype.buildImplied=function(b){if(!b.links)b.links=pv.Layout.Hierarchy.links.call(this);pv.Layout.Network.prototype.buildImplied.call(this,b)};pv.Layout.Hierarchy.links=function(){return this.nodes().filter(function(b){return b.parentNode}).map(function(b){return{sourceNode:b,targetNode:b.parentNode,linkValue:1}})};
5526+pv.Layout.Hierarchy.NodeLink={buildImplied:function(b){function c(m){return m.parentNode?m.depth*(o-q)+q:0}function d(m){return m.parentNode?(m.breadth-0.25)*2*Math.PI:0}function f(m){switch(i){case "left":return m.depth*l;case "right":return l-m.depth*l;case "top":return m.breadth*l;case "bottom":return l-m.breadth*l;case "radial":return l/2+c(m)*Math.cos(m.midAngle)}}function g(m){switch(i){case "left":return m.breadth*k;case "right":return k-m.breadth*k;case "top":return m.depth*k;case "bottom":return k-
5527+m.depth*k;case "radial":return k/2+c(m)*Math.sin(m.midAngle)}}var h=b.nodes,i=b.orient,j=/^(top|bottom)$/.test(i),l=b.width,k=b.height;if(i=="radial"){var q=b.innerRadius,o=b.outerRadius;if(q==null)q=0;if(o==null)o=Math.min(l,k)/2}for(b=0;b<h.length;b++){var n=h[b];n.midAngle=i=="radial"?d(n):j?Math.PI/2:0;n.x=f(n);n.y=g(n);if(n.firstChild)n.midAngle+=Math.PI}}};
5528+pv.Layout.Hierarchy.Fill={constructor:function(){this.node.strokeStyle("#fff").fillStyle("#ccc").width(function(b){return b.dx}).height(function(b){return b.dy}).innerRadius(function(b){return b.innerRadius}).outerRadius(function(b){return b.outerRadius}).startAngle(function(b){return b.startAngle}).angle(function(b){return b.angle});this.label.textAlign("center").left(function(b){return b.x+b.dx/2}).top(function(b){return b.y+b.dy/2});delete this.link},buildImplied:function(b){function c(p,v){return(p+
5529+v)/(1+v)}function d(p){switch(o){case "left":return c(p.minDepth,s)*m;case "right":return(1-c(p.maxDepth,s))*m;case "top":return p.minBreadth*m;case "bottom":return(1-p.maxBreadth)*m;case "radial":return m/2}}function f(p){switch(o){case "left":return p.minBreadth*r;case "right":return(1-p.maxBreadth)*r;case "top":return c(p.minDepth,s)*r;case "bottom":return(1-c(p.maxDepth,s))*r;case "radial":return r/2}}function g(p){switch(o){case "left":case "right":return(p.maxDepth-p.minDepth)/(1+s)*m;case "top":case "bottom":return(p.maxBreadth-
5530+p.minBreadth)*m;case "radial":return p.parentNode?(p.innerRadius+p.outerRadius)*Math.cos(p.midAngle):0}}function h(p){switch(o){case "left":case "right":return(p.maxBreadth-p.minBreadth)*r;case "top":case "bottom":return(p.maxDepth-p.minDepth)/(1+s)*r;case "radial":return p.parentNode?(p.innerRadius+p.outerRadius)*Math.sin(p.midAngle):0}}function i(p){return Math.max(0,c(p.minDepth,s/2))*(x-u)+u}function j(p){return c(p.maxDepth,s/2)*(x-u)+u}function l(p){return(p.parentNode?p.minBreadth-0.25:0)*
5531+2*Math.PI}function k(p){return(p.parentNode?p.maxBreadth-p.minBreadth:1)*2*Math.PI}var q=b.nodes,o=b.orient,n=/^(top|bottom)$/.test(o),m=b.width,r=b.height,s=-q[0].minDepth;if(o=="radial"){var u=b.innerRadius,x=b.outerRadius;if(u==null)u=0;if(u)s*=2;if(x==null)x=Math.min(m,r)/2}for(b=0;b<q.length;b++){var t=q[b];t.x=d(t);t.y=f(t);if(o=="radial"){t.innerRadius=i(t);t.outerRadius=j(t);t.startAngle=l(t);t.angle=k(t);t.midAngle=t.startAngle+t.angle/2}else t.midAngle=n?-Math.PI/2:0;t.dx=g(t);t.dy=h(t)}}};
5532+pv.Layout.Grid=function(){pv.Layout.call(this);var b=this;(this.cell=(new pv.Mark).data(function(){return b.scene[b.index].$grid}).width(function(){return b.width()/b.cols()}).height(function(){return b.height()/b.rows()}).left(function(){return this.width()*(this.index%b.cols())}).top(function(){return this.height()*Math.floor(this.index/b.cols())})).parent=this};pv.Layout.Grid.prototype=pv.extend(pv.Layout).property("rows").property("cols");pv.Layout.Grid.prototype.defaults=(new pv.Layout.Grid).extend(pv.Layout.prototype.defaults).rows(1).cols(1);
5533+pv.Layout.Grid.prototype.buildImplied=function(b){pv.Layout.prototype.buildImplied.call(this,b);var c=b.rows,d=b.cols;if(typeof d=="object")c=pv.transpose(d);if(typeof c=="object"){b.$grid=pv.blend(c);b.rows=c.length;b.cols=c[0]?c[0].length:0}else b.$grid=pv.repeat([b.data],c*d)};
5534+pv.Layout.Stack=function(){function b(i){return function(){return f[i](this.parent.index,this.index)}}pv.Layout.call(this);var c=this,d=function(){return null},f={t:d,l:d,r:d,b:d,w:d,h:d},g,h=c.buildImplied;this.buildImplied=function(i){h.call(this,i);var j=i.layers,l=j.length,k,q=i.orient,o=/^(top|bottom)\b/.test(q),n=this.parent[o?"height":"width"](),m=[],r=[],s=[],u=pv.Mark.stack,x={parent:{parent:this}};u.unshift(null);g=[];for(var t=0;t<l;t++){s[t]=[];r[t]=[];x.parent.index=t;u[0]=j[t];g[t]=
5535+this.$values.apply(x.parent,u);if(!t)k=g[t].length;u.unshift(null);for(var p=0;p<k;p++){u[0]=g[t][p];x.index=p;t||(m[p]=this.$x.apply(x,u));s[t][p]=this.$y.apply(x,u)}u.shift()}u.shift();switch(i.order){case "inside-out":var v=s.map(function(A){return pv.max.index(A)});x=pv.range(l).sort(function(A,D){return v[A]-v[D]});j=s.map(function(A){return pv.sum(A)});var w=u=0,y=[],z=[];for(t=0;t<l;t++){p=x[t];if(u<w){u+=j[p];y.push(p)}else{w+=j[p];z.push(p)}}j=z.reverse().concat(y);break;case "reverse":j=
5536+pv.range(l-1,-1,-1);break;default:j=pv.range(l);break}switch(i.offset){case "silohouette":for(p=0;p<k;p++){for(t=x=0;t<l;t++)x+=s[t][p];r[j[0]][p]=(n-x)/2}break;case "wiggle":for(t=x=0;t<l;t++)x+=s[t][0];r[j[0]][0]=x=(n-x)/2;for(p=1;p<k;p++){u=n=0;w=m[p]-m[p-1];for(t=0;t<l;t++)n+=s[t][p];for(t=0;t<l;t++){y=(s[j[t]][p]-s[j[t]][p-1])/(2*w);for(i=0;i<t;i++)y+=(s[j[i]][p]-s[j[i]][p-1])/w;u+=y*s[j[t]][p]}r[j[0]][p]=x-=n?u/n*w:0}break;case "expand":for(p=0;p<k;p++){for(t=i=r[j[0]][p]=0;t<l;t++)i+=s[t][p];
5537+if(i){i=n/i;for(t=0;t<l;t++)s[t][p]*=i}else{i=n/l;for(t=0;t<l;t++)s[t][p]=i}}break;default:for(p=0;p<k;p++)r[j[0]][p]=0;break}for(p=0;p<k;p++){x=r[j[0]][p];for(t=1;t<l;t++){x+=s[j[t-1]][p];r[j[t]][p]=x}}t=q.indexOf("-");l=o?"h":"w";o=t<0?o?"l":"b":q.charAt(t+1);q=q.charAt(0);for(var C in f)f[C]=d;f[o]=function(A,D){return m[D]};f[q]=function(A,D){return r[A][D]};f[l]=function(A,D){return s[A][D]}};this.layer=(new pv.Mark).data(function(){return g[this.parent.index]}).top(b("t")).left(b("l")).right(b("r")).bottom(b("b")).width(b("w")).height(b("h"));
5538+this.layer.add=function(i){return c.add(pv.Panel).data(function(){return c.layers()}).add(i).extend(this)}};pv.Layout.Stack.prototype=pv.extend(pv.Layout).property("orient",String).property("offset",String).property("order",String).property("layers");a=pv.Layout.Stack.prototype;a.defaults=(new pv.Layout.Stack).extend(pv.Layout.prototype.defaults).orient("bottom-left").offset("zero").layers([[]]);a.$x=pv.Layout.Stack.prototype.$y=function(){return 0};a.x=function(b){this.$x=pv.functor(b);return this};
5539+a.y=function(b){this.$y=pv.functor(b);return this};a.$values=pv.identity;a.values=function(b){this.$values=pv.functor(b);return this};
5540+pv.Layout.Treemap=function(){pv.Layout.Hierarchy.call(this);this.node.strokeStyle("#fff").fillStyle("rgba(31, 119, 180, .25)").width(function(b){return b.dx}).height(function(b){return b.dy});this.label.visible(function(b){return!b.firstChild}).left(function(b){return b.x+b.dx/2}).top(function(b){return b.y+b.dy/2}).textAlign("center").textAngle(function(b){return b.dx>b.dy?0:-Math.PI/2});(this.leaf=(new pv.Mark).extend(this.node).fillStyle(null).strokeStyle(null).visible(function(b){return!b.firstChild})).parent=
5541+this;delete this.link};pv.Layout.Treemap.prototype=pv.extend(pv.Layout.Hierarchy).property("round",Boolean).property("paddingLeft",Number).property("paddingRight",Number).property("paddingTop",Number).property("paddingBottom",Number).property("mode",String).property("order",String);a=pv.Layout.Treemap.prototype;a.defaults=(new pv.Layout.Treemap).extend(pv.Layout.Hierarchy.prototype.defaults).mode("squarify").order("ascending");a.padding=function(b){return this.paddingLeft(b).paddingRight(b).paddingTop(b).paddingBottom(b)};
5542+a.$size=function(b){return Number(b.nodeValue)};a.size=function(b){this.$size=pv.functor(b);return this};
5543+a.buildImplied=function(b){function c(r,s,u,x,t,p,v){for(var w=0,y=0;w<r.length;w++){var z=r[w];if(u){z.x=x+y;z.y=t;y+=z.dx=n(p*z.size/s);z.dy=v}else{z.x=x;z.y=t+y;z.dx=p;y+=z.dy=n(v*z.size/s)}}if(z)if(u)z.dx+=p-y;else z.dy+=v-y}function d(r,s){for(var u=-Infinity,x=Infinity,t=0,p=0;p<r.length;p++){var v=r[p].size;if(v<x)x=v;if(v>u)u=v;t+=v}t*=t;s*=s;return Math.max(s*u/t,t/(s*x))}function f(r,s){function u(A){var D=p==y,G=pv.sum(A,o),E=y?n(G/y):0;c(A,G,D,x,t,D?p:E,D?E:v);if(D){t+=E;v-=E}else{x+=
5544+E;p-=E}y=Math.min(p,v);return D}var x=r.x+j,t=r.y+k,p=r.dx-j-l,v=r.dy-k-q;if(m!="squarify")c(r.childNodes,r.size,m=="slice"?true:m=="dice"?false:s&1,x,t,p,v);else{var w=[];s=Infinity;var y=Math.min(p,v),z=p*v/r.size;if(!(r.size<=0)){r.visitBefore(function(A){A.size*=z});for(r=r.childNodes.slice();r.length;){var C=r[r.length-1];if(C.size){w.push(C);z=d(w,y);if(z<=s){r.pop();s=z}else{w.pop();u(w);w.length=0;s=Infinity}}else r.pop()}if(u(w))for(s=0;s<w.length;s++)w[s].dy+=v;else for(s=0;s<w.length;s++)w[s].dx+=
5545+p}}}if(!pv.Layout.Hierarchy.prototype.buildImplied.call(this,b)){var g=this,h=b.nodes[0],i=pv.Mark.stack,j=b.paddingLeft,l=b.paddingRight,k=b.paddingTop,q=b.paddingBottom,o=function(r){return r.size},n=b.round?Math.round:Number,m=b.mode;i.unshift(null);h.visitAfter(function(r,s){r.depth=s;r.x=r.y=r.dx=r.dy=0;r.size=r.firstChild?pv.sum(r.childNodes,function(u){return u.size}):g.$size.apply(g,(i[0]=r,i))});i.shift();switch(b.order){case "ascending":h.sort(function(r,s){return r.size-s.size});break;
5546+case "descending":h.sort(function(r,s){return s.size-r.size});break;case "reverse":h.reverse();break}h.x=0;h.y=0;h.dx=b.width;h.dy=b.height;h.visitBefore(f)}};pv.Layout.Tree=function(){pv.Layout.Hierarchy.call(this)};pv.Layout.Tree.prototype=pv.extend(pv.Layout.Hierarchy).property("group",Number).property("breadth",Number).property("depth",Number).property("orient",String);pv.Layout.Tree.prototype.defaults=(new pv.Layout.Tree).extend(pv.Layout.Hierarchy.prototype.defaults).group(1).breadth(15).depth(60).orient("top");
5547+pv.Layout.Tree.prototype.buildImplied=function(b){function c(p){var v,w,y;if(p.firstChild){v=p.firstChild;w=p.lastChild;for(var z=y=v;z;z=z.nextSibling){c(z);y=f(z,y)}j(p);w=0.5*(v.prelim+w.prelim);if(v=p.previousSibling){p.prelim=v.prelim+k(p.depth,true);p.mod=p.prelim-w}else p.prelim=w}else if(v=p.previousSibling)p.prelim=v.prelim+k(p.depth,true)}function d(p,v,w){p.breadth=p.prelim+v;v+=p.mod;for(p=p.firstChild;p;p=p.nextSibling)d(p,v,w)}function f(p,v){var w=p.previousSibling;if(w){var y=p,z=
5548+p,C=w;w=p.parentNode.firstChild;var A=y.mod,D=z.mod,G=C.mod,E=w.mod;C=h(C);for(y=g(y);C&&y;){C=C;y=y;w=g(w);z=h(z);z.ancestor=p;var B=C.prelim+G-(y.prelim+A)+k(C.depth,false);if(B>0){i(l(C,p,v),p,B);A+=B;D+=B}G+=C.mod;A+=y.mod;E+=w.mod;D+=z.mod;C=h(C);y=g(y)}if(C&&!h(z)){z.thread=C;z.mod+=G-D}if(y&&!g(w)){w.thread=y;w.mod+=A-E;v=p}}return v}function g(p){return p.firstChild||p.thread}function h(p){return p.lastChild||p.thread}function i(p,v,w){var y=v.number-p.number;v.change-=w/y;v.shift+=w;p.change+=
5549+w/y;v.prelim+=w;v.mod+=w}function j(p){var v=0,w=0;for(p=p.lastChild;p;p=p.previousSibling){p.prelim+=v;p.mod+=v;w+=p.change;v+=p.shift+w}}function l(p,v,w){return p.ancestor.parentNode==v.parentNode?p.ancestor:w}function k(p,v){return(v?1:u+1)/(m=="radial"?p:1)}function q(p){return m=="radial"?p.breadth/r:0}function o(p){switch(m){case "left":return p.depth;case "right":return x-p.depth;case "top":case "bottom":return p.breadth+x/2;case "radial":return x/2+p.depth*Math.cos(q(p))}}function n(p){switch(m){case "left":case "right":return p.breadth+
5550+t/2;case "top":return p.depth;case "bottom":return t-p.depth;case "radial":return t/2+p.depth*Math.sin(q(p))}}if(!pv.Layout.Hierarchy.prototype.buildImplied.call(this,b)){var m=b.orient,r=b.depth,s=b.breadth,u=b.group,x=b.width,t=b.height;b=b.nodes[0];b.visitAfter(function(p,v){p.ancestor=p;p.prelim=0;p.mod=0;p.change=0;p.shift=0;p.number=p.previousSibling?p.previousSibling.number+1:0;p.depth=v});c(b);d(b,-b.prelim,0);b.visitAfter(function(p){p.breadth*=s;p.depth*=r;p.midAngle=q(p);p.x=o(p);p.y=n(p);
5551+if(p.firstChild)p.midAngle+=Math.PI;delete p.breadth;delete p.depth;delete p.ancestor;delete p.prelim;delete p.mod;delete p.change;delete p.shift;delete p.number;delete p.thread})}};pv.Layout.Indent=function(){pv.Layout.Hierarchy.call(this);this.link.interpolate("step-after")};pv.Layout.Indent.prototype=pv.extend(pv.Layout.Hierarchy).property("depth",Number).property("breadth",Number);pv.Layout.Indent.prototype.defaults=(new pv.Layout.Indent).extend(pv.Layout.Hierarchy.prototype.defaults).depth(15).breadth(15);
5552+pv.Layout.Indent.prototype.buildImplied=function(b){function c(i,j,l){i.x=g+l++*f;i.y=h+j++*d;i.midAngle=0;for(i=i.firstChild;i;i=i.nextSibling)j=c(i,j,l);return j}if(!pv.Layout.Hierarchy.prototype.buildImplied.call(this,b)){var d=b.breadth,f=b.depth,g=0,h=0;c(b.nodes[0],1,1)}};pv.Layout.Pack=function(){pv.Layout.Hierarchy.call(this);this.node.radius(function(b){return b.radius}).strokeStyle("rgb(31, 119, 180)").fillStyle("rgba(31, 119, 180, .25)");this.label.textAlign("center");delete this.link};
5553+pv.Layout.Pack.prototype=pv.extend(pv.Layout.Hierarchy).property("spacing",Number).property("order",String);pv.Layout.Pack.prototype.defaults=(new pv.Layout.Pack).extend(pv.Layout.Hierarchy.prototype.defaults).spacing(1).order("ascending");pv.Layout.Pack.prototype.$radius=function(){return 1};pv.Layout.Pack.prototype.size=function(b){this.$radius=typeof b=="function"?function(){return Math.sqrt(b.apply(this,arguments))}:(b=Math.sqrt(b),function(){return b});return this};
5554+pv.Layout.Pack.prototype.buildImplied=function(b){function c(o){var n=pv.Mark.stack;n.unshift(null);for(var m=0,r=o.length;m<r;m++){var s=o[m];if(!s.firstChild)s.radius=i.$radius.apply(i,(n[0]=s,n))}n.shift()}function d(o){var n=[];for(o=o.firstChild;o;o=o.nextSibling){if(o.firstChild)o.radius=d(o);o.n=o.p=o;n.push(o)}switch(b.order){case "ascending":n.sort(function(m,r){return m.radius-r.radius});break;case "descending":n.sort(function(m,r){return r.radius-m.radius});break;case "reverse":n.reverse();
5555+break}return f(n)}function f(o){function n(B){u=Math.min(B.x-B.radius,u);x=Math.max(B.x+B.radius,x);t=Math.min(B.y-B.radius,t);p=Math.max(B.y+B.radius,p)}function m(B,F){var H=B.n;B.n=F;F.p=B;F.n=H;H.p=F}function r(B,F){B.n=F;F.p=B}function s(B,F){var H=F.x-B.x,I=F.y-B.y;B=B.radius+F.radius;return B*B-H*H-I*I>0.0010}var u=Infinity,x=-Infinity,t=Infinity,p=-Infinity,v,w,y,z,C;v=o[0];v.x=-v.radius;v.y=0;n(v);if(o.length>1){w=o[1];w.x=w.radius;w.y=0;n(w);if(o.length>2){y=o[2];g(v,w,y);n(y);m(v,y);v.p=
5556+y;m(y,w);w=v.n;for(var A=3;A<o.length;A++){g(v,w,y=o[A]);var D=0,G=1,E=1;for(z=w.n;z!=w;z=z.n,G++)if(s(z,y)){D=1;break}if(D==1)for(C=v.p;C!=z.p;C=C.p,E++)if(s(C,y)){if(E<G){D=-1;z=C}break}if(D==0){m(v,y);w=y;n(y)}else if(D>0){r(v,z);w=z;A--}else if(D<0){r(z,w);v=z;A--}}}}v=(u+x)/2;w=(t+p)/2;for(A=y=0;A<o.length;A++){z=o[A];z.x-=v;z.y-=w;y=Math.max(y,z.radius+Math.sqrt(z.x*z.x+z.y*z.y))}return y+b.spacing}function g(o,n,m){var r=n.radius+m.radius,s=o.radius+m.radius,u=n.x-o.x;n=n.y-o.y;var x=Math.sqrt(u*
5557+u+n*n),t=(s*s+x*x-r*r)/(2*s*x);r=Math.acos(t);t=t*s;s=Math.sin(r)*s;u/=x;n/=x;m.x=o.x+t*u+s*n;m.y=o.y+t*n-s*u}function h(o,n,m,r){for(var s=o.firstChild;s;s=s.nextSibling){s.x+=o.x;s.y+=o.y;h(s,n,m,r)}o.x=n+r*o.x;o.y=m+r*o.y;o.radius*=r}if(!pv.Layout.Hierarchy.prototype.buildImplied.call(this,b)){var i=this,j=b.nodes,l=j[0];c(j);l.x=0;l.y=0;l.radius=d(l);j=this.width();var k=this.height(),q=1/Math.max(2*l.radius/j,2*l.radius/k);h(l,j/2,k/2,q)}};
5558+pv.Layout.Force=function(){pv.Layout.Network.call(this);this.link.lineWidth(function(b,c){return Math.sqrt(c.linkValue)*1.5});this.label.textAlign("center")};
5559+pv.Layout.Force.prototype=pv.extend(pv.Layout.Network).property("bound",Boolean).property("iterations",Number).property("dragConstant",Number).property("chargeConstant",Number).property("chargeMinDistance",Number).property("chargeMaxDistance",Number).property("chargeTheta",Number).property("springConstant",Number).property("springDamping",Number).property("springLength",Number);pv.Layout.Force.prototype.defaults=(new pv.Layout.Force).extend(pv.Layout.Network.prototype.defaults).dragConstant(0.1).chargeConstant(-40).chargeMinDistance(2).chargeMaxDistance(500).chargeTheta(0.9).springConstant(0.1).springDamping(0.3).springLength(20);
5560+pv.Layout.Force.prototype.buildImplied=function(b){function c(q){return q.fix?1:q.vx*q.vx+q.vy*q.vy}if(pv.Layout.Network.prototype.buildImplied.call(this,b)){if(b=b.$force){b.next=this.binds.$force;this.binds.$force=b}}else{for(var d=this,f=b.nodes,g=b.links,h=b.iterations,i=b.width,j=b.height,l=0,k;l<f.length;l++){k=f[l];if(isNaN(k.x))k.x=i/2+40*Math.random()-20;if(isNaN(k.y))k.y=j/2+40*Math.random()-20}k=pv.simulation(f);k.force(pv.Force.drag(b.dragConstant));k.force(pv.Force.charge(b.chargeConstant).domain(b.chargeMinDistance,
5561+b.chargeMaxDistance).theta(b.chargeTheta));k.force(pv.Force.spring(b.springConstant).damping(b.springDamping).length(b.springLength).links(g));k.constraint(pv.Constraint.position());b.bound&&k.constraint(pv.Constraint.bound().x(6,i-6).y(6,j-6));if(h==null){k.step();k.step();b.$force=this.binds.$force={next:this.binds.$force,nodes:f,min:1.0E-4*(g.length+1),sim:k};if(!this.$timer)this.$timer=setInterval(function(){for(var q=false,o=d.binds.$force;o;o=o.next)if(pv.max(o.nodes,c)>o.min){o.sim.step();
5562+q=true}q&&d.render()},42)}else for(l=0;l<h;l++)k.step()}};pv.Layout.Cluster=function(){pv.Layout.Hierarchy.call(this);var b,c=this.buildImplied;this.buildImplied=function(d){c.call(this,d);b=/^(top|bottom)$/.test(d.orient)?"step-before":/^(left|right)$/.test(d.orient)?"step-after":"linear"};this.link.interpolate(function(){return b})};
5563+pv.Layout.Cluster.prototype=pv.extend(pv.Layout.Hierarchy).property("group",Number).property("orient",String).property("innerRadius",Number).property("outerRadius",Number);pv.Layout.Cluster.prototype.defaults=(new pv.Layout.Cluster).extend(pv.Layout.Hierarchy.prototype.defaults).group(0).orient("top");
5564+pv.Layout.Cluster.prototype.buildImplied=function(b){if(!pv.Layout.Hierarchy.prototype.buildImplied.call(this,b)){var c=b.nodes[0],d=b.group,f,g,h=0,i=0.5-d/2,j=undefined;c.visitAfter(function(l){if(l.firstChild)l.depth=1+pv.max(l.childNodes,function(k){return k.depth});else{if(d&&j!=l.parentNode){j=l.parentNode;h+=d}h++;l.depth=0}});f=1/h;g=1/c.depth;j=undefined;c.visitAfter(function(l){if(l.firstChild)l.breadth=pv.mean(l.childNodes,function(k){return k.breadth});else{if(d&&j!=l.parentNode){j=l.parentNode;
5565+i+=d}l.breadth=f*i++}l.depth=1-l.depth*g});c.visitAfter(function(l){l.minBreadth=l.firstChild?l.firstChild.minBreadth:l.breadth-f/2;l.maxBreadth=l.firstChild?l.lastChild.maxBreadth:l.breadth+f/2});c.visitBefore(function(l){l.minDepth=l.parentNode?l.parentNode.maxDepth:0;l.maxDepth=l.parentNode?l.depth+c.depth:l.minDepth+2*c.depth});c.minDepth=-g;pv.Layout.Hierarchy.NodeLink.buildImplied.call(this,b)}};pv.Layout.Cluster.Fill=function(){pv.Layout.Cluster.call(this);pv.Layout.Hierarchy.Fill.constructor.call(this)};
5566+pv.Layout.Cluster.Fill.prototype=pv.extend(pv.Layout.Cluster);pv.Layout.Cluster.Fill.prototype.buildImplied=function(b){pv.Layout.Cluster.prototype.buildImplied.call(this,b)||pv.Layout.Hierarchy.Fill.buildImplied.call(this,b)};pv.Layout.Partition=function(){pv.Layout.Hierarchy.call(this)};pv.Layout.Partition.prototype=pv.extend(pv.Layout.Hierarchy).property("order",String).property("orient",String).property("innerRadius",Number).property("outerRadius",Number);
5567+pv.Layout.Partition.prototype.defaults=(new pv.Layout.Partition).extend(pv.Layout.Hierarchy.prototype.defaults).orient("top");pv.Layout.Partition.prototype.$size=function(){return 1};pv.Layout.Partition.prototype.size=function(b){this.$size=b;return this};
5568+pv.Layout.Partition.prototype.buildImplied=function(b){if(!pv.Layout.Hierarchy.prototype.buildImplied.call(this,b)){var c=this,d=b.nodes[0],f=pv.Mark.stack,g=0;f.unshift(null);d.visitAfter(function(i,j){if(j>g)g=j;i.size=i.firstChild?pv.sum(i.childNodes,function(l){return l.size}):c.$size.apply(c,(f[0]=i,f))});f.shift();switch(b.order){case "ascending":d.sort(function(i,j){return i.size-j.size});break;case "descending":d.sort(function(i,j){return j.size-i.size});break}var h=1/g;d.minBreadth=0;d.breadth=
5569+0.5;d.maxBreadth=1;d.visitBefore(function(i){for(var j=i.minBreadth,l=i.maxBreadth-j,k=i.firstChild;k;k=k.nextSibling){k.minBreadth=j;k.maxBreadth=j+=k.size/i.size*l;k.breadth=(j+k.minBreadth)/2}});d.visitAfter(function(i,j){i.minDepth=(j-1)*h;i.maxDepth=i.depth=j*h});pv.Layout.Hierarchy.NodeLink.buildImplied.call(this,b)}};pv.Layout.Partition.Fill=function(){pv.Layout.Partition.call(this);pv.Layout.Hierarchy.Fill.constructor.call(this)};pv.Layout.Partition.Fill.prototype=pv.extend(pv.Layout.Partition);
5570+pv.Layout.Partition.Fill.prototype.buildImplied=function(b){pv.Layout.Partition.prototype.buildImplied.call(this,b)||pv.Layout.Hierarchy.Fill.buildImplied.call(this,b)};pv.Layout.Arc=function(){pv.Layout.Network.call(this);var b,c,d,f=this.buildImplied;this.buildImplied=function(g){f.call(this,g);c=g.directed;b=g.orient=="radial"?"linear":"polar";d=g.orient=="right"||g.orient=="top"};this.link.data(function(g){var h=g.sourceNode;g=g.targetNode;return d!=(c||h.breadth<g.breadth)?[h,g]:[g,h]}).interpolate(function(){return b})};
5571+pv.Layout.Arc.prototype=pv.extend(pv.Layout.Network).property("orient",String).property("directed",Boolean);pv.Layout.Arc.prototype.defaults=(new pv.Layout.Arc).extend(pv.Layout.Network.prototype.defaults).orient("bottom");pv.Layout.Arc.prototype.sort=function(b){this.$sort=b;return this};
5572+pv.Layout.Arc.prototype.buildImplied=function(b){function c(m){switch(h){case "top":return-Math.PI/2;case "bottom":return Math.PI/2;case "left":return Math.PI;case "right":return 0;case "radial":return(m-0.25)*2*Math.PI}}function d(m){switch(h){case "top":case "bottom":return m*l;case "left":return 0;case "right":return l;case "radial":return l/2+q*Math.cos(c(m))}}function f(m){switch(h){case "top":return 0;case "bottom":return k;case "left":case "right":return m*k;case "radial":return k/2+q*Math.sin(c(m))}}
5573+if(!pv.Layout.Network.prototype.buildImplied.call(this,b)){var g=b.nodes,h=b.orient,i=this.$sort,j=pv.range(g.length),l=b.width,k=b.height,q=Math.min(l,k)/2;i&&j.sort(function(m,r){return i(g[m],g[r])});for(b=0;b<g.length;b++){var o=g[j[b]],n=o.breadth=(b+0.5)/g.length;o.x=d(n);o.y=f(n);o.midAngle=c(n)}}};
5574+pv.Layout.Horizon=function(){pv.Layout.call(this);var b=this,c,d,f,g,h,i,j=this.buildImplied;this.buildImplied=function(l){j.call(this,l);c=l.bands;d=l.mode;f=Math.round((d=="color"?0.5:1)*l.height);g=l.backgroundStyle;h=pv.ramp(g,l.negativeStyle).domain(0,c);i=pv.ramp(g,l.positiveStyle).domain(0,c)};c=(new pv.Panel).data(function(){return pv.range(c*2)}).overflow("hidden").height(function(){return f}).top(function(l){return d=="color"?(l&1)*f:0}).fillStyle(function(l){return l?null:g});this.band=
5575+(new pv.Mark).top(function(l,k){return d=="mirror"&&k&1?(k+1>>1)*f:null}).bottom(function(l,k){return d=="mirror"?k&1?null:(k+1>>1)*-f:(k&1||-1)*(k+1>>1)*f}).fillStyle(function(l,k){return(k&1?h:i)((k>>1)+1)});this.band.add=function(l){return b.add(pv.Panel).extend(c).add(l).extend(this)}};pv.Layout.Horizon.prototype=pv.extend(pv.Layout).property("bands",Number).property("mode",String).property("backgroundStyle",pv.color).property("positiveStyle",pv.color).property("negativeStyle",pv.color);
5576+pv.Layout.Horizon.prototype.defaults=(new pv.Layout.Horizon).extend(pv.Layout.prototype.defaults).bands(2).mode("offset").backgroundStyle("white").positiveStyle("#1f77b4").negativeStyle("#d62728");
5577+pv.Layout.Rollup=function(){pv.Layout.Network.call(this);var b=this,c,d,f=b.buildImplied;this.buildImplied=function(g){f.call(this,g);c=g.$rollup.nodes;d=g.$rollup.links};this.node.data(function(){return c}).size(function(g){return g.nodes.length*20});this.link.interpolate("polar").eccentricity(0.8);this.link.add=function(g){return b.add(pv.Panel).data(function(){return d}).add(g).extend(this)}};pv.Layout.Rollup.prototype=pv.extend(pv.Layout.Network).property("directed",Boolean);
5578+pv.Layout.Rollup.prototype.x=function(b){this.$x=pv.functor(b);return this};pv.Layout.Rollup.prototype.y=function(b){this.$y=pv.functor(b);return this};
5579+pv.Layout.Rollup.prototype.buildImplied=function(b){function c(r){return i[r]+","+j[r]}if(!pv.Layout.Network.prototype.buildImplied.call(this,b)){var d=b.nodes,f=b.links,g=b.directed,h=d.length,i=[],j=[],l=0,k={},q={},o=pv.Mark.stack,n={parent:this};o.unshift(null);for(var m=0;m<h;m++){n.index=m;o[0]=d[m];i[m]=this.$x.apply(n,o);j[m]=this.$y.apply(n,o)}o.shift();for(m=0;m<d.length;m++){h=c(m);o=k[h];if(!o){o=k[h]=pv.extend(d[m]);o.index=l++;o.x=i[m];o.y=j[m];o.nodes=[]}o.nodes.push(d[m])}for(m=0;m<
5580+f.length;m++){l=f[m].targetNode;d=k[c(f[m].sourceNode.index)];l=k[c(l.index)];h=!g&&d.index>l.index?l.index+","+d.index:d.index+","+l.index;(o=q[h])||(o=q[h]={sourceNode:d,targetNode:l,linkValue:0,links:[]});o.links.push(f[m]);o.linkValue+=f[m].linkValue}b.$rollup={nodes:pv.values(k),links:pv.values(q)}}};
5581+pv.Layout.Matrix=function(){pv.Layout.Network.call(this);var b,c,d,f,g,h=this.buildImplied;this.buildImplied=function(i){h.call(this,i);b=i.nodes.length;c=i.width/b;d=i.height/b;f=i.$matrix.labels;g=i.$matrix.pairs};this.link.data(function(){return g}).left(function(){return c*(this.index%b)}).top(function(){return d*Math.floor(this.index/b)}).width(function(){return c}).height(function(){return d}).lineWidth(1.5).strokeStyle("#fff").fillStyle(function(i){return i.linkValue?"#555":"#eee"}).parent=
5582+this;delete this.link.add;this.label.data(function(){return f}).left(function(){return this.index&1?c*((this.index>>1)+0.5):null}).top(function(){return this.index&1?null:d*((this.index>>1)+0.5)}).textMargin(4).textAlign(function(){return this.index&1?"left":"right"}).textAngle(function(){return this.index&1?-Math.PI/2:0});delete this.node};pv.Layout.Matrix.prototype=pv.extend(pv.Layout.Network).property("directed",Boolean);pv.Layout.Matrix.prototype.sort=function(b){this.$sort=b;return this};
5583+pv.Layout.Matrix.prototype.buildImplied=function(b){if(!pv.Layout.Network.prototype.buildImplied.call(this,b)){var c=b.nodes,d=b.links,f=this.$sort,g=c.length,h=pv.range(g),i=[],j=[],l={};b.$matrix={labels:i,pairs:j};f&&h.sort(function(m,r){return f(c[m],c[r])});for(var k=0;k<g;k++)for(var q=0;q<g;q++){var o=h[k],n=h[q];j.push(l[o+"."+n]={row:k,col:q,sourceNode:c[o],targetNode:c[n],linkValue:0})}for(k=0;k<g;k++){o=h[k];i.push(c[o],c[o])}for(k=0;k<d.length;k++){i=d[k];g=i.sourceNode.index;h=i.targetNode.index;
5584+i=i.linkValue;l[g+"."+h].linkValue+=i;b.directed||(l[h+"."+g].linkValue+=i)}}};
5585+pv.Layout.Bullet=function(){pv.Layout.call(this);var b=this,c=b.buildImplied,d=b.x=pv.Scale.linear(),f,g,h,i,j;this.buildImplied=function(l){c.call(this,j=l);f=l.orient;g=/^left|right$/.test(f);h=pv.ramp("#bbb","#eee").domain(0,Math.max(1,j.ranges.length-1));i=pv.ramp("steelblue","lightsteelblue").domain(0,Math.max(1,j.measures.length-1))};(this.range=new pv.Mark).data(function(){return j.ranges}).reverse(true).left(function(){return f=="left"?0:null}).top(function(){return f=="top"?0:null}).right(function(){return f==
5586+"right"?0:null}).bottom(function(){return f=="bottom"?0:null}).width(function(l){return g?d(l):null}).height(function(l){return g?null:d(l)}).fillStyle(function(){return h(this.index)}).antialias(false).parent=b;(this.measure=new pv.Mark).extend(this.range).data(function(){return j.measures}).left(function(){return f=="left"?0:g?null:this.parent.width()/3.25}).top(function(){return f=="top"?0:g?this.parent.height()/3.25:null}).right(function(){return f=="right"?0:g?null:this.parent.width()/3.25}).bottom(function(){return f==
5587+"bottom"?0:g?this.parent.height()/3.25:null}).fillStyle(function(){return i(this.index)}).parent=b;(this.marker=new pv.Mark).data(function(){return j.markers}).left(function(l){return f=="left"?d(l):g?null:this.parent.width()/2}).top(function(l){return f=="top"?d(l):g?this.parent.height()/2:null}).right(function(l){return f=="right"?d(l):null}).bottom(function(l){return f=="bottom"?d(l):null}).strokeStyle("black").shape("bar").angle(function(){return g?0:Math.PI/2}).parent=b;(this.tick=new pv.Mark).data(function(){return d.ticks(7)}).left(function(l){return f==
5588+"left"?d(l):null}).top(function(l){return f=="top"?d(l):null}).right(function(l){return f=="right"?d(l):g?null:-6}).bottom(function(l){return f=="bottom"?d(l):g?-8:null}).height(function(){return g?6:null}).width(function(){return g?null:6}).parent=b};pv.Layout.Bullet.prototype=pv.extend(pv.Layout).property("orient",String).property("ranges").property("markers").property("measures").property("maximum",Number);pv.Layout.Bullet.prototype.defaults=(new pv.Layout.Bullet).extend(pv.Layout.prototype.defaults).orient("left").ranges([]).markers([]).measures([]);
5589+pv.Layout.Bullet.prototype.buildImplied=function(b){pv.Layout.prototype.buildImplied.call(this,b);var c=this.parent[/^left|right$/.test(b.orient)?"width":"height"]();b.maximum=b.maximum||pv.max([].concat(b.ranges,b.markers,b.measures));this.x.domain(0,b.maximum).range(0,c)};pv.Behavior={};
5590+pv.Behavior.drag=function(){function b(l){g=this.index;f=this.scene;var k=this.mouse();i=((h=l).fix=pv.vector(l.x,l.y)).minus(k);j={x:this.parent.width()-(l.dx||0),y:this.parent.height()-(l.dy||0)};f.mark.context(f,g,function(){this.render()});pv.Mark.dispatch("dragstart",f,g)}function c(){if(f){f.mark.context(f,g,function(){var l=this.mouse();h.x=h.fix.x=Math.max(0,Math.min(i.x+l.x,j.x));h.y=h.fix.y=Math.max(0,Math.min(i.y+l.y,j.y));this.render()});pv.Mark.dispatch("drag",f,g)}}function d(){if(f){h.fix=
5591+null;f.mark.context(f,g,function(){this.render()});pv.Mark.dispatch("dragend",f,g);f=null}}var f,g,h,i,j;pv.listen(window,"mousemove",c);pv.listen(window,"mouseup",d);return b};
5592+pv.Behavior.point=function(b){function c(k,q){k=k[q];q={cost:Infinity};for(var o=0,n=k.visible&&k.children.length;o<n;o++){var m=k.children[o],r=m.mark,s;if(r.type=="panel"){r.scene=m;for(var u=0,x=m.length;u<x;u++){r.index=u;s=c(m,u);if(s.cost<q.cost)q=s}delete r.scene;delete r.index}else if(r.$handlers.point){r=r.mouse();u=0;for(x=m.length;u<x;u++){var t=m[u];s=r.x-t.left-(t.width||0)/2;t=r.y-t.top-(t.height||0)/2;var p=i*s*s+j*t*t;if(p<q.cost){q.distance=s*s+t*t;q.cost=p;q.scene=m;q.index=u}}}}return q}
5593+function d(){var k=c(this.scene,this.index);if(k.cost==Infinity||k.distance>l)k=null;if(g){if(k&&g.scene==k.scene&&g.index==k.index)return;pv.Mark.dispatch("unpoint",g.scene,g.index)}if(g=k){pv.Mark.dispatch("point",k.scene,k.index);pv.listen(this.root.canvas(),"mouseout",f)}}function f(k){if(g&&!pv.ancestor(this,k.relatedTarget)){pv.Mark.dispatch("unpoint",g.scene,g.index);g=null}}var g,h=null,i=1,j=1,l=arguments.length?b*b:900;d.collapse=function(k){if(arguments.length){h=String(k);switch(h){case "y":i=
5594+1;j=0;break;case "x":i=0;j=1;break;default:j=i=1;break}return d}return h};return d};
5595+pv.Behavior.select=function(){function b(j){g=this.index;f=this.scene;i=this.mouse();h=j;h.x=i.x;h.y=i.y;h.dx=h.dy=0;pv.Mark.dispatch("selectstart",f,g)}function c(){if(f){f.mark.context(f,g,function(){var j=this.mouse();h.x=Math.max(0,Math.min(i.x,j.x));h.y=Math.max(0,Math.min(i.y,j.y));h.dx=Math.min(this.width(),Math.max(j.x,i.x))-h.x;h.dy=Math.min(this.height(),Math.max(j.y,i.y))-h.y;this.render()});pv.Mark.dispatch("select",f,g)}}function d(){if(f){pv.Mark.dispatch("selectend",f,g);f=null}}var f,
5596+g,h,i;pv.listen(window,"mousemove",c);pv.listen(window,"mouseup",d);return b};
5597+pv.Behavior.resize=function(b){function c(l){h=this.index;g=this.scene;j=this.mouse();i=l;switch(b){case "left":j.x=i.x+i.dx;break;case "right":j.x=i.x;break;case "top":j.y=i.y+i.dy;break;case "bottom":j.y=i.y;break}pv.Mark.dispatch("resizestart",g,h)}function d(){if(g){g.mark.context(g,h,function(){var l=this.mouse();i.x=Math.max(0,Math.min(j.x,l.x));i.y=Math.max(0,Math.min(j.y,l.y));i.dx=Math.min(this.parent.width(),Math.max(l.x,j.x))-i.x;i.dy=Math.min(this.parent.height(),Math.max(l.y,j.y))-i.y;
5598+this.render()});pv.Mark.dispatch("resize",g,h)}}function f(){if(g){pv.Mark.dispatch("resizeend",g,h);g=null}}var g,h,i,j;pv.listen(window,"mousemove",d);pv.listen(window,"mouseup",f);return c};
5599+pv.Behavior.pan=function(){function b(){g=this.index;f=this.scene;i=pv.vector(pv.event.pageX,pv.event.pageY);h=this.transform();j=1/(h.k*this.scale);if(l)l={x:(1-h.k)*this.width(),y:(1-h.k)*this.height()}}function c(){if(f){f.mark.context(f,g,function(){var k=h.translate((pv.event.pageX-i.x)*j,(pv.event.pageY-i.y)*j);if(l){k.x=Math.max(l.x,Math.min(0,k.x));k.y=Math.max(l.y,Math.min(0,k.y))}this.transform(k).render()});pv.Mark.dispatch("pan",f,g)}}function d(){f=null}var f,g,h,i,j,l;b.bound=function(k){if(arguments.length){l=
5600+Boolean(k);return this}return Boolean(l)};pv.listen(window,"mousemove",c);pv.listen(window,"mouseup",d);return b};
5601+pv.Behavior.zoom=function(b){function c(){var f=this.mouse(),g=pv.event.wheel*b;f=this.transform().translate(f.x,f.y).scale(g<0?1E3/(1E3-g):(1E3+g)/1E3).translate(-f.x,-f.y);if(d){f.k=Math.max(1,f.k);f.x=Math.max((1-f.k)*this.width(),Math.min(0,f.x));f.y=Math.max((1-f.k)*this.height(),Math.min(0,f.y))}this.transform(f).render();pv.Mark.dispatch("zoom",this.scene,this.index)}var d;arguments.length||(b=1/48);c.bound=function(f){if(arguments.length){d=Boolean(f);return this}return Boolean(d)};return c};
5602+pv.Geo=function(){};
5603+pv.Geo.projections={mercator:{project:function(b){return{x:b.lng/180,y:b.lat>85?1:b.lat<-85?-1:Math.log(Math.tan(Math.PI/4+pv.radians(b.lat)/2))/Math.PI}},invert:function(b){return{lng:b.x*180,lat:pv.degrees(2*Math.atan(Math.exp(b.y*Math.PI))-Math.PI/2)}}},"gall-peters":{project:function(b){return{x:b.lng/180,y:Math.sin(pv.radians(b.lat))}},invert:function(b){return{lng:b.x*180,lat:pv.degrees(Math.asin(b.y))}}},sinusoidal:{project:function(b){return{x:pv.radians(b.lng)*Math.cos(pv.radians(b.lat))/Math.PI,
5604+y:b.lat/90}},invert:function(b){return{lng:pv.degrees(b.x*Math.PI/Math.cos(b.y*Math.PI/2)),lat:b.y*90}}},aitoff:{project:function(b){var c=pv.radians(b.lng);b=pv.radians(b.lat);var d=Math.acos(Math.cos(b)*Math.cos(c/2));return{x:2*(d?Math.cos(b)*Math.sin(c/2)*d/Math.sin(d):0)/Math.PI,y:2*(d?Math.sin(b)*d/Math.sin(d):0)/Math.PI}},invert:function(b){var c=b.y*Math.PI/2;return{lng:pv.degrees(b.x*Math.PI/2/Math.cos(c)),lat:pv.degrees(c)}}},hammer:{project:function(b){var c=pv.radians(b.lng);b=pv.radians(b.lat);
5605+var d=Math.sqrt(1+Math.cos(b)*Math.cos(c/2));return{x:2*Math.SQRT2*Math.cos(b)*Math.sin(c/2)/d/3,y:Math.SQRT2*Math.sin(b)/d/1.5}},invert:function(b){var c=b.x*3;b=b.y*1.5;var d=Math.sqrt(1-c*c/16-b*b/4);return{lng:pv.degrees(2*Math.atan2(d*c,2*(2*d*d-1))),lat:pv.degrees(Math.asin(d*b))}}},identity:{project:function(b){return{x:b.lng/180,y:b.lat/90}},invert:function(b){return{lng:b.x*180,lat:b.y*90}}}};
5606+pv.Geo.scale=function(b){function c(m){if(!o||m.lng!=o.lng||m.lat!=o.lat){o=m;m=d(m);n={x:l(m.x),y:k(m.y)}}return n}function d(m){return j.project({lng:m.lng-q.lng,lat:m.lat})}function f(m){m=j.invert(m);m.lng+=q.lng;return m}var g={x:0,y:0},h={x:1,y:1},i=[],j=pv.Geo.projections.identity,l=pv.Scale.linear(-1,1).range(0,1),k=pv.Scale.linear(-1,1).range(1,0),q={lng:0,lat:0},o,n;c.x=function(m){return c(m).x};c.y=function(m){return c(m).y};c.ticks={lng:function(m){var r;if(i.length>1){var s=pv.Scale.linear();
5607+if(m==undefined)m=10;r=s.domain(i,function(u){return u.lat}).ticks(m);m=s.domain(i,function(u){return u.lng}).ticks(m)}else{r=pv.range(-80,81,10);m=pv.range(-180,181,10)}return m.map(function(u){return r.map(function(x){return{lat:x,lng:u}})})},lat:function(m){return pv.transpose(c.ticks.lng(m))}};c.invert=function(m){return f({x:l.invert(m.x),y:k.invert(m.y)})};c.domain=function(m,r){if(arguments.length){i=m instanceof Array?arguments.length>1?pv.map(m,r):m:Array.prototype.slice.call(arguments);
5608+if(i.length>1){var s=i.map(function(x){return x.lng}),u=i.map(function(x){return x.lat});q={lng:(pv.max(s)+pv.min(s))/2,lat:(pv.max(u)+pv.min(u))/2};s=i.map(d);l.domain(s,function(x){return x.x});k.domain(s,function(x){return x.y})}else{q={lng:0,lat:0};l.domain(-1,1);k.domain(-1,1)}o=null;return this}return i};c.range=function(m,r){if(arguments.length){if(typeof m=="object"){g={x:Number(m.x),y:Number(m.y)};h={x:Number(r.x),y:Number(r.y)}}else{g={x:0,y:0};h={x:Number(m),y:Number(r)}}l.range(g.x,h.x);
5609+k.range(h.y,g.y);o=null;return this}return[g,h]};c.projection=function(m){if(arguments.length){j=typeof m=="string"?pv.Geo.projections[m]||pv.Geo.projections.identity:m;return this.domain(i)}return m};c.by=function(m){function r(){return c(m.apply(this,arguments))}for(var s in c)r[s]=c[s];return r};arguments.length&&c.projection(b);return c};
5610hunk ./src/allmydata/web/root.py 167
5611         self.child_named = FileHandler(client)
5612         self.child_status = status.Status(client.get_history())
5613         self.child_statistics = status.Statistics(client.stats_provider)
5614+        def f(name):
5615+            return nevow_File(resource_filename('allmydata.web', name))
5616+        self.putChild("jquery.js", f("jquery.js"))
5617+        self.putChild("download_status_timeline.js", f("download_status_timeline.js"))
5618+        self.putChild("protovis-r3.2.js", f("protovis-r3.2.js"))
5619 
5620     def child_helper_status(self, ctx):
5621         # the Helper isn't attached until after the Tub starts, so this child
5622hunk ./src/allmydata/web/status.py 334
5623         d.addCallback(_render)
5624         return d
5625 
5626+def tfmt(when):
5627+    #return when * 1000.0 # stupid JS timestamps
5628+    return "%.6f" % when
5629+    # the timeline markers represent UTC. To make these events line up, we
5630+    # must supply the "Z" suffix.
5631+    #return "%.2f" % (1000*when)
5632+    t = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(when))
5633+    fract = "%.6f" % (when % 1.0)
5634+    if fract.startswith("0."):
5635+        fract = fract[2:]
5636+    return t+"."+fract+"Z"
5637+
5638 class DownloadStatusPage(DownloadResultsRendererMixin, rend.Page):
5639     docFactory = getxmlfile("download-status.xhtml")
5640 
5641hunk ./src/allmydata/web/status.py 353
5642         rend.Page.__init__(self, data)
5643         self.download_status = data
5644 
5645+    def child_timeline(self, ctx):
5646+        return DownloadStatusTimelinePage(self.download_status)
5647+
5648     def download_results(self):
5649         return defer.maybeDeferred(self.download_status.get_results)
5650 
5651hunk ./src/allmydata/web/status.py 362
5652     def relative_time(self, t):
5653         if t is None:
5654             return t
5655-        if self.download_status.started is not None:
5656-            return t - self.download_status.started
5657+        if self.download_status.first_timestamp is not None:
5658+            return t - self.download_status.first_timestamp
5659         return t
5660     def short_relative_time(self, t):
5661         t = self.relative_time(t)
5662hunk ./src/allmydata/web/status.py 371
5663             return ""
5664         return "+%.6fs" % t
5665 
5666-    def renderHTTP(self, ctx):
5667-        req = inevow.IRequest(ctx)
5668-        t = get_arg(req, "t")
5669-        if t == "json":
5670-            return self.json(req)
5671-        return rend.Page.renderHTTP(self, ctx)
5672+    def _find_overlap(self, events, start_key, end_key):
5673+        # given a list of event dicts, return a new list in which each event
5674+        # has an extra "row" key (an int, starting at 0). This is a hint to
5675+        # our JS frontend about how to overlap the parts of the graph it is
5676+        # drawing.
5677+
5678+        # we must always make a copy, since we're going to be adding "row"
5679+        # keys and don't want to change the original objects. If we're
5680+        # stringifying serverids, we'll also be changing the serverid keys.
5681+        new_events = []
5682+        rows = []
5683+        for ev in events:
5684+            ev = ev.copy()
5685+            if "serverid" in ev:
5686+                ev["serverid"] = base32.b2a(ev["serverid"])
5687+            # find an empty slot in the rows
5688+            free_slot = None
5689+            for row,finished in enumerate(rows):
5690+                if finished is not None:
5691+                    if ev[start_key] > finished:
5692+                        free_slot = row
5693+                        break
5694+            if free_slot is None:
5695+                free_slot = len(rows)
5696+                rows.append(ev[end_key])
5697+            else:
5698+                rows[free_slot] = ev[end_key]
5699+            ev["row"] = free_slot
5700+            new_events.append(ev)
5701+        return new_events
5702 
5703hunk ./src/allmydata/web/status.py 402
5704-    def json(self, req):
5705-        req.setHeader("content-type", "text/plain")
5706-        data = {}
5707-        dyhb_events = []
5708-        for serverid,requests in self.download_status.dyhb_requests.iteritems():
5709-            for req in requests:
5710-                dyhb_events.append( (base32.b2a(serverid),) + req )
5711-        dyhb_events.sort(key=lambda req: req[1])
5712-        data["dyhb"] = dyhb_events
5713-        request_events = []
5714-        for serverid,requests in self.download_status.requests.iteritems():
5715-            for req in requests:
5716-                request_events.append( (base32.b2a(serverid),) + req )
5717-        request_events.sort(key=lambda req: (req[4],req[1]))
5718-        data["requests"] = request_events
5719-        data["segment"] = self.download_status.segment_events
5720-        data["read"] = self.download_status.read_events
5721+    def _find_overlap_requests(self, events):
5722+        """We compute a three-element 'row tuple' for each event: (serverid,
5723+        shnum, row). All elements are ints. The first is a mapping from
5724+        serverid to group number, the second is a mapping from shnum to
5725+        subgroup number. The third is a row within the subgroup.
5726+
5727+        We also return a list of lists of rowcounts, so renderers can decide
5728+        how much vertical space to give to each row.
5729+        """
5730+
5731+        serverid_to_group = {}
5732+        groupnum_to_rows = {} # maps groupnum to a table of rows. Each table
5733+                              # is a list with an element for each row number
5734+                              # (int starting from 0) that contains a
5735+                              # finish_time, indicating that the row is empty
5736+                              # beyond that time. If finish_time is None, it
5737+                              # indicate a response that has not yet
5738+                              # completed, so the row cannot be reused.
5739+        new_events = []
5740+        for ev in events:
5741+            # DownloadStatus promises to give us events in temporal order
5742+            ev = ev.copy()
5743+            ev["serverid"] = base32.b2a(ev["serverid"])
5744+            if ev["serverid"] not in serverid_to_group:
5745+                groupnum = len(serverid_to_group)
5746+                serverid_to_group[ev["serverid"]] = groupnum
5747+            groupnum = serverid_to_group[ev["serverid"]]
5748+            if groupnum not in groupnum_to_rows:
5749+                groupnum_to_rows[groupnum] = []
5750+            rows = groupnum_to_rows[groupnum]
5751+            # find an empty slot in the rows
5752+            free_slot = None
5753+            for row,finished in enumerate(rows):
5754+                if finished is not None:
5755+                    if ev["start_time"] > finished:
5756+                        free_slot = row
5757+                        break
5758+            if free_slot is None:
5759+                free_slot = len(rows)
5760+                rows.append(ev["finish_time"])
5761+            else:
5762+                rows[free_slot] = ev["finish_time"]
5763+            ev["row"] = (groupnum, free_slot)
5764+            new_events.append(ev)
5765+        # maybe also return serverid_to_group, groupnum_to_rows, and some
5766+        # indication of the highest finish_time
5767+        #
5768+        # actually, return the highest rownum for each groupnum
5769+        highest_rownums = [len(groupnum_to_rows[groupnum])
5770+                           for groupnum in range(len(serverid_to_group))]
5771+        return new_events, highest_rownums
5772+
5773+    def child_timeline_parameters(self, ctx):
5774+        ds = self.download_status
5775+        d = { "start": tfmt(ds.started),
5776+              "end": tfmt(ds.started+2.0),
5777+              }
5778+        return simplejson.dumps(d, indent=1) + "\n"
5779+
5780+    def child_event_json(self, ctx):
5781+        inevow.IRequest(ctx).setHeader("content-type", "text/plain")
5782+        data = { } # this will be returned to the GET
5783+        ds = self.download_status
5784+
5785+        data["read"] = self._find_overlap(ds.read_events,
5786+                                          "start_time", "finish_time")
5787+        data["segment"] = self._find_overlap(ds.segment_events,
5788+                                             "start_time", "finish_time")
5789+        data["dyhb"] = self._find_overlap(ds.dyhb_requests,
5790+                                          "start_time", "finish_time")
5791+        data["block"],data["block_rownums"] = self._find_overlap_requests(ds.block_requests)
5792+
5793+        servernums = {}
5794+        serverid_strings = {}
5795+        for d_ev in data["dyhb"]:
5796+            if d_ev["serverid"] not in servernums:
5797+                servernum = len(servernums)
5798+                servernums[d_ev["serverid"]] = servernum
5799+                #title= "%s: %s" % ( ",".join([str(shnum) for shnum in shnums]))
5800+                serverid_strings[servernum] = d_ev["serverid"][:4]
5801+        data["server_info"] = dict([(serverid, {"num": servernums[serverid],
5802+                                                "color": self.color(base32.a2b(serverid)),
5803+                                                "short": serverid_strings[servernum],
5804+                                                })
5805+                                   for serverid in servernums.keys()])
5806+        data["num_serverids"] = len(serverid_strings)
5807+        data["serverids"] = serverid_strings;
5808+        data["bounds"] = {"min": ds.first_timestamp,
5809+                          "max": ds.last_timestamp,
5810+                          }
5811+        # for testing
5812+        ## data["bounds"]["max"] = tfmt(max([d_ev["finish_time"]
5813+        ##                                   for d_ev in data["dyhb"]
5814+        ##                                   if d_ev["finish_time"] is not None]
5815+        ##                                  ))
5816         return simplejson.dumps(data, indent=1) + "\n"
5817 
5818hunk ./src/allmydata/web/status.py 499
5819+    def render_timeline_link(self, ctx, data):
5820+        from nevow import url
5821+        return T.a(href=url.URL.fromContext(ctx).child("timeline"))["timeline"]
5822+
5823+    def _rate_and_time(self, bytes, seconds):
5824+        time_s = self.render_time(None, seconds)
5825+        if seconds != 0:
5826+            rate = self.render_rate(None, 1.0 * bytes / seconds)
5827+            return T.span(title=rate)[time_s]
5828+        return T.span[time_s]
5829+
5830     def render_events(self, ctx, data):
5831         if not self.download_status.storage_index:
5832             return
5833hunk ./src/allmydata/web/status.py 519
5834         t = T.table(class_="status-download-events")
5835         t[T.tr[T.td["serverid"], T.td["sent"], T.td["received"],
5836                T.td["shnums"], T.td["RTT"]]]
5837-        dyhb_events = []
5838-        for serverid,requests in self.download_status.dyhb_requests.iteritems():
5839-            for req in requests:
5840-                dyhb_events.append( (serverid,) + req )
5841-        dyhb_events.sort(key=lambda req: req[1])
5842-        for d_ev in dyhb_events:
5843-            (serverid, sent, shnums, received) = d_ev
5844+        for d_ev in self.download_status.dyhb_requests:
5845+            serverid = d_ev["serverid"]
5846+            sent = d_ev["start_time"]
5847+            shnums = d_ev["response_shnums"]
5848+            received = d_ev["finish_time"]
5849             serverid_s = idlib.shortnodeid_b2a(serverid)
5850             rtt = None
5851             if received is not None:
5852hunk ./src/allmydata/web/status.py 542
5853                T.td["time"], T.td["decrypttime"], T.td["pausedtime"],
5854                T.td["speed"]]]
5855         for r_ev in self.download_status.read_events:
5856-            (start, length, requesttime, finishtime, bytes, decrypt, paused) = r_ev
5857-            if finishtime is not None:
5858-                rtt = finishtime - requesttime - paused
5859+            start = r_ev["start"]
5860+            length = r_ev["length"]
5861+            bytes = r_ev["bytes_returned"]
5862+            decrypt_time = ""
5863+            if bytes:
5864+                decrypt_time = self._rate_and_time(bytes, r_ev["decrypt_time"])
5865+            speed, rtt = "",""
5866+            if r_ev["finish_time"] is not None:
5867+                rtt = r_ev["finish_time"] - r_ev["start_time"] - r_ev["paused_time"]
5868                 speed = self.render_rate(None, compute_rate(bytes, rtt))
5869                 rtt = self.render_time(None, rtt)
5870hunk ./src/allmydata/web/status.py 553
5871-                decrypt = self.render_time(None, decrypt)
5872-                paused = self.render_time(None, paused)
5873-            else:
5874-                speed, rtt, decrypt, paused = "","","",""
5875+            paused = self.render_time(None, r_ev["paused_time"])
5876+
5877             t[T.tr[T.td["[%d:+%d]" % (start, length)],
5878hunk ./src/allmydata/web/status.py 556
5879-                   T.td[srt(requesttime)], T.td[srt(finishtime)],
5880-                   T.td[bytes], T.td[rtt], T.td[decrypt], T.td[paused],
5881+                   T.td[srt(r_ev["start_time"])], T.td[srt(r_ev["finish_time"])],
5882+                   T.td[bytes], T.td[rtt],
5883+                   T.td[decrypt_time], T.td[paused],
5884                    T.td[speed],
5885                    ]]
5886         l["Read Events:", t]
5887hunk ./src/allmydata/web/status.py 564
5888 
5889         t = T.table(class_="status-download-events")
5890-        t[T.tr[T.td["type"], T.td["segnum"], T.td["when"], T.td["range"],
5891+        t[T.tr[T.td["segnum"], T.td["start"], T.td["active"], T.td["finish"],
5892+               T.td["range"],
5893                T.td["decodetime"], T.td["segtime"], T.td["speed"]]]
5894hunk ./src/allmydata/web/status.py 567
5895-        reqtime = (None, None)
5896         for s_ev in self.download_status.segment_events:
5897hunk ./src/allmydata/web/status.py 568
5898-            (etype, segnum, when, segstart, seglen, decodetime) = s_ev
5899-            if etype == "request":
5900-                t[T.tr[T.td["request"], T.td["seg%d" % segnum],
5901-                       T.td[srt(when)]]]
5902-                reqtime = (segnum, when)
5903-            elif etype == "delivery":
5904-                if reqtime[0] == segnum:
5905-                    segtime = when - reqtime[1]
5906+            range_s = ""
5907+            segtime_s = ""
5908+            speed = ""
5909+            decode_time = ""
5910+            if s_ev["finish_time"] is not None:
5911+                if s_ev["success"]:
5912+                    segtime = s_ev["finish_time"] - s_ev["active_time"]
5913+                    segtime_s = self.render_time(None, segtime)
5914+                    seglen = s_ev["segment_length"]
5915+                    range_s = "[%d:+%d]" % (s_ev["segment_start"], seglen)
5916                     speed = self.render_rate(None, compute_rate(seglen, segtime))
5917hunk ./src/allmydata/web/status.py 579
5918-                    segtime = self.render_time(None, segtime)
5919+                    decode_time = self._rate_and_time(seglen, s_ev["decode_time"])
5920                 else:
5921hunk ./src/allmydata/web/status.py 581
5922-                    segtime, speed = "", ""
5923-                t[T.tr[T.td["delivery"], T.td["seg%d" % segnum],
5924-                       T.td[srt(when)],
5925-                       T.td["[%d:+%d]" % (segstart, seglen)],
5926-                       T.td[self.render_time(None,decodetime)],
5927-                       T.td[segtime], T.td[speed]]]
5928-            elif etype == "error":
5929-                t[T.tr[T.td["error"], T.td["seg%d" % segnum]]]
5930+                    # error
5931+                    range_s = "error"
5932+            else:
5933+                # not finished yet
5934+                pass
5935+
5936+            t[T.tr[T.td["seg%d" % s_ev["segment_number"]],
5937+                   T.td[srt(s_ev["start_time"])],
5938+                   T.td[srt(s_ev["active_time"])],
5939+                   T.td[srt(s_ev["finish_time"])],
5940+                   T.td[range_s],
5941+                   T.td[decode_time],
5942+                   T.td[segtime_s], T.td[speed]]]
5943         l["Segment Events:", t]
5944 
5945         t = T.table(border="1")
5946hunk ./src/allmydata/web/status.py 598
5947         t[T.tr[T.td["serverid"], T.td["shnum"], T.td["range"],
5948-               T.td["txtime"], T.td["rxtime"], T.td["received"], T.td["RTT"]]]
5949-        reqtime = (None, None)
5950-        request_events = []
5951-        for serverid,requests in self.download_status.requests.iteritems():
5952-            for req in requests:
5953-                request_events.append( (serverid,) + req )
5954-        request_events.sort(key=lambda req: (req[4],req[1]))
5955-        for r_ev in request_events:
5956-            (peerid, shnum, start, length, sent, receivedlen, received) = r_ev
5957+               T.td["txtime"], T.td["rxtime"],
5958+               T.td["received"], T.td["RTT"]]]
5959+        for r_ev in self.download_status.block_requests:
5960             rtt = None
5961hunk ./src/allmydata/web/status.py 602
5962-            if received is not None:
5963-                rtt = received - sent
5964-            peerid_s = idlib.shortnodeid_b2a(peerid)
5965-            t[T.tr(style="background: %s" % self.color(peerid))[
5966-                T.td[peerid_s], T.td[shnum],
5967-                T.td["[%d:+%d]" % (start, length)],
5968-                T.td[srt(sent)], T.td[srt(received)], T.td[receivedlen],
5969+            if r_ev["finish_time"] is not None:
5970+                rtt = r_ev["finish_time"] - r_ev["start_time"]
5971+            serverid_s = idlib.shortnodeid_b2a(r_ev["serverid"])
5972+            t[T.tr(style="background: %s" % self.color(r_ev["serverid"]))[
5973+                T.td[serverid_s], T.td[r_ev["shnum"]],
5974+                T.td["[%d:+%d]" % (r_ev["start"], r_ev["length"])],
5975+                T.td[srt(r_ev["start_time"])], T.td[srt(r_ev["finish_time"])],
5976+                T.td[r_ev["response_length"] or ""],
5977                 T.td[self.render_time(None, rtt)],
5978                 ]]
5979         l["Requests:", t]
5980hunk ./src/allmydata/web/status.py 660
5981     def render_status(self, ctx, data):
5982         return data.get_status()
5983 
5984+class DownloadStatusTimelinePage(rend.Page):
5985+    docFactory = getxmlfile("download-status-timeline.xhtml")
5986+
5987+    def render_started(self, ctx, data):
5988+        TIME_FORMAT = "%H:%M:%S %d-%b-%Y"
5989+        started_s = time.strftime(TIME_FORMAT,
5990+                                  time.localtime(data.get_started()))
5991+        return started_s + " (%s)" % data.get_started()
5992+
5993+    def render_si(self, ctx, data):
5994+        si_s = base32.b2a_or_none(data.get_storage_index())
5995+        if si_s is None:
5996+            si_s = "(None)"
5997+        return si_s
5998+
5999+    def render_helper(self, ctx, data):
6000+        return {True: "Yes",
6001+                False: "No"}[data.using_helper()]
6002+
6003+    def render_total_size(self, ctx, data):
6004+        size = data.get_size()
6005+        if size is None:
6006+            return "(unknown)"
6007+        return size
6008+
6009+    def render_progress(self, ctx, data):
6010+        progress = data.get_progress()
6011+        # TODO: make an ascii-art bar
6012+        return "%.1f%%" % (100.0 * progress)
6013+
6014+    def render_status(self, ctx, data):
6015+        return data.get_status()
6016+
6017 class RetrieveStatusPage(rend.Page, RateAndTimeMixin):
6018     docFactory = getxmlfile("retrieve-status.xhtml")
6019 
6020}
6021
6022Context:
6023
6024[TAG allmydata-tahoe-1.8.0
6025zooko@zooko.com**20100924021631
6026 Ignore-this: 494ca0a885c5e20c883845fc53e7ab5d
6027]
6028Patch bundle hash:
6029eb30b2704886f398e8c65863a28d38059a2259c9