PKI˜9“×2EGG-INFO/dependency_links.txt PKI˜9Õ"HbbEGG-INFO/entry_points.txt[trac.plugins] mastertickets.web_ui = mastertickets.web_ui mastertickets.api = mastertickets.api PKI˜9÷Ô’’EGG-INFO/PKG-INFOMetadata-Version: 1.0 Name: TracMasterTickets Version: 2.1.3 Summary: Provides support for ticket dependencies and master tickets. Home-page: http://trac-hacks.org/wiki/MasterTicketsPlugin Author: Noah Kantrowitz Author-email: noah@coderanger.net License: BSD Description: UNKNOWN Keywords: trac plugin ticket dependencies master Platform: UNKNOWN Classifier: Framework :: Trac Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: License :: OSI Approved :: BSD License Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python PKI˜9,^D†EGG-INFO/requires.txtTrac>=0.11 Genshi>=0.5PKI˜9Ç9/³  EGG-INFO/SOURCES.txtsetup.py TracMasterTickets.egg-info/PKG-INFO TracMasterTickets.egg-info/SOURCES.txt TracMasterTickets.egg-info/dependency_links.txt TracMasterTickets.egg-info/entry_points.txt TracMasterTickets.egg-info/requires.txt TracMasterTickets.egg-info/top_level.txt mastertickets/__init__.py mastertickets/api.py mastertickets/db_default.py mastertickets/graphviz.py mastertickets/model.py mastertickets/util.py mastertickets/web_ui.py mastertickets/htdocs/caution.png mastertickets/htdocs/checkmark.gif mastertickets/htdocs/disable_resolve.js mastertickets/htdocs/exclaim.png mastertickets/htdocs/jquery.js mastertickets/htdocs/linkify_blockedby.js mastertickets/htdocs/linkify_blocking.js mastertickets/htdocs/ticket.css mastertickets/htdocs/x.png mastertickets/templates/depgraph.html PKI˜9z< EGG-INFO/top_level.txtmastertickets PKI˜9“×2EGG-INFO/zip-safe PK²6f6mastertickets/__init__.pyPKI˜93ʨsŒŒmastertickets/__init__.pyc;ò q€íEc@sdS(N((((s<build/bdist.darwin-8.11.1-i386/egg/mastertickets/__init__.pys?sPKÃZ¡8E𮍛›mastertickets/api.py# Created by Noah Kantrowitz on 2007-07-04. # Copyright (c) 2007 Noah Kantrowitz. All rights reserved. import re from trac.core import * from trac.env import IEnvironmentSetupParticipant from trac.db import DatabaseManager from trac.ticket.api import ITicketChangeListener, ITicketManipulator from trac.util.compat import set, sorted import db_default from model import TicketLinks class MasterTicketsSystem(Component): """Central functionality for the MasterTickets plugin.""" implements(IEnvironmentSetupParticipant, ITicketChangeListener, ITicketManipulator) NUMBERS_RE = re.compile(r'\d+', re.U) # IEnvironmentSetupParticipant methods def environment_created(self): self.found_db_version = 0 self.upgrade_environment(self.env.get_db_cnx()) def environment_needs_upgrade(self, db): cursor = db.cursor() cursor.execute("SELECT value FROM system WHERE name=%s", (db_default.name,)) value = cursor.fetchone() if not value: self.found_db_version = 0 return True else: self.found_db_version = int(value[0]) #self.log.debug('WeatherWidgetSystem: Found db version %s, current is %s' % (self.found_db_version, db_default.version)) if self.found_db_version < db_default.version: return True # Check for our custom fields if 'blocking' not in self.config['ticket-custom'] or 'blockedby' not in self.config['ticket-custom']: return True # Fall through return False def upgrade_environment(self, db): db_manager, _ = DatabaseManager(self.env)._get_connector() # Insert the default table old_data = {} # {table_name: (col_names, [row, ...]), ...} cursor = db.cursor() if not self.found_db_version: cursor.execute("INSERT INTO system (name, value) VALUES (%s, %s)",(db_default.name, db_default.version)) else: cursor.execute("UPDATE system SET value=%s WHERE name=%s",(db_default.version, db_default.name)) for tbl in db_default.tables: try: cursor.execute('SELECT * FROM %s'%tbl.name) old_data[tbl.name] = ([d[0] for d in cursor.description], cursor.fetchall()) cursor.execute('DROP TABLE %s'%tbl.name) except Exception, e: if 'OperationalError' not in e.__class__.__name__: raise e # If it is an OperationalError, just move on to the next table for tbl in db_default.tables: for sql in db_manager.to_sql(tbl): cursor.execute(sql) # Try to reinsert any old data if tbl.name in old_data: data = old_data[tbl.name] sql = 'INSERT INTO %s (%s) VALUES (%s)' % \ (tbl.name, ','.join(data[0]), ','.join(['%s'] * len(data[0]))) for row in data[1]: try: cursor.execute(sql, row) except Exception, e: if 'OperationalError' not in e.__class__.__name__: raise e custom = self.config['ticket-custom'] config_dirty = False if 'blocking' not in custom: custom.set('blocking', 'text') custom.set('blocking.label', 'Blocking') config_dirty = True if 'blockedby' not in custom: custom.set('blockedby', 'text') custom.set('blockedby.label', 'Blocked By') config_dirty = True if config_dirty: self.config.save() # ITicketChangeListener methods def ticket_created(self, tkt): self.ticket_changed(tkt, '', tkt['reporter'], {}) def ticket_changed(self, tkt, comment, author, old_values): db = self.env.get_db_cnx() links = TicketLinks(self.env, tkt, db) links.blocking = set(self.NUMBERS_RE.findall(tkt['blocking'] or '')) links.blocked_by = set(self.NUMBERS_RE.findall(tkt['blockedby'] or '')) links.save(author, comment, tkt.time_changed, db) db.commit() def ticket_deleted(self, tkt): db = self.env.get_db_cnx() links = TicketLinks(self.env, tkt, db) links.blocking = set() links.blocked_by = set() links.save('trac', 'Ticket #%s deleted'%tkt.id, when=None, db=db) db.commit() # ITicketManipulator methods def prepare_ticket(self, req, ticket, fields, actions): pass def validate_ticket(self, req, ticket): db = self.env.get_db_cnx() cursor = db.cursor() for field in ('blocking', 'blockedby'): try: ids = self.NUMBERS_RE.findall(ticket[field] or '') for id in ids[:]: cursor.execute('SELECT id FROM ticket WHERE id=%s', (id,)) row = cursor.fetchone() if row is None: ids.remove(id) ticket[field] = ', '.join(sorted(ids, key=lambda x: int(x))) except Exception, e: self.log.debug('MasterTickets: Error parsing %s "%s": %s', field, ticket[field], e) yield field, 'Not a valid list of ticket IDs'PKI˜9Ü`ü)//mastertickets/api.pyc;ò N Hc@s€dkZdkTdklZdklZdklZlZdk l Z l Z dk Z dk lZdefd„ƒYZdS( N(s*(sIEnvironmentSetupParticipant(sDatabaseManager(sITicketChangeListenersITicketManipulator(ssetssorted(s TicketLinkssMasterTicketsSystemcBs{tZdZeeeeƒeidei ƒZ d„Z d„Z d„Z d„Zd„Zd„Zd„Zd „ZRS( s3Central functionality for the MasterTickets plugin.s\d+cCs#d|_|i|iiƒƒdS(Ni(sselfsfound_db_versionsupgrade_environmentsenvs get_db_cnx(sself((s7build/bdist.darwin-8.11.1-i386/egg/mastertickets/api.pysenvironment_createds cCs­|iƒ}|idtifƒ|iƒ}| od|_t Sn/t |dƒ|_|iti jot Snd|i djpd|i djot Snt SdS(Ns&SELECT value FROM system WHERE name=%sisblockings ticket-customs blockedby(sdbscursorsexecutes db_defaultsnamesfetchonesvaluesselfsfound_db_versionsTruesintsversionsconfigsFalse(sselfsdbsvaluescursor((s7build/bdist.darwin-8.11.1-i386/egg/mastertickets/api.pysenvironment_needs_upgrades   (c Cs¾t|iƒiƒ\}} h}|iƒ} |i o | i dt i t i fƒnÓ| i dt i t i fƒx³t iD]¨} ym| i d| i ƒgi}| iD]}||dƒq¬~| iƒf|| i <| i d| i ƒWq~tj o&}d|iijo |‚q&q~Xq~Wxôt iD]é} x$|i| ƒD]} | i | ƒqJW| i |jo¬|| i } d| i di| dƒdid gt| dƒƒf} x_| d D]O}y| i | |ƒWqÆtj o&}d|iijo |‚qqÆXqÆWq4q4W|id }t!}d |jo*|i#d d ƒ|i#ddƒt$}nd|jo*|i#dd ƒ|i#ddƒt$}n|o|ii%ƒndS(Ns0INSERT INTO system (name, value) VALUES (%s, %s)s(UPDATE system SET value=%s WHERE name=%ssSELECT * FROM %sis DROP TABLE %ssOperationalErrorsINSERT INTO %s (%s) VALUES (%s)s,s%sis ticket-customsblockingstextsblocking.labelsBlockings blockedbysblockedby.labels Blocked By(&sDatabaseManagersselfsenvs_get_connectors db_managers_sold_datasdbscursorsfound_db_versionsexecutes db_defaultsnamesversionstablesstblsappends_[1]s descriptionsdsfetchalls Exceptionses __class__s__name__sto_sqlssqlsdatasjoinslensrowsconfigscustomsFalses config_dirtyssetsTruessave(sselfsdbs_[1]sold_datasesds db_managers config_dirtyscustomscursorstblssqlsdatas_srow((s7build/bdist.darwin-8.11.1-i386/egg/mastertickets/api.pysupgrade_environment.sT    A  =      cCs|i|d|dhƒdS(Nssreporter(sselfsticket_changedstkt(sselfstkt((s7build/bdist.darwin-8.11.1-i386/egg/mastertickets/api.pysticket_created`scCs—|iiƒ}t|i||ƒ}t|ii |dpdƒƒ|_ t|ii |dpdƒƒ|_ |i |||i|ƒ|iƒdS(Nsblockingss blockedby(sselfsenvs get_db_cnxsdbs TicketLinksstktslinksssets NUMBERS_REsfindallsblockings blocked_byssavesauthorscomments time_changedscommit(sselfstktscommentsauthors old_valuesslinkssdb((s7build/bdist.darwin-8.11.1-i386/egg/mastertickets/api.pysticket_changedcs &&cCsm|iiƒ}t|i||ƒ}tƒ|_tƒ|_ |i dd|i dt d|ƒ|i ƒdS(NstracsTicket #%s deletedswhensdb(sselfsenvs get_db_cnxsdbs TicketLinksstktslinksssetsblockings blocked_byssavesidsNonescommit(sselfstktslinkssdb((s7build/bdist.darwin-8.11.1-i386/egg/mastertickets/api.pysticket_deletedms   #cCsdS(N((sselfsreqsticketsfieldssactions((s7build/bdist.darwin-8.11.1-i386/egg/mastertickets/api.pysprepare_ticketxsc cs|iiƒ}|iƒ}xåddfD]×}y’|ii||pdƒ}xL|D]C}|i d|fƒ|i ƒ} | tjo|i|ƒqVqVWdit|dd„ƒƒ||‡ss(MasterTickets: Error parsing %s "%s": %ssNot a valid list of ticket IDs(sselfsenvs get_db_cnxsdbscursorsfields NUMBERS_REsfindallsticketsidssidsexecutesfetchonesrowsNonesremovesjoinssorteds Exceptionseslogsdebug( sselfsreqsticketsesdbsidsscursorsfieldsidsrow((s7build/bdist.darwin-8.11.1-i386/egg/mastertickets/api.pysvalidate_ticket{s     &(s__name__s __module__s__doc__s implementssIEnvironmentSetupParticipantsITicketChangeListenersITicketManipulatorsrescompilesUs NUMBERS_REsenvironment_createdsenvironment_needs_upgradesupgrade_environmentsticket_createdsticket_changedsticket_deletedsprepare_ticketsvalidate_ticket(((s7build/bdist.darwin-8.11.1-i386/egg/mastertickets/api.pysMasterTicketsSystems    2  (sres trac.corestrac.envsIEnvironmentSetupParticipantstrac.dbsDatabaseManagerstrac.ticket.apisITicketChangeListenersITicketManipulatorstrac.util.compatssetssorteds db_defaultsmodels TicketLinkss ComponentsMasterTicketsSystem( ssetsITicketChangeListenersITicketManipulatorsMasterTicketsSystemsresIEnvironmentSetupParticipantsDatabaseManagerssorteds TicketLinkss db_default((s7build/bdist.darwin-8.11.1-i386/egg/mastertickets/api.pys?s     PKϘä6Ö'<¾&&mastertickets/db_default.py# Created by Noah Kantrowitz on 2007-07-04. # Copyright (c) 2007 Noah Kantrowitz. All rights reserved. from trac.db import Table, Column name = 'mastertickets' version = 1 tables = [ Table('mastertickets', key=('source','dest'))[ Column('source'), Column('dest'), ], ]PKI˜9œ‹Â0§§mastertickets/db_default.pyc;ò 'RŒFc@sTdklZlZdZdZeddddfƒedƒedƒfgZdS((sTablesColumns masterticketsiskeyssourcesdestN(strac.dbsTablesColumnsnamesversionstables(sColumnsTablesversionsnamestables((s>build/bdist.darwin-8.11.1-i386/egg/mastertickets/db_default.pys?sPKÅ‹9 Uâ^­­mastertickets/graphviz.py# -*- coding: utf-8 -*- # Created by Noah Kantrowitz on 2007-12-21. # Copyright (c) 2007 Noah Kantrowitz. All rights reserved. import os import subprocess import tempfile import time import itertools try: set = set except NameError: from sets import Set as set def _format_options(base_string, options): return u'%s [%s]'%(base_string, u', '.join([u'%s="%s"'%x for x in options.iteritems()])) class Edge(dict): """Model for an edge in a dot graph.""" def __init__(self, source, dest, **kwargs): self.source = source self.dest = dest dict.__init__(self, **kwargs) def __str__(self): ret = u'%s -> %s'%(self.source.name, self.dest.name) if self: ret = _format_options(ret, self) return ret def __hash__(self): return hash(id(self)) class Node(dict): """Model for a node in a dot graph.""" def __init__(self, name, **kwargs): self.name = unicode(name) self.edges = [] dict.__init__(self, **kwargs) def __str__(self): ret = self.name if self: ret = _format_options(ret, self) return ret def __gt__(self, other): """Allow node1 > node2 to add an edge.""" edge = Edge(self, other) self.edges.append(edge) other.edges.append(edge) return edge def __lt__(self, other): edge = Edge(other, self) self.edges.append(edge) other.edges.append(edge) return edge def __hash__(self): return hash(id(self)) class Graph(object): """A model object for a graphviz digraph.""" def __init__(self, name=u'graph'): super(Graph,self).__init__() self.name = name self.nodes = [] self._node_map = {} self.edges = [] def add(self, obj): if isinstance(obj, Node): self.nodes.append(obj) self._node_map[obj.name] = obj elif isinstance(obj, Edge): self.edges.append(obj) def __getitem__(self, key): key = unicode(key) if key not in self._node_map: new_node = Node(key) self._node_map[key] = new_node self.nodes.append(new_node) return self._node_map[key] def __delitem__(self, key): key = unicode(key) node = self._node_map.pop(key) self.nodes.remove(node) def __str__(self): edges = [] nodes = [] memo = set() def process(lst): for obj in lst: if obj in memo: continue memo.add(obj) if isinstance(obj, Node): nodes.append(obj) process(obj.edges) elif isinstance(obj, Edge): edges.append(obj) if isinstance(obj.source, Node): process((obj.source,)) if isinstance(obj.dest, Node): process((obj.dest,)) process(self.nodes) process(self.edges) lines = [u'digraph "%s" {'%self.name] for obj in itertools.chain(nodes, edges): lines.append(u'\t%s;'%obj) lines.append(u'}') return u'\n'.join(lines) def render(self, dot_path='dot', format='png'): """Render a dot graph.""" proc = subprocess.Popen([dot_path, '-T%s'%format], stdin=subprocess.PIPE, stdout=subprocess.PIPE) out, _ = proc.communicate(unicode(self).encode('utf8')) return out if __name__ == '__main__': g = Graph() root = Node('me') root > Node('them') root < Node(u'Üs') g.add(root) print g.render()PKI˜9Q!=Dmastertickets/graphviz.pyc;ò ý±Hc@sdkZdkZdkZdkZdkZy eZWn ej odklZnXd„Z de fd„ƒYZ de fd„ƒYZ de fd„ƒYZed joQeƒZe d ƒZee d ƒjee d ƒjeieƒeiƒGHndS( N(sSetcCsFd|digi}|iƒD]}|d|ƒq ~ƒfSdS(Nu%s [%s]u, u%s="%s"(s base_stringsjoinsappends_[1]soptionss iteritemssx(s base_stringsoptionss_[1]sx((s<build/bdist.darwin-8.11.1-i386/egg/mastertickets/graphviz.pys_format_optionsssEdgecBs)tZdZd„Zd„Zd„ZRS(s!Model for an edge in a dot graph.cKs&||_||_ti||dS(N(ssourcesselfsdestsdicts__init__skwargs(sselfssourcesdestskwargs((s<build/bdist.darwin-8.11.1-i386/egg/mastertickets/graphviz.pys__init__s  cCs>d|ii|iif}|ot||ƒ}n|SdS(Nu%s -> %s(sselfssourcesnamesdestsrets_format_options(sselfsret((s<build/bdist.darwin-8.11.1-i386/egg/mastertickets/graphviz.pys__str__scCstt|ƒƒSdS(N(shashsidsself(sself((s<build/bdist.darwin-8.11.1-i386/egg/mastertickets/graphviz.pys__hash__ s(s__name__s __module__s__doc__s__init__s__str__s__hash__(((s<build/bdist.darwin-8.11.1-i386/egg/mastertickets/graphviz.pysEdges   sNodecBs;tZdZd„Zd„Zd„Zd„Zd„ZRS(s Model for a node in a dot graph.cKs,t|ƒ|_g|_ti||dS(N(sunicodesnamesselfsedgessdicts__init__skwargs(sselfsnameskwargs((s<build/bdist.darwin-8.11.1-i386/egg/mastertickets/graphviz.pys__init__'s cCs+|i}|ot||ƒ}n|SdS(N(sselfsnamesrets_format_options(sselfsret((s<build/bdist.darwin-8.11.1-i386/egg/mastertickets/graphviz.pys__str__,s cCs7t||ƒ}|ii|ƒ|ii|ƒ|SdS(s#Allow node1 > node2 to add an edge.N(sEdgesselfsothersedgesedgessappend(sselfsothersedge((s<build/bdist.darwin-8.11.1-i386/egg/mastertickets/graphviz.pys__gt__2s cCs7t||ƒ}|ii|ƒ|ii|ƒ|SdS(N(sEdgesothersselfsedgesedgessappend(sselfsothersedge((s<build/bdist.darwin-8.11.1-i386/egg/mastertickets/graphviz.pys__lt__9scCstt|ƒƒSdS(N(shashsidsself(sself((s<build/bdist.darwin-8.11.1-i386/egg/mastertickets/graphviz.pys__hash__?s(s__name__s __module__s__doc__s__init__s__str__s__gt__s__lt__s__hash__(((s<build/bdist.darwin-8.11.1-i386/egg/mastertickets/graphviz.pysNode$s     sGraphcBsMtZdZdd„Zd„Zd„Zd„Zd„Zddd „ZRS( s&A model object for a graphviz digraph.ugraphcCs;tt|ƒiƒ||_g|_h|_g|_dS(N(ssupersGraphsselfs__init__snamesnodess _node_mapsedges(sselfsname((s<build/bdist.darwin-8.11.1-i386/egg/mastertickets/graphviz.pys__init__Fs    cCs\t|tƒo$|ii|ƒ||i|i'% \ (self.tkt.id, l(getattr(self, 'blocking', [])), l(getattr(self, 'blocked_by', []))) def walk(self): """Return an iterable of all links reachable directly above or below this one.""" def visit(tkt, memo, next_fn): if tkt in memo: return False links = TicketLinks(self.env, tkt) memo[tkt] = links for n in next_fn(links): visit(n, memo, next_fn) memo1 = {} memo2 = {} visit(str(self.tkt.id), memo1, lambda links: links.blocking) visit(str(self.tkt.id), memo2, lambda links: links.blocked_by) memo1.update(memo2) return memo1.itervalues() PKI˜99îfÒ¢¢mastertickets/model.pyc;ò ²Hc@scdkZdklZdklZdklZlZdklZl Z de fd„ƒYZ dS(N(sdatetime(sTicket(ssetssorted(sutcs to_timestamps TicketLinkscBsGtZdZed„Zdeed„Zd„Zd„Zd„ZRS(s0A model for the ticket links used MasterTickets.cCs!||_t|tƒ ot|i|ƒ}n||_|p |iiƒ}|iƒ}|id|ii fƒt gi }|D]\}||ƒq…~ƒ|_ti|iƒ|_|id|ii fƒt gi }|D]\}||ƒqæ~ƒ|_ti|iƒ|_dS(Ns<SELECT dest FROM mastertickets WHERE source=%s ORDER BY dests>SELECT source FROM mastertickets WHERE dest=%s ORDER BY source(senvsselfs isinstancestktsTicketsdbs get_db_cnxscursorsexecutesidssetsappends_[1]snumsblockingscopys _old_blockings blocked_bys_old_blocked_by(sselfsenvstktsdbs_[1]scursorsnum((s9build/bdist.darwin-8.11.1-i386/egg/mastertickets/model.pys__init__ s   33sc sÕ|tjotitƒ}nt|ƒ} t}|tjoˆi i ƒ}t }n|iƒ}ˆiˆidddffˆiˆidddffg}x|D]\} }}} xü| |BD]ð}t} || jo ||jo0|id| ˆii|fƒ‡d†} nK|| jo ||jo0|id| ˆii|fƒ‡d†} n| tj oC|id ||fƒ|iƒpd fd }gi}|i!d ƒD]'}|i#ƒo||i#ƒƒq¸q¸~} | | ƒd i%t&| dd„ƒƒ} |id|| |||| fƒ|o6|id|| |dd dˆii|ffƒn|id| ||fƒ|i) o|id||| fƒq´qÄqÄWq§W|o|i*ƒndS(sSave new links.s blockedbyssourcesdestsblockings4INSERT INTO mastertickets (%s, %s) VALUES (%%s, %%s)cs|itˆiiƒƒS(N(slstsappendsstrsselfstktsid(slst(sself(s9build/bdist.darwin-8.11.1-i386/egg/mastertickets/model.pys6ss1DELETE FROM mastertickets WHERE %s=%%s AND %s=%%scs|itˆiiƒƒS(N(slstsremovesstrsselfstktsid(slst(sself(s9build/bdist.darwin-8.11.1-i386/egg/mastertickets/model.pys:ss;SELECT value FROM ticket_custom WHERE ticket=%s AND name=%ssis,s, skeycCs t|ƒS(N(sintsx(sx((s9build/bdist.darwin-8.11.1-i386/egg/mastertickets/model.pysBsskINSERT INTO ticket_change (ticket, time, author, field, oldvalue, newvalue) VALUES (%s, %s, %s, %s, %s, %s)scomments (In #%s) %ss=UPDATE ticket_custom SET value=%s WHERE ticket=%s AND name=%ssCINSERT INTO ticket_custom (ticket, name, value) VALUES (%s, %s, %s)N(+swhensNonesdatetimesnowsutcs to_timestampswhen_tssFalses handle_commitsdbsselfsenvs get_db_cnxsTruescursorsblockings _old_blockings blocked_bys_old_blocked_bysto_checksnew_idssold_idssfields sourcedestsns update_fieldsexecutestktsidsfetchones old_valuesappends_[1]ssplitsxsstrips new_valuesjoinssortedsauthorscommentsrowcountscommit(sselfsauthorscommentswhensdbs old_values_[1]sfields handle_commits sourcedestswhen_tss new_values update_fieldsnew_idssnscursorsold_idssxsto_check((sselfs9build/bdist.darwin-8.11.1-i386/egg/mastertickets/model.pyssavesP     <      G   -    cCs!t|iƒp t|iƒSdS(N(sboolsselfsblockings blocked_by(sself((s9build/bdist.darwin-8.11.1-i386/egg/mastertickets/model.pys __nonzero__bscCsHd„}d|ii|t|dgƒƒ|t|dgƒƒfSdS(NcCsVg}x8|D]0}t|tƒo |i}n|i|ƒq Wddi|ƒSdS(Ns[%s]s,(sarr2sarrstkts isinstancesTicketsidsappendsjoin(sarrsarr2stkt((s9build/bdist.darwin-8.11.1-i386/egg/mastertickets/model.pyslfs s?sblockings blocked_by(slsselfstktsidsgetattr(sselfsl((s9build/bdist.darwin-8.11.1-i386/egg/mastertickets/model.pys__repr__es cst‡‡d†‰h}h}ˆtˆiiƒ|d„ƒˆtˆiiƒ|d„ƒ|i|ƒ|iƒSdS(sKReturn an iterable of all links reachable directly above or below this one.cs\||jotSntˆi|ƒ}|||WdS(N( stktsmemosFalses TicketLinkssselfsenvslinkssnext_fnsnsvisit(stktsmemosnext_fnslinkssn(svisitsself(s9build/bdist.darwin-8.11.1-i386/egg/mastertickets/model.pysvisitss   cCs|iS(N(slinkssblocking(slinks((s9build/bdist.darwin-8.11.1-i386/egg/mastertickets/model.pysscCs|iS(N(slinkss blocked_by(slinks((s9build/bdist.darwin-8.11.1-i386/egg/mastertickets/model.pys€sN( svisitsmemo1smemo2sstrsselfstktsidsupdates itervalues(sselfsvisitsmemo2smemo1((sselfsvisits9build/bdist.darwin-8.11.1-i386/egg/mastertickets/model.pyswalkqs  ( s__name__s __module__s__doc__sNones__init__ssaves __nonzero__s__repr__swalk(((s9build/bdist.darwin-8.11.1-i386/egg/mastertickets/model.pys TicketLinks s  D  ( scopysdatetimestrac.ticket.modelsTicketstrac.util.compatssetssortedstrac.util.datefmtsutcs to_timestampsobjects TicketLinks(sutcssetsdatetimes to_timestampssortedsTicketscopys TicketLinks((s9build/bdist.darwin-8.11.1-i386/egg/mastertickets/model.pys?s   PKÝ–9Ø|Ñ__mastertickets/util.pyfrom trac.ticket.model import Ticket from trac.resource import ResourceNotFound from trac.util.compat import set from genshi.builder import tag def linkify_ids(env, req, ids): data = [] for id in sorted(ids, key=lambda x: int(x)): try: tkt = Ticket(env, id) data.append(tag.a('#%s'%tkt.id, href=req.href.ticket(tkt.id), class_='%s ticket'%tkt['status'], title=tkt['summary'])) except ResourceNotFound: data.append('#%s'%id) data.append(', ') if data: del data[-1] # Remove the last comma if needed return tag.span(*data) PKI˜9ø7ˆmastertickets/util.pyc;ò ó²Hc@sAdklZdklZdklZdklZd„ZdS((sTicket(sResourceNotFound(sset(stagc CsÚg}x®t|dd„ƒD]—}y]t||ƒ}|iti d|id|i i |iƒdd|dd|d ƒƒWn$t j o|id|ƒnX|id ƒqW|o |d =nti|ŒSdS( NskeycCs t|ƒS(N(sintsx(sx((s8build/bdist.darwin-8.11.1-i386/egg/mastertickets/util.pysss#%sshrefsclass_s %s ticketsstatusstitlessummarys, iÿÿÿÿ(sdatassortedsidssidsTicketsenvstktsappendstagsasreqshrefsticketsResourceNotFoundsspan(senvsreqsidsstktsdatasid((s8build/bdist.darwin-8.11.1-i386/egg/mastertickets/util.pys linkify_idssN N( strac.ticket.modelsTickets trac.resourcesResourceNotFoundstrac.util.compatssetsgenshi.builderstags linkify_ids(s linkify_idssTicketssetstagsResourceNotFound((s8build/bdist.darwin-8.11.1-i386/egg/mastertickets/util.pys?s    PKn—9¹ê)@iimastertickets/web_ui.pyimport subprocess from pkg_resources import resource_filename from genshi.core import Markup, START, END, TEXT from genshi.builder import tag from genshi.filters.transform import Transformer from trac.core import * from trac.web.api import IRequestHandler, IRequestFilter, ITemplateStreamFilter from trac.web.chrome import ITemplateProvider, add_stylesheet, add_script, \ add_ctxtnav from trac.ticket.api import ITicketManipulator from trac.ticket.model import Ticket from trac.config import Option, BoolOption from trac.util.html import html, Markup from trac.util.compat import set, sorted, partial import graphviz from util import * from model import TicketLinks class MasterTicketsModule(Component): """Provides support for ticket dependencies.""" implements(IRequestHandler, IRequestFilter, ITemplateStreamFilter, ITemplateProvider, ITicketManipulator) dot_path = Option('mastertickets', 'dot_path', default='dot', doc='Path to the dot executable.') gs_path = Option('mastertickets', 'gs_path', default='gs', doc='Path to the ghostscript executable.') use_gs = BoolOption('mastertickets', 'use_gs', default=False, doc='If enabled, use ghostscript to produce nicer output.') FIELD_XPATH = 'div[@id="ticket"]/table[@class="properties"]/td[@headers="h_%s"]/text()' fields = set(['blocking', 'blockedby']) # IRequestFilter methods def pre_process_request(self, req, handler): return handler def post_process_request(self, req, template, data, content_type): if req.path_info.startswith('/ticket/'): tkt = data['ticket'] links = TicketLinks(self.env, tkt) for i in links.blocked_by: if Ticket(self.env, i)['status'] != 'closed': add_script(req, 'mastertickets/disable_resolve.js') break data['mastertickets'] = { 'field_values': { 'blocking': linkify_ids(self.env, req, links.blocking), 'blockedby': linkify_ids(self.env, req, links.blocked_by), }, } # Add link to depgraph if needed if links: add_ctxtnav(req, 'Depgraph', req.href.depgraph(tkt.id)) for change in data.get('changes', []): for field, field_data in change['fields'].iteritems(): if field in self.fields: if field_data['new'].strip(): new = set([int(n) for n in field_data['new'].split(',')]) else: new = set() if field_data['old'].strip(): old = set([int(n) for n in field_data['old'].split(',')]) else: old = set() add = new - old sub = old - new elms = tag() if add: elms.append( tag.em(u', '.join([unicode(n) for n in sorted(add)])) ) elms.append(u' added') if add and sub: elms.append(u'; ') if sub: elms.append( tag.em(u', '.join([unicode(n) for n in sorted(sub)])) ) elms.append(u' removed') field_data['rendered'] = elms return template, data, content_type # ITemplateStreamFilter methods def filter_stream(self, req, method, filename, stream, data): if 'mastertickets' in data: for field, value in data['mastertickets']['field_values'].iteritems(): stream |= Transformer(self.FIELD_XPATH % field).replace(value) return stream # ITicketManipulator methods def prepare_ticket(self, req, ticket, fields, actions): pass def validate_ticket(self, req, ticket): if req.args.get('action') == 'resolve': links = TicketLinks(self.env, ticket) for i in links.blocked_by: if Ticket(self.env, i)['status'] != 'closed': yield None, 'Ticket #%s is blocking this ticket'%i # ITemplateProvider methods def get_htdocs_dirs(self): """Return the absolute path of a directory containing additional static resources (such as images, style sheets, etc). """ return [('mastertickets', resource_filename(__name__, 'htdocs'))] def get_templates_dirs(self): """Return the absolute path of the directory containing the provided ClearSilver templates. """ return [resource_filename(__name__, 'templates')] # IRequestHandler methods def match_request(self, req): return req.path_info.startswith('/depgraph') def process_request(self, req): path_info = req.path_info[10:] if not path_info: raise TracError('No ticket specified') tkt_id = path_info.split('/', 1)[0] g = self._build_graph(req, tkt_id) if '/' in path_info or 'format' in req.args: format = req.args.get('format') if format == 'text': req.send(str(g), 'text/plain') elif format == 'debug': import pprint req.send(pprint.pformat(TicketLinks(self.env, tkt_id)), 'text/plain') elif format is not None: req.send(g.render(self.dot_path, format), 'text/plain') if self.use_gs: ps = g.render(self.dot_path, 'ps2') gs = subprocess.Popen([self.gs_path, '-q', '-dTextAlphaBits=4', '-dGraphicsAlphaBits=4', '-sDEVICE=png16m', '-o', '%stdout%', '-'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) img, err = gs.communicate(ps) if err: self.log.debug('MasterTickets: Error from gs: %s', err) else: img = g.render(self.dot_path) req.send(img, 'image/png') else: data = {} tkt = Ticket(self.env, tkt_id) data['tkt'] = tkt data['graph'] = g data['graph_render'] = partial(g.render, self.dot_path) data['use_gs'] = self.use_gs add_ctxtnav(req, 'Back to Ticket #%s'%tkt.id, req.href.ticket(tkt_id)) return 'depgraph.html', data, None def _build_graph(self, req, tkt_id): links = TicketLinks(self.env, tkt_id) g = graphviz.Graph() node_default = g['node'] node_default['style'] = 'filled' edge_default = g['edge'] edge_default['style'] = '' # Force this to the top of the graph g[tkt_id] links = sorted(links.walk(), key=lambda link: link.tkt.id) for link in links: tkt = link.tkt node = g[tkt.id] node['label'] = u'#%s'%tkt.id node['fillcolor'] = tkt['status'] == 'closed' and 'green' or 'red' node['URL'] = req.href.ticket(tkt.id) node['alt'] = u'Ticket #%s'%tkt.id node['tooltip'] = tkt['summary'] for n in link.blocking: node > g[n] return g PKI˜9D¡÷b ( (mastertickets/web_ui.pyc;ò ²Hc@sdkZdklZdklZlZlZlZdkl Z dk l Z dk Tdk lZlZlZdklZlZlZlZdklZd klZd klZlZd klZlZd kl Z l!Z!l"Z"dk#Z#dk$Td k%l&Z&de'fd„ƒYZ(dS(N(sresource_filename(sMarkupsSTARTsENDsTEXT(stag(s Transformer(s*(sIRequestHandlersIRequestFiltersITemplateStreamFilter(sITemplateProvidersadd_stylesheets add_scripts add_ctxtnav(sITicketManipulator(sTicket(sOptions BoolOption(shtmlsMarkup(ssetssortedspartial(s TicketLinkssMasterTicketsModulecBsçtZdZeeeeeeƒe ddddddƒZ e dddddd ƒZ e dd de dd ƒZd Zed dgƒZd„Zd„Zd„Zd„Zd„Zd„Zd„Zd„Zd„Zd„ZRS(s)Provides support for ticket dependencies.s masterticketssdot_pathsdefaultsdotsdocsPath to the dot executable.sgs_pathsgss#Path to the ghostscript executable.suse_gss4If enabled, use ghostscript to produce nicer output.sGdiv[@id="ticket"]/table[@class="properties"]/td[@headers="h_%s"]/text()sblockings blockedbycCs|SdS(N(shandler(sselfsreqshandler((s:build/bdist.darwin-8.11.1-i386/egg/mastertickets/web_ui.pyspre_process_request'sc Cs|iidƒoò|d}t|i|ƒ}x@|i D]5}t |i|ƒddjot |dƒPq9q9Whdhdt |i||iƒ<dt |i||i ƒ<<|d <|o#t|d |ii|iƒƒnx|id gƒD]}xü|d iƒD]ê\} } | |ijoÎ| d iƒoDtgi}| d idƒD]}|t|ƒƒqZ~ƒ} n tƒ} | diƒoDtgi}| didƒD]}|t|ƒƒq¸~ƒ}n tƒ}| |} || } t$ƒ}| o]|it$i&di'gi}t(| ƒD]}|t)|ƒƒq1~ƒƒƒ|idƒn| o| o|idƒn| o]|it$i&di'gi}t(| ƒD]}|t)|ƒƒq´~ƒƒƒ|idƒn|| d    ) # $!   #c Cs%t|i|ƒ}tiƒ}|d}d|d<|d}d|d<||t |i ƒdd„ƒ}x±|D]©} | i }||i}d|i|d <|d d jod pd |d<|ii|iƒ|d·su#%sslabelsstatussclosedsgreensreds fillcolorsURLu Ticket #%ssaltssummarystooltip(s TicketLinkssselfsenvstkt_idslinkssgraphvizsGraphsgs node_defaults edge_defaultssortedswalkslinkstktsidsnodesreqshrefsticketsblockingsn( sselfsreqstkt_idsnodes edge_defaults node_defaultsgslinksstktslinksn((s:build/bdist.darwin-8.11.1-i386/egg/mastertickets/web_ui.pys _build_graph©s*       " (s__name__s __module__s__doc__s implementssIRequestHandlersIRequestFiltersITemplateStreamFiltersITemplateProvidersITicketManipulatorsOptionsdot_pathsgs_paths BoolOptionsFalsesuse_gss FIELD_XPATHssetsfieldsspre_process_requestspost_process_requests filter_streamsprepare_ticketsvalidate_ticketsget_htdocs_dirssget_templates_dirss match_requestsprocess_requests _build_graph(((s:build/bdist.darwin-8.11.1-i386/egg/mastertickets/web_ui.pysMasterTicketsModules*        4       )()s subprocesss pkg_resourcessresource_filenames genshi.coresMarkupsSTARTsENDsTEXTsgenshi.builderstagsgenshi.filters.transforms Transformers trac.cores trac.web.apisIRequestHandlersIRequestFiltersITemplateStreamFilterstrac.web.chromesITemplateProvidersadd_stylesheets add_scripts add_ctxtnavstrac.ticket.apisITicketManipulatorstrac.ticket.modelsTickets trac.configsOptions BoolOptionstrac.util.htmlshtmlstrac.util.compatssetssortedspartialsgraphvizsutilsmodels TicketLinkss ComponentsMasterTicketsModule(s TransformerssetspartialsMasterTicketsModulesIRequestHandlersTEXTsresource_filenames subprocesssITemplateProviderstags add_ctxtnavs add_scriptsOptionsadd_stylesheetshtmlsTicketsENDsMarkupsIRequestFiltersITicketManipulatorsSTARTssortedsgraphvizsITemplateStreamFilters BoolOptions TicketLinks((s:build/bdist.darwin-8.11.1-i386/egg/mastertickets/web_ui.pys?s        PK²6f6 4ßBB'mastertickets/htdocs/disable_resolve.js$(function() { $('#resolve').attr('disabled', 'disabled'); });PK²6f6 " ¡Þ¡Þmastertickets/htdocs/jquery.js/* prevent execution of jQuery if included more than once */ if(typeof window.jQuery == "undefined") { /* * jQuery 1.1 - New Wave Javascript * * Copyright (c) 2007 John Resig (jquery.com) * Dual licensed under the MIT (MIT-LICENSE.txt) * and GPL (GPL-LICENSE.txt) licenses. * * $Date: 2007-01-14 17:37:33 -0500 (Sun, 14 Jan 2007) $ * $Rev: 1073 $ */ // Global undefined variable window.undefined = window.undefined; var jQuery = function(a,c) { // If the context is global, return a new object if ( window == this ) return new jQuery(a,c); // Make sure that a selection was provided a = a || document; // HANDLE: $(function) // Shortcut for document ready // Safari reports typeof on DOM NodeLists as a function if ( jQuery.isFunction(a) && !a.nodeType && a[0] == undefined ) return new jQuery(document)[ jQuery.fn.ready ? "ready" : "load" ]( a ); // Handle HTML strings if ( typeof a == "string" ) { var m = /^[^<]*(<.+>)[^>]*$/.exec(a); a = m ? // HANDLE: $(html) -> $(array) jQuery.clean( [ m[1] ] ) : // HANDLE: $(expr) jQuery.find( a, c ); } return this.setArray( // HANDLE: $(array) a.constructor == Array && a || // HANDLE: $(arraylike) // Watch for when an array-like object is passed as the selector (a.jquery || a.length && a != window && !a.nodeType && a[0] != undefined && a[0].nodeType) && jQuery.makeArray( a ) || // HANDLE: $(*) [ a ] ); }; // Map over the $ in case of overwrite if ( typeof $ != "undefined" ) jQuery._$ = $; // Map the jQuery namespace to the '$' one var $ = jQuery; jQuery.fn = jQuery.prototype = { jquery: "1.1", size: function() { return this.length; }, length: 0, get: function( num ) { return num == undefined ? // Return a 'clean' array jQuery.makeArray( this ) : // Return just the object this[num]; }, pushStack: function( a ) { var ret = jQuery(this); ret.prevObject = this; return ret.setArray( a ); }, setArray: function( a ) { this.length = 0; [].push.apply( this, a ); return this; }, each: function( fn, args ) { return jQuery.each( this, fn, args ); }, index: function( obj ) { var pos = -1; this.each(function(i){ if ( this == obj ) pos = i; }); return pos; }, attr: function( key, value, type ) { var obj = key; // Look for the case where we're accessing a style value if ( key.constructor == String ) if ( value == undefined ) return jQuery[ type || "attr" ]( this[0], key ); else { obj = {}; obj[ key ] = value; } // Check to see if we're setting style values return this.each(function(){ // Set all the styles for ( var prop in obj ) jQuery.attr( type ? this.style : this, prop, jQuery.prop(this, obj[prop], type) ); }); }, css: function( key, value ) { return this.attr( key, value, "curCSS" ); }, text: function(e) { if ( typeof e == "string" ) return this.empty().append( document.createTextNode( e ) ); var t = ""; jQuery.each( e || this, function(){ jQuery.each( this.childNodes, function(){ if ( this.nodeType != 8 ) t += this.nodeType != 1 ? this.nodeValue : jQuery.fn.text([ this ]); }); }); return t; }, wrap: function() { // The elements to wrap the target around var a = jQuery.clean(arguments); // Wrap each of the matched elements individually return this.each(function(){ // Clone the structure that we're using to wrap var b = a[0].cloneNode(true); // Insert it before the element to be wrapped this.parentNode.insertBefore( b, this ); // Find the deepest point in the wrap structure while ( b.firstChild ) b = b.firstChild; // Move the matched element to within the wrap structure b.appendChild( this ); }); }, append: function() { return this.domManip(arguments, true, 1, function(a){ this.appendChild( a ); }); }, prepend: function() { return this.domManip(arguments, true, -1, function(a){ this.insertBefore( a, this.firstChild ); }); }, before: function() { return this.domManip(arguments, false, 1, function(a){ this.parentNode.insertBefore( a, this ); }); }, after: function() { return this.domManip(arguments, false, -1, function(a){ this.parentNode.insertBefore( a, this.nextSibling ); }); }, end: function() { return this.prevObject || jQuery([]); }, find: function(t) { return this.pushStack( jQuery.map( this, function(a){ return jQuery.find(t,a); }) ); }, clone: function(deep) { return this.pushStack( jQuery.map( this, function(a){ return a.cloneNode( deep != undefined ? deep : true ); }) ); }, filter: function(t) { return this.pushStack( jQuery.isFunction( t ) && jQuery.grep(this, function(el, index){ return t.apply(el, [index]) }) || jQuery.multiFilter(t,this) ); }, not: function(t) { return this.pushStack( t.constructor == String && jQuery.multiFilter(t,this,true) || jQuery.grep(this,function(a){ if ( t.constructor == Array || t.jquery ) return jQuery.inArray( t, a ) < 0; else return a != t; }) ); }, add: function(t) { return this.pushStack( jQuery.merge( this.get(), typeof t == "string" ? jQuery(t).get() : t ) ); }, is: function(expr) { return expr ? jQuery.filter(expr,this).r.length > 0 : false; }, val: function( val ) { return val == undefined ? ( this.length ? this[0].value : null ) : this.attr( "value", val ); }, html: function( val ) { return val == undefined ? ( this.length ? this[0].innerHTML : null ) : this.empty().append( val ); }, domManip: function(args, table, dir, fn){ var clone = this.length > 1; var a = jQuery.clean(args); if ( dir < 0 ) a.reverse(); return this.each(function(){ var obj = this; if ( table && this.nodeName.toUpperCase() == "TABLE" && a[0].nodeName.toUpperCase() == "TR" ) obj = this.getElementsByTagName("tbody")[0] || this.appendChild(document.createElement("tbody")); jQuery.each( a, function(){ fn.apply( obj, [ clone ? this.cloneNode(true) : this ] ); }); }); } }; jQuery.extend = jQuery.fn.extend = function() { // copy reference to target object var target = arguments[0], a = 1; // extend jQuery itself if only one argument is passed if ( arguments.length == 1 ) { target = this; a = 0; } var prop; while (prop = arguments[a++]) // Extend the base object for ( var i in prop ) target[i] = prop[i]; // Return the modified object return target; }; jQuery.extend({ noConflict: function() { if ( jQuery._$ ) $ = jQuery._$; }, isFunction: function( fn ) { return fn && typeof fn == "function"; }, // args is for internal usage only each: function( obj, fn, args ) { if ( obj.length == undefined ) for ( var i in obj ) fn.apply( obj[i], args || [i, obj[i]] ); else for ( var i = 0, ol = obj.length; i < ol; i++ ) if ( fn.apply( obj[i], args || [i, obj[i]] ) === false ) break; return obj; }, prop: function(elem, value, type){ // Handle executable functions if ( jQuery.isFunction( value ) ) return value.call( elem ); // Handle passing in a number to a CSS property if ( value.constructor == Number && type == "curCSS" ) return value + "px"; return value; }, className: { // internal only, use addClass("class") add: function( elem, c ){ jQuery.each( c.split(/\s+/), function(i, cur){ if ( !jQuery.className.has( elem.className, cur ) ) elem.className += ( elem.className ? " " : "" ) + cur; }); }, // internal only, use removeClass("class") remove: function( elem, c ){ elem.className = c ? jQuery.grep( elem.className.split(/\s+/), function(cur){ return !jQuery.className.has( c, cur ); }).join(" ") : ""; }, // internal only, use is(".class") has: function( t, c ) { t = t.className || t; return t && new RegExp("(^|\\s)" + c + "(\\s|$)").test( t ); } }, swap: function(e,o,f) { for ( var i in o ) { e.style["old"+i] = e.style[i]; e.style[i] = o[i]; } f.apply( e, [] ); for ( var i in o ) e.style[i] = e.style["old"+i]; }, css: function(e,p) { if ( p == "height" || p == "width" ) { var old = {}, oHeight, oWidth, d = ["Top","Bottom","Right","Left"]; jQuery.each( d, function(){ old["padding" + this] = 0; old["border" + this + "Width"] = 0; }); jQuery.swap( e, old, function() { if (jQuery.css(e,"display") != "none") { oHeight = e.offsetHeight; oWidth = e.offsetWidth; } else { e = jQuery(e.cloneNode(true)) .find(":radio").removeAttr("checked").end() .css({ visibility: "hidden", position: "absolute", display: "block", right: "0", left: "0" }).appendTo(e.parentNode)[0]; var parPos = jQuery.css(e.parentNode,"position"); if ( parPos == "" || parPos == "static" ) e.parentNode.style.position = "relative"; oHeight = e.clientHeight; oWidth = e.clientWidth; if ( parPos == "" || parPos == "static" ) e.parentNode.style.position = "static"; e.parentNode.removeChild(e); } }); return p == "height" ? oHeight : oWidth; } return jQuery.curCSS( e, p ); }, curCSS: function(elem, prop, force) { var ret; if (prop == "opacity" && jQuery.browser.msie) return jQuery.attr(elem.style, "opacity"); if (prop == "float" || prop == "cssFloat") prop = jQuery.browser.msie ? "styleFloat" : "cssFloat"; if (!force && elem.style[prop]) ret = elem.style[prop]; else if (document.defaultView && document.defaultView.getComputedStyle) { if (prop == "cssFloat" || prop == "styleFloat") prop = "float"; prop = prop.replace(/([A-Z])/g,"-$1").toLowerCase(); var cur = document.defaultView.getComputedStyle(elem, null); if ( cur ) ret = cur.getPropertyValue(prop); else if ( prop == "display" ) ret = "none"; else jQuery.swap(elem, { display: "block" }, function() { var c = document.defaultView.getComputedStyle(this, ""); ret = c && c.getPropertyValue(prop) || ""; }); } else if (elem.currentStyle) { var newProp = prop.replace(/\-(\w)/g,function(m,c){return c.toUpperCase();}); ret = elem.currentStyle[prop] || elem.currentStyle[newProp]; } return ret; }, clean: function(a) { var r = []; jQuery.each( a, function(i,arg){ if ( !arg ) return; if ( arg.constructor == Number ) arg = arg.toString(); // Convert html string into DOM nodes if ( typeof arg == "string" ) { // Trim whitespace, otherwise indexOf won't work as expected var s = jQuery.trim(arg), div = document.createElement("div"), tb = []; var wrap = // option or optgroup !s.indexOf("", ""] || (!s.indexOf("", ""] || !s.indexOf("", ""] || // matched above (!s.indexOf("", ""] || [0,"",""]; // Go to html and back, then peel off extra wrappers div.innerHTML = wrap[1] + s + wrap[2]; // Move to the right depth while ( wrap[0]-- ) div = div.firstChild; // Remove IE's autoinserted from table fragments if ( jQuery.browser.msie ) { // String was a , *may* have spurious if ( !s.indexOf(" or else if ( wrap[1] == "
" && s.indexOf("= 0 ; --n ) if ( tb[n].nodeName.toUpperCase() == "TBODY" && !tb[n].childNodes.length ) tb[n].parentNode.removeChild(tb[n]); } arg = div.childNodes; } if ( arg.length === 0 ) return; if ( arg[0] == undefined ) r.push( arg ); else r = jQuery.merge( r, arg ); }); return r; }, attr: function(elem, name, value){ var fix = { "for": "htmlFor", "class": "className", "float": jQuery.browser.msie ? "styleFloat" : "cssFloat", cssFloat: jQuery.browser.msie ? "styleFloat" : "cssFloat", innerHTML: "innerHTML", className: "className", value: "value", disabled: "disabled", checked: "checked", readonly: "readOnly", selected: "selected" }; // IE actually uses filters for opacity ... elem is actually elem.style if ( name == "opacity" && jQuery.browser.msie && value != undefined ) { // IE has trouble with opacity if it does not have layout // Force it by setting the zoom level elem.zoom = 1; // Set the alpha filter to set the opacity return elem.filter = elem.filter.replace(/alpha\([^\)]*\)/gi,"") + ( value == 1 ? "" : "alpha(opacity=" + value * 100 + ")" ); } else if ( name == "opacity" && jQuery.browser.msie ) return elem.filter ? parseFloat( elem.filter.match(/alpha\(opacity=(.*)\)/)[1] ) / 100 : 1; // Mozilla doesn't play well with opacity 1 if ( name == "opacity" && jQuery.browser.mozilla && value == 1 ) value = 0.9999; // Certain attributes only work when accessed via the old DOM 0 way if ( fix[name] ) { if ( value != undefined ) elem[fix[name]] = value; return elem[fix[name]]; } else if ( value == undefined && jQuery.browser.msie && elem.nodeName && elem.nodeName.toUpperCase() == "FORM" && (name == "action" || name == "method") ) return elem.getAttributeNode(name).nodeValue; // IE elem.getAttribute passes even for style else if ( elem.tagName ) { if ( value != undefined ) elem.setAttribute( name, value ); return elem.getAttribute( name ); } else { name = name.replace(/-([a-z])/ig,function(z,b){return b.toUpperCase();}); if ( value != undefined ) elem[name] = value; return elem[name]; } }, trim: function(t){ return t.replace(/^\s+|\s+$/g, ""); }, makeArray: function( a ) { var r = []; if ( a.constructor != Array ) for ( var i = 0, al = a.length; i < al; i++ ) r.push( a[i] ); else r = a.slice( 0 ); return r; }, inArray: function( b, a ) { for ( var i = 0, al = a.length; i < al; i++ ) if ( a[i] == b ) return i; return -1; }, merge: function(first, second) { var r = [].slice.call( first, 0 ); // Now check for duplicates between the two arrays // and only add the unique items for ( var i = 0, sl = second.length; i < sl; i++ ) // Check for duplicates if ( jQuery.inArray( second[i], r ) == -1 ) // The item is unique, add it first.push( second[i] ); return first; }, grep: function(elems, fn, inv) { // If a string is passed in for the function, make a function // for it (a handy shortcut) if ( typeof fn == "string" ) fn = new Function("a","i","return " + fn); var result = []; // Go through the array, only saving the items // that pass the validator function for ( var i = 0, el = elems.length; i < el; i++ ) if ( !inv && fn(elems[i],i) || inv && !fn(elems[i],i) ) result.push( elems[i] ); return result; }, map: function(elems, fn) { // If a string is passed in for the function, make a function // for it (a handy shortcut) if ( typeof fn == "string" ) fn = new Function("a","return " + fn); var result = [], r = []; // Go through the array, translating each of the items to their // new value (or values). for ( var i = 0, el = elems.length; i < el; i++ ) { var val = fn(elems[i],i); if ( val !== null && val != undefined ) { if ( val.constructor != Array ) val = [val]; result = result.concat( val ); } } var r = result.length ? [ result[0] ] : []; check: for ( var i = 1, rl = result.length; i < rl; i++ ) { for ( var j = 0; j < i; j++ ) if ( result[i] == r[j] ) continue check; r.push( result[i] ); } return r; } }); /* * Whether the W3C compliant box model is being used. * * @property * @name $.boxModel * @type Boolean * @cat JavaScript */ new function() { var b = navigator.userAgent.toLowerCase(); // Figure out what browser is being used jQuery.browser = { safari: /webkit/.test(b), opera: /opera/.test(b), msie: /msie/.test(b) && !/opera/.test(b), mozilla: /mozilla/.test(b) && !/(compatible|webkit)/.test(b) }; // Check to see if the W3C box model is being used jQuery.boxModel = !jQuery.browser.msie || document.compatMode == "CSS1Compat"; }; jQuery.each({ parent: "a.parentNode", parents: "jQuery.parents(a)", next: "jQuery.nth(a,2,'nextSibling')", prev: "jQuery.nth(a,2,'previousSibling')", siblings: "jQuery.sibling(a.parentNode.firstChild,a)", children: "jQuery.sibling(a.firstChild)" }, function(i,n){ jQuery.fn[ i ] = function(a) { var ret = jQuery.map(this,n); if ( a && typeof a == "string" ) ret = jQuery.multiFilter(a,ret); return this.pushStack( ret ); }; }); jQuery.each({ appendTo: "append", prependTo: "prepend", insertBefore: "before", insertAfter: "after" }, function(i,n){ jQuery.fn[ i ] = function(){ var a = arguments; return this.each(function(){ for ( var j = 0, al = a.length; j < al; j++ ) jQuery(a[j])[n]( this ); }); }; }); jQuery.each( { removeAttr: function( key ) { jQuery.attr( this, key, "" ); this.removeAttribute( key ); }, addClass: function(c){ jQuery.className.add(this,c); }, removeClass: function(c){ jQuery.className.remove(this,c); }, toggleClass: function( c ){ jQuery.className[ jQuery.className.has(this,c) ? "remove" : "add" ](this, c); }, remove: function(a){ if ( !a || jQuery.filter( a, [this] ).r.length ) this.parentNode.removeChild( this ); }, empty: function() { while ( this.firstChild ) this.removeChild( this.firstChild ); } }, function(i,n){ jQuery.fn[ i ] = function() { return this.each( n, arguments ); }; }); jQuery.each( [ "eq", "lt", "gt", "contains" ], function(i,n){ jQuery.fn[ n ] = function(num,fn) { return this.filter( ":" + n + "(" + num + ")", fn ); }; }); jQuery.each( [ "height", "width" ], function(i,n){ jQuery.fn[ n ] = function(h) { return h == undefined ? ( this.length ? jQuery.css( this[0], n ) : null ) : this.css( n, h.constructor == String ? h : h + "px" ); }; }); jQuery.extend({ expr: { "": "m[2]=='*'||a.nodeName.toUpperCase()==m[2].toUpperCase()", "#": "a.getAttribute('id')==m[2]", ":": { // Position Checks lt: "im[3]-0", nth: "m[3]-0==i", eq: "m[3]-0==i", first: "i==0", last: "i==r.length-1", even: "i%2==0", odd: "i%2", // Child Checks "nth-child": "jQuery.nth(a.parentNode.firstChild,m[3],'nextSibling',a)==a", "first-child": "jQuery.nth(a.parentNode.firstChild,1,'nextSibling')==a", "last-child": "jQuery.nth(a.parentNode.lastChild,1,'previousSibling')==a", "only-child": "jQuery.sibling(a.parentNode.firstChild).length==1", // Parent Checks parent: "a.firstChild", empty: "!a.firstChild", // Text Check contains: "jQuery.fn.text.apply([a]).indexOf(m[3])>=0", // Visibility visible: 'a.type!="hidden"&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden"', hidden: 'a.type=="hidden"||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden"', // Form attributes enabled: "!a.disabled", disabled: "a.disabled", checked: "a.checked", selected: "a.selected||jQuery.attr(a,'selected')", // Form elements text: "a.type=='text'", radio: "a.type=='radio'", checkbox: "a.type=='checkbox'", file: "a.type=='file'", password: "a.type=='password'", submit: "a.type=='submit'", image: "a.type=='image'", reset: "a.type=='reset'", button: 'a.type=="button"||a.nodeName=="BUTTON"', input: "/input|select|textarea|button/i.test(a.nodeName)" }, ".": "jQuery.className.has(a,m[2])", "@": { "=": "z==m[4]", "!=": "z!=m[4]", "^=": "z&&!z.indexOf(m[4])", "$=": "z&&z.substr(z.length - m[4].length,m[4].length)==m[4]", "*=": "z&&z.indexOf(m[4])>=0", "": "z", _resort: function(m){ return ["", m[1], m[3], m[2], m[5]]; }, _prefix: "z=a[m[3]]||jQuery.attr(a,m[3]);" }, "[": "jQuery.find(m[2],a).length" }, // The regular expressions that power the parsing engine parse: [ // Match: [@value='test'], [@foo] /^\[ *(@)([a-z0-9_-]*) *([!*$^=]*) *('?"?)(.*?)\4 *\]/i, // Match: [div], [div p] /^(\[)\s*(.*?(\[.*?\])?[^[]*?)\s*\]/, // Match: :contains('foo') /^(:)([a-z0-9_-]*)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/i, // Match: :even, :last-chlid /^([:.#]*)([a-z0-9_*-]*)/i ], token: [ /^(\/?\.\.)/, "a.parentNode", /^(>|\/)/, "jQuery.sibling(a.firstChild)", /^(\+)/, "jQuery.nth(a,2,'nextSibling')", /^(~)/, function(a){ var s = jQuery.sibling(a.parentNode.firstChild); return s.slice(0, jQuery.inArray(a,s)); } ], multiFilter: function( expr, elems, not ) { var old, cur = []; while ( expr && expr != old ) { old = expr; var f = jQuery.filter( expr, elems, not ); expr = f.t.replace(/^\s*,\s*/, "" ); cur = not ? elems = f.r : jQuery.merge( cur, f.r ); } return cur; }, find: function( t, context ) { // Quickly handle non-string expressions if ( typeof t != "string" ) return [ t ]; // Make sure that the context is a DOM Element if ( context && !context.nodeType ) context = null; // Set the correct context (if none is provided) context = context || document; // Handle the common XPath // expression if ( !t.indexOf("//") ) { context = context.documentElement; t = t.substr(2,t.length); // And the / root expression } else if ( !t.indexOf("/") ) { context = context.documentElement; t = t.substr(1,t.length); if ( t.indexOf("/") >= 1 ) t = t.substr(t.indexOf("/"),t.length); } // Initialize the search var ret = [context], done = [], last = null; // Continue while a selector expression exists, and while // we're no longer looping upon ourselves while ( t && last != t ) { var r = []; last = t; t = jQuery.trim(t).replace( /^\/\//i, "" ); var foundToken = false; // An attempt at speeding up child selectors that // point to a specific element tag var re = /^[\/>]\s*([a-z0-9*-]+)/i; var m = re.exec(t); if ( m ) { // Perform our own iteration and filter jQuery.each( ret, function(){ for ( var c = this.firstChild; c; c = c.nextSibling ) if ( c.nodeType == 1 && ( c.nodeName == m[1].toUpperCase() || m[1] == "*" ) ) r.push( c ); }); ret = r; t = jQuery.trim( t.replace( re, "" ) ); foundToken = true; } else { // Look for pre-defined expression tokens for ( var i = 0; i < jQuery.token.length; i += 2 ) { // Attempt to match each, individual, token in // the specified order var re = jQuery.token[i]; var m = re.exec(t); // If the token match was found if ( m ) { // Map it against the token's handler r = ret = jQuery.map( ret, jQuery.isFunction( jQuery.token[i+1] ) ? jQuery.token[i+1] : function(a){ return eval(jQuery.token[i+1]); }); // And remove the token t = jQuery.trim( t.replace( re, "" ) ); foundToken = true; break; } } } // See if there's still an expression, and that we haven't already // matched a token if ( t && !foundToken ) { // Handle multiple expressions if ( !t.indexOf(",") ) { // Clean the result set if ( ret[0] == context ) ret.shift(); // Merge the result sets jQuery.merge( done, ret ); // Reset the context r = ret = [context]; // Touch up the selector string t = " " + t.substr(1,t.length); } else { // Optomize for the case nodeName#idName var re2 = /^([a-z0-9_-]+)(#)([a-z0-9\\*_-]*)/i; var m = re2.exec(t); // Re-organize the results, so that they're consistent if ( m ) { m = [ 0, m[2], m[3], m[1] ]; } else { // Otherwise, do a traditional filter check for // ID, class, and element selectors re2 = /^([#.]?)([a-z0-9\\*_-]*)/i; m = re2.exec(t); } // Try to do a global search by ID, where we can if ( m[1] == "#" && ret[ret.length-1].getElementById ) { // Optimization for HTML document case var oid = ret[ret.length-1].getElementById(m[2]); // Do a quick check for node name (where applicable) so // that div#foo searches will be really fast ret = r = oid && (!m[3] || oid.nodeName == m[3].toUpperCase()) ? [oid] : []; } else { // Pre-compile a regular expression to handle class searches if ( m[1] == "." ) var rec = new RegExp("(^|\\s)" + m[2] + "(\\s|$)"); // We need to find all descendant elements, it is more // efficient to use getAll() when we are already further down // the tree - we try to recognize that here jQuery.each( ret, function(){ // Grab the tag name being searched for var tag = m[1] != "" || m[0] == "" ? "*" : m[2]; // Handle IE7 being really dumb about s if ( this.nodeName.toUpperCase() == "OBJECT" && tag == "*" ) tag = "param"; jQuery.merge( r, m[1] != "" && ret.length != 1 ? jQuery.getAll( this, [], m[1], m[2], rec ) : this.getElementsByTagName( tag ) ); }); // It's faster to filter by class and be done with it if ( m[1] == "." && ret.length == 1 ) r = jQuery.grep( r, function(e) { return rec.test(e.className); }); // Same with ID filtering if ( m[1] == "#" && ret.length == 1 ) { // Remember, then wipe out, the result set var tmp = r; r = []; // Then try to find the element with the ID jQuery.each( tmp, function(){ if ( this.getAttribute("id") == m[2] ) { r = [ this ]; return false; } }); } ret = r; } t = t.replace( re2, "" ); } } // If a selector string still exists if ( t ) { // Attempt to filter it var val = jQuery.filter(t,r); ret = r = val.r; t = jQuery.trim(val.t); } } // Remove the root context if ( ret && ret[0] == context ) ret.shift(); // And combine the results jQuery.merge( done, ret ); return done; }, filter: function(t,r,not) { // Look for common filter expressions while ( t && /^[a-z[({<*:.#]/i.test(t) ) { var p = jQuery.parse, m; jQuery.each( p, function(i,re){ // Look for, and replace, string-like sequences // and finally build a regexp out of it m = re.exec( t ); if ( m ) { // Remove what we just matched t = t.substring( m[0].length ); // Re-organize the first match if ( jQuery.expr[ m[1] ]._resort ) m = jQuery.expr[ m[1] ]._resort( m ); return false; } }); // :not() is a special case that can be optimized by // keeping it out of the expression list if ( m[1] == ":" && m[2] == "not" ) r = jQuery.filter(m[3], r, true).r; // Handle classes as a special case (this will help to // improve the speed, as the regexp will only be compiled once) else if ( m[1] == "." ) { var re = new RegExp("(^|\\s)" + m[2] + "(\\s|$)"); r = jQuery.grep( r, function(e){ return re.test(e.className || ""); }, not); // Otherwise, find the expression to execute } else { var f = jQuery.expr[m[1]]; if ( typeof f != "string" ) f = jQuery.expr[m[1]][m[2]]; // Build a custom macro to enclose it eval("f = function(a,i){" + ( jQuery.expr[ m[1] ]._prefix || "" ) + "return " + f + "}"); // Execute it against the current filter r = jQuery.grep( r, f, not ); } } // Return an array of filtered elements (r) // and the modified expression string (t) return { r: r, t: t }; }, getAll: function( o, r, token, name, re ) { for ( var s = o.firstChild; s; s = s.nextSibling ) if ( s.nodeType == 1 ) { var add = true; if ( token == "." ) add = s.className && re.test(s.className); else if ( token == "#" ) add = s.getAttribute("id") == name; if ( add ) r.push( s ); if ( token == "#" && r.length ) break; if ( s.firstChild ) jQuery.getAll( s, r, token, name, re ); } return r; }, parents: function( elem ){ var matched = []; var cur = elem.parentNode; while ( cur && cur != document ) { matched.push( cur ); cur = cur.parentNode; } return matched; }, nth: function(cur,result,dir,elem){ result = result || 1; var num = 0; for ( ; cur; cur = cur[dir] ) { if ( cur.nodeType == 1 ) num++; if ( num == result || result == "even" && num % 2 == 0 && num > 1 && cur == elem || result == "odd" && num % 2 == 1 && cur == elem ) return cur; } }, sibling: function( n, elem ) { var r = []; for ( ; n; n = n.nextSibling ) { if ( n.nodeType == 1 && (!elem || n != elem) ) r.push( n ); } return r; } }); /* * A number of helper functions used for managing events. * Many of the ideas behind this code orignated from * Dean Edwards' addEvent library. */ jQuery.event = { // Bind an event to an element // Original by Dean Edwards add: function(element, type, handler, data) { // For whatever reason, IE has trouble passing the window object // around, causing it to be cloned in the process if ( jQuery.browser.msie && element.setInterval != undefined ) element = window; // if data is passed, bind to handler if( data ) handler.data = data; // Make sure that the function being executed has a unique ID if ( !handler.guid ) handler.guid = this.guid++; // Init the element's event structure if (!element.events) element.events = {}; // Get the current list of functions bound to this event var handlers = element.events[type]; // If it hasn't been initialized yet if (!handlers) { // Init the event handler queue handlers = element.events[type] = {}; // Remember an existing handler, if it's already there if (element["on" + type]) handlers[0] = element["on" + type]; } // Add the function to the element's handler list handlers[handler.guid] = handler; // And bind the global event handler to the element element["on" + type] = this.handle; // Remember the function in a global list (for triggering) if (!this.global[type]) this.global[type] = []; this.global[type].push( element ); }, guid: 1, global: {}, // Detach an event or set of events from an element remove: function(element, type, handler) { if (element.events) if ( type && type.type ) delete element.events[ type.type ][ type.handler.guid ]; else if (type && element.events[type]) if ( handler ) delete element.events[type][handler.guid]; else for ( var i in element.events[type] ) delete element.events[type][i]; else for ( var j in element.events ) this.remove( element, j ); }, trigger: function(type,data,element) { // Clone the incoming data, if any data = jQuery.makeArray(data || []); // Handle a global trigger if ( !element ) { var g = this.global[type]; if ( g ) jQuery.each( g, function(){ jQuery.event.trigger( type, data, this ); }); // Handle triggering a single element } else if ( element["on" + type] ) { // Pass along a fake event data.unshift( this.fix({ type: type, target: element }) ); // Trigger the event var val = element["on" + type].apply( element, data ); if ( val !== false && jQuery.isFunction( element[ type ] ) ) element[ type ](); } }, handle: function(event) { if ( typeof jQuery == "undefined" ) return false; // Empty object is for triggered events with no data event = jQuery.event.fix( event || window.event || {} ); // returned undefined or false var returnValue; var c = this.events[event.type]; var args = [].slice.call( arguments, 1 ); args.unshift( event ); for ( var j in c ) { // Pass in a reference to the handler function itself // So that we can later remove it args[0].handler = c[j]; args[0].data = c[j].data; if ( c[j].apply( this, args ) === false ) { event.preventDefault(); event.stopPropagation(); returnValue = false; } } // Clean up added properties in IE to prevent memory leak if (jQuery.browser.msie) event.target = event.preventDefault = event.stopPropagation = event.handler = event.data = null; return returnValue; }, fix: function(event) { // Fix target property, if necessary if ( !event.target && event.srcElement ) event.target = event.srcElement; // Calculate pageX/Y if missing and clientX/Y available if ( event.pageX == undefined && event.clientX != undefined ) { var e = document.documentElement, b = document.body; event.pageX = event.clientX + (e.scrollLeft || b.scrollLeft); event.pageY = event.clientY + (e.scrollTop || b.scrollTop); } // check if target is a textnode (safari) if (jQuery.browser.safari && event.target.nodeType == 3) { // store a copy of the original event object // and clone because target is read only var originalEvent = event; event = jQuery.extend({}, originalEvent); // get parentnode from textnode event.target = originalEvent.target.parentNode; // add preventDefault and stopPropagation since // they will not work on the clone event.preventDefault = function() { return originalEvent.preventDefault(); }; event.stopPropagation = function() { return originalEvent.stopPropagation(); }; } // fix preventDefault and stopPropagation if (!event.preventDefault) event.preventDefault = function() { this.returnValue = false; }; if (!event.stopPropagation) event.stopPropagation = function() { this.cancelBubble = true; }; return event; } }; jQuery.fn.extend({ bind: function( type, data, fn ) { return this.each(function(){ jQuery.event.add( this, type, fn || data, data ); }); }, one: function( type, data, fn ) { return this.each(function(){ jQuery.event.add( this, type, function(event) { jQuery(this).unbind(event); return (fn || data).apply( this, arguments); }, data); }); }, unbind: function( type, fn ) { return this.each(function(){ jQuery.event.remove( this, type, fn ); }); }, trigger: function( type, data ) { return this.each(function(){ jQuery.event.trigger( type, data, this ); }); }, toggle: function() { // Save reference to arguments for access in closure var a = arguments; return this.click(function(e) { // Figure out which function to execute this.lastToggle = this.lastToggle == 0 ? 1 : 0; // Make sure that clicks stop e.preventDefault(); // and execute the function return a[this.lastToggle].apply( this, [e] ) || false; }); }, hover: function(f,g) { // A private function for handling mouse 'hovering' function handleHover(e) { // Check if mouse(over|out) are still within the same parent element var p = (e.type == "mouseover" ? e.fromElement : e.toElement) || e.relatedTarget; // Traverse up the tree while ( p && p != this ) try { p = p.parentNode } catch(e) { p = this; }; // If we actually just moused on to a sub-element, ignore it if ( p == this ) return false; // Execute the right function return (e.type == "mouseover" ? f : g).apply(this, [e]); } // Bind the function to the two event listeners return this.mouseover(handleHover).mouseout(handleHover); }, ready: function(f) { // If the DOM is already ready if ( jQuery.isReady ) // Execute the function immediately f.apply( document, [jQuery] ); // Otherwise, remember the function for later else { // Add the function to the wait list jQuery.readyList.push( function() { return f.apply(this, [jQuery]) } ); } return this; } }); jQuery.extend({ /* * All the code that makes DOM Ready work nicely. */ isReady: false, readyList: [], // Handle when the DOM is ready ready: function() { // Make sure that the DOM is not already loaded if ( !jQuery.isReady ) { // Remember that the DOM is ready jQuery.isReady = true; // If there are functions bound, to execute if ( jQuery.readyList ) { // Execute all of them jQuery.each( jQuery.readyList, function(){ this.apply( document ); }); // Reset the list of functions jQuery.readyList = null; } // Remove event lisenter to avoid memory leak if ( jQuery.browser.mozilla || jQuery.browser.opera ) document.removeEventListener( "DOMContentLoaded", jQuery.ready, false ); } } }); new function(){ jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," + "mousedown,mouseup,mousemove,mouseover,mouseout,change,select," + "submit,keydown,keypress,keyup,error").split(","), function(i,o){ // Handle event binding jQuery.fn[o] = function(f){ return f ? this.bind(o, f) : this.trigger(o); }; }); // If Mozilla is used if ( jQuery.browser.mozilla || jQuery.browser.opera ) // Use the handy event callback document.addEventListener( "DOMContentLoaded", jQuery.ready, false ); // If IE is used, use the excellent hack by Matthias Miller // http://www.outofhanwell.com/blog/index.php?title=the_window_onload_problem_revisited else if ( jQuery.browser.msie ) { // Only works if you document.write() it document.write("<\/script>"); // Use the defer script hack var script = document.getElementById("__ie_init"); // script does not exist if jQuery is loaded dynamically if ( script ) script.onreadystatechange = function() { if ( this.readyState != "complete" ) return; this.parentNode.removeChild( this ); jQuery.ready(); }; // Clear from memory script = null; // If Safari is used } else if ( jQuery.browser.safari ) // Continually check to see if the document.readyState is valid jQuery.safariTimer = setInterval(function(){ // loaded and complete are both valid states if ( document.readyState == "loaded" || document.readyState == "complete" ) { // If either one are found, remove the timer clearInterval( jQuery.safariTimer ); jQuery.safariTimer = null; // and execute any waiting functions jQuery.ready(); } }, 10); // A fallback to window.onload, that will always work jQuery.event.add( window, "load", jQuery.ready ); }; // Clean up after IE to avoid memory leaks if (jQuery.browser.msie) jQuery(window).one("unload", function() { var global = jQuery.event.global; for ( var type in global ) { var els = global[type], i = els.length; if ( i && type != 'unload' ) do jQuery.event.remove(els[i-1], type); while (--i); } }); jQuery.fn.extend({ show: function(speed,callback){ var hidden = this.filter(":hidden"); return speed ? hidden.animate({ height: "show", width: "show", opacity: "show" }, speed, callback) : hidden.each(function(){ this.style.display = this.oldblock ? this.oldblock : ""; if ( jQuery.css(this,"display") == "none" ) this.style.display = "block"; }); }, hide: function(speed,callback){ var visible = this.filter(":visible"); return speed ? visible.animate({ height: "hide", width: "hide", opacity: "hide" }, speed, callback) : visible.each(function(){ this.oldblock = this.oldblock || jQuery.css(this,"display"); if ( this.oldblock == "none" ) this.oldblock = "block"; this.style.display = "none"; }); }, // Save the old toggle function _toggle: jQuery.fn.toggle, toggle: function( fn, fn2 ){ var args = arguments; return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ? this._toggle( fn, fn2 ) : this.each(function(){ jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ] .apply( jQuery(this), args ); }); }, slideDown: function(speed,callback){ return this.animate({height: "show"}, speed, callback); }, slideUp: function(speed,callback){ return this.animate({height: "hide"}, speed, callback); }, slideToggle: function(speed, callback){ return this.each(function(){ var state = jQuery(this).is(":hidden") ? "show" : "hide"; jQuery(this).animate({height: state}, speed, callback); }); }, fadeIn: function(speed, callback){ return this.animate({opacity: "show"}, speed, callback); }, fadeOut: function(speed, callback){ return this.animate({opacity: "hide"}, speed, callback); }, fadeTo: function(speed,to,callback){ return this.animate({opacity: to}, speed, callback); }, animate: function( prop, speed, easing, callback ) { return this.queue(function(){ this.curAnim = jQuery.extend({}, prop); var opt = jQuery.speed(speed, easing, callback); for ( var p in prop ) { var e = new jQuery.fx( this, opt, p ); if ( prop[p].constructor == Number ) e.custom( e.cur(), prop[p] ); else e[ prop[p] ]( prop ); } }); }, queue: function(type,fn){ if ( !fn ) { fn = type; type = "fx"; } return this.each(function(){ if ( !this.queue ) this.queue = {}; if ( !this.queue[type] ) this.queue[type] = []; this.queue[type].push( fn ); if ( this.queue[type].length == 1 ) fn.apply(this); }); } }); jQuery.extend({ speed: function(speed, easing, fn) { var opt = speed && speed.constructor == Object ? speed : { complete: fn || !fn && easing || jQuery.isFunction( speed ) && speed, duration: speed, easing: fn && easing || easing && easing.constructor != Function && easing }; opt.duration = (opt.duration && opt.duration.constructor == Number ? opt.duration : { slow: 600, fast: 200 }[opt.duration]) || 400; // Queueing opt.old = opt.complete; opt.complete = function(){ jQuery.dequeue(this, "fx"); if ( jQuery.isFunction( opt.old ) ) opt.old.apply( this ); }; return opt; }, easing: {}, queue: {}, dequeue: function(elem,type){ type = type || "fx"; if ( elem.queue && elem.queue[type] ) { // Remove self elem.queue[type].shift(); // Get next function var f = elem.queue[type][0]; if ( f ) f.apply( elem ); } }, /* * I originally wrote fx() as a clone of moo.fx and in the process * of making it small in size the code became illegible to sane * people. You've been warned. */ fx: function( elem, options, prop ){ var z = this; // The styles var y = elem.style; // Store display property var oldDisplay = jQuery.css(elem, "display"); // Set display property to block for animation y.display = "block"; // Make sure that nothing sneaks out y.overflow = "hidden"; // Simple function for setting a style value z.a = function(){ if ( options.step ) options.step.apply( elem, [ z.now ] ); if ( prop == "opacity" ) jQuery.attr(y, "opacity", z.now); // Let attr handle opacity else if ( parseInt(z.now) ) // My hate for IE will never die y[prop] = parseInt(z.now) + "px"; }; // Figure out the maximum number to run to z.max = function(){ return parseFloat( jQuery.css(elem,prop) ); }; // Get the current size z.cur = function(){ var r = parseFloat( jQuery.curCSS(elem, prop) ); return r && r > -10000 ? r : z.max(); }; // Start an animation from one number to another z.custom = function(from,to){ z.startTime = (new Date()).getTime(); z.now = from; z.a(); z.timer = setInterval(function(){ z.step(from, to); }, 13); }; // Simple 'show' function z.show = function(){ if ( !elem.orig ) elem.orig = {}; // Remember where we started, so that we can go back to it later elem.orig[prop] = this.cur(); options.show = true; // Begin the animation z.custom(0, elem.orig[prop]); // Stupid IE, look what you made me do if ( prop != "opacity" ) y[prop] = "1px"; }; // Simple 'hide' function z.hide = function(){ if ( !elem.orig ) elem.orig = {}; // Remember where we started, so that we can go back to it later elem.orig[prop] = this.cur(); options.hide = true; // Begin the animation z.custom(elem.orig[prop], 0); }; //Simple 'toggle' function z.toggle = function() { if ( !elem.orig ) elem.orig = {}; // Remember where we started, so that we can go back to it later elem.orig[prop] = this.cur(); if(oldDisplay == "none") { options.show = true; // Stupid IE, look what you made me do if ( prop != "opacity" ) y[prop] = "1px"; // Begin the animation z.custom(0, elem.orig[prop]); } else { options.hide = true; // Begin the animation z.custom(elem.orig[prop], 0); } }; // Each step of an animation z.step = function(firstNum, lastNum){ var t = (new Date()).getTime(); if (t > options.duration + z.startTime) { // Stop the timer clearInterval(z.timer); z.timer = null; z.now = lastNum; z.a(); if (elem.curAnim) elem.curAnim[ prop ] = true; var done = true; for ( var i in elem.curAnim ) if ( elem.curAnim[i] !== true ) done = false; if ( done ) { // Reset the overflow y.overflow = ""; // Reset the display y.display = oldDisplay; if (jQuery.css(elem, "display") == "none") y.display = "block"; // Hide the element if the "hide" operation was done if ( options.hide ) y.display = "none"; // Reset the properties, if the item has been hidden or shown if ( options.hide || options.show ) for ( var p in elem.curAnim ) if (p == "opacity") jQuery.attr(y, p, elem.orig[p]); else y[p] = ""; } // If a callback was provided, execute it if ( done && jQuery.isFunction( options.complete ) ) // Execute the complete function options.complete.apply( elem ); } else { var n = t - this.startTime; // Figure out where in the animation we are and set the number var p = n / options.duration; // If the easing function exists, then use it z.now = options.easing && jQuery.easing[options.easing] ? jQuery.easing[options.easing](p, n, firstNum, (lastNum-firstNum), options.duration) : // else use default linear easing ((-Math.cos(p*Math.PI)/2) + 0.5) * (lastNum-firstNum) + firstNum; // Perform the next step of the animation z.a(); } }; } }); jQuery.fn.extend({ loadIfModified: function( url, params, callback ) { this.load( url, params, callback, 1 ); }, load: function( url, params, callback, ifModified ) { if ( jQuery.isFunction( url ) ) return this.bind("load", url); callback = callback || function(){}; // Default to a GET request var type = "GET"; // If the second parameter was provided if ( params ) // If it's a function if ( jQuery.isFunction( params.constructor ) ) { // We assume that it's the callback callback = params; params = null; // Otherwise, build a param string } else { params = jQuery.param( params ); type = "POST"; } var self = this; // Request the remote document jQuery.ajax({ url: url, type: type, data: params, ifModified: ifModified, complete: function(res, status){ if ( status == "success" || !ifModified && status == "notmodified" ) // Inject the HTML into all the matched elements self.attr("innerHTML", res.responseText) // Execute all the scripts inside of the newly-injected HTML .evalScripts() // Execute callback .each( callback, [res.responseText, status, res] ); else callback.apply( self, [res.responseText, status, res] ); } }); return this; }, serialize: function() { return jQuery.param( this ); }, evalScripts: function() { return this.find("script").each(function(){ if ( this.src ) jQuery.getScript( this.src ); else jQuery.globalEval( this.text || this.textContent || this.innerHTML || "" ); }).end(); } }); // If IE is used, create a wrapper for the XMLHttpRequest object if ( jQuery.browser.msie && typeof XMLHttpRequest == "undefined" ) XMLHttpRequest = function(){ return new ActiveXObject("Microsoft.XMLHTTP"); }; // Attach a bunch of functions for handling common AJAX events jQuery.each( "ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","), function(i,o){ jQuery.fn[o] = function(f){ return this.bind(o, f); }; }); jQuery.extend({ get: function( url, data, callback, type, ifModified ) { // shift arguments if data argument was ommited if ( jQuery.isFunction( data ) ) { callback = data; data = null; } return jQuery.ajax({ url: url, data: data, success: callback, dataType: type, ifModified: ifModified }); }, getIfModified: function( url, data, callback, type ) { return jQuery.get(url, data, callback, type, 1); }, getScript: function( url, callback ) { return jQuery.get(url, null, callback, "script"); }, getJSON: function( url, data, callback ) { return jQuery.get(url, data, callback, "json"); }, post: function( url, data, callback, type ) { return jQuery.ajax({ type: "POST", url: url, data: data, success: callback, dataType: type }); }, // timeout (ms) //timeout: 0, ajaxTimeout: function( timeout ) { jQuery.ajaxSettings.timeout = timeout; }, ajaxSetup: function( settings ) { jQuery.extend( jQuery.ajaxSettings, settings ); }, ajaxSettings: { global: true, type: "GET", timeout: 0, contentType: "application/x-www-form-urlencoded", processData: true, async: true, data: null }, // Last-Modified header cache for next request lastModified: {}, ajax: function( s ) { // TODO introduce global settings, allowing the client to modify them for all requests, not only timeout s = jQuery.extend({}, jQuery.ajaxSettings, s); // if data available if ( s.data ) { // convert data if not already a string if (s.processData && typeof s.data != "string") s.data = jQuery.param(s.data); // append data to url for get requests if( s.type.toLowerCase() == "get" ) // "?" + data or "&" + data (in case there are already params) s.url += ((s.url.indexOf("?") > -1) ? "&" : "?") + s.data; } // Watch for a new set of requests if ( s.global && ! jQuery.active++ ) jQuery.event.trigger( "ajaxStart" ); var requestDone = false; // Create the request object var xml = new XMLHttpRequest(); // Open the socket xml.open(s.type, s.url, s.async); // Set the correct header, if data is being sent if ( s.data ) xml.setRequestHeader("Content-Type", s.contentType); // Set the If-Modified-Since header, if ifModified mode. if ( s.ifModified ) xml.setRequestHeader("If-Modified-Since", jQuery.lastModified[s.url] || "Thu, 01 Jan 1970 00:00:00 GMT" ); // Set header so the called script knows that it's an XMLHttpRequest xml.setRequestHeader("X-Requested-With", "XMLHttpRequest"); // Make sure the browser sends the right content length if ( xml.overrideMimeType ) xml.setRequestHeader("Connection", "close"); // Allow custom headers/mimetypes if( s.beforeSend ) s.beforeSend(xml); if ( s.global ) jQuery.event.trigger("ajaxSend", [xml, s]); // Wait for a response to come back var onreadystatechange = function(isTimeout){ // The transfer is complete and the data is available, or the request timed out if ( xml && (xml.readyState == 4 || isTimeout == "timeout") ) { requestDone = true; var status; try { status = jQuery.httpSuccess( xml ) && isTimeout != "timeout" ? s.ifModified && jQuery.httpNotModified( xml, s.url ) ? "notmodified" : "success" : "error"; // Make sure that the request was successful or notmodified if ( status != "error" ) { // Cache Last-Modified header, if ifModified mode. var modRes; try { modRes = xml.getResponseHeader("Last-Modified"); } catch(e) {} // swallow exception thrown by FF if header is not available if ( s.ifModified && modRes ) jQuery.lastModified[s.url] = modRes; // process the data (runs the xml through httpData regardless of callback) var data = jQuery.httpData( xml, s.dataType ); // If a local callback was specified, fire it and pass it the data if ( s.success ) s.success( data, status ); // Fire the global callback if( s.global ) jQuery.event.trigger( "ajaxSuccess", [xml, s] ); } else jQuery.handleError(s, xml, status); } catch(e) { status = "error"; jQuery.handleError(s, xml, status, e); } // The request was completed if( s.global ) jQuery.event.trigger( "ajaxComplete", [xml, s] ); // Handle the global AJAX counter if ( s.global && ! --jQuery.active ) jQuery.event.trigger( "ajaxStop" ); // Process result if ( s.complete ) s.complete(xml, status); // Stop memory leaks xml.onreadystatechange = function(){}; xml = null; } }; xml.onreadystatechange = onreadystatechange; // Timeout checker if ( s.timeout > 0 ) setTimeout(function(){ // Check to see if the request is still happening if ( xml ) { // Cancel the request xml.abort(); if( !requestDone ) onreadystatechange( "timeout" ); } }, s.timeout); // save non-leaking reference var xml2 = xml; // Send the data try { xml2.send(s.data); } catch(e) { jQuery.handleError(s, xml, null, e); } // firefox 1.5 doesn't fire statechange for sync requests if ( !s.async ) onreadystatechange(); // return XMLHttpRequest to allow aborting the request etc. return xml2; }, handleError: function( s, xml, status, e ) { // If a local callback was specified, fire it if ( s.error ) s.error( xml, status, e ); // Fire the global callback if ( s.global ) jQuery.event.trigger( "ajaxError", [xml, s, e] ); }, // Counter for holding the number of active queries active: 0, // Determines if an XMLHttpRequest was successful or not httpSuccess: function( r ) { try { return !r.status && location.protocol == "file:" || ( r.status >= 200 && r.status < 300 ) || r.status == 304 || jQuery.browser.safari && r.status == undefined; } catch(e){} return false; }, // Determines if an XMLHttpRequest returns NotModified httpNotModified: function( xml, url ) { try { var xmlRes = xml.getResponseHeader("Last-Modified"); // Firefox always returns 200. check Last-Modified date return xml.status == 304 || xmlRes == jQuery.lastModified[url] || jQuery.browser.safari && xml.status == undefined; } catch(e){} return false; }, /* Get the data out of an XMLHttpRequest. * Return parsed XML if content-type header is "xml" and type is "xml" or omitted, * otherwise return plain text. * (String) data - The type of data that you're expecting back, * (e.g. "xml", "html", "script") */ httpData: function( r, type ) { var ct = r.getResponseHeader("content-type"); var data = !type && ct && ct.indexOf("xml") >= 0; data = type == "xml" || data ? r.responseXML : r.responseText; // If the type is "script", eval it in global context if ( type == "script" ) jQuery.globalEval( data ); // Get the JavaScript object, if JSON is used. if ( type == "json" ) eval( "data = " + data ); // evaluate scripts within html if ( type == "html" ) jQuery("
").html(data).evalScripts(); return data; }, // Serialize an array of form elements or a set of // key/values into a query string param: function( a ) { var s = []; // If an array was passed in, assume that it is an array // of form elements if ( a.constructor == Array || a.jquery ) // Serialize the form elements jQuery.each( a, function(){ s.push( encodeURIComponent(this.name) + "=" + encodeURIComponent( this.value ) ); }); // Otherwise, assume that it's an object of key/value pairs else // Serialize the key/values for ( var j in a ) // If the value is an array then the key names need to be repeated if ( a[j].constructor == Array ) jQuery.each( a[j], function(){ s.push( encodeURIComponent(j) + "=" + encodeURIComponent( this ) ); }); else s.push( encodeURIComponent(j) + "=" + encodeURIComponent( a[j] ) ); // Return the resulting serialization return s.join("&"); }, // evalulates a script in global context // not reliable for safari globalEval: function( data ) { if ( window.execScript ) window.execScript( data ); else if ( jQuery.browser.safari ) // safari doesn't provide a synchronous global eval window.setTimeout( data, 0 ); else eval.call( window, data ); } }); } PK²6f6µ†G\\)mastertickets/htdocs/linkify_blockedby.js$(function() { $('td[@headers=h_blockedby]').html($('#linkified_blockedby').html()); });PK²6f68€ÄZZ(mastertickets/htdocs/linkify_blocking.js$(function() { $('td[@headers=h_blocking]').html($('#linkified_blocking').html()); });PK²6f6R0 ^mmmastertickets/htdocs/ticket.cssinput#blockedby { display: none; } label[for=blockedby] { display: none; } img.blockedby_icon { width: 1em; }PKÄ‹9¯u33%mastertickets/templates/depgraph.html Dependency Graph #$tkt.id

Dependency Graph for Ticket #$tkt.id

Dependency graph ${Markup(graph_render('cmapx').decode('utf8'))}
PKI˜9“×2¤EGG-INFO/dependency_links.txtPKI˜9Õ"Hbb¤<EGG-INFO/entry_points.txtPKI˜9÷Ô’’¤ÕEGG-INFO/PKG-INFOPKI˜9,^D†¤–EGG-INFO/requires.txtPKI˜9Ç9/³  ¤ßEGG-INFO/SOURCES.txtPKI˜9z< ¤EGG-INFO/top_level.txtPKI˜9“×2¤^EGG-INFO/zip-safePK²6f6¤Žmastertickets/__init__.pyPKI˜93ʨsŒŒ¤Åmastertickets/__init__.pycPKÃZ¡8E𮍛›¤‰mastertickets/api.pyPKI˜9Ü`ü)//¤Vmastertickets/api.pycPKϘä6Ö'<¾&&¤¸9mastertickets/db_default.pyPKI˜9œ‹Â0§§¤;mastertickets/db_default.pycPKÅ‹9 Uâ^­­¤ø<mastertickets/graphviz.pyPKI˜9Q!=D¤ÜKmastertickets/graphviz.pycPK¢9–Ö=d..¤£hmastertickets/model.pyPKI˜99îfÒ¢¢¤mastertickets/model.pycPKÝ–9Ø|Ñ__¤Ü™mastertickets/util.pyPKI˜9ø7ˆ¤nœmastertickets/util.pycPKn—9¹ê)@ii¤¼¡mastertickets/web_ui.pyPKI˜9D¡÷b ( (¤ZÀmastertickets/web_ui.pycPK²6f6 4ßBB'¤°èmastertickets/htdocs/disable_resolve.jsPK²6f6 " ¡Þ¡Þ¤7émastertickets/htdocs/jquery.jsPK²6f6µ†G\\)¤Èmastertickets/htdocs/linkify_blockedby.jsPK²6f68€ÄZZ(¤·Èmastertickets/htdocs/linkify_blocking.jsPK²6f6R0 ^mm¤WÉmastertickets/htdocs/ticket.cssPKÄ‹9¯u33%¤Êmastertickets/templates/depgraph.htmlPK˜wÍ