o k`@sddlZddlmZmZddlmZddlmZmZmZddl Tddl m Z m Z m Z ddlmZmZddlmZmZdd lmZmZdd lmZmZmZmZdd lmZmZmZdd l m!Z!m"Z"dd l#m$Z$m%Z%ddl&m'Z'm(Z(ddl)Tddl*m+Z+m,Z,ddl-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5ddl6m7Z7m8Z8m9Z9ddl:m;Z;mZ?Gddde@ZAGdddeBZCGdddeBZDGddde@ZEGdddeBZFGd d!d!e@ZGdS)"N)datetime timedelta fnmatchcase) BoolOption ListOptionOption)*)IHTMLPreviewAnnotatorMimeview is_binary)IPermissionRequestorPermissionError)ResourceResourceNotFound)as_boolembedded_numbers) datetime_now http_date to_datetimeutc)Markupescapetag)exception_to_unicode shorten_line)_ cleandoc_)NoSuchChangesetRepositoryManager)IRequestHandler RequestDone)ChromeINavigationContributor add_ctxtnavadd_link add_scriptadd_stylesheet prevnext_nav web_context)IWikiMacroProviderIWikiSyntaxProvider parse_args)format_to_htmlformat_to_onelineric@s eZdZdZddZddZdS)IPropertyRendererz>Render node properties in TracBrowser and TracChangeset views.cCdS)aIndicate whether this renderer can treat the given property `mode` is the current rendering context, which can be: - 'browser' rendered in the browser view - 'changeset' rendered in the changeset view as a node property - 'revprop' rendered in the changeset view as a revision property Other identifiers might be used by plugins, so it's advised to simply ignore unknown modes. Returns a quality number, ranging from 0 (unsupported) to 9 (''perfect'' match). N)namemoder1r1D/usr/lib/python3/dist-packages/trac/versioncontrol/web_ui/browser.pymatch_property0z IPropertyRenderer.match_propertycCr0)aRender the given property. `name` is the property name as given to `match()`, `mode` is the same as for `match_property`, `context` is the context for the node being render (useful when the rendering depends on the node kind) and `props` is the collection of the corresponding properties (i.e. the `node.get_properties()`). The rendered result can be one of the following: - `None`: the property will be skipped - a `str` value: the property will be displayed as text - a `RenderedProperty` instance: the property will only be displayed using the instance's `content` attribute, and the other attributes will also be used in some display contexts (like `revprop`) - `Markup` or `Fragment`: the property will be displayed normally, using that content as a block-level markup Nr1)r2r3contextpropsr1r1r4render_property?r6z!IPropertyRenderer.render_propertyN)__name__ __module__ __qualname____doc__r5r9r1r1r1r4r/-s r/c@seZdZ  dddZdS)RenderedPropertyNcCs||_||_||_||_dSN)r2name_attributescontentcontent_attributes)selfr2r@rArBr1r1r4__init__Us zRenderedProperty.__init__)NNNN)r:r;r<rDr1r1r1r4r>Tsr>c@s(eZdZdZeeddZddZdS)DefaultPropertyRendererz*Default version control property renderer.cCr0)Nr1rCr2r3r1r1r4r5bz&DefaultPropertyRenderer.match_propertycCs6||}|rd|vrtddd|dD}|S)N css|] }dt|VqdS)z
%sN)r.0vr1r1r4 isz:DefaultPropertyRenderer.render_property..)rjoinsplit)rCr2r3r7r8valuer1r1r4r9es    z'DefaultPropertyRenderer.render_propertyN)r:r;r<r= implementsr/r5r9r1r1r1r4rE]s  rEc@sHeZdZdZeeedddddZedddd dZd d Z d d Z dS)WikiPropertyRendererzWiki text property renderer.browserwiki_propertiesztrac:descriptionzxComma-separated list of version control properties to render as wiki content in the repository browser. doconeliner_propertiesz trac:summaryzComma-separated list of version control properties to render as oneliner wiki content in the repository browser. cCs||jvs ||jvr dSdS)Nr)rUrXrGr1r1r4r5s  z#WikiPropertyRenderer.match_propertycCs.||jvrt|j|||St|j|||Sr?)rUr-envr.)rCr2r3r7r8r1r1r4r9s z$WikiPropertyRenderer.render_propertyN) r:r;r<r=rRr/rrUrXr5r9r1r1r1r4rSns rSc @sReZdZedddddddeZddZddZddZd d Z d d Z d dZ dS) TimeRangerFrcCs||_|_d|_dSr?)oldestnewest_total)rCbaser1r1r4rDs  zTimeRange.__init__cCs||}|jdd|jS)Ni)daysseconds)rCdt1dt2deltar1r1r4seconds_betweenszTimeRange.seconds_betweencCs||tjSr?)rfr[min)rCdtr1r1r4 to_secondszTimeRange.to_secondscCstjtt|dS)NiQ)r[rgrdivmod)rCsecsr1r1r4 from_secondsszTimeRange.from_secondscCsB|jdurt||j|j|_d}|jr|||j|j}|SNg?)r^floatrfr]r\)rCrager1r1r4relatives zTimeRange.relativecCs&d|_t|j||_t|j||_dSr?)r^rgr\maxr])rCrr1r1r4insertszTimeRange.insertN) r:r;r<rrrgrDrfrirmrqrsr1r1r1r4r[s r[c@seZdZeeeeeee e e Z e jZedddddZedddddZd Zedd eed dZd Zedd eeddZedddddZedddddZeddddZedddddZddZddZddZ d d!Z!d"d#Z"d$d%Z#d&d'Z$d(d)Z%d*d+Z&dPd-d.Z'dPd/d0Z(d1d2Z)d3d4Z*d5d6Z+d7d8Z,d9d:Z-d;d<Z.d=d>Z/d?d@Z0e12dAZ3dBdCZ4dDdEZ5dFdGZ6dHdIZ7dJdKZ8dLdMZ9dNdOZ:d,S)Q BrowserModulerTdownloadable_pathsz/trunk, /branches/*, /tags/*aDList of repository paths that can be downloaded. Leave this option empty if you want to disable all downloads, otherwise set it to a comma-separated list of authorized paths (those paths are glob patterns, i.e. "*" can be used as a wild card). In a multi-repository environment, the path must be qualified with the repository name if the path does not point to the default repository (e.g. /reponame/trunk). Note that a simple prefix matching is performed on the paths, so aliases won't get automatically resolved. rV color_scaleTzEnable colorization of the ''age'' column. This uses the same color scale as the source code annotation: blue is older, red is newer. )rx newest_colorz(r,g,b) color triple to use for the color corresponding to the newest color, for the color scale used in ''blame'' or the browser ''age'' column if `color_scale` is enabled. )rxrxrw oldest_colorz(r,g,b) color triple to use for the color corresponding to the oldest color, for the color scale used in ''blame'' or the browser ''age'' column if `color_scale` is enabled. intermediate_pointrJzIf set to a value between 0 and 1 (exclusive), this will be the point chosen to set the `intermediate_color` for interpolating the color value. intermediate_colora,(r,g,b) color triple to use for the color corresponding to the intermediate color, if two linear interpolations are used for the color scale (see `intermediate_point`). If not set, the intermediate color between `oldest_color` and `newest_color` will be used. render_unsafe_contentfalseaWhether raw files should be rendered in the browser, or only made downloadable. Pretty much any file may be interpreted as HTML by the browser, which allows a malicious user to create a file containing cross-site scripting attacks. For open repositories where anyone can check-in a file, it is recommended to leave this option disabled.hide_propertiesz svk:mergezhComma-separated list of version control properties to hide from the repository browser. csdddd}||j|j||j|jzt|jWn ty(dYnwrK||jds?tddt Dfdd }|Sfd d }|S) z?Returns a converter for values from [0.0, 1.0] to a RGB triple.cstfddt||DS)Ncs$g|]\}}t|||qSr1intrLabrQr1r4 s$zKBrowserModule.get_custom_colorizer..interpolate..)tuplezip)oldnewrQr1rr4 interpolatesz7BrowserModule.get_custom_colorizer..interpolatecSsTztddtd|dddD}t|dkr|WS|WSty)|YSw)NcSsg|]}t|qSr1rrKr1r1r4rszKBrowserModule.get_custom_colorizer..parse_color..z(\d+)rF)rrerPlen ValueError)rgbdefaulttr1r1r4 parse_colors $ z7BrowserModule.get_custom_colorizer..parse_colorNcSsg|] \}}||dqS)rr1rr1r1r4rsz6BrowserModule.get_custom_colorizer..cs8|kr|}|S|d}|Srnr1r intermediater|rryrzr1r4 colorizers   z5BrowserModule.get_custom_colorizer..colorizercs |Sr?r1r)rryrzr1r4rs ) ry NEWEST_COLORrz OLDEST_COLORror{rr|rr)rCrrr1rr4get_custom_colorizers&   z"BrowserModule.get_custom_colorizercCr0)NrTr1)rCreqr1r1r4get_active_navigation_item#rHz(BrowserModule.get_active_navigation_itemc#sNt|j}tfdd|Dr%ddtjtdjdfVdSdS)Nc3s|] }|jVqdSr? is_viewableperm)rLreposrr1r4rN(sz5BrowserModule.get_navigation_items..mainnavrTz Browse Sourcehref) rrZanyget_real_repositoriesrrrrrT)rCrrmr1rr4get_navigation_items&s   z"BrowserModule.get_navigation_itemscCsddgS)N BROWSER_VIEW FILE_VIEWr1rCr1r1r4get_permission_actions/sz$BrowserModule.get_permission_actionscCstd|j}|r[|\}}|dkr8|r7d|vr7|dd}t|dkr'dS|d}|d|jd<d |jd <n|d krR|j|jj ||j d|j d d d d|pUd|jd<d SdS)Nz/(export|browser|file)(/.*)?$export/rrFrFrevrawformatfilerrT) permanentpath) rmatch path_infogroupsrPrargsredirectrrTget)rCrrr3r path_eltsr1r1r4 match_request4s*      zBrowserModule.match_requestc Cs|jd}|r|d|jdr|||jdd}|jdd}|dvr/d}|jd}|jdd }d |jv}t|j}| } | |\} } }| oZ|dk} | rp| rpt | dd sn| |j spd} | s|| r|ttd | d | r| | jkr|j} ||j| jpd|| rd| nd| r| jnd} t|}d}d}dd}| rz|r| |}|p| j}t|| ||}Wnty}zt|td|d}~ww|rz| |j}Wn tyYnw|| jj|j||d}| j}t|j| ||||}d}}}| r||| ||}|r[| |j s1t|j r*dnd|j|j|j rN|dvrC|!||| |||"|| ||||}n |j#r[|$||| ||}| s}|rf|ds}|j %d| ruttdttd|dd}}|r|j&s|'d||(}t)| *|}id|d| d| d| | pdd|d|o|jd|d |d!|d"|o|j+d#|o|j,d$|d%|d|d |rd&ndd'|d(||||j-d!.d)d*}|j&rd+|fS|s|rt/|d,t/|d-|r|j#rt| j0|j,|j+d.}|r2|jj| |j+|d/}t1|d0|td1||d2|durCt1|d3|j| |j+| j2|j,|j+d.}|rf|jj| |j+|d/}t1|d4|td1||d2t3|td5td6td7n&|dkrt1|d3|d8d9td:t4|t5j6td;|j7|j,| |j+d<|j#r|d=d>}|rt4|td?td@|jj| |j+|d/dA|dBkrt4|tdCtdD|jj| |j+|dBdEdAt4|tdF|jj8| ||d/d<| 9||}|r|dGr|j:dH|}t4|tdI|d<t;|dJdK|fS)LN preselectedrrrrJ)rJheadrorderr2deschiddenzRepository '%(repo)s' not foundrepo?cSs|Sr?r1rr1r1r4mr6z/BrowserModule.process_request..zInvalid changeset number)versionrr)r repositorieszNo viewable repositorieszNo node %(path)srrTr7reponamerrepoinfo stickyrev display_rev changeset created_path created_rev properties path_linksrFrdirwiki_format_messages)rquickjump_entriesrzdir_entries.htmlzcommon/js/expand_dir.jszcommon/js/keyboard_nav.js)rrrprevzRevision %(num)s)numupnextzPrevious Revisionz Next RevisionzLatest RevisionrzParent directoryz Last ChangerrannotateNormalzView file without annotationstitlerblameBlamezQAnnotate each line with the last changed revision (this can be time consuming...))rrz Revision Logz//:zRepository URLcommon/css/browser.cssz browser.html).repo_orderauthorcSs.|\}}}}}}|r|jndt|fS)NrJ)rrrrr1r1r4r'rcSs|\}}}}}}t|Sr?)rrrr1r1r4r,s keyreverse)r timerange colorize_age)rvrrrZitemsrrget_repository TracErrorrrrrrrr[rrs_get_download_hrefrrrrappendsorted)rCr7rrrr custom_colorizerrrrrrrentryrraw_hrefrootrr1r1r4rsb            z&BrowserModule._render_repository_indexcs|jd|jGfdddtfdd|D}tdd|D|jr;j }nt j }d} |j r{t |jd} jd} fd d| | fD} d dD} | | D]}|qo|} |d krfd d n|dkrdd n|dkrfdd ndd |rdndfdd}t|||d}|j|}|rtd|tddd|| oӈjoڈjdS)Nrcs2eZdZdZedgZfddZdS)z(BrowserModule._render_dir..entryz3name rev created_rev kind isdir path content_lengthr*cs4jD] }t||t||qj||_dSr?)_copysetattrgetattrrr*)rCrf download_hrefr)rrrr1r4rD?s z1BrowserModule._render_dir..entry.__init__N)r:r;r<rPr, __slots__rDr1r0r1r4r):s  r)cs g|] }|jr|qSr1r)rLn)r)rr1r4rDs z-BrowserModule._render_dir..cSsg|]}|jqSr1)r)rLir1r1r4rFsrange_max_secsrange_min_secscsg|] }|rt|qSr1)rmr)rLs)r r1r4rTscSsg|]}|r|jqSr1)r)rLcr1r1r4rVsrcs|jjt|jfSr?)rrrr2rrchangesr1r4 file_order]s  z-BrowserModule._render_dir..file_ordersizecSs|jt|jfSr?)content_lengthrr2rr9r1r1r4r<as rcs|jjt|jfSr?)rrrrr2r9r:r1r4r<es cSst|jSr?)rr2rr9r1r1r4r<irjrFcs|jrnd|fSr)rr9) dir_orderr<r1r4 browse_ordernsz/BrowserModule._render_dir..browse_orderr alternatez Zip Archivezapplication/zipr)entriesr;r r!r5r6)rrrr%object get_entries get_changesrrrrtzrvr[rrvaluesrsrr'rr%rrir]r\)rCrrrrrrrCr]r(max_smin_s parent_range this_rangerhrAzip_hrefr1) r;r@r1r)r<rrrr r4r5sX           zBrowserModule._render_dirccsH|g}|r"|}|V|jr|t|dddd|sdSdS)NcSs|jSr?)r2)xr1r1r4rsz+BrowserModule._iter_nodes..Tr)poprextendr'rE)rCrstackr1r1r4 _iter_nodess  zBrowserModule._iter_nodesNc Csr|||js ttd||jd|jd}|r"|j}n|j p&d}d||j f}t |||||j dS)NzPath not available for downloadrrrz %s-%s.zip) is_path_downloadablerr$rrrrrstripr2rr render_ziprR) rCrr7r root_noder root_path archive_namefilenamer1r1r4rs   zBrowserModule._render_zipc CsH||jdt|j}t|x}|t}|j } | r#| dkr.| |j |p-| p-d} |j d} | dvr|d|d| dkrFdn| |d t|j|durh|d d |d d |d d|jsq|dd||r|||t}|swtWdn1swY||j} t|s| dkr|jj|jpd|j|dd} t|d| tdd|j|p|j |jpd|j} t|d| td| |j!"d|j || t#|ddg}|j d}|r|$d|t|}|j%|||&| |j'| |t(|d}Wdn 1swY| |j)||dS)Nrzapplication/octet-streamz text/plainr)rtxtz Content-TyperZz Last-ModifiedPragmazno-cachez Cache-ControlExpireszFri, 01 Jan 1999 00:00:00 GMTzContent-Disposition attachmentrrBz Plain TextzOriginal Formatz1Rendering preview of node %s@%s with mime-type %szcommon/css/code.csslinenorr) annotations force_source)rr=previewr)*rrrr rZcontent_closingget_processed_contentread CHUNK_SIZE content_type get_mimetyper2rr send_response send_headerr last_modifiedr} end_headerswriter!rrr rrTrrr%rrrrdebugr'rs preview_dataget_content_lengthrboolr>)rCrr7rrrmimeviewrAchunk mime_typerr plain_hrefr*r`rror1r1r4rs            !    zBrowserModule._render_filecCsn|dur|jr||p d|jpd|jS|durdn|jd}|||r5|j|jp,d||p1|jddSdS)z?Return the URL for downloading a file, or a directory as a ZIP.NHEADrJrrr)rrrrstriprSrTr)rCrrrrrr1r1r4r%s  z BrowserModule._get_download_hrefcs,|jr |jdtfdd|jDS)Nrc3s |] }t|dVqdS)rN)rrw)rLdprr1r4rNsz5BrowserModule.is_path_downloadable..)rrru)rCrrr1rr4rSs  z"BrowserModule.is_path_downloadablecs&ttdfddtDS)z0Prepare rendering of a collection of properties.Ncsg|] }|qSr1)r9)rLr2r7r3r8rCr1r4rsz3BrowserModule.render_properties..)rfilterr')rCr3r7r8r1ryr4rs zBrowserModule.render_propertiesc Cs||jvrdSg}|jD]}|||}|dkr|||fq |jdd|D]L\}}z'|||||}|s<|WSt|trE|j} n|} d}|| |d} | WSt yt} z|j d||j j t| ddWYd} ~ q(d} ~ wwdS)z Renders a node property to HTML.NrTr)r2rQrenderedz5Rendering failed for property %s with renderer %s: %s) traceback)hidden_propertiesproperty_renderersr5r&sortr9 isinstancer>rA Exceptionrwarning __class__r:r) rCr2r3r7r8 candidatesrendererqualityr|rQpropr r1r1r4r9s:          zBrowserModule.render_propertycCsgSr?r1rr1r1r4get_wiki_syntaxrHzBrowserModule.get_wiki_syntaxcCs$d|jfd|jfd|jfd|jfgS)a TracBrowser link resolvers. `source:` and `browser:` * simple paths (/dir/file) * paths at a given revision (/dir/file@234) * paths with line number marks (/dir/file@234:10,20-30) * paths with line number anchor (/dir/file@234#L100) Marks and anchor can be combined. The revision must be present when specifying line numbers. In the few cases where it would be redundant (e.g. for tags), the revision number itself can be omitted: /tags/v10/file@100-110#L99 rrsourcerT)_format_browser_link_format_export_linkrr1r1r4get_link_resolverss z BrowserModule.get_link_resolversc Cs||\}}}d|vr|dd\}}nd|vr"|dd\}}nd|}}||||j|j\} } } | rAtj|d| || dStj|ddS)NrrF@r)class_rrzmissing exportr) split_linkrP_get_link_inforrrr) rC formatternsrlabelqueryfragmentrrrr*rr1r1r4r0s   z!BrowserModule._format_export_linkcCs||\}}}d}}|j|} | r| \}}}|j} | j|||d||} ||||j|j\} } }| s@tj |ddStj |d| d}| r]t|tj d| ||| j rXdndd }|S) N)rmarkszmissing sourcerr)rru​z trac-rawlinkz trac-ziplink)rrr) r PATH_LINK_RErrrrTrrrrr)rCrrrrrrrrrrsrc_hrefrr*rlinkr1r1r4r?s(    z"BrowserModule._format_browser_linkz<([^@#:]*)[@:]([^#:]+)?(?::(\d+(?:-\d+)?(?:,\d+(?:-\d+)?)*))?c Cst|j}d}}}z(||\} } } t| | ||}|dur2||| ||}|jr.tdntd}Wn ty<Ynw|||fS)NDownloadzDownload as Zip archive)rrZrget_allowed_noder%rrr$) rCrrrrrrr*rrrnpathr1r1r4rXs    zBrowserModule._get_link_infocCsdtdtdfS)NrRevz"Revision in which the line changed)rrr1r1r4get_annotation_typehsz!BrowserModule.get_annotation_typecCs t|j|S)z9Cache the annotation data corresponding to each revision.)BlameAnnotatorrZ)rCr7r1r1r4get_annotation_dataks z!BrowserModule.get_annotation_datacCs|||dSr?)r)rCr7rowr_lineblame_annotatorr1r1r4 annotate_rowoszBrowserModule.annotate_rowccs dVdS)NRepositoryIndexr1rr1r1r4 get_macrosts zBrowserModule.get_macroscCstd}d|fS)Na  Display the list of available repositories. Can be given the following named arguments: ''format'':: Select the rendering format: - ''compact'' produces a comma-separated list of repository prefix names (default) - ''list'' produces a description list of repository prefix names - ''table'' produces a table view, similar to the one visible in the ''Browse View'' page ''glob'':: Do a glob-style filtering on the repository names (defaults to '*') ''order'':: Order repositories by the given column (one of "name", "date" or "author") ''desc'':: When set to 1, order by descending order messages)r)rCr2 descriptionr1r1r4get_macro_descriptionwsz#BrowserModule.get_macro_descriptionc sPt|\}}|dd}|dd|d}t|dd}t|jtfdd D} |d krh|j | ||} t j d |j d  d } | ||rTdndddd| d} t|jj j d| Sfddfdd| D} tfdd | D|d} fdd|dkrtfdd| DStdfdd | DS)Nrcompactglobr rrrc3s"|] }t|dr|VqdS)rNr)rLrdata)rr1r4rNs z-BrowserModule.expand_macro..tablerrrrFr)rrrrrrrzrepository_index.htmlcs"z|WStyYdSwr?)r#r$)r)rr1r4r#s   z2BrowserModule.expand_macro..get_repositorycsg|]}||fqSr1r1)rLr)r#r1r4rsz.BrowserModule.expand_macro..c3s<|]\}}|rt|jds|jr||fVqdS)rN)rparamsrrrrLrrrr1r4rNs  r{cs6|ptd}ttj|td|dj|jpddS)Nz (default)zView repository %(repo)srr)rrrrrrTr)rrrrr1r4repolinks  z,BrowserModule.expand_macro..repolinkrc s4g|]\}}tt||t|jdqS)r)rrhddrrrrr1r4rs z, c3s|] \}}||VqdSr?r1rrr1r4rNs)r,rrrrZdictrr"rr7r'rrrr"render_fragmentr'rdlrrO) rCrr2rArkwargsrrr all_reposrrrr1)rr#rrrr4 expand_macrosL          zBrowserModule.expand_macror?);r:r;r<rRr#r r r+r r*ExtensionPointr/rr source_realmrrrurrvrrreprryrrzr{r|r}r~rrrrrrrrrRrrr%rSrr9rrrrrcompilerrrrrrrrr1r1r1r4rts~    ) 1>K N   rtc@s$eZdZddZddZddZdS)rcCsx||_||_t|j}||jjj|_|jj|_|jj |_ d|_ i|_ t |jdt|jdt|jd|dS)Nzcommon/js/blame.jszcommon/css/changeset.csszcommon/css/diff.css)rZr7rr#rparentidrrrr prev_chgset chgset_datar&rr'reset)rCrZr7rr1r1r4rDs       zBlameAnnotator.__init__c Cs|j}|j|j|}||_g|_|j|}||i}t|j |_ t t |jD]%}|j|}| |}|sI|j|}|||<|j |j |j|q*i|_|D] \}}}||j|<qWt|j}||_dSr?)rrget_noderget_annotationsr` changesetsrr[rr rangerrrsr&paths get_historyrtrZrr!) rCrrchgsetchgsetsidxrchgrTr1r1r4rs(        zBlameAnnotator.resetc Csl|t|jkr|tdS|j|d}|j|d}|j|}||jvrl|j j ||j j p3d|}|jddd}td||jf}tjd|j |||d} ||j|j} d| } | | f|j|<n|j|\} } |j|kr{| |_|r||jkrd}|j} |t|jkr|j||kr| d 7} tj| d |d } |j|kr| | ||_|| dS) NrF rz%s: %sz[%s]rz"background-color: rgb(%d, %d, %d);rJz border-bottom: none;z blame r%s)styler)rr`r&rthrrrrr7rrrrrrPrmessager short_revr!r rqrr prev_styler) rCrr_rrr chgset_href short_authorranchorcolorr blame_colr1r1r4rs@     zBlameAnnotator.annotateN)r:r;r<rDrrr1r1r1r4rs r)Hrrrfnmatchr trac.configrrr trac.coretrac.mimeview.apir r r trac.permr r trac.resourcerr trac.utilrrtrac.util.datefmtrrrrtrac.util.htmlrrrtrac.util.textrrtrac.util.translationrrtrac.versioncontrol.apirrtrac.versioncontrol.web_ui.util trac.web.apir r!trac.web.chromer"r#r$r%r&r'r(r) trac.wiki.apir*r+r,trac.wiki.formatterr-r.rf Interfacer/rDr> ComponentrErSr[rtrr1r1r1r4sB (' !!